坐下 4 / 6
循环只有三拍。曲线告诉你第几拍坏了。
梯度算对只完成一半。还要按固定顺序更新,并且真的在看两条损失,而不是只盯训练数字往下掉就鼓掌。
zero_grad → backward → step
PyTorch 默认把梯度累加。一个 mini-batch 用完,下一步若不清零,新梯度会叠在旧的上面,步子越走越怪。典型一拍:
for x, y in loader:
opt.zero_grad(set_to_none=True)
loss = criterion(model(x), y)
loss.backward()
opt.step()
backward 只填 .grad,不改参数。step 才按学习率去减。把 zero_grad 写在 step 之后且下一次循环开始前也行,前提是你清楚「这轮用的是刚算的那份」。写丢其中一拍,曲线会给你三种常见样子:不动、乱跳、训练损失假下降。
学习率 0.1 在上一页那个五参数例子里,损失从 0.211 降到 0.108。换成 10,一步就可能越过谷底,损失变大。换成 1e-8,五十步看起来像一条平线。先用能在十步内拉动训练损失的步长,再谈 Adam 的 β。
先过拟合一个小集合
拿 8 到 32 个样本、关掉随机增强、把模型开得略大,故意让它把这一小撮记住。训练损失应能降到接近 0,训练准确率顶到 1。这一步过不了:标签和 logits 对错轴、学习率炸了、忘了 model.train()、损失接到了常数。先修管道,再谈泛化。
管道通了,再打开验证集。验证损失用于挑何时停。测试集仍封着。不要用验证曲线的最低点去对外宣传——那是选择模型用的,不是最终估计。shuffle 只打乱训练;验证按固定顺序,曲线才能和上次比。batch 从 32 改到 2,损失噪声会变大,看起来像没收敛,其实只是估计变差。先固定 batch 再谈学习率。
三条线分别叫什么
训练降、验证降:还在学。若两者一起降但停在很高的地方,容量不够或标签噪声大,先别加 dropout,那会再挡一层。
训练降、验证升:记住训练样本了。停早、加数据、加一点权重衰减。继续报训练损失没有意义。
两条都平:学习率太小像没走;太大通常先抖再变 NaN;也可能 zero_grad 没写、目标是错的、把准确率当损失在最小化。先印几个 batch 的 loss 原始值。从第一步起就是 0 或 NaN,是代码,不是「还需要更多 epoch」。交叉熵第一步常在 log K 附近:十类约 2.3。一上来就是 1e-5,多半标签和 softmax 接反了。
给三条草图起名
实线训练,虚线验证。点选名称。
自己对过
一起降:还在学。分叉:过拟合。卡住:先查学习率和那三拍有没有写全。