神经网络学习原理详解:梯度下降与优化算法
深入解析了神经网络的学习原理,重点介绍了如何通过梯度下降算法最小化成本函数(如 MSE)。文章从暴力搜索方法的低效性出发,引出梯度下降的核心思想,即利用导数确定参数更新的方向和步长。内容涵盖了单参数优化、多参数偏导数计算、链式法则的应用,以及梯度下降在处理非凸函数时面临的局部最小值挑战。此外,还对比了标准梯度下降、随机梯度下降(SGD)和小批量梯度下降的区别与适用场景,并提供了 Python 代码示例辅助理解参数更新过程。

深入解析了神经网络的学习原理,重点介绍了如何通过梯度下降算法最小化成本函数(如 MSE)。文章从暴力搜索方法的低效性出发,引出梯度下降的核心思想,即利用导数确定参数更新的方向和步长。内容涵盖了单参数优化、多参数偏导数计算、链式法则的应用,以及梯度下降在处理非凸函数时面临的局部最小值挑战。此外,还对比了标准梯度下降、随机梯度下降(SGD)和小批量梯度下降的区别与适用场景,并提供了 Python 代码示例辅助理解参数更新过程。

在本文中,我们将深入训练过程,探讨神经网络到底是如何学习的。
假设我们想创建一个神经网络,这个神经网络使用温度和星期几特征来预测每天冰淇淋的销售额。
这是我们使用的训练数据集:

要构建一个神经网络,正如我们在之前的文章中学习的那样,我们首先需要确定其架构。
这包括确定隐藏层的数量、每层中的神经元数量以及每个神经元的激活函数。假设我们决定使用以下架构:1 个隐藏层、2 个神经元,1 个输出神经元,所有这些都使用整流器激活函数(ReLU)。

一旦我们确定了架构,就可以通过输入一些数据来训练模型了。
在这个训练过程中,神经网络将学习权重和偏置项的最优值。假设使用上面的训练数据训练模型后,它产生了以下最优值:

本文将重点介绍我们如何得到这些最优值。
让我们从一个简单的示例开始。假设我们有了所有最优值,除了外层神经元的偏置项。

因为我们不知道偏置的确切值,所以我们首先进行初始猜测并将值设置为 0。通常,偏置值在开始时都被初始化为 0。

现在,我们需要将所有冰淇淋商店的特征输入以进行收入预测(也就是我们在前一篇文章中学习的前向传播),假设最后一个偏置项为 0。让我们将训练数据的 10 行输入到神经网络中……

……得到以下预测:

现在我们有了最后一个偏差项等于 0 时的预测,我们就可以将它们与实际收入进行比较。
在上一篇文章中,我们了解到可以使用成本函数来衡量我们预测的准确性,特别是对于我们这种情况下的均方误差(MSE)。

计算此模型在偏置为 0 时的 MSE:

我们也知道任何模型的最终目标都是减少 MSE,所以,现在的目标是找到一个最佳的偏置值,来最小化这个 MSE。
比较不同偏置值下的 MSE 值的一种方法是通过暴力破解,并尝试为最后一个偏置项设置不同的值。
例如,让我们对略高于最后一个值 0 的偏差项进行第二次猜测。接下来让我们尝试偏差 = 0.1。

我们将训练数据传递给新的模型,该模型的偏置=0.1……

……这将导致这些预测……

……然后我们使用这些预测来计算 MSE:

我们可以看到,当偏置设为 0.1 时,这个模型的 MSE(0.03791)比偏置设为 0 时的 MSE(0.08651)略好。
为了更清楚地可视化这一点,让我们将这些值绘制在图表上。

我们可以通过继续猜测值来使用这种暴力破解方法。
假设我们还猜测了另外 4 个值:偏置=0.2、0.3、0.4 和 0.5。
我们重复上述相同的过程,生成一个像这样的 MSE 图表:

