赞
踩
人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度学习实战(不定时更新)
Anaconda3 python 3.7、TensorFlow2、CUDA10、cuDNN7.6.5
window下安装 Keras、TensorFlow(先安装CUDA、cuDNN,再安装Keras、TensorFlow)
为什么需要深度学习框架
但是如果您需要实现更复杂的模型,如卷积神经网络(CNN)或循环神经网络(RNN)时,会发现从头开始实现复杂模型是不切实际的,因此深度学习框架应运而生,它可以帮助您轻松实现您自己的神经网络:
3、PyTorch在研究领域日益占据主导地位
首先当然是先用数据说话。下图显示了顶级研究会议接受论文中,使用TensorFlow或Pythorch的比率。可以发现,所有的折线都向上倾,并且在2019年,主要会议的论文中,多数使用的都是PyTorch。
4、TensorFlow版本变化缺点
tensorflow的github地址:https://github.com/tensorflow/tensorflow
框架选择:TensorFlow 是市场需求最多,也是增长最快的框架,它的领先地位不会在短期内被颠覆。 PyTorch 也在迅速发展,它在工作列表中的大量增加证明了其使用和需求的增加。在过去的六个月里,Keras 也有了很大的发展。最后,值得注意的是,FastAI 是从较小的基数开始发展的,它是最年轻的深度学习框架。TensorFlow 和 PyTorch 都是很好的值得学习的框架。
注:前几年一直关注AI框架,但是近年来框架的同质化说明了它不再是一个需要花大精力解决的问题,TensorFlow、Pytorch这样的框架在工业界的广泛应用,以及各种框架利用 Python 在建模领域的优秀表现,已经可以帮助我们解决很多以前需要自己编程实现的问题,如果作为 AI 工程师,我们应该跳出框架的桎梏,往更广泛的领域寻找价值。
官网:https://www.tensorflow.org/, 介绍:An open source machine learning platform
TensorFlow 可以为以上的这些需求提供完整的解决方案。具体而言,TensorFlow 包含以下特性:
作为开发者和工程师你可能希望在你的产品中加入一些与人工智能相关的功能,抑或需要将已有的深度学习模型部署到各种场景中。具体而言,包括:
4.1.2.1 TF2.0 模型使用最新架构图
TensorFlow 2.0 将专注于 简单性 和 易用性,具有以下更新:
1、使用tf.data加载数据。使用输入管道读取训练数据,输入管道使用tf.data创建。利用tf.feature_column描述特征,如分段和特征交叉。
2、使用tf.keras构建、训练并验证模型,或者使用Premade Estimators。
3、使用分布式策略进行分布式训练。对于大型机器学习训练任务,分布式策略API可以轻松地在不同硬件配置上分配和训练模型,无需更改模型的定义。由于TensorFlow支持各种硬件加速器,如CPU,GPU和TPU,因此用户可以将训练负载分配到单节点/多加速器以及多节点/多加速器配置上(包括TPU Pod)。
4、导出到Saved Model。 TensorFlow将对Saved Model进行标准化,作为TensorFlow服务的一部分,他将成为TensorFlow Lite、TensorFlow.js、TensorFlow Hub等格式的可互换格式。
工作流程
API级别:其中Keras是一个用Python编写的开源神经网络库,能够在TensorFlow、Microsoft Cognitive Toolkit、Theano或PlaidML之上运行。Keras旨在快速实现深度神经网络,专注于用户友好、模块化和可扩展性,是ONEIROS(开放式神经电子智能机器人操作系统)项目研究工作的部分产.2017年,Google的TensorFlow团队决定在TensorFlow核心库中支持Keras。 Chollet解释道,Keras被认为是一个接口,而非独立的机器学习框架。它提供了更高级别、更直观的抽象集
TensorFlow提供了很多常见开源数据集,并且相应模型库也包含在TensorFlow中,用于迁移学习中重复利用模型
探索可支持和加速 TensorFlow 工作流程的工具。可以支持我们分析模型、构建流水线工程等等。
探索使用TensorFlow构建高级模型或方法的库,并访问可扩展TensorFlow的特定领域的应用程序。举几个例子
安装 TensorFlow在64 位系统上测试这些系统支持 TensorFlow:
进入虚拟环境当中再安装。刚开始的环境比较简单,只要下载tensorflow即可
安装较慢,指定镜像源,请在带有numpy等库的虚拟环境中安装
ubuntu安装
pip install tensorflow==2.0.0 -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install tensorflow-gpu==2.0.0 -i https://pypi.tuna.tsinghua.edu.cn/simple
注:如果需要下载GPU版本的(TensorFlow只提供windows和linux版本的,没有Macos版本的)参考的官网网址:https://www.tensorflow.org/install/gpu?hl=zh-cn, 这里我们给大家提供了centos的安装教程,会易懂些,参考本地文件:TensorFlow2.0GPU安装教程.pdf
拓展:
1、TensorFlow 所需的硬件配置
在很多人的刻板印象中,TensorFlow 乃至深度学习是一件非常 “吃硬件” 的事情,以至于一接触 TensorFlow,第一件事情可能就是想如何升级自己的电脑硬件。不过,TensorFlow 所需的硬件配置很大程度是视任务和使用环境而定的:
- 对于 TensorFlow 初学者,大部分教学示例,大部分当前主流的个人电脑(即使没有 GPU)均可胜任,无需添置其他硬件设备。如果涉及计算量较大的示例(例如 在 cats_vs_dogs 数据集上训练 CNN 图像分类),一块主流的 NVIDIA GPU 会大幅加速训练。如果自己的个人电脑难以胜任,可以考虑在云端训练
- 对于参加数据科学竞赛(比如 Kaggle)或者经常在本机进行训练的个人爱好者或开发者,一块高性能的 NVIDIA GPU 往往是必要的。核心数和显存大小是决定显卡机器学习性能的两个关键参数,前者决定训练速度,后者决定可以训练多大的模型以及训练时的最大 Batch Size,对于较大规模的训练而言尤其敏感。
- 对于前沿的机器学习研究(尤其是计算机视觉和自然语言处理领域),多 GPU 并行训练是标准配置。为了快速迭代实验结果以及训练更大规模的模型以提升性能,4 卡、8 卡或更高达到10块的 GPU 数量是常态。
2、常见显卡速度对比,以及目前较好的显卡对比,详情请参考官网:https://developer.nvidia.com/cuda-gpus
CUDA compute capability,这是英伟达公司对显卡计算能力的一个衡量指标;
FLOPS 每秒浮点运算次数,TFLOPS表示每秒万亿(10^12)次浮点计算;
显存大小也决定了实验中能够使用的样本数量和模型复杂度, 越高越好。
两种主要系列:
GTX 系列显卡优缺点:优点:单精度计算能力强大,显存最大12Gb,性价比高;缺点:双精度计算能力弱,没有计算纠错ECC 内存,对于超高精度计算不利
Tesla 优缺点优点:双精度计算能力最强,拥有ECC内存增强计算准确率,缺点:单精度计算能力差,价格较高
GeForce and TITAN 系列:
GPU Compute Capability NVIDIA TITAN RTX 7.5 Geforce RTX 2080 Ti 7.5 Geforce RTX 2080 7.5 Geforce RTX 2070 7.5 Geforce RTX 2060 7.5 NVIDIA TITAN V 7.0 NVIDIA TITAN Xp 6.1 NVIDIA TITAN X 6.1 GeForce GTX 1080 Ti 6.1 Tesla系列:
GPU Compute Capability Tesla T4 7.5 Tesla V100 7.0 Tesla P100 6.0 Tesla P40 6.1 Tesla P4 6.1 Tesla M60 5.2 Tesla M40 5.2 Tesla K80 3.7 Tesla K40 3.5
Keras是一个用Python编写的开源神经网络库。它能够运行在TensorFlow,Microsoft Cognitive Toolkit,Theano或PlaidML之上。TensorFlow 1.9 新增 tf.keras,Keras与TF的深度集成。
在如今无数深度学习框架中,为什么要使用 Keras 而非其他?以下是 Keras 与现有替代品的一些比较。
因为 Keras 与底层深度学习语言(特别是 TensorFlow)集成在一起,所以它可以让你实现任何你可以用基础语言编写的东西。特别是,tf.keras
作为 Keras API 可以与 TensorFlow 工作流无缝集成。
Keras 被工业界和学术界广泛采用
截至 2018 年中期,Keras 拥有超过 250,000 名个人用户。与其他任何深度学习框架相比,Keras 在行业和研究领域的应用率更高(除 TensorFlow 之外,且 Keras API 是 TensorFlow 的官方前端,通过 tf.keras
模块使用)。
Keras 拥有强大的多 GPU 和分布式训练支持
Keras 的发展得到深度学习生态系统中的关键公司的支持
Keras API 以 tf.keras
的形式包装在 TensorFlow 中。
4.1.4.1 tf.keras与keras API
keras与tf.keras相关API设置一样,主要有以下常用模块
applications
模块:Keras应用程序是具有预训练权重的固定架构。
callbacks
module:回调:在模型训练期间在某些点调用的实用程序。
datasets
module:Keras内置数据集。
initializers
模块:Keras初始化器序列化/反序列化。
layers
模块:Keras层API。
losses
模块:内置损失功能。
metrics
模块:内置指标。
models
module:模型克隆代码,以及与模型相关的API。
optimizers
module:内置优化器类。
preprocessing
模块:Keras数据预处理工具。
regularizers
模块:内置正规化器。
utils
模块:Keras实用程序。
4.1.4.2 tf.keras 数据集
1、CIFAR10 小图片分类数据
50000张32x32大小的训练数据和10000张测试数据,总共100个类别。
- from keras.datasets import cifar100
-
- (x_train, y_train), (x_test, y_test) = cifar100.load_data()
image_data_format
后端设定的 channels_first
或 channels_last
。- 1、默认下载置于用户目录的 `.keras/dataset` 目录下(Windows 下用户目录为 C:\Users\用户名 ,Linux 下用户目录为 `/home/用户名` )
- 2、mnist = tf.keras.datasets.mnist将从网络上自动下载 MNIST 数据集并加载。如果运行时出现网络连接错误,可以从 https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz 或 https://s3.amazonaws.com/img-datasets/mnist.npz 下载 MNIST 数据集 mnist.npz文件
2、时装分类Mnist数据集
60,000张28x28总共10个类别的灰色图片,10,000张用于测试。
类别编号 | 类别 |
---|---|
0 | T-shirt/top |
1 | Trouser |
2 | Pullover |
3 | Dress |
4 | Coat |
5 | Sandal |
6 | Shirt |
7 | Sneaker |
8 | Bag |
9 | Ankle boot |
- from keras.datasets import fashion_mnist
-
- (x_train, y_train), (x_test, y_test) = fashion_mnist.load_data()
TensorFlow 视为一个科学计算库。导入TensorFlow
import tensorflow as tf
TensorFlow 使用 张量 (Tensor)作为数据的基本单位。TensorFlow 的张量在概念上等同于多维数组,我们可以使用它来描述数学中的标量(0 维数组)、向量(1 维数组)、矩阵(2 维数组)等各种量,示例如下:
- # 定义一个随机数(标量)
- random_float = tf.random.uniform(shape=())
-
- # 定义一个有2个元素的零向量
- zero_vector = tf.zeros(shape=(2))
-
- # 定义两个2×2的常量矩阵
- A = tf.constant([[1., 2.], [3., 4.]])
- B = tf.constant([[5., 6.], [7., 8.]])
张量的重要属性是其形状、类型和值。可以通过张量的 shape
、 dtype
属性和 numpy()
方法获得。例如:
- # 查看矩阵A的形状、类型和值
- print(A.shape) # 输出(2, 2),即矩阵的长和宽均为2
- print(A.dtype) # 输出<dtype: 'float32'>
- print(A.numpy()) # 输出[[1. 2.]
- # [3. 4.]]
类型变换
张量的数学运算
算术运算符
参考官网链接:https://www.tensorflow.org/api_docs/python/tf/Tensor
在机器学习中,我们经常需要计算函数的导数。TensorFlow 提供了强大的自动求导机制来计算导数。
- import tensorflow as tf
-
- x = tf.Variable(initial_value=3.)
- with tf.GradientTape() as tape: # 在 tf.GradientTape() 的上下文内,所有计算步骤都会被记录以用于求导
- y = tf.square(x)
- y_grad = tape.gradient(y, x) # 计算y关于x的导数
- print([y, y_grad])
输出:
[array([9.], dtype=float32), array([6.], dtype=float32)]
1、这里x是一个初始化为 3 的 变量 (Variable),使用 tf.Variable()声明。与普通张量一样,变量同样具有形状、类型和值三种属性。使用变量需要有一个初始化过程,可以通过在 tf.Variable()中指定 initial_value
参数来指定初始值。
tf.GradientTape()
是一个自动求导的记录器,在其中的变量和计算步骤都会被自动记录。在上面的示例中,变量 x和计算步骤 y = tf.square(x)
被自动记录,因此可以通过 y_grad = tape.gradient(y, x)
求张量 y
对变量 x
的导数。
通常我们实际应用中更多的是对多元函数求偏导数,以及对向量或矩阵的求导。如下面例子:
- X = tf.constant([[1, 2], [3., 4.]])
- y = tf.constant([[1], [2.]])
- w = tf.Variable(initial_value=[[1.], [2.]])
- b = tf.Variable(initial_value=1.)
- with tf.GradientTape() as tape:
- L = 0.5 * tf.reduce_sum(tf.square(tf.matmul(X, w) + b - y))
- w_grad, b_grad = tape.gradient(L, [w, b])
- print([L.numpy(), w_grad.numpy(), b_grad.numpy()])
输出:
- [62.5, array([[35.],
- [50.]], dtype=float32), 15.0]
求导公式如下:
axis
参数来指定求和的维度,不指定则默认对所有元素求和)考虑一个实际问题,某城市在 2013 年 - 2017 年的房价如下表所示:
年份 | 2013 | 2014 | 2015 | 2016 | 2017 |
---|---|---|---|---|---|
房价 | 12000 | 14000 | 15000 | 16500 | 17500 |
现在,我们希望通过对该数据进行线性回归,即使用线性模型y = ax + by=ax+b来拟合上述数据,此处 a
和 b
是待求的参数。首先,我们定义数据,进行基本的归一化操作。
- import numpy as np
-
- X_raw = np.array([2013, 2014, 2015, 2016, 2017], dtype=np.float32)
- y_raw = np.array([12000, 14000, 15000, 16500, 17500], dtype=np.float32)
-
- X = (X_raw - X_raw.min()) / (X_raw.max() - X_raw.min())
- y = (y_raw - y_raw.min()) / (y_raw.max() - y_raw.min())
https://zh.wikipedia.org/wiki/%E6%A2%AF%E5%BA%A6%E4%B8%8B%E9%99%8D%E6%B3%95
1、NumPy 下的线性回归
NumPy 提供了多维数组支持,可以表示向量、矩阵以及更高维的张量。下面为实现过程:
- a, b = 0, 0
- num_epoch = 10000
- learning_rate = 1e-3
- for e in range(num_epoch):
- # 手动计算损失函数关于自变量(模型参数)的梯度
- y_pred = a * X + b
- grad_a, grad_b = (y_pred - y).dot(X), (y_pred - y).sum()
-
- # 更新参数
- a, b = a - learning_rate * grad_a, b - learning_rate * grad_b
- print(a, b)
使用常规的科学计算库实现机器学习模型的问题:
而 TensorFlow 等深度学习框架的出现很大程度上解决了这些痛点,为机器学习模型的实现带来了很大的便利。
2、TensorFlow 下的线性回归
TensorFlow 的 Eager Execution(动态图)模式与上述 NumPy 的运行方式十分类似,然而提供了更快速的运算(GPU 支持)、自动求导、优化器等一系列对深度学习非常重要的功能。
tape.gradient(ys, xs)
自动计算梯度;optimizer.apply_gradients(grads_and_vars)
自动更新模型参数。tf.keras.optimizers.SGD(learning_rate=)
进行指定优化器- # 1、定义Tensor类型
- X = tf.constant(X)
- y = tf.constant(y)
-
- # 2、参数使用变量初始化
- a = tf.Variable(initial_value=0.)
- b = tf.Variable(initial_value=0.)
- variables = [a, b]
-
- num_epoch = 10000
- optimizer = tf.keras.optimizers.SGD(learning_rate=1e-3)
- for e in range(num_epoch):
- # 使用tf.GradientTape()记录损失函数的梯度信息
- with tf.GradientTape() as tape:
- y_pred = a * X + b
- loss = 0.5 * tf.reduce_sum(tf.square(y_pred - y))
- # TensorFlow自动计算损失函数关于自变量(模型参数)的梯度
- grads = tape.gradient(loss, variables)
- # TensorFlow自动根据梯度更新参数
- optimizer.apply_gradients(grads_and_vars=zip(grads, variables))
-
- print(a, b)
tf.keras.optimizers.SGD(learning_rate=1e-3)
声明了一个梯度下降 优化器 (Optimizer),其学习率为 1e-3。优化器可以帮助我们根据计算出的求导结果更新模型参数,从而最小化某个特定的损失函数,具体使用方式是调用其 apply_gradients()
方法。optimizer.apply_gradients()
需要提供参数 grads_and_vars
,具体而言,这里需要传入一个 Python 列表(List),列表中的每个元素是一个 (变量的偏导数,变量) 对,比如这里是 [(grad_a, a), (grad_b, b)]。在实际应用中,我们编写的模型往往比这里一行就能写完的线性模型 y = a * x + b 要复杂得多。所以,我们往往会编写并实例化一个模型类model = Model(),然后使用 y_pred = model(X)调用模型,使用 model.variables
获取模型参数。
gradient.py
- import tensorflow as tf
-
-
- def main():
-
- # 1、单变量函数导数 y = x^2
- # x = tf.Variable(initial_value=3.)
- #
- # with tf.GradientTape() as tape:
- # y = tf.square(x)
- #
- # # 使用tape中的gradient的方法计算导数
- # y_grad = tape.gradient(y, x)
- # print(y, y_grad)
-
- # 2、多元函数求导
- # X = tf.constant([[1., 2.], [3., 4.]])
- # # y = tf.constant([[1.], [2.]])
- # # # 函数参数
- # # w = tf.Variable(initial_value=[[1.], [2.]])
- # # b = tf.Variable(initial_value=1.)
- # #
- # # with tf.GradientTape() as tape:
- # # L = 0.5 * tf.reduce_sum(tf.square(tf.matmul(X, w) + b - y))
- # #
- # # w_grad, b_grad = tape.gradient(L, [w, b])
- # # print(L.numpy(), w_grad.numpy(), b_grad.numpy())
-
- # 3、线性回归求解模型参数
- import numpy as np
-
- X_raw = np.array([2013, 2014, 2015, 2016, 2017], dtype=np.float32)
- y_raw = np.array([12000, 14000, 15000, 16500, 17500], dtype=np.float32)
-
- X = (X_raw - X_raw.min()) / (X_raw.max() - X_raw.min())
- y = (y_raw - y_raw.min()) / (y_raw.max() - y_raw.min())
-
-
- # 1、定义好数据类型以及参数类型
- X = tf.constant(X)
- y = tf.constant(y)
-
- a = tf.Variable(initial_value=0.)
- b = tf.Variable(initial_value=0.)
- variables = [a, b]
-
- # 2、应用gradientTape进行迭代计算导数更新
- num_epoch = 1000
- optimizer = tf.keras.optimizers.SGD(learning_rate=1e-3)
- for i in range(num_epoch):
- # gradientTape
- with tf.GradientTape() as tape:
- y_pred = a * X + b
- loss = 0.5 * tf.reduce_sum(tf.square(y_pred - y))
-
- # tensorflow自动求导
- grads = tape.gradient(loss, variables)
-
- # 进行梯度更新参数
- optimizer.apply_gradients(grads_and_vars=zip(grads, variables))
-
- print(a, b)
- return None
-
-
- # 1、定义一个线性回归模型
- class Linear(tf.keras.Model):
- """自定义线性回归类
- """
- def __init__(self):
- super(Linear, self).__init__()
- # 实现一个线性回归层
- self.dense = tf.keras.layers.Dense(
- units=1,
- activation=None,
- kernel_initializer=tf.zeros_initializer(),
- bias_initializer=tf.zeros_initializer()
- )
-
- def call(self, input):
- """调用模型的实现函数
- :param input: 模型输入值
- :return: 模型输出值
- """
- output = self.dense(input)
- return output
-
-
- def linear_with_model():
-
- X = tf.constant([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
- y = tf.constant([[10.0], [20.0]])
-
- # 2、进行训练步骤定义
- model = Linear()
- optimizer = tf.keras.optimizers.SGD(learning_rate=0.01)
- for i in range(100):
- with tf.GradientTape() as tape:
- y_pred = model(X)
- loss = 0.5 * tf.reduce_mean(tf.square(y_pred - y))
-
- # 梯度计算和更新
- grads = tape.gradient(loss, model.variables)
- optimizer.apply_gradients(grads_and_vars=zip(grads, model.variables))
-
- print(model.variables)
- print(model.layers)
- print(model.inputs)
- print(model.outputs)
- print(model.summary())
- return None
-
-
- if __name__ == '__main__':
- # main()
- linear_with_model()
在 TensorFlow 中,推荐使用 Keras( tf.keras)构建模型。Keras 是一个广为流行的高级神经网络 API,简单、快速而不失灵活性,现已得到 TensorFlow 的官方内置和全面支持。
Keras 有两个重要的概念: 模型(Model) 和 层(Layer) 。
Keras 模型以类的形式呈现,我们可以通过继承 tf.keras.Model这个 Python 类来定义自己的模型。在继承类中,我们需要重写 __init__()
(构造函数,初始化)和 call(input)
(模型调用)两个方法,同时也可以根据需要增加自定义的方法。
- class MyModel(tf.keras.Model):
- def __init__(self):
- super().__init__()
- # 此处添加初始化代码(包含 call 方法中会用到的层),例如
- # layer1 = tf.keras.layers.BuiltInLayer(...)
- # layer2 = MyCustomLayer(...)
-
- def call(self, input):
- # 此处添加模型调用的代码(处理输入并返回输出),例如
- # x = layer1(input)
- # output = layer2(x)
- return output
-
- # 还可以添加自定义的方法
继承 tf.keras.Model
后,我们同时可以使用父类的若干方法和属性,例如在实例化类 model = Model()
后,可以通过 model.variables
这一属性直接获得模型中的所有变量,免去我们一个个显式指定变量的麻烦。
对于上面的 y_pred = w * X + b ,我们可以通过模型类的方式编写如下:
- import tensorflow as tf
-
- X = tf.constant([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
- y = tf.constant([[10.0], [20.0]])
-
- # 1、构建线性模型
- class Linear(tf.keras.Model):
- def __init__(self):
- super().__init__()
- self.dense = tf.keras.layers.Dense(
- units=1,
- activation=None,
- kernel_initializer=tf.zeros_initializer(),
- bias_initializer=tf.zeros_initializer()
- )
-
- def call(self, input):
- output = self.dense(input)
- return output
-
-
- # 以下代码结构与前节类似
- model = Linear()
- optimizer = tf.keras.optimizers.SGD(learning_rate=0.01)
- for i in range(100):
- with tf.GradientTape() as tape:
- y_pred = model(X)
- loss = 0.5 * tf.reduce_mean(tf.square(y_pred - y))
- # 使用 model.variables 这一属性直接获得模型中的所有变量
- grads = tape.gradient(loss, model.variables)
- optimizer.apply_gradients(grads_and_vars=zip(grads, model.variables))
- print(model.variables)
这里,我们没有显式地声明a 和 b 两个变量并写出 y_pred = wX + b 这一线性变换,而是建立了一个继承了 tf.keras.Model
的模型类 Linear
。这个类在初始化部分实例化了一个 全连接层 ( tf.keras.layers.Dense
),并在 call 方法中对这个层进行调用,实现了线性变换的计算。
在 Keras 中,您可以通过组合层来构建模型。模型(通常)是由层构成的图。最常见的模型类型是层的堆叠,keras.layers中就有很多模型
- from tensorflow.python.keras.layers import Dense
- from tensorflow.python.keras.layers import DepthwiseConv2D
- from tensorflow.python.keras.layers import Dot
- from tensorflow.python.keras.layers import Dropout
- from tensorflow.python.keras.layers import ELU
- from tensorflow.python.keras.layers import Embedding
- from tensorflow.python.keras.layers import Flatten
- from tensorflow.python.keras.layers import GRU
- from tensorflow.python.keras.layers import GRUCell
- from tensorflow.python.keras.layers import LSTMCell
Dense:添加一层神经元
4.3.1.2 Models
Model(inputs=a, outputs=b)
Models属性
model.layers
:获取模型结构列表- print(model.layers)
- [<tensorflow.python.keras.layers.core.Flatten object at 0x10864a780>, <tensorflow.python.keras.layers.core.Dense object at 0x10f95b128>, <tensorflow.python.keras.layers.core.Dense object at 0x125bd6fd0>, <tensorflow.python.keras.layers.core.Dense object at 0x125bf9240>]
model.inputs
是模型的输入张量列表- print(model.inputs)
- [<tf.Tensor 'flatten_input:0' shape=(?, 28, 28) dtype=float32>]
model.outputs
是模型的输出张量列表- print(model.outputs)
- [<tf.Tensor 'dense_2/Softmax:0' shape=(?, 10) dtype=float32>]
model.summary()
打印模型的摘要表示- Layer (type) Output Shape Param #
- =================================================================
- flatten (Flatten) (None, 784) 0
- _________________________________________________________________
- dense (Dense) (None, 64) 50240
- _________________________________________________________________
- dense_1 (Dense) (None, 128) 8320
- _________________________________________________________________
- dense_2 (Dense) (None, 10) 1290
- =================================================================
- Total params: 59,850
- Trainable params: 59,850
- Non-trainable params: 0
一个最简单的多层感知机(Multilayer Perceptron, MLP),或者说 “多层全连接神经网络” 开始,介绍 TensorFlow 的模型编写方式。
目的:我们使用多层感知机完成 MNIST 手写体数字图片数据集的分类任务
步骤:
tf.keras.datasets
获得数据集并预处理tf.keras.Model
和 tf.keras.layers
构建模型tf.keras.losses
计算损失函数,并使用 tf.keras.optimizer
优化模型tf.keras.metrics
计算评估指标1、数据获取及预处理: tf.keras.datasets
先进行预备工作,实现一个简单的 MNISTLoader
类来读取 MNIST 数据集数据。这里使用了 tf.keras.datasets
快速载入 MNIST 数据集。
- import tensorflow as tf
- import numpy as np
- class MNISTLoader(object):
- """数据加载处理类
- """
- def __init__(self):
- """
- """
- # 1、获取数据
- (self.train_data, self.train_label), (self.test_data, self.test_label) = tf.keras.datasets.mnist.load_data()
- # 2、处理数据,归一化,维度以及类型
- # MNIST中的图像默认为uint8(0-255的数字)。以下代码将其归一化到0-1之间的浮点数,并在最后增加一维作为颜色通道
- # 默认下载是(60000, 28, 28),扩展到四维方便计算理解[60000, 28, 28, 1]
- self.train_data = np.expand_dims(self.train_data.astype(np.float32) / 255.0, axis=-1)
- # [10000, 28, 28, 1]
- self.test_data = np.expand_dims(self.test_data.astype(np.float32) / 255.0, axis=-1)
- self.train_label = self.train_label.astype(np.int32) # [60000]
- self.test_label = self.test_label.astype(np.int32) # [10000]
- # 获取数据的大小
- self.num_train_data, self.num_test_data = self.train_data.shape[0], self.test_data.shape[0]
-
- def get_batch(self, batch_size):
- """
- 随机获取获取批次数据
- :param batch_size: 批次大小
- :return:
- """
- # 从数据集中随机取出batch_size个元素并返回
- index = np.random.randint(0, np.shape(self.train_data)[0], batch_size)
- return self.train_data[index, :], self.train_label[index]
-
-
- if __name__ == '__main__':
- mnist = MNISTLoader()
- train_data, train_label = mnist.get_batch(50)
- print(train_data.shape, train_label)
注:在 TensorFlow 中,图像数据集的一种典型表示是 [图像数目,长,宽,色彩通道数]的四维张量。
2、模型的构建:tf.keras.Model 和 tf.keras.layers
多层感知机的模型类实现与上面的线性模型类似,使用 tf.keras.Model 和 tf.keras.layers 构建,引入了非线性激活函数(这里使用了 ReLU 函数 , 即下方的 activation=tf.nn.relu ),模型输出 10 维的向量,分别代表这张图片属于 0 到 9 的概率。
- class MLP(tf.keras.Model):
- """自定义MLP类
- """
- def __init__(self):
- super().__init__()
- # 定义两层神经网络,第一层100个神经元,激活函数relu,第二层10个神经元输出给softmax
- self.flatten = tf.keras.layers.Flatten()
- self.dense1 = tf.keras.layers.Dense(units=100, activation=tf.nn.relu)
- self.dense2 = tf.keras.layers.Dense(units=10)
-
- def call(self, inputs):
- # [batch_size, 28, 28, 1]
- x = self.flatten(inputs)
- # [batch_size, 784]
- x = self.dense1(x)
- # [batch_size, 100]
- x = self.dense2(x)
- # [batch_size, 10]
- output = tf.nn.softmax(x)
- return output
3、模型的训练: tf.keras.losses 和 tf.keras.optimizer
定义一些模型超参数:
- num_epochs = 5
- batch_size = 50
- learning_rate = 0.001
然后迭代进行以下步骤:
1、从 DataLoader 中随机取一批训练数据;
2、将这批数据送入模型,计算出模型的预测值;
3、将模型预测值与真实值进行比较,计算损失函数(loss)。这里使用 tf.keras.losses 中的交叉熵函数作为损失函数;
4、计算损失函数关于模型变量的导数;
5、将求出的导数值传入优化器,使用优化器的 apply_gradients 方法更新模型参数以最小化损失函数(优化器的详细使用方法见 前章 )。
具体代码实现
- # 实例化模型和数据读取类,并实例化一个优化器,这里使用 Adam 优化器
- model = MLP()
- data_loader = MNISTLoader()
- optimizer = tf.keras.optimizers.Adam(learning_rate=learning_rate)
- # 计算出大概需要迭代批次大小
- num_batches = int(data_loader.num_train_data // batch_size * num_epochs)
- # 进行批次数据获取
- for batch_index in range(num_batches):
- X, y = data_loader.get_batch(batch_size)
- with tf.GradientTape() as tape:
- y_pred = model(X)
- # 使用tf.keras.losses计算损失
- loss = tf.keras.losses.sparse_categorical_crossentropy(y_true=y, y_pred=y_pred)
- # 求出平均损失
- loss = tf.reduce_mean(loss)
- print("batch %d: loss %f" % (batch_index, loss.numpy()))
- grads = tape.gradient(loss, model.variables)
- optimizer.apply_gradients(grads_and_vars=zip(grads, model.variables))
注:在 tf.keras中,有两个交叉熵相关的损失函数 tf.keras.losses.categorical_crossentropy 和 tf.keras.losses.sparse_categorical_crossentropy 。其中 sparse 的含义是,真实的标签值 y_true可以直接传入 int 类型的标签类别。具体而言:
loss = tf.keras.losses.sparse_categorical_crossentropy(y_true=y, y_pred=y_pred)
与
loss = tf.keras.losses.categorical_crossentropy( y_true=tf.one_hot(y, depth=tf.shape(y_pred)[-1]), y_pred=y_pred )的结果相同。
4、模型的评估: tf.keras.metrics
最后,我们使用测试集评估模型的性能。这里,我们使用 tf.keras.metrics 中的 SparseCategoricalAccuracy 评估器来评估模型在测试集上的性能。
在以下代码中,我们实例化了一个 tf.keras.metrics.SparseCategoricalAccuracy 评估器,并使用 For 循环迭代分批次传入了测试集数据的预测结果与真实结果,并输出训练后的模型在测试数据集上的准确率。
- y_pred = model.predict(data_loader.test_data)
- # 定义评估函数
- sparse_categorical_accuracy = tf.keras.metrics.SparseCategoricalAccuracy()
- # 定义测试数据集一共批次的大小
- sparse_categorical_accuracy.update_state(y_true=data_loader.test_label, y_pred=y_pred)
- print("测试准确率: %f" % sparse_categorical_accuracy.result())
输出结果:
测试准确率: 0.972300
tf.keras.Model
和 tf.keras.layers
tf.keras.losses
tf.keras.optimizer
tf.keras.metrics
keras_mlp.py
- import tensorflow as tf
- import numpy as np
- import os
- os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2"
-
- num_epochs = 5
- batch_size = 64
- learning_rate = 0.001
-
-
- class MnistLoader(object):
- """数据加载处理类
- """
- def __init__(self):
- # 1、获取数据
- (self.train_data, self.train_label), (self.test_data, self.test_label) = \
- tf.keras.datasets.mnist.load_data()
-
- # 2、处理数据, 归一化,维度拓展,类型
- self.train_data = np.expand_dims(self.train_data.astype(np.float32) / 255.0, axis=-1)
- self.test_data = np.expand_dims(self.test_data.astype(np.float32) / 255.0, axis=-1)
-
- self.train_label = self.train_label.astype(np.int32)
- self.test_label = self.test_label.astype(np.int32)
-
- # 获取一个变量接收数据量
- self.num_train_data, self.num_test_data = self.train_data.shape[0], self.test_data.shape[0]
-
- def get_batch(self, batch_size):
- """按照训练获取指定大小数据的批次数据
- :param batch_size: 每批次数据的大小
- :return:
- """
- # 获取随机生成的batch_size大小的下标
- index = np.random.randint(0, self.train_data.shape[0], batch_size)
- return self.train_data[index, :], self.train_label[index]
-
-
- class MLP(tf.keras.Model):
- """自定义MLP类
- """
- def __init__(self):
- super().__init__()
- # 卷积到全连接层的数据形状处理
- self.flatten = tf.keras.layers.Flatten()
- self.dense1 = tf.keras.layers.Dense(units=100, activation=tf.nn.relu)
- self.dense2 = tf.keras.layers.Dense(units=10)
-
- def call(self, inputs):
- """
- :param inputs: 模型的输入
- :return:
- """
- # 此例子中输入[batch_size, 28 ,28, 1]
- x = self.flatten(inputs)
- x = self.dense1(x)
- x = self.dense2(x)
-
- # 经过softmax计算[batch_size, 10]
- output = tf.nn.softmax(x)
- return output
-
-
- class CNN(tf.keras.Model):
- """自定义CNN类,两层卷积池化+两个全连接层
- """
- def __init__(self):
- super().__init__()
- # 两层卷积池化+两个全连接层
- # [batch_size, 28 ,28, 1]--->[batch_size, 14, 14, 32]
- # 第一层:32个filter, 5 * 5, padding=same
- self.conv1 = tf.keras.layers.Conv2D(
- filters=32, # 卷积核数量
- kernel_size=[5, 5], # 卷积核大小
- padding='same', # 领填充方式
- activation=tf.nn.relu # 激活函数
- )
- self.pool1 = tf.keras.layers.MaxPool2D(pool_size=[2, 2], strides=2)
-
- # 第二层:64个filter, 5 * 5, padding=same
- # [batch_size, 14 ,14, 32]--->[batch_size, 7, 7, 64]
- self.conv2 = tf.keras.layers.Conv2D(
- filters=64, # 卷积核数量
- kernel_size=[5, 5], # 卷积核大小
- padding='same', # 领填充方式
- activation=tf.nn.relu # 激活函数
- )
- self.pool2 = tf.keras.layers.MaxPool2D(pool_size=[2, 2], strides=2)
-
- # 经过一个形状变化在输入到全连接层网络
- self.flatten = tf.keras.layers.Reshape(target_shape=(7 * 7 * 64,))
- self.dense1 = tf.keras.layers.Dense(units=1024, activation=tf.nn.relu)
- self.dense2 = tf.keras.layers.Dense(units=10)
-
- def call(self, inputs):
- """模型输入输出构建
- :param inputs: 输入[batch_size, 28 ,28, 1]
- :return:
- """
- x = self.conv1(inputs)
- x = self.pool1(x)
- x = self.conv2(x)
- x = self.pool2(x)
- x = self.flatten(x)
- x = self.dense1(x)
- x = self.dense2(x)
- output = tf.nn.softmax(x)
- return output
-
-
- def train():
- """模型训练逻辑
- :return:
- """
-
- # 1、从 DataLoader 中随机取一批训练数据,并且初始化模型
- mnist = MnistLoader()
- # model = MLP()
- model = CNN()
- optimizer = tf.keras.optimizers.Adam(learning_rate=learning_rate)
-
- # 2、将这批数据送入模型,计算出模型的预测值;
- # 总共样本len(train_data), 迭代次数epoches表示所有数据过几遍,batch_size:每批次训练的样本32, 64
- # 一共需要多少批次 len(train_data)/ batch_size * epoches举例 1000/10 = 10批次才训练完成,10 * 5
- num_batches = int(mnist.num_train_data // batch_size * num_epochs)
- for batch_index in range(num_batches):
- X, y = mnist.get_batch(batch_size)
- with tf.GradientTape() as tape:
- y_pred = model(X)
-
- # 3、将模型预测值与真实值进行比较,计算损失函数(loss)。这里使用
- # tf.keras.losses 中的交叉熵函数作为损失函数;
- loss = tf.reduce_mean(tf.keras.losses.sparse_categorical_crossentropy(y_true=y, y_pred=y_pred))
- print("批次 %d: 损失 %f" % (batch_index, loss.numpy()))
-
- # 4、计算损失函数关于模型变量的导数;
- grads = tape.gradient(loss, model.variables)
-
- # 5、将求出的导数值传入优化器,使用优化器的 apply_gradients 方法更新模型参数以最小化损失函数(优化器的详细使用方法见 前章 )。
- optimizer.apply_gradients(grads_and_vars=zip(grads, model.variables))
-
- # 3、对测试数据及进行评估
- y_pred = model.predict(mnist.test_data)
- # 初始化一个metrics
- sparse_categorical_accuracy = tf.keras.metrics.SparseCategoricalAccuracy()
- sparse_categorical_accuracy.update_state(y_true=mnist.test_label, y_pred=y_pred)
- print("测试准确率:%f" % (sparse_categorical_accuracy.result()))
-
- return None
-
-
- if __name__ == '__main__':
- # mnist = MnistLoader()
- # train_data, train_label = mnist.get_batch(64)
- # print(train_data, train_label)
- train()
tfrecords_example.py
- import os
- import tensorflow as tf
- import os
- os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2"
-
- train_cats_dir = './cats_vs_dogs/train/cats/'
- train_dogs_dir = './cats_vs_dogs/train/dogs/'
- tfrecord_file = './cats_vs_dogs/train.tfrecords'
-
-
- def main():
-
- train_cat_filenames = [train_cats_dir + filename for filename in os.listdir(train_cats_dir)]
- train_dog_filenames = [train_dogs_dir + filename for filename in os.listdir(train_dogs_dir)]
- train_filenames = train_cat_filenames + train_dog_filenames
- # 将 cat 类的标签设为0,dog 类的标签设为1
- train_labels = [0] * len(train_cat_filenames) + [1] * len(train_dog_filenames)
-
- with tf.io.TFRecordWriter(tfrecord_file) as writer:
- for filename, label in zip(train_filenames, train_labels):
- # 1、读取数据集图片到内存,image 为一个 Byte 类型的字符串
- image = open(filename, 'rb').read()
- # 2、建立 tf.train.Feature 字典
- feature = {
- 'image': tf.train.Feature(bytes_list=tf.train.BytesList(value=[image])), # 图片是一个 Bytes 对象
- 'label': tf.train.Feature(int64_list=tf.train.Int64List(value=[label])) # 标签是一个 Int 对象
- }
- # 3、通过字典建立 Example
- example = tf.train.Example(features=tf.train.Features(feature=feature))
- # 4\将Example序列化并写入 TFRecord 文件
- writer.write(example.SerializeToString())
-
-
- def read():
-
- # 1、读取 TFRecord 文件
- raw_dataset = tf.data.TFRecordDataset(tfrecord_file)
-
- # 2、定义Feature结构,告诉解码器每个Feature的类型是什么
- feature_description = {
- 'image': tf.io.FixedLenFeature([], tf.string),
- 'label': tf.io.FixedLenFeature([], tf.int64),
- }
-
- # 3、将 TFRecord 文件中的每一个序列化的 tf.train.Example 解码
- def _parse_example(example_string):
- feature_dict = tf.io.parse_single_example(example_string, feature_description)
- feature_dict['image'] = tf.io.decode_jpeg(feature_dict['image']) # 解码JPEG图片
- return feature_dict['image'], feature_dict['label']
-
- dataset = raw_dataset.map(_parse_example)
-
- for image, label in dataset:
- print(image, label)
-
-
- if __name__ == '__main__':
- # main()
- read()
model_serving.py
- import tensorflow as tf
- import os
- os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2"
-
-
- def main():
- num_epochs = 1
- batch_size = 32
- learning_rate = 0.001
-
- model = tf.keras.models.Sequential([
- tf.keras.layers.Flatten(),
- tf.keras.layers.Dense(120, activation=tf.nn.relu),
- tf.keras.layers.Dense(100),
- tf.keras.layers.Softmax()
- ])
-
- (train, train_label), (test, test_label) = \
- tf.keras.datasets.cifar100.load_data()
-
- model.compile(
- optimizer=tf.keras.optimizers.Adam(learning_rate=learning_rate),
- loss=tf.keras.losses.sparse_categorical_crossentropy,
- metrics=[tf.keras.metrics.sparse_categorical_accuracy]
- )
- model.fit(train, train_label, epochs=num_epochs, batch_size=batch_size)
-
- tf.saved_model.save(model, "./saved/mlp/2")
-
-
- def test():
-
- model = tf.saved_model.load("./saved/mlp/2")
-
- (_, _), (test, test_label) = \
- tf.keras.datasets.cifar100.load_data()
-
- y_predict = model(test)
-
- sparse_categorical_accuracy = tf.keras.metrics.SparseCategoricalAccuracy()
- sparse_categorical_accuracy.update_state(y_true=test_label, y_pred=y_predict)
- print("测试集的准确率为: %f" % sparse_categorical_accuracy.result())
-
-
- def client():
- import json
- import numpy as np
- import requests
-
- (_, _), (test, test_label) = \
- tf.keras.datasets.cifar100.load_data()
-
- # 1、构造好请求
- data = json.dumps({"instances": test[:10].tolist()})
- headers = {"content-type": "application/json"}
-
- json_response = requests.post('http://localhost:8501/v1/models/mlp:predict',
- data=data, headers=headers)
-
- predictions = np.array(json.loads(json_response.text)['predictions'])
- print(predictions)
- print(np.argmax(predictions, axis=-1))
- print(test_label[:10])
-
-
- if __name__ == '__main__':
- # main()
- # test()
- client()
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。