Stochastic Gradient Descent (SGD)
SGD 使用在小型随机数据批次上计算出的许多低成本权重更新来训练模型。内容涵盖更新规则、动量、批次大小和代码。
随机梯度下降(SGD)是一种优化算法,它通过反复使用训练数据中小型随机样本的损失梯度更新模型权重来训练模型,而不是使用整个数据集。每个样本的梯度都是全数据集梯度的含噪但无偏估计,因此,相比全批量梯度下降进行一次昂贵更新,SGD 能在相同时间内进行许多低成本更新。该方法源自 Robbins 和 Monro 于 1951 年提出的随机逼近方法;加入动量后,它仍是卷积神经网络(CNN)的标准优化器。
SGD 的工作原理#
SGD 的每一步都会取一个小批次 B,使用反向传播计算该批次上的损失梯度,然后沿着梯度的反方向移动每个权重一小步:w ← w − η·∇L_B(w),其中 η 是学习率。严格来说,SGD 每步只使用一个样本;但深度学习框架会将其应用于包含几十到数千个样本的小批次,因此在实际使用中,“SGD”和“小批次梯度下降”是同义词。较大的批次大小可以降低梯度噪声并提高硬件利用率,但会减少每个轮次中的更新次数。
训练会在每个轮次开始时打乱数据,将数据划分为小批次逐批遍历,并对每个批次执行一次更新。对 1,000 个带噪点拟合一条直线可以展示整个过程:
import torch
torch.manual_seed(0)
# 1,000 noisy samples of y = 3x + 2
x = torch.randn(1000, 1)
y = 3 * x + 2 + 0.1 * torch.randn(1000, 1)
model = torch.nn.Linear(1, 1)
optimizer = torch.optim.SGD(model.parameters(), lr=0.05, momentum=0.9)
for epoch in range(5):
# Reshuffle every epoch, then update the weights once per 32-sample mini-batch
for idx in torch.randperm(1000).split(32):
loss = torch.nn.functional.mse_loss(model(x[idx]), y[idx])
optimizer.zero_grad()
loss.backward()
optimizer.step()
print(f"epoch {epoch}: w = {model.weight.item():.3f}, b = {model.bias.item():.3f}, loss = {loss.item():.4f}")经过两个轮次、共 64 次更新后,权重达到 3.081,偏置达到 2.012。在接下来的三个轮次中,权重会继续在 2.967 到 3.003 之间移动,而不是趋于稳定,因为每个小批次的梯度都包含采样噪声;最后一个批次的损失保持在 0.01 左右,这正是添加到 y 中的噪声方差。
学习率、噪声与批量大小#
在学习率恒定时,SGD 会在最小值附近的区域内波动,而该区域的大小会随着学习率和梯度噪声增大。随机逼近理论保证,只有当学习率逐渐衰减至零时,算法才会收敛,因此实际训练会随着时间降低学习率,采用阶梯衰减或余弦调度,通常还会先进行短暂的预热。小批量带来的梯度噪声也会引导 SGD 找到比大批量训练往往找到的尖锐极小值泛化效果更好的平坦极小值,这是一种隐式的正则化。
批量大小和学习率会相互影响。将学习率按批量大小的比例提高,并进行五个 epoch 的预热后,ResNet-50 可以用 8,192 张图像的小批量在一小时内完成 ImageNet 训练,且不会损失准确率。
动量与 Nesterov 动量#
在损失曲面上又长又窄的谷底中,梯度大多指向横穿谷底的方向,因此普通 SGD 会在两侧壁之间来回摆动,沿谷底前进的速度却很慢。动量会维护一个累积速度 v ← μ·v + g,并沿其方向更新 w ← w − η·v;这样,方向一致的梯度会逐渐加速,而方向交替的梯度则会相互抵消。μ = 0.9 通常是默认值。Nesterov 动量会沿速度方向先向前看一步,再计算梯度,从而进一步抑制过冲。PyTorch 的 SGD实现了这两种动量,并通过将 λ·w 加到梯度上来应用 weight_decay;对于 SGD,这等价于对权重施加 L2 惩罚。
SGD 与其他优化器的比较#
- 批量梯度下降:每次更新都会基于整个数据集计算精确梯度,因此每个 epoch 只执行一步,内存需求也会随数据集增大。
- Adam:根据梯度及其平方的滑动平均值,为每个参数设置单独的步长;每个参数会存储两个状态值,而带动量的 SGD 每个参数只存储一个。Adam 前期进展更快,对学习率也不那么敏感;不过,在 CNN 上,经过良好调优的带动量 SGD 往往能达到或超过 Adam 的最终准确率。AdamW 是一种采用解耦权重衰减的变体,也是 Transformer 的标准优化器。
- Muon:将每个权重矩阵的动量更新整体正交化,并已扩展到大语言模型训练。
当 optimizer="SGD" 已设置时,Ultralytics YOLO 训练会构建带 Nesterov 动量的 PyTorch SGD,默认使用 lr0=0.01 和 momentum=0.937。默认的 optimizer="auto" 会忽略 lr0,运行超过 10,000 次迭代时选择MuSGD,这是一种融合 SGD 与 Muon 更新的混合优化器;较短的运行则使用 AdamW。
SGD 的应用场景#
带动量的 SGD 曾用于训练大多数具有里程碑意义的 ImageNet CNN。最初的 ResNet模型使用 0.9 的动量、0.0001 的权重衰减和每批 256 张图像的迷你批量;学习率从 0.1 开始,并在误差停滞时除以 10。在深度学习之外,scikit-learn 的 SGDClassifier 和 SGDRegressor使用 SGD 拟合线性模型,例如逻辑回归和线性支持向量机;它们的 partial_fit 方法则会一次处理一个数据块,训练无法全部载入内存的数据集。










