SGD与反向传播:区别与联系详解(含代码示例)
2025-03-24 20:56:38
SGD 和反向传播:一样吗?不一样在哪儿?
经常有人问:随机梯度下降 (SGD) 和反向传播,这俩到底啥关系?是不是一回事? 这篇博客就来好好聊聊这个问题,一次性给你讲明白。
问题:SGD 和反向传播到底有啥区别?
简单来说,这两者不是同一个东西,它们解决的问题不同。
- 反向传播 (Backpropagation): 是一种计算梯度的 方法。你可以把它想象成一个精密的数学公式计算器,用于计算神经网络中每个参数对最终误差的影响程度(也就是梯度)。
- SGD (Stochastic Gradient Descent): 是一种 优化算法。有了梯度,就得用这个梯度来更新网络的参数。SGD 就是众多更新参数的方法之一,它每次只用 一部分 数据(一个 batch)来计算梯度并更新参数。
打个比方:你要下山,反向传播告诉你哪个方向最陡峭(梯度),SGD 决定你每次迈多大步子、朝哪个方向走(参数更新)。
为什么会把它们搞混?
最主要的原因,就是在训练神经网络时,它们总是成对出现的。 我们用反向传播计算梯度,然后用 SGD(或者其他优化算法,如 Adam)来更新参数。流程太过紧密,时间久了就容易让人觉得它们是一体的。
详细解析:它们各自的作用和原理
一、反向传播 (Backpropagation)
反向传播的核心思想,其实是链式法则 (Chain Rule)。
神经网络可以看成是一个非常复杂的复合函数。 输入数据经过一层层的计算,最终得到一个输出。 要知道每个参数对最终结果的影响,就需要从输出层开始,一层一层地往回推导。
1. 基本原理
链式法则告诉我们,如果有一个复合函数 f(g(x))
, 那么它的导数可以这样计算:
df/dx = (df/dg) * (dg/dx)
在神经网络中,每一层都可以看作一个函数,损失函数是关于这些函数输出的函数。 反向传播就是不断地运用链式法则,从最后一层(损失函数)开始,逐层计算每个参数的梯度。
2. 代码示例 (简单示意)
# 假设有一个简单的两层神经网络
import numpy as np
#输入
X = np.array([1, 2])
#权重
W1 = np.array([[0.1, 0.2], [0.3, 0.4]])
W2 = np.array([0.5, 0.6])
#真实的标签
y_true = 0.8
#偏置项
b1=np.array([0.1,0.1])
b2=0.1
# 前向传播
z1 = np.dot(X, W1) + b1
a1 = 1 / (1 + np.exp(-z1)) # 使用 Sigmoid 激活函数
z2 = np.dot(a1, W2)+b2
y_pred = 1 / (1 + np.exp(-z2))
#计算误差, 简单采用y_true-y_pred, 不是正规误差的表示方法,但是用来计算可以
loss = y_true-y_pred
# 反向传播(为了方便理解,只演示部分的参数更新)
# 计算输出层梯度,假设损失函数对输出层输入的偏导已经给出 d_z2
d_z2=loss*(1-y_pred)*y_pred
d_W2 = np.outer(a1, d_z2)
d_b2 = d_z2
d_a1 = d_z2 * W2
d_z1 = d_a1 * (1-a1) * a1 #链式规则
d_W1 = np.outer(X, d_z1)
d_b1=d_z1
#梯度有了之后开始更新,具体的实现交给优化器
# ... 省略了隐藏层的梯度计算,因为涉及更多层的链式法则
# ... 这里的重点是展示反向传播的逐层回推的思想
print("W2的梯度为: \n",d_W1)
这段代码仅仅是用来理解原理, 真正的神经网络库(如 TensorFlow, PyTorch)对这些计算过程做了高度优化。
二、随机梯度下降 (SGD)
SGD 的目的是找到一组参数,使得损失函数的值最小。它采取的策略是“朝着梯度的反方向走”。
1. 基本原理
梯度是指向函数值增长最快的方向。所以,要让函数值变小,就得朝着梯度的 反方向 走。
SGD 的更新公式很简单:
新参数 = 旧参数 - 学习率 * 梯度
- 学习率 (Learning Rate): 这是一个需要我们手动设置的参数,它控制了每次更新的步长大小。学习率太大,可能会导致“震荡”,在最小值附近来回跳动;学习率太小,收敛速度会很慢。
2. 为什么叫“随机”?
传统的梯度下降 (Gradient Descent) 使用 所有 训练数据来计算梯度,而 SGD 每次只使用 一个样本 或 一小批样本 (mini-batch) 来计算梯度。
用一小部分数据计算梯度,虽然会引入一些噪声(因为这一小部分数据不能完全代表整个数据集),但带来的好处是:
- 速度快: 数据少了,计算量自然就小了。
- 能跳出局部最优: 噪声有时能帮助算法跳出局部最小值,找到更好的全局最小值。
3. 代码示例
# 使用上面的梯度计算结果来更新参数 (假设学习率为 0.1)
learning_rate = 0.1
new_W2=0
new_W1=0
new_b1=0
new_b2=0
#为了突出重点,仅使用SGD跟新W1
new_W1 = W1-learning_rate*d_W1
new_W2 = W2 - learning_rate * d_W2
new_b1 = b1 - learning_rate * d_b1
new_b2 = b2 - learning_rate * d_b2
print ("新的w1:",new_W1)
4. SGD 的变种和进阶
除了最基本的 SGD,还有很多改进版本:
- Momentum: 模拟物理中的动量,让参数更新具有惯性,减少震荡,加速收敛。
- Adagrad: 自适应地调整每个参数的学习率,对于梯度大的参数,减小其学习率;对于梯度小的参数,增大学习率。
- RMSprop: 对 Adagrad 的改进,解决了学习率过快衰减的问题。
- Adam: 结合了 Momentum 和 RMSprop 的思想,是目前非常流行的一种优化算法。
这些高级优化算法,内部通常都包含了梯度的计算过程(还是依赖于反向传播)以及一些针对性处理(例如对历史梯度进行加权平均等)。它们的目的都是使模型更快、更好地收敛。
选择使用那种方法,要针对具体数据集、模型架构调整。没有万金油方法。
###总结
SGD 和反向传播,是神经网络训练中两个不同的、但又紧密相关的概念。 掌握它们之间的区别,对于理解神经网络的训练过程至关重要。记住这个比喻,可能对你理解他们之间的关系更有帮助:下山, 反向传播告诉你哪里坡度大,SGD 告诉你每步走多远,最终目的是下山, 也就是获取误差的最小值。