(十三)优化器与每批一次更新
# 项目文件:demos/sgd_loop.py
import torch
from torch import nn
model = nn.Linear(1, 1)
with torch.no_grad():
model.weight.fill_(1)
model.bias.zero_()
optimizer = torch.optim.SGD(model.parameters(), lr=0.05)
x, y = torch.tensor([[2.0]]), torch.tensor([[5.0]])
for epoch in range(3):
optimizer.zero_grad(set_to_none=True) # 清理上一轮梯度。
loss = nn.MSELoss()(model(x), y)
loss.backward() # 只计算梯度;参数更新由 step 执行。
optimizer.step()
print("轮数", epoch + 1, "更新前损失", round(loss.item(), 6))
print("最终预测", round(model(x).item(), 6))这份程序把线性层的初始权重设为 1、偏置设为 0。SGD 的基本更新仍为 ,所以第一轮与手算完全相同。三次更新前的损失依次为 9、2.25、0.5625,第三次更新后的预测为 4.625。
| 调用 | 这一步实际发生的动作 |
|---|---|
optimizer.zero_grad(set_to_none=True) |
清理该优化器管理的参数梯度 |
model(x)、计算损失 |
用当前参数做前向,并建立本批计算图 |
loss.backward() |
把梯度累积到参数的 .grad |
optimizer.step() |
按优化器规则修改参数 |
完整项目使用 torch.optim.Adam。它还为各参数维护梯度的平滑统计和平方统计,按这些状态调整更新幅度。调用顺序与上表相同,具体更新规则与 SGD 不同,因此恢复 Adam 训练时还要保存优化器状态,不能只装回权重。
一批中有多条样本,一轮(epoch)会把训练集安排的各批走完;更新次数由批次数决定。144 条训练记录、每批 24 条时,一轮执行六次参数更新。