torch.optim.SGD
torch.optim.SGD
是 PyTorch 中实现的 随机梯度下降(SGD)优化器,用于更新模型参数。它是最基础也是最常见的优化算法之一。SGD 在训练神经网络时通过最小化损失函数来调整网络权重。
1. SGD 基本原理
随机梯度下降(SGD)是优化算法中的一种,它通过计算损失函数的梯度(即损失函数相对于模型参数的导数),然后沿着负梯度方向更新模型参数。它的更新公式如下:
θ = θ − η ⋅ ∇ θ J ( θ ) \theta = \theta - \eta \cdot \nabla_{\theta} J(\theta) θ=θ−η⋅∇θJ(θ)
- θ \theta θ:模型的参数。
- η \eta η:学习率(step size)。
- ∇ θ J ( θ ) \nabla_{\theta} J(\theta) ∇θJ(θ):损失函数相对于参数的梯度。
SGD 是一个基于批量的优化方法,每次更新只基于一个样本(或者一个小批量)。相比于 批量梯度下降(使用所有样本计算梯度),SGD 每次只计算一个样本的梯度,因而可以节省计算资源,尤其是在数据集较大的时候。
2. 语法
torch.optim.SGD(
params, # 需要优化的参数,通常是模型的参数
lr=0.01, # 学习率(默认为 0.01)
momentum=0, # 动量(默认为 0),用于加速SGD收敛
dampening=0, # 动量衰减(默认为 0)
weight_decay=0, # 权重衰减(L2正则化)系数
nesterov=False, # 是否使用 Nesterov 加速梯度(默认为 False)
foreach=None, # 是否使用每次迭代的 batch 更新,通常用在分布式训练中
maximize=False, # 是否最大化目标函数(默认为最小化损失函数)
differentiated=False # 是否与分布式环境兼容
)
3. 参数说明
-
params
:- 需要优化的参数,通常是模型的参数。可以传递一个包含模型参数的迭代器,通常使用
model.parameters()
。
- 需要优化的参数,通常是模型的参数。可以传递一个包含模型参数的迭代器,通常使用
-
lr
(学习率):- 控制每次参数更新的步长。较大的学习率可能导致梯度更新过大,而较小的学习率可能导致收敛速度过慢。
-
momentum
(动量):- 控制优化过程中的惯性,帮助加速 SGD 的收敛。动量项的引入可以有效减少更新过程中震荡的波动,使得更新趋于平稳。
-
dampening
:- 动量衰减,控制每次迭代中动量的衰减,默认为 0,通常不常用。
-
weight_decay
(权重衰减):- 是 L2 正则化的系数,控制权重的大小。较大的
weight_decay
会对较大的权重进行惩罚,防止过拟合。
- 是 L2 正则化的系数,控制权重的大小。较大的
-
nesterov
:- 是否启用 Nesterov 动量。Nesterov 动量在更新参数前会先预测一次梯度更新,从而比标准动量更快收敛。
-
foreach
:- 如果设置为
True
,则采用foreach
方法加速某些操作,通常在分布式训练中使用。
- 如果设置为
-
maximize
:- 是否最大化目标函数。默认是最小化目标函数(损失函数),如果要最大化目标函数(例如强化学习中的回报),可以将其设置为
True
。
- 是否最大化目标函数。默认是最小化目标函数(损失函数),如果要最大化目标函数(例如强化学习中的回报),可以将其设置为
-
differentiated
:- 是否与分布式环境兼容,通常用于分布式训练。
4. 基本使用示例
4.1 使用 SGD 优化器训练模型
import torch
import torch.nn as nn
import torch.optim as optim
# 定义一个简单的模型
class SimpleModel(nn.Module):
def __init__(self):
super(SimpleModel, self).__init__()
self.fc = nn.Linear(10, 2) # 输入大小10,输出大小2
def forward(self, x):
return self.fc(x)
# 创建模型实例
model = SimpleModel()
# 定义损失函数
criterion = nn.CrossEntropyLoss()
# 创建 SGD 优化器
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
# 模拟训练过程
for epoch in range(5):
optimizer.zero_grad() # 清空梯度
# 随机生成一个输入样本和目标标签
inputs = torch.randn(32, 10) # 假设一个批次32个样本,每个样本10个特征
labels = torch.randint(0, 2, (32,)) # 32个样本的二分类标签
# 前向传播
outputs = model(inputs)
# 计算损失
loss = criterion(outputs, labels)
# 反向传播
loss.backward()
# 更新参数
optimizer.step()
print(f'Epoch {epoch+1}, Loss: {loss.item():.4f}')
4.2 使用带动量的 SGD
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
# 与上述类似,进行训练时的参数更新
在这个例子中,momentum=0.9
使得每次更新不仅依赖于当前的梯度,还考虑了之前更新的历史信息,这可以加速收敛并减少震荡。
4.3 使用 Nesterov 动量
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9, nesterov=True)
Nesterov 动量比标准动量更加智能,它通过先进行预测更新来提高收敛速度。在优化过程中,Nesterov 动量比标准动量在收敛上更为高效。
5. 适用场景
- 常见深度学习优化算法:SGD 是最基础的优化算法之一,适用于大多数任务,尤其是参数较多且数据量较大的情况。
- 动量和 Nesterov 动量:当模型在训练过程中存在震荡时,可以启用动量或 Nesterov 动量来帮助加速收敛。
- L2 正则化:通过设置
weight_decay
参数,SGD 可以集成 L2 正则化,有助于控制模型的复杂度,防止过拟合。
6. 优缺点
优点:
- 简单且高效:SGD 是最基础的优化方法,理论简单,计算量小。
- 易于实现:与其他复杂优化算法相比,SGD 的实现非常简单。
- 适用于大规模数据:由于每次只计算一个样本的梯度,因此适合处理大规模数据。
缺点:
- 收敛速度慢:SGD 可能收敛较慢,特别是当数据复杂且梯度变化大时。
- 震荡问题:在某些情况下,SGD 更新会震荡,尤其在陡峭的梯度下降区域。
- 需要调参:需要调节学习率、动量等超参数来找到最佳的训练效果。
7. 总结
torch.optim.SGD
是 PyTorch 中最常用的优化器之一,适用于多种神经网络训练任务。- 通过设置不同的超参数(如
momentum
、weight_decay
、nesterov
等),SGD 可以更好地适应不同的训练场景和问题。 - 对于更复杂的任务,可以结合其他高级优化器(如 Adam)来进一步提高模型的训练效率和准确性。