一、反向传播就像教小朋友认字
想象你在教小朋友认字,每次写错就擦掉重写。卷积神经网络(CNN)也是这样学习的:
- 前向传播相当于小朋友写出答案
- 反向传播就是老师用红笔圈出错误
- 参数更新就是小朋友根据批改结果改正
用Python示例说明参数更新过程(技术栈:PyTorch):
import torch
import torch.nn as nn
# 定义一个简单的CNN
model = nn.Sequential(
nn.Conv2d(1, 3, kernel_size=3), # 输入1通道,输出3通道
nn.ReLU(),
nn.MaxPool2d(2),
nn.Flatten(),
nn.Linear(27, 10) # 假设最终输出10类
)
# 模拟输入和标签
inputs = torch.randn(5, 1, 10, 10) # 5张10x10的灰度图
labels = torch.randint(0, 10, (5,)) # 随机生成5个标签
# 前向传播
outputs = model(inputs)
loss = nn.CrossEntropyLoss()(outputs, labels)
# 关键的三步曲
loss.backward() # 反向传播计算梯度
optimizer = torch.optim.SGD(model.parameters(), lr=0.1)
optimizer.step() # 参数更新
注释说明:
loss.backward()会计算每个参数的梯度optimizer.step()根据梯度更新参数- 这里的
lr=0.1就是学习率,相当于小朋友每次改正的力度
二、学习率衰减就像调整教学进度
刚开始学习时步子可以迈大些(大学习率),后期要小步调整(小学习率)。常见衰减策略:
- 阶梯衰减:每10轮学习率减半
scheduler = torch.optim.lr_scheduler.StepLR(
optimizer,
step_size=10, # 每10个epoch
gamma=0.5 # 学习率乘0.5
)
- 余弦退火:像余弦曲线一样平滑下降
scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(
optimizer,
T_max=50 # 50个epoch完成一个周期
)
- 热重启:偶尔突然提高学习率跳出局部最优
scheduler = torch.optim.lr_scheduler.CosineAnnealingWarmRestarts(
optimizer,
T_0=10 # 每10个epoch重启一次
)
实际案例对比:
# 训练循环示例
for epoch in range(100):
train(...)
validate(...)
scheduler.step() # 更新学习率
# 打印当前学习率
print(f"Epoch {epoch}, LR: {optimizer.param_groups[0]['lr']}")
注意事项:
- 图像分类任务常用初始学习率0.1-0.001
- 学习率太小会导致训练停滞,太大会震荡
- 配合验证集准确率监控调整策略
三、动量优化相当于给参数更新加惯性
想象滑雪下坡时会有惯性,动量优化同理:
- 普通动量:像带着重量的球滚下山坡
optimizer = torch.optim.SGD(
model.parameters(),
lr=0.01,
momentum=0.9 # 动量系数
)
- Adam:动态调整每个参数的动量
optimizer = torch.optim.Adam(
model.parameters(),
lr=0.001,
betas=(0.9, 0.999) # 一阶和二阶动量系数
)
动量工作原理示例:
# 模拟参数更新过程
v = 0 # 初始速度
momentum = 0.9
for i in range(100):
grad = get_gradient() # 获取当前梯度
v = momentum * v - 0.01 * grad # 新速度 = 旧速度*动量 - 学习率*梯度
param += v # 参数更新
典型应用场景:
- 处理损失函数的鞍点和平缓区域
- 当梯度方向频繁变化时特别有效
- 对批量归一化(BatchNorm)层尤其重要
四、组合拳实战案例
以CIFAR-10图像分类为例的完整配置:
model = ResNet18().cuda()
optimizer = torch.optim.SGD(
model.parameters(),
lr=0.1,
momentum=0.9,
weight_decay=5e-4 # L2正则化
)
# 学习率先预热再余弦衰减
scheduler = torch.optim.lr_scheduler.SequentialLR(
optimizer,
[
# 前5个epoch线性增加学习率
torch.optim.lr_scheduler.LinearLR(
optimizer, start_factor=0.01, total_iters=5
),
# 之后余弦衰减
torch.optim.lr_scheduler.CosineAnnealingLR(
optimizer, T_max=195
)
]
)
# 训练循环
for epoch in range(200):
adjust_learning_rate(optimizer, epoch) # 自定义调整策略
train_one_epoch(model, optimizer)
scheduler.step()
关键技巧总结:
- 先用大学习率快速收敛,后期用小学习率微调
- 配合动量避免陷入局部最优
- 重要参数要监控梯度变化
- 不同层可以使用不同学习率(如 backbone 和 head)
五、常见问题诊断手册
当训练出现这些问题时应该检查:
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 损失值剧烈震荡 | 学习率太大 | 减小学习率或增加批量大小 |
| 验证集准确率不提升 | 陷入局部最优 | 增加动量或尝试Adam优化器 |
| 训练后期进展缓慢 | 学习率衰减过快 | 改用余弦衰减或热重启策略 |
| 不同层收敛速度差异大 | 未分层设置学习率 | 使用param_groups分别设置 |
最后记住:没有放之四海而皆准的超参配置,关键是要:
- 理解算法原理
- 建立有效的监控机制
- 根据任务特性做针对性调整
评论