在前向传播中,将输入层连接到隐藏层,隐藏层再连接到输出层。在第一次迭代中,随机初始化权重,然后计算这些权重造成的损失。在反向传播中,我们采用相反的方法。从前向传播中得到的损失值开始,更新网络的权重,使损失值尽可能小。
我们执行以下步骤来减小损失值:
1.少量改变神经网络中的每个权重——每次一个。
2.当权重值改变( δW )时,度量损失的变化( δL )。
3.将权重更新为 (其中 k 是某个正值,是一个称为 学习率 的超参数)。
注意,对特定权重所做的更新与通过对其进行少量更改而减少的损失量成正比。从直观上看,如果改变某个权重减少了很大的损失,就可以对该权重进行较大的更新。但是,如果通过改变权重而减少的损失很小,那么就进行较小的更新。
如果在整个数据集上执行 n 次上述步骤(完成前向传播和反向传播),就会实现对模型 n 轮(epoch)的训练。
由于一个典型的神经网络包含数千或数百万(如果不是数十亿)个权重,改变每个权重的值,并检查损失是增加还是减少并不是最优的做法。上述列表中的核心步骤是权重变化时对“损失变化”的度量。正如你可能在微积分中学习过的那样,这个度量和计算权重相关的损失 梯度 是一样的。在下一节讨论反向传播链式法则时,将有更多关于利用微积分中的偏导数来计算与权重相关的损失梯度的内容。
在本节中,我们将通过每次对一个权重进行少量更新的方式来实现梯度下降,这在本节开始部分已经进行了详细介绍。不过,在实现反向传播之前,需要先了解神经网络的另一个细节: 学习率 。
直观地说,学习率有助于在算法中建立信任。例如,在决定权重更新大小的时候,可能不会一次性改变权重值,而是进行较慢的更新。
模型通过学习率获得了稳定性,将在1.6节中具体讨论学习率如何有助于提高稳定性。
通过更新权重来减少误差的整个过程称为 梯度下降 。
随机梯度下降 是最小化前述误差的一种具体实现方法。如前所述, 梯度 表示差异(即权重值被少量更新时损失值的差异), 下降 表示减少。 随机 表示对随机样本的选择,并在此基础上做出决定。
除了随机梯度下降之外,还有许多其他类似的优化器可以帮助最小化损失值。下一章将讨论这些不同的优化器。
在接下来的两节中,我们将学习如何使用Python从头开始编写反向传播算法的代码,并简要讨论如何使用链式法则进行反向传播。
下面将给出梯度下降的Python实现代码。
下列代码可以从本书GitHub存储库(https://tinyurl.com/mcvp-packt)Chapter01文件夹中的Gradient_descent.ipynb获得。
1.定义前馈网络并计算均方误差损失值,正如我们在1.3.5节中所做的那样:
2.将每个权重和偏置项增加一个非常小的量(0.0001),并对每个权重和偏置项更新一次,计算总体误差损失的平方值。
❍ 在下面的代码中,创建了一个名为update_weights的函数,它通过执行梯度下降过程来更新权重。函数的输入是网络的输入变量inputs、期望的outputs、weights(在模型训练开始时进行随机初始化),以及模型的学习率lr(有关学习率的更多内容见后面的章节):
❍ 确保对权重列表进行了deepcopy操作。由于权重将在后面的步骤中被操纵,deepcopy确保了我们可以在不干扰实际权重的情况下使用多个权重副本。创建作为函数输入传递的原始权重集的三个副本——original_weights、temp_weights和updated_weights:
❍ 通过feed_forward函数传递inputs、outputs和original_weights,使用原始的权重集计算损失值(original_loss):
❍ 循环遍历网络的所有层:
❍ 在神经网络中总共有四个参数列表:两个连接输入层和隐藏层的权重与偏置参数列表,另外两个连接隐藏层和输出层的权重与偏置参数列表。现在,我们循环遍历所有单独的参数,因为每个列表有不同的形状,利用np.ndenumerate循环遍历给定列表中的每个参数:
❍ 现在将原始权重集存储在temp_weights中。选择其在第 i 层存在的指标权重,并将其增加一个较小的量。最后,用神经网络的新权重集计算新的损失:
在上述代码的第一行中,将temp_weights重置为原始的权重集,正如在每次迭代中那样更新不同的参数,由此计算出在给定轮内对参数进行少量更新时得到的新的损失。
❍ 计算由于权重变化而产生的梯度(损失值的变化):
通过非常小的增量更新一个参数,然后计算相应的梯度,这个过程相当于一个微分过程。
❍ 最后,更新updated_weights对应层和index中的参数。更新后的权重值将按梯度值的比例减小。此外,我们还引入了一种机制,通过使用学习率lr(关于学习率的更多信息,见1.6节)来缓慢地建立信任,而不是将其完全减小为梯度值:
❍ 一旦更新了所有层的参数值和层内的索引,我们就返回更新后的权重值updated_weights:
神经网络的另一个参数是在计算损失值时需要考虑的 批大小 (batch size)。
前面使用所有数据点来计算损失(均方误差)值。然而在实践中,当有成千上万(或者在某些情况下数百万)的数据点时,使用较多数据点计算损失值,其增量贡献将遵循收益递减规律,因此我们将使用比数据点总数要小得多的批大小进行模型训练。在一轮的训练中,每次使用一个批次数据点进行梯度下降(在前向传播之后),直到用尽所有的数据点。
训练模型时典型的批大小是32和1024之间的任意数。
在本节中,我们了解了当权重值发生少量变化时,如何基于损失值的变化更新权重值。在下一节中,将学习如何在不计算梯度的情况下更新权重。
到目前为止,通过对权重进行少量更新计算出权重损失的梯度,然后计算出原有场景(权重不变时)的前馈损失与权重更新后前馈损失的差值。使用这种方式更新权重值的一个缺点是,当网络很大时,需要使用大量的计算来计算损失值(事实上要做两次计算,首先在权重值不变时计算损失值,然后在权重值少量更新时计算损失值)。这将导致需要更多的计算资源和计算时间。在这一节中,我们将学习使用链式法则计算梯度的方法。这种方法不需要我们通过手动计算损失值的方式获得与权重值相关的损失梯度。
在第一次迭代中(随机初始化权重),输出的预测值是1.235。
为得到理论公式,将权重、隐藏层值和隐藏层激活分别表示为 w 、 h 、 a ,如图1-14所示。
图1-14
注意,在图1-14中,取了左图的每个分量值,并将其推广到右图中。
为了便于理解,这一节将介绍如何使用链式法则来计算仅关于 w 11 的损失值的梯度。同样的方法可以推广到神经网络的所有权重和偏置项。我们鼓励你练习并将链式法则计算应用到剩下的权重和偏置项上。
本书的GitHub存储库Chapter01文件夹中的chain_rule.ipynb notebook包含了使用链式法则计算网络中所有关于权重参数和偏置项变化的梯度的方法。
此外,为了便于学习,我们这里只处理一个数据点,其中输入为{1,1},期望的输出为{0}。
假设正在使用 w 11 计算损失值的梯度,可以通过图1-15理解所有在计算梯度时需要包含的中间分量(没有连接输出到 w 11 的分量在图1-15中显示为灰色)。
图1-15
从图1-15中可以看到 w 11 通过突出显示的路径 ——h 11 、 a 11 和 形成了损失值。
下面分别阐明如何获得 h 11 、 a 11 和 。
网络损失值计算公式如下:
预测输出值 的计算公式如下:
隐藏层激活值(S型函数激活)的计算公式如下:
隐藏层值的计算公式如下:
h 11 = x 1 × w 11 + x 2 × w 21
现在已经写出了所有的计算公式,可以计算权重变化对损失值( C )变化的影响,具体计算公式如下:
这称为 链式法则 。它本质上是通过一系列的微分获得需要的微分。
注意,上述计算公式建立了一个关于链的偏微分方程,现在可以分别对四个组件进行偏微分,由此最终完成损失值关于权重值 w 11 导数的计算。
上式中各个偏导数的计算方法如下:
❍ 损失值关于预测输出值 的偏导数为
❍ 预测输出值 关于隐藏层激活值 a 11 的偏导数为
❍ 隐藏层激活值 a 11 关于激活前隐藏层值 h 11 的偏导数为
注意,上述等式中S型函数 a 的导数是 a× (1v a )。
❍ 激活前隐藏层值 h 11 关于权重值 w 11 的偏导数为
在此基础上,用上述计算结果替换相应的偏微分项,就可以算出损失值关于权重 w 11 的梯度,具体计算公式如下:
从上述公式中可以看出,现在可以计算权重值的一个小变化(相对于权重的损失梯度)对损失值的影响,而不用再强行重新计算前向传播。
接下来,可以使用下列公式不断更新权重值:
更新后的权重=原始权重-学习率×损失关于权重的梯度
1)用链式法则确定梯度,然后更新权重;2)通过学习权重值小的变化对损失值的影响来实现权重值的更新。这两种方法获得的计算结果是相同的,见本书的GitHub存储库(https://tinyurl.com/mcvp-packt)Chapter01文件夹中的chain_rule.ipynb notebook。
在梯度下降中,依次执行权重更新过程(一次更新一个权重)。通过链式法则,可以找到一种替代方法来计算权重的变化对损失值的影响,从而为并行计算执行提供了可能性。
因为是跨所有层更新参数,所以参数更新的整个过程可以进行并行化计算。此外,考虑到现实场景中可能存在数百万个跨层参数,将这些参数分配到不同GPU内核上分别进行计算实现权重更新所花费的时间,显然比每次循环只计算一个权重实现更新所花费的时间少得多。
目前已经从直觉角度和利用链式法则的角度对反向传播有了很好的理解,在下一节中,我们将学习前向传播和反向传播如何通过协同工作获得最优权重值。