我们注意到,当偏置=0.3 时,MSE 达到了最低点。
而当偏置=0.4 时,MSE 又开始增加。
这告诉我们,在偏置=0.3 时,MSE 达到了最小值。
幸运的是,我们在几次有根据的猜测后就能确定这一点,然后通过进一步的尝试进行确认。
但是,如果最优的 MSE 值是 100,那怎么办呢?在那种情况下,我们可能需要做 1000 次(100 x 10)猜测才能达到这个值。
因此,这种方法在寻找最优偏置值时并不是非常高效。
此外,我们如何确定具有最低 MSE 值的偏置就是 0.3 呢?如果它是 0.2998 或 0.301 呢?
所以使用这种方法很难做出精确的猜测。
不过我们有一个更高效的方法来确定最优偏置值。我们将使用一种叫做梯度下降的概念。
简单来说,通过使用梯度下降和导数,我们可以有效地达到任何凸曲线(基本上是一个 U 形曲线)的最低点。
这在我们当前的情况下是理想的,因为上面的 MSE 图表类似于 U 形曲线,我们需要找到 MSE 最小化的谷底。
梯度下降通过指示每一步的大小和方向来引导我们,以尽快到达曲线的底部。
现在,让我们重新开始使用梯度下降中提出的步骤来寻找最优偏置。
我们可以从偏置=0 开始:

接下来,我们需要确定应该采取的步骤的方向和大小。
这可以通过计算步长来实现,步长是将一个称为学习率的常数值与偏置值处 MSE 的梯度相乘的结果。
在这种情况下,对于这次迭代,偏置值为 0。

注意:学习率是一个用于控制步长的常数。通常,它的值介于 0 和 1 之间。
让我们更仔细地检查导数值。我们知道 MSE 是 r_hat 的函数,如公式所示:

而且我们还知道 r_hat 是由最后一个神经元中的 ReLU 函数确定的,因为我们只能通过使用激活函数来获得 r_hat:

我们知道最后一个神经元中的 ReLU 函数包含偏置项。
现在,如果我们想要计算 MSE 关于偏置的导数,我们将使用称为链式法则的东西,这是微积分的一个非常重要的部分,它利用了上述三个关键信息。

我们需要使用链式法则,因为各个项是相互依赖的,但并不直接依赖。
它被称为链式法则是因为它们都是通过一个链式结构相互连接的。
你可以认为分子和分母相互抵消了。
这就是我们如何计算 MSE 关于偏置的导数。
我们在当前的偏置值(0)处计算这个导数。

这将为我们提供一个新的偏置值,这个值有可以让我们更接近最优偏置值。

我们将继续重复这一步骤的过程。

……采取微小的跳跃,随着我们逐渐接近最低点,步长也在缩小……

直到最后……

我们达到最优值!
注意:当步长接近 0,或者当我们达到算法中设定的最大步数时,我们就得到了最优值。
这就是在假设其他变量的最优值已知的情况下,我们如何找到偏置项的方法。
现在,让我们再进一步,考虑一个场景,其中我们知道除了偏置项和进入最后一个神经元的第二个输入的权重之外的所有最优值。

同样,我们需要找到这两个项的最优值,以使 MSE 最小化。
对于权重和偏置的不同值,我们创建一个 MSE 图。
这个图将与上面显示的图类似,但将是三维的。

与之前的 MSE 曲线类似,我们需要找到使 MSE 最小化的点。
这个点,称为谷底点,将为我们提供偏置和权重项的最优值。
我们可以使用梯度下降法来达到这个最低点。这个过程在这里也基本上是一样的。
步骤 1:随机初始化权重和偏置的值
步骤 2:使用偏导数计算步长

这里有一点小的偏差。
我们不是计算均方误差(MSE)的导数,而是计算所谓的偏导数,并同时更新步长。
这里的'同时'意味着我们需要在当前的权重和偏置值下计算偏梯度的值,并且我们再次使用链式法则:

步骤 3:同时更新权重和偏置项

步骤 4:重复步骤 2-3,直到我们收敛到最优值
我们可以进一步拓展这个思路。
现在,如果我们想要优化神经网络中的所有 9 个值,要怎么做呢?

