1.2.3 TensorFlow 2程序样例
从这里开始,我们将学习一个使用TensorFlow做线性回归的样例程序,直观体验一下深度学习框架的使用感受。
如图1-7所示,首先导入相关依赖(第1~2行)。这里我们使用Tensorflow来定义和训练模型,使用numpy来模拟生成数据。我们使用的模型包含两个参数权重W和偏置项b,并将它们分别初始化为1和0(第7~8行)。这里初值的选取是随机的。__call__方法中则定义了模型前向计算的过程,对应于数学公式y=Wx+b(第10~11行)。相应地,我们选取均方误差函数为损失函数(第14~15行)。此处略去了系数1/2,是因为TensorFlow会自动帮我们求导,编程时无须再关注导数形式是否简洁(16)。需要注意的是,这里y_pred和y_true分别是一个小批量的模型预测值和真实值,形状都是一维向量,而最终的函数返回值是小批量里所有样本的损失函数的平均值,是一个实数。
准备好模型之后,我们再来准备训练数据(第18~21行)。这里随机生成一些在直线y=2x-1附近的样本点,横坐标的选取范围为[-5,5]。有了人工合成的数据,我们就可以开始训练模型了。在第23~25行,我们首先实例化一个模型,并指定相应的超参数批大小和学习率。然后开始遍历训练数据(第26行),每次选取一个小批量的数据(第27~28行)进行前向运算并计算损失函数(第29~31行)。注意只有在GradientTape环境中,TensorFlow才会追踪张量的计算过程并生成梯度的计算方法,因此必须把需要计算梯度的代码块置于GradientTape上下文(第29行)中。在第32行,我们计算损失函数关于模型参数的梯度,并在33~34行中进行一步梯度下降。每300步我们会打印一次损失函数和模型参数的相关信息(第35~37行),观察模型训练情况。TensorFlow 2中的张量默认为Eager Tensor,可以通过.numpy()方法来将其转换成numpy数组,方便展示或与其他Python库(例如matplotlib等)结合使用。
图1-7 使用TensorFlow 2做线性回归
经过多步循环后,可以发现模型学到的参数值已经非常接近真值了:
At step 0, loss = 7.9497, W = 2.4238, b = -0.1667 At step 300, loss = 0.0022, W = 2.0021, b = -0.9586 At step 600, loss = 0.0000, W = 2.0004, b = -0.9939 At step 900, loss = 0.0000, W = 1.9995, b = -0.9951 At step 1200, loss = 0.0000, W = 2.0003, b = -0.9952 At step 1500, loss = 0.0000, W = 2.0001, b = -0.9950 At step 1800, loss = 0.0000, W = 1.9992, b = -0.9948 At step 2100, loss = 0.0000, W = 2.0003, b = -0.9948 At step 2400, loss = 0.0000, W = 1.9996, b = -0.9949 At step 2700, loss = 0.0000, W = 2.0009, b = -0.9951
(1) 亦称训练。学习和训练在机器学习语境下是同义词,本书将不加区别地使用两者。
(2) 亦可选取输入恒为x0=1、权重为-θ。
(3) 视定义不同,自变量为0时函数值可以取0、1/2或1。
(4) 深层神经网络中梯度随着网络层数加深越来越小,导致网络训练缓慢等现象。
(5) 深层神经网络中梯度随着网络层数加深越来越大,导致网络训练困难,参数更新出现NaN等。
(6) 这里所说的输入输出值的形状是针对单个输入样本而言的。深度学习中常常把一批样本同时送入网络进行运算,以提高计算资源利用率;此时所有输入输出值都会提升一个维度(例如标量变向量,向量变矩阵),多出的这一维度坐标轴通常放在最前面,这一维的大小为同时参与计算的样本数量,也称为批量大小(Batch Size)。
(7) 大多数情况下max函数无须近似,因为它是分片可微(Piecewise Differentiable)的。
(8) 对于均方误差函数,若n>1,导数前还会产生一个系数1/n。
(9) 理论上也可以进行前向传播。假如要求的梯度,当n<m时前向模式(Forward Mode)更省计算量,n>m时后向模式(Reverse Mode)更省计算量。机器学习中后一种情形更常见,所以一般使用反向传播算法。
(10) 实践中还可能用到其他终止条件,例如训练达到一定步数、损失函数的值足够小等。
(11) 非凸性的来源是多层复合,而不是激活函数的非凸性。即便采用ReLU等凸激活函数,多层神经网络依然是非凸的。
(12) 严格来讲,Word2vec中的神经网络只有三层,并不深。但一般也归类在深度学习领域。
(13) 本书将不加区别地使用求导和微分两个术语。
(14) 扰动的增量并非越小越好,因为计算机中的浮点数存在数值精度问题。通常取1e-6即可。
(15) 使用静态图框架时务必形成良好的编程习惯,例如备注张量的形状、多做单元测试等。
(16) 省略此系数会导致梯度变为原先的两倍,但不会影响模型的收敛性。