TensorFlow 2.0 快速上手教程与手写数字识别例子讲解
文章目录
- TensorFlow 基础
- 自动求导机制
- 参数优化
- TensorFlow 模型建立、训练与评估
- 通用模型的类结构
- 多层感知机手写数字识别
- Keras Pipeline *
TensorFlow 2.0 出来后不久就有人整理了一份简洁高效的中文指导手册: 简单粗暴 TensorFlow 2,本文对其中一些重点内容加以梳理,方便快速上手。
如果你还没装上 TensorFlow 2.0 ,或者希望对 TensorFlow 2.0 的新特性有个大概的了解,可以查看我之前的文章:tensorflow2.0 GPU 版本安装测试教程及新特性初探
TensorFlow 基础
自动求导机制
TensorFlow 提供了强大的 自动求导机制 来计算导数。在即时执行模式(eager execution)下,TensorFlow 引入了 tf.GradientTape()
这个 “求导记录器” 来实现自动求导。以线性回归为例子,假设其损失函数为:
L(w,b)=∣∣Xw+b−y∣∣2L(w, b) = ||Xw+b-y||^2 L(w,b)=∣∣Xw+b−y∣∣2
我们用下面的代码计算给定 X 与 y 后, L(w,b)L(w,b)L(w,b) 在 w=(1,2)T,b=1w=(1,2)^T, \; b=1w=(1,2)T,b=1 时对 w,bw,bw,b 的偏导数。
import tensorflow as tfX = tf.constant([[1., 2.], [3., 4.]])
y = tf.constant([[1.], [2.]])
# 初始化要学习的参数
w = tf.Variable(initial_value=[[1.], [2.]])
b = tf.Variable(initial_value=1.)# 在 tf.GradientTape() 的上下文内,所有计算步骤都会被记录以用于求导
with tf.GradientTape() as tape:L = tf.reduce_sum(tf.square(tf.matmul(X, w) + b - y))# 计算L(w, b)关于w, b的偏导数
w_grad, b_grad = tape.gradient(L, [w, b])
print(L, w_grad, b_grad)
输出:
tf.Tensor(125.0, shape=(), dtype=float32) tf.Tensor( [[ 70.] [100.]], shape=(2, 1), dtype=float32) tf.Tensor(30.0, shape=(), dtype=float32)
从输出结果可见 TensorFlow 帮我们计算出了梯度值。
上面的代码中,变量 w 和 b 使用 tf.Variable()
申明,通过这种方式得到的变量默认能够被 TensorFlow 的自动求导机制所求导,因此往往被用于定义机器学习模型的参数。tf.GradientTape()
是一个自动求导的记录器。只要进入了 with tf.GradientTape() as tape
的上下文环境,则在该环境中计算步骤都会被自动记录。比如在上面的示例中,计算步骤 L = tf.reduce_sum(tf.square(tf.matmul(X, w) + b - y))
即被自动记录。离开上下文环境后,记录将停止,但记录器 tape
依然可用,因此可以通过 w_grad, b_grad = tape.gradient(L, [w, b])
求张量 L
对变量 w,b
的导数。
TIPS:
tf.square()
操作代表对输入张量的每一个元素求平方,不改变张量形状。tf.reduce_sum()
操作代表对输入张量的所有元素求和,输出一个形状为空的纯量张量(可以通过axis
参数来指定求和的维度,不指定则默认对所有元素求和)。TensorFlow 中有大量的张量操作 API,包括数学运算、张量形状操作(如tf.reshape()
)、切片和连接(如tf.concat()
)等多种类型
参数优化
本节以 TensorFlow 下的线性回归示例展开,讲解如何进行参数优化。
首先,我们定义数据,进行基本的归一化操作:
import numpy as npX_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())
TensorFlow 的 即时执行模式提供了更快速的GPU运算、自动求导、优化器等一系列对深度学习非常重要的功能。以下展示了如何使用 TensorFlow 计算线性回归:
X = tf.constant(X)
y = tf.constant(y)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=5e-4)
for e in range(num_epoch):# 使用tf.GradientTape()记录损失函数的梯度信息with tf.GradientTape() as tape:y_pred = a * X + bloss = tf.reduce_sum(tf.square(y_pred - y))# TensorFlow自动计算损失函数关于自变量(模型参数)的梯度grads = tape.gradient(loss, variables)# TensorFlow自动根据梯度更新参数optimizer.apply_gradients(grads_and_vars=zip(grads, variables))
在这里,我们使用了前文的方式计算了损失函数关于参数的偏导数。同时,使用 tf.keras.optimizers.SGD(learning_rate=5e-4)
声明了一个梯度下降 优化器 (Optimizer),其学习率为 5e-4。优化器可以帮助我们根据计算出的求导结果更新模型参数,从而最小化某个特定的损失函数,具体使用方式是调用其 apply_gradients()
方法。
注意到 optimizer.apply_gradients()
需要提供参数 grads_and_vars
,即待更新的变量(如上述代码中的 variables
)及损失函数关于这些变量的偏导数(如上述代码中的 grads
)。具体而言,这里需要传入一个 Python 列表(List),列表中的每个元素是一个 (变量的偏导数,变量)
对。比如上例中需要传入的参数是 [(grad_a, a), (grad_b, b)]
。我们通过 grads = tape.gradient(loss, variables)
求出 tape 中记录的 loss
关于 variables = [a, b]
中每个变量的偏导数,也就是 grads = [grad_a, grad_b]
,再使用 Python 的 zip()
函数将 grads = [grad_a, grad_b]
和 variables = [a, b]
拼装在一起,就可以组合出所需的参数了。
接下来的部分,是一个更正式的例子。
TensorFlow 模型建立、训练与评估
在 TensorFlow2.0 中,比较推荐使用 Keras( tf.keras
)构建模型。Keras 在 tf.keras.layers
下内置了深度学习中大量常用的的预定义层(例如基本的全连接层,CNN 的卷积层、池化层等),同时也允许我们自定义层。
通用模型的类结构
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
这一属性直接获得模型中的所有变量,免去我们一个个显式指定变量的麻烦。
TIPS:前面的文章说到,在计算梯度的时候,需要传递要计算梯度的变量,这些变量可以通过
model.variables
一次性获取。
多层感知机手写数字识别
下面以多层感知机实现手写数字识别为例子,讲解如何构建模型、如何训练、如何评估结果。
首先定义一个类,完成数据的加载:
class MNISTLoader():def __init__(self):mnist = tf.keras.datasets.mnist(self.train_data, self.train_label), (self.test_data, self.test_label) = mnist.load_data()# 在 TensorFlow 中,图像数据集的一种典型表示是 [图像数目,长,宽,色彩通道数]# MNIST中的图像默认为uint8(0-255的数字)。以下代码将其归一化到0-1之间的浮点数,并在最后增加一维作为颜色通道self.train_data = np.expand_dims(self.train_data.astype(np.float32) / 255.0, axis=-1) # [60000, 28, 28, 1]self.test_data = np.expand_dims(self.test_data.astype(np.float32) / 255.0, axis=-1) # [10000, 28, 28, 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):# 从数据集中随机取出batch_size个元素并返回index = np.random.randint(0, self.num_train_data, batch_size)return self.train_data[index, :], self.train_label[index]
接下来是模型的构建:
class MLP(tf.keras.Model):def __init__(self):super().__init__()# Flatten层将除第一维(batch_size)以外的维度展平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
在训练前需要的准备工作:
# 定义训练参数
num_epochs = 5
batch_size = 50
learning_rate = 0.001# 实例化模型和数据读取类
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)
然后来是模型的迭代与训练:
- 从 DataLoader 中随机取一批训练数据;
- 将这批数据送入模型,计算出模型的预测值;
- 将模型预测值与真实值进行比较,计算损失函数(loss)。这里使用
tf.keras.losses
中的交叉熵函数作为损失函数; - 计算损失函数关于模型变量的导数;
- 将求出的导数值传入优化器,使用优化器的
apply_gradients
方法更新模型参数以最小化损失函数
代码如下:
for batch_index in range(num_batches):X, y = data_loader.get_batch(batch_size)with tf.GradientTape() as tape:y_pred = model(X)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))
TIPS:在
tf.keras.losses
中,有两个交叉熵相关的损失函数,都需要接受真实标签y_true
与预测结果y_pred
作为输入,二者的主要区别体现在y_true
的形式不同。1,
sparse_categorical_crossentropy
:这也是我们的代码中使用的损失函数,需要将模型的预测值
y_pred
与真实的标签值y
作为函数参数传入,由 Keras 帮助我们计算损失函数的值。其中y_pred
是 10 维的向量,表示样本属于各个类别的概率值,而标签y
则是真实值,例如8,1,2等。2,
categorical_crossentropy
:与
sparse_categorical_crossentropy
不同的是,在多分类问题中,参数y_true
的输入值应该是经过 onehot 编码后的向量。也就是说: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 )
最后是模型的评估:
sparse_categorical_accuracy = tf.keras.metrics.SparseCategoricalAccuracy()
num_batches = int(data_loader.num_test_data // batch_size)
for batch_index in range(num_batches):start_index, end_index = batch_index * batch_size, (batch_index + 1) * batch_sizey_pred = model.predict(data_loader.test_data[start_index: end_index])sparse_categorical_accuracy.update_state(y_true=data_loader.test_label[start_index: end_index], y_pred=y_pred)
print("test accuracy: %f" % sparse_categorical_accuracy.result())
TIPS:这里,我们使用
tf.keras.metrics
中的SparseCategoricalAccuracy
评估器来评估模型在测试集上的性能,该评估器能够对模型预测的结果与真实结果进行比较,并输出预测正确的样本数占总样本数的比例。我们迭代测试数据集,每次通过update_state()
方法向评估器输入两个参数:y_pred
和y_true
,即模型预测出的结果和真实结果。评估器具有内部变量来保存当前评估指标相关的参数数值(例如当前已传入的累计样本数和当前预测正确的样本数)。迭代结束后,我们使用result()
方法输出最终的评估指标值(预测正确的样本数占总样本数的比例)。当然,也可以把每次的预测结果转换成numpy的形式保存起来,然后使用 sklearn 中的评估函数进行评估。
Keras Pipeline *
以上示例均使用了 Keras 的 Subclassing API 建立模型,即对 tf.keras.Model
类进行扩展以定义自己的新模型,同时手工编写了训练和评估模型的流程。这种方式灵活度高,且与其他流行的深度学习框架(如 PyTorch、Chainer)共通,是本手册所推荐的方法。
不过在很多时候,我们只需要建立一个结构相对简单和典型的神经网络(比如上文中的 MLP 和 CNN),并使用常规的手段进行训练。这时,Keras 也给我们提供了另一套更为简单高效的内置方法来建立、训练和评估模型。具体的使用方法与常规的 Keras 十分相似,这里就不展开讲解了。
参考文章:
TensorFlow 基础
TensorFlow 模型建立与训练
TensorFlow 2.0 快速上手教程与手写数字识别例子讲解相关推荐
- 小生不才:tensorflow实战01-基于bp神经网络的手写数字识别
前言 利用搭建网络八股,使用简单的bp神经网络完成手写数字的识别. 搭建过程 导入相应的包 获取数据集,划分数据集和测试集并进行简单处理(归一化等) 对数据进行乱序处理 定义网络结构 选择网络优化器以 ...
- AI常用框架和工具丨11. 基于TensorFlow(Keras)+Flask部署MNIST手写数字识别至本地web
代码实例,基于TensorFlow+Flask部署MNIST手写数字识别至本地web,希望对您有所帮助. 文章目录 环境说明 文件结构 模型训练 本地web创建 实现效果 环境说明 操作系统:Wind ...
- Tensorflow之 CNN卷积神经网络的MNIST手写数字识别
点击"阅读原文"直接打开[北京站 | GPU CUDA 进阶课程]报名链接 作者,周乘,华中科技大学电子与信息工程系在读. 前言 tensorflow中文社区对官方文档进行了完整翻 ...
- TensorFlow 第四步 多层神经网络 Mnist手写数字识别
从训练样例中取1000个进行训练,再对1000个测试样例进行检测,出现过拟合情况,而且损失函数值和测试精度值波动很大. # coding=utf-8 import os os.environ[&quo ...
- python手写多个字母识别_一个带界面的CNN手写数字识别,使用Python(tensorflow, kivy)实现...
CNN_Handwritten_Digit_Recognizer (CNN手写数字识别) A CNN handwritten digit recognizer with graphical UI, i ...
- matlab朴素贝叶斯手写数字识别_TensorFlow手写数字识别(一)
本篇文章通过TensorFlow搭建最基础的全连接网络,使用MNIST数据集实现基础的模型训练和测试. MNIST数据集 MNIST数据集 :包含7万张黑底白字手写数字图片,其中55000张为训练集, ...
- python 手写数字识别 封装GUI,手写板获取鼠标写字轨迹信息
python 手写数字识别知识不用多说,本文用深度学习Python库Keras实现深度学习入门教程mnist手写数字识别.mnist手写数字识别是机器学习和深度学习领域的"hello wor ...
- tensorflow2 minist手写数字识别数据训练
✨ 博客主页:小小马车夫的主页 ✨ 所属专栏:Tensorflow 文章目录 前言 一.tenosrflow minist手写数字识别代码 二.输出 三.参考资料 总结 前言 刚开始学习tensorf ...
- 深度学习导论(5)手写数字识别问题步骤
深度学习导论(5)手写数字识别问题步骤 手写数字识别分类问题具体步骤(Training an handwritten digit classification) 加载数据 显示训练集中的图片 定义神经 ...
最新文章
- 联想笔记本电脑的F1至F12键盘问题。怎么设置才能不按FN就使用F1
- jquery DataTable默认显示指定页
- pytorch中torch.manual_seed()的理解
- python元组_Python元组
- java socket第三方库_Java基于Socket实现HTTP下载客户端
- win10系统盘分多大合适?
- 中国正式发放5G牌照,预计中国移动推进最快
- R语言学习笔记5_参数的假设检验
- 16年,平凡而又收获的一年
- R语言rank函数详细解析
- pandas基础用法详解
- math.h里的数学计算公式
- 【小米商城】--类别展示,登出,注销商品详情展示
- Android集成微信支付之-天坑
- 实现canvas圆形橡皮檫像素清空功能
- 教你用matlab低版本打开版本simulink文件
- scrapinghub 爬取amztracker页面信息
- 看完这篇文章保你面试稳操胜券 ——(必考题)javaScript 篇
- linux kernel -- oops场景奈何桥
- python可以开发app吗-python可以写APP吗(python能做手机软件吗)
热门文章
- @property的必要性
- BCEWithLogitsLoss的使用案例
- dataframe筛选某列的单元格等于某个值的一行数据
- 最强鸿蒙系统txt_鸿蒙OS最新进展,余承东将亲自解说,是时候对谷歌“亮剑”了...
- vba 压缩图片_1分钟批量处理100张图片,Word图片批量压缩/提取/居中统统搞定
- python对csv文件中的数据进行分类_利用Python对csv文件中的数据进行排序
- 合作式智能运输系统 车用通信系统应用层及应用数据交互标准(第二阶段)_携手推进汽车与信息通信标准化融合发展,CSAE与CCSA签署标准化工作备忘录...
- ubuntu-基本命令篇-18-压缩包管理
- win7/WIN8.1(x64) 下使用MSDE WIN10不行
- 使用account lock或者account unlock语句