我们面临的是一个涉及九个变量同时优化的复杂问题,需要确保这九个方程在每一次迭代中都能同步更新,以共同寻找函数的最小值。
尽管随着需要同时解决的方程数量的增加,手动进行数学计算变得更加复杂,但概念仍然相同。我们试图逐渐移动到谷底,依靠梯度下降来引导我们。
通过应用上述讨论的方程和优化程序,数据的隐藏模式自然会浮现出来。
这使我们能够找到这些深层模式,而无需任何人为干预。
好的,总结一下,我们现在明白了我们总是想要最小化成本函数(在上面的案例中是 MSE),以及如何使用梯度下降来获取使 MSE 最小化的权重和偏置项的最优值。
我们了解到,通过使用梯度下降,我们可以轻松地遍历一个凸形曲线以到达底部。
幸运的是,在我们的案例研究中,我们有一个看起来很漂亮的凸形曲线。
但是有时我们可能会遇到不产生完美凸形曲线的成本函数,而是产生像这样的东西:

如果我们使用梯度下降法,有时可能会错误地将许多局部最小值(看起来是最低点但实际上并不是)中的一个识别为最低点,而不是全局最小值(实际的最低点)。

梯度下降法的另一个问题是,随着数据集中数据点数量的增加或项数的增加,执行梯度下降所需的时间也会增加。
这是因为涉及的数学计算变得更加复杂。
在我们的小例子中,我们有 10 个数据点(这非常不现实,通常我们有数十万个数据点),并且我们试图优化 9 个参数(这个数字可能非常高,取决于架构的复杂性)。
目前,对于梯度下降的每次迭代,我们使用 10 个数据点来计算偏导数并更新 9 个参数值。
这基本上就是是梯度下降在做的事:

在每次迭代中,我们执行大约 90 次(9*10)小的计算,来计算每个单独数据点的 MSE 的导数。
通常,我们会进行大约 1000 次这样的迭代,总共需要进行 90,000 次(90*1000)计算。
但是,如果我们有 10 万个数据点而不是只有 10 个数据点呢?
在这种情况下,我们需要计算所有 10 万个数据点的 MSE,并对 90 万个(= 9*100,000)项取导数。
通常,我们会执行大约 1000 步梯度下降以达到我们的最优值,这将导致惊人的 9 亿(900,000*1000)次计算。
此外,我们的数据可能会变得更加复杂,数字达到数百万,并且需要优化更多的参数。
这很快就会变得非常具有挑战性。
为了避免这个问题,我们可以利用更快、更强大的替代优化算法。
随机梯度下降(SGD)与梯度下降类似,但存在微小的差异。
在梯度下降中,我们在计算了整个包含所有 10 个值的训练数据集的均方误差(MSE)后更新我们的值。
然而,在 SGD 中,我们只使用数据集中的一个数据点来计算 MSE。
该算法随机选择一个数据点,并使用它来更新参数值,而不是使用整个数据集。

这种方法更加轻便,因此比其全面覆盖的对应方法更快。
这种方法是常规梯度下降和随机梯度下降的结合。
我们不是基于单个数据点或整个数据集来更新值,而是每次迭代处理一批数据点。我们可以选择批次大小为 5、10、100、256 等。
例如,如果我们的批次大小为 4,我们将基于 4 行数据来计算用于偏导数的 MSE。

为了更直观地理解梯度下降的更新过程,下面是一个简化的 Python 代码示例,展示了如何使用梯度下降更新单个参数:
import numpy as np
def gradient_descent(initial_bias, learning_rate, num_iterations):
bias = initial_bias
# 模拟损失函数 L(bias) = (bias - 0.3)^2 + 0.1
# 导数 dL/dbias = 2 * (bias - 0.3)
for i in range(num_iterations):
loss_gradient = 2 * (bias - 0.3)
new_bias = bias - learning_rate * loss_gradient
print(f"Iteration {i}: Bias = {new_bias:.4f}, Gradient = {loss_gradient:.4f}")
bias = new_bias
return bias
# 运行梯度下降
final_bias = gradient_descent(initial_bias=0.0, learning_rate=0.1, num_iterations=10)
print(f"Final Bias: {final_bias:.4f}")
这段代码模拟了一个简单的二次损失函数,演示了如何通过计算梯度并反向更新参数来逼近最优解。
本文详细阐述了神经网络的学习机制,核心在于通过优化算法最小化成本函数。
掌握这些基础原理,是深入理解深度学习框架及高级优化算法的前提。在实际应用中,选择合适的学习率和优化器对于模型性能至关重要。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online