4.3 优化器:调整参数的节奏与步幅


4.3 优化器:调整参数的节奏与步幅

本节摘要:优化器拿到梯度后决定"往哪走、走多快"。基础款 SGD 沿负梯度走固定步长;动量把近期梯度滑动平均,冲过小坑洼;Adam 再给每个参数配自适应步长,成为多数任务的默认起点。本节在一维抛物线上把三款的手感跑出来,并给出学习率的选择经验与排查套路。

三个步子的进化

参数更新的原始式只有一行:参数 = 参数 − 学习率 × 梯度。学习率是唯一的旋钮,太大一步迈过谷底来回震荡,太小半天挪不动。优化器的进化史就是在这行代码上做加法:动量给更新加惯性,Adam 给每个参数配各自的步长。理解它们的捷径不是背公式,而是在最简单的一维山谷里各跑几步——下面的账目全部可以手算复核。

学习目标

阅读完本节,你应当能够:

  1. 手算纯 SGD 与动量 SGD 在 f(w)=(w−3)² 上的前三步;
  2. 解释动量为何能加速穿过平缓区、抑制震荡;
  3. 说出 Adam 的两个滑动量与默认学习率 1e-3 的由来;
  4. 按任务规模与批大小给优化器和学习率做初始选型。

一、一维山谷里的三步账

目标函数 f(w) = (w−3)²,梯度 2(w−3),起点 w=0,学习率 0.1。纯 SGD 每步走 0.1×梯度:第一步 0 − 0.1×(−6) = 0.6,第二步 1.08,第三步 1.464——稳步逼近 3 但越走越慢。动量版给更新加一个 0.9 的惯性:每步位移 = 0.9×上次位移 − 0.1×梯度。手算三步:位移 0.6、1.02、1.194,位置 0.6、1.62、2.814——同样三步,动量版已经几乎抵达谷底。

def grad(w): # 目标:最小化 f(w) = (w − 3) 的平方 return 2 * (w - 3) w = 0.0 for i in range(3): w = w - 0.1 * grad(w) print(f"纯SGD 第{i+1}步 w={round(w, 3)}") # 0.6 1.08 1.464 w, v = 0.0, 0.0 for i in range(3): v = 0.9 * v - 0.1 * grad(w) # 位移是梯度的滑动平均 w = w + v print(f"动量SGD 第{i+1}步 w={round(w, 3)}") # 0.6 1.62 2.814

动量的含义读代码就懂:连续同向的梯度会累积位移(平缓的长坡上越滚越快),方向来回翻转的梯度互相抵消(震荡被滤平)。神经网络的损失面到处是平缓区与窄沟,这两个性质恰好对症——0.9 这个系数因此成了行业默认。

二、Adam:给每个参数配步长

动量解决了"方向",没解决"步长的贫富差距":梯度常年很大的参数(如嵌入层)步子总是很大,梯度常年很小的参数(如深层权重)步子总是很小。Adam 的方案是给每个参数记两个滑动量:梯度的均值(动量)与梯度的平方均值(振幅),更新时用均值除以振幅的平方根——梯度大的参数自动缩步,梯度小的自动扩步。默认学习率 1e-3 是它广泛测试后的甜点值,前几百步还会有一个小的预热,防止初期估计不稳。

import torch torch.manual_seed(0) X = torch.linspace(0, 1, 64).unsqueeze(1) y = 3 * X + 0.5 + 0.05 * torch.randn_like(X) # 拟合目标:w≈3,b≈0.5 def train(name, lr, steps=300): w = torch.zeros(1, 1, requires_grad=True) b = torch.zeros(1, requires_grad=True) opt = {"sgd": torch.optim.SGD([w, b], lr=lr), "adam": torch.optim.Adam([w, b], lr=lr)}[name] for _ in range(steps): opt.zero_grad() loss = ((X @ w.T + b - y) ** 2).mean() loss.backward() opt.step() return round(w.item(), 2), round(b.item(), 2) print("SGD lr=0.1 :", train("sgd", 0.1)) # 逼近 (3.0, 0.5) print("Adam lr=1e-3:", train("adam", 1e-3)) # 同样逼近,前几十步明显更快

两个优化器最终都收敛到 w≈3、b≈0.5,差别在收敛路径:Adam 前期走得又稳又快,SGD 配合学习率调度在长期精度上常有微弱优势。经验法则由此而来:赶基线用 Adam(1e-3),打磨精度用 SGD 加动量(0.01 到 0.1)配余弦退火;4.6 节的调度正好接上后半句。

三、选型速查与排错

场景 首选 初始学习率 备注
视觉分类从零训练 SGD 加动量 0.9 0.01 到 0.1 配合调度器
快速原型与微调头 Adam 或 AdamW 1e-3(头)到 1e-4(主干) 微调另见 4.7
小批次(8 到 16) Adam 系 1e-4 到 3e-4 批小噪音大,步子收小
损失爆炸 降学习率 + 梯度裁剪 减半到减十倍 先排除数据标签错误

排错口诀按顺序执行:损失不降先查学习率是否过大或过小;震荡查批大小与学习率;NaN 先查数据里有没有异常值、再上梯度裁剪;训练正常但验证不动,转去 4.6 节谈正则化。

追问两则

问:AdamW 的权重衰减为什么默认 0.01,和 SGD 的 5e-4 差这么多?答:两者作用机制不同——AdamW 的衰减与自适应步长相乘后等效强度被放大,量级自然上调,两者不是同一刻度,别互相照抄。问:热身要多少步?答:经验上占前半个到一个轮次即可(几百到几千步),图小批小时短些,大模型大批时长些;判断标准是训练初期的损失曲线是否平稳下行、没有尖刺。

巡检记录

  • 一行原始式:参数 = 参数 − 学习率 × 梯度,所有优化器都是它的加工升级;
  • 动量的三步账:0.6、1.62、2.814 对纯 SGD 的 0.6、1.08、1.464,惯性把平缓区走成了加速带;
  • Adam 的自适应:梯度均值管方向、平方均值管步长,默认 1e-3 是赶基线的默认答案;
  • 经验分工:精度打磨 SGD 加调度,速度优先 Adam 系,爆炸先降学习率再谈其他。

⚠️ 常见坑:换优化器时沿用旧学习率。Adam 的 1e-3 直接搬到 SGD 上几乎必然震荡(SGD 的常用值要大一到两个数量级),优化器与学习率是绑定选型,不能拆开换。

参数更新的节奏定了,还差原料的量与质。下一节看数据增强:如何在有限标注下把进料口撑宽。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U