一、反向传播就像教小朋友认字

想象你在教小朋友认字,每次写错就擦掉重写。卷积神经网络(CNN)也是这样学习的:

  1. 前向传播相当于小朋友写出答案
  2. 反向传播就是老师用红笔圈出错误
  3. 参数更新就是小朋友根据批改结果改正

用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就是学习率,相当于小朋友每次改正的力度

二、学习率衰减就像调整教学进度

刚开始学习时步子可以迈大些(大学习率),后期要小步调整(小学习率)。常见衰减策略:

  1. 阶梯衰减:每10轮学习率减半
scheduler = torch.optim.lr_scheduler.StepLR(
    optimizer, 
    step_size=10,  # 每10个epoch
    gamma=0.5     # 学习率乘0.5
)
  1. 余弦退火:像余弦曲线一样平滑下降
scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(
    optimizer,
    T_max=50  # 50个epoch完成一个周期
)
  1. 热重启:偶尔突然提高学习率跳出局部最优
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
  • 学习率太小会导致训练停滞,太大会震荡
  • 配合验证集准确率监控调整策略

三、动量优化相当于给参数更新加惯性

想象滑雪下坡时会有惯性,动量优化同理:

  1. 普通动量:像带着重量的球滚下山坡
optimizer = torch.optim.SGD(
    model.parameters(),
    lr=0.01,
    momentum=0.9  # 动量系数
)
  1. 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()

关键技巧总结:

  1. 先用大学习率快速收敛,后期用小学习率微调
  2. 配合动量避免陷入局部最优
  3. 重要参数要监控梯度变化
  4. 不同层可以使用不同学习率(如 backbone 和 head)

五、常见问题诊断手册

当训练出现这些问题时应该检查:

现象 可能原因 解决方案
损失值剧烈震荡 学习率太大 减小学习率或增加批量大小
验证集准确率不提升 陷入局部最优 增加动量或尝试Adam优化器
训练后期进展缓慢 学习率衰减过快 改用余弦衰减或热重启策略
不同层收敛速度差异大 未分层设置学习率 使用param_groups分别设置

最后记住:没有放之四海而皆准的超参配置,关键是要:

  1. 理解算法原理
  2. 建立有效的监控机制
  3. 根据任务特性做针对性调整