随机梯队下降SGD
以下是对 PyTorch 中 `torch.optim.SGD` 优化器的中文解读,结合提供的伪代码,详细解析其参数、算法逻辑、公式和计算过程,确保清晰易懂。
—
### PyTorch SGD 优化器概述
`torch.optim.SGD` 是 PyTorch 中实现的随机梯度下降(Stochastic Gradient Descent, SGD)优化器,支持标准 SGD、动量法(Momentum)、Nesterov 动量法、权重衰减(Weight Decay)等功能。它是最基础且广泛使用的优化器,适用于各种深度学习任务。
**函数签名**:
“`python
torch.optim.SGD(params, lr=0.001, momentum=0, dampening=0, weight_decay=0, nesterov=False, *, maximize=False, foreach=None, differentiable=False, fused=None)
“`
**参数说明**:
– **params**: 模型的可优化参数(通常是 `model.parameters()`),即 \(\theta_0\)。
– **lr**: 学习率(\(\gamma\)),默认 0.001,控制参数更新的步长。
– **momentum**: 动量系数(\(\mu\)),默认 0,控制历史梯度的累积,典型值如 0.9。
– **dampening**: 动量阻尼系数(\(\tau\)),默认 0,降低当前梯度对动量的影响。
– **weight_decay**: 权重衰减系数(\(\lambda\)),默认 0,添加 L2 正则化项。
– **nesterov**: 布尔值,默认 False,是否启用 Nesterov 动量法。
– **maximize**: 布尔值,默认 False,决定优化目标是最大化(True)还是最小化(False)损失函数。
– **foreach**: 是否使用 foreach 实现以提高性能(None 表示自动选择)。
– **differentiable**: 是否支持可微优化(实验性功能,默认 False)。
– **fused**: 是否使用融合实现(优化性能,默认 None,视硬件支持)。
**优化目标**:
优化器通过迭代更新参数 \(\theta_t\),以最小化(或最大化)目标函数 \(f(\theta)\),通常是损失函数。
—
### 伪代码解读
以下是提供的伪代码,逐行解析其逻辑:
“`pseudo
input: γ (lr), θ_0 (params), f(θ) (objective), λ (weight decay), μ (momentum), τ (dampening), nesterov, maximize
for t = 1 to … do
g_t ← ∇_θ f_t(θ_{t-1}) # 计算当前梯度
if λ ≠ 0 # 权重衰减
g_t ← g_t + λ θ_{t-1}
if μ ≠ 0 # 动量法
if t > 1
b_t ← μ b_{t-1} + (1 – τ) g_t # 更新动量(带阻尼)
else
b_t ← g_t # 初始动量为当前梯度
if nesterov
g_t ← g_t + μ b_t # Nesterov 动量
else
g_t ← b_t # 标准动量
if maximize
θ_t ← θ_{t-1} + γ g_t # 最大化目标
else
θ_t ← θ_{t-1} – γ g_t # 最小化目标
return θ_t
“`
#### 逐行解析
1. **输入参数**:
– \(\gamma\): 学习率(`lr`),控制更新步长。
– \(\theta_0\): 初始参数(`params`)。
– \(f(\theta)\): 目标函数(损失函数)。
– \(\lambda\): 权重衰减系数(`weight_decay`)。
– \(\mu\): 动量系数(`momentum`)。
– \(\tau\): 阻尼系数(`dampening`)。
– `nesterov`: 是否使用 Nesterov 动量。
– `maximize`: 是否最大化目标函数。
2. **计算梯度**:
\[ g_t = \nabla_\theta f_t(\theta_{t-1}) \]
– 计算当前参数 \(\theta_{t-1}\) 处的梯度 \(g_t\),即目标函数对参数的偏导数。
3. **权重衰减**:
\[ \text{if } \lambda \neq 0: \quad g_t \leftarrow g_t + \lambda \theta_{t-1} \]
– 如果设置了权重衰减(\(\lambda > 0\)),在梯度中加入正则化项 \(\lambda \theta_{t-1}\),等效于 L2 正则化,惩罚参数的大小,增强模型泛化能力。
4. **动量更新**:
\[ \text{if } \mu \neq 0: \]
– 如果启用了动量(\(\mu > 0\)):
– 对于 \(t > 1\):
\[ b_t = \mu b_{t-1} + (1 – \tau) g_t \]
– \(b_t\) 是动量(速度),结合历史动量 \(b_{t-1}\) 和当前梯度 \(g_t\)。
– \(\mu b_{t-1}\): 保留历史动量。
– \((1 – \tau) g_t\): 当前梯度的贡献,阻尼系数 \(\tau\) 降低其影响(通常 \(\tau = 0\))。
– 对于 \(t = 1\):
\[ b_t = g_t \]
– 初始动量直接设为当前梯度。
5. **Nesterov 动量**:
\[ \text{if nesterov}: \quad g_t \leftarrow g_t + \mu b_t \]
– 如果启用 Nesterov 动量,计算预测位置的梯度贡献:
– 标准动量法直接使用 \(b_t\) 更新参数。
– Nesterov 动量法额外加上 \(\mu b_t\),模拟在预测位置 \(\theta_{t-1} – \mu b_{t-1}\) 处的梯度(实际实现中通过调整公式实现)。
\[ \text{else}: \quad g_t \leftarrow b_t \]
– 如果不使用 Nesterov,则直接使用动量 \(b_t\)。
6. **参数更新**:
\[ \text{if maximize}: \quad \theta_t = \theta_{t-1} + \gamma g_t \]
\[ \text{else}: \quad \theta_t = \theta_{t-1} – \gamma g_t \]
– 如果 `maximize=True`,沿梯度方向更新以最大化目标函数(用于某些任务,如对抗网络)。
– 否则,沿负梯度方向更新以最小化损失(默认行为)。
7. **返回**:
\[ \text{return } \theta_t \]
– 返回更新后的参数。
—
### 计算过程
假设一个简单场景:优化损失函数 \(f(\theta) = \theta^2\),初始参数 \(\theta_0 = 1.0\),学习率 \(\gamma = 0.1\),动量 \(\mu = 0.9\),阻尼 \(\tau = 0\),权重衰减 \(\lambda = 0.01\),启用 Nesterov 动量,`maximize=False`。
1. **初始化**:
– \(\theta_0 = 1.0\), \(b_0 = 0\)。
2. **迭代 t = 1**:
– 计算梯度:\(g_1 = \nabla_\theta f(\theta_0) = 2 \theta_0 = 2.0\)。
– 权重衰减:\(g_1 = 2.0 + 0.01 \cdot 1.0 = 2.01\)。
– 动量更新(\(t = 1\)):\(b_1 = g_1 = 2.01\)(无历史动量)。
– Nesterov 动量:\(g_1 = g_1 + \mu b_1 = 2.01 + 0.9 \cdot 2.01 = 3.819\)。
– 参数更新:\(\theta_1 = \theta_0 – \gamma g_1 = 1.0 – 0.1 \cdot 3.819 = 0.6181\)。
3. **迭代 t = 2**:
– 计算梯度:\(g_2 = 2 \cdot 0.6181 = 1.2362\)。
– 权重衰减:\(g_2 = 1.2362 + 0.01 \cdot 0.6181 = 1.2424\)。
– 动量更新:\(b_2 = \mu b_1 + (1 – \tau) g_2 = 0.9 \cdot 2.01 + 1.0 \cdot 1.2424 = 3.0514\)。
– Nesterov 动量:\(g_2 = 1.2424 + 0.9 \cdot 3.0514 = 3.9887\)。
– 参数更新:\(\theta_2 = 0.6181 – 0.1 \cdot 3.9887 = 0.2192\)。
4. 重复迭代,损失逐渐减小。
—
### 特点与应用
– **灵活性**: 支持标准 SGD、动量法、Nesterov 动量和权重衰减,适配多种任务。
– **动量加速**: 动量(\(\mu > 0\))平滑更新方向,加速收敛,适合平坦区域。
– **Nesterov 优势**: 提前预测梯度方向,减少过冲,收敛更快。
– **权重衰减**: 通过 \(\lambda \theta_{t-1}\) 控制参数规模,防止过拟合。
– **最大化支持**: `maximize=True` 适用于需要最大化目标的场景(如 GAN)。
– **性能优化**: `foreach` 和 `fused` 参数利用硬件加速,提升效率。
**局限性**:
– 需手动调优学习率 \(\gamma\) 和动量 \(\mu\),对超参数敏感。
– 在非凸问题中可能陷入局部极值,需结合自适应优化器(如 Adam)。
—
### 代码示例
以下是 PyTorch 中使用 SGD 的示例:
“`python
import torch
import torch.nn as nn
import torch.optim as optim
# 定义简单模型
model = nn.Linear(10, 1)
loss_fn = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9, weight_decay=0.01, nesterov=True)
# 训练循环
for data, target in dataloader:
optimizer.zero_grad() # 清零梯度
output = model(data)
loss = loss_fn(output, target)
loss.backward() # 计算梯度
optimizer.step() # 更新参数
“`
—
### 总结
`torch.optim.SGD` 是一个功能强大的优化器,通过支持动量法、Nesterov 动量、权重衰减和最大化选项,适应多种优化需求。其核心逻辑是基于梯度更新参数,结合动量平滑更新路径,Nesterov 动量通过预测位置进一步提高效率。权重衰减增强泛化能力,阻尼系数提供额外灵活性。在实际应用中,需根据任务调优学习率和动量系数以获得最佳性能。
如果需要更详细的数学推导、收敛曲线对比或其他优化器的比较,请告诉我!