5.4 验证与调参:训练在变好吗


文档摘要

5.4 验证与调参:训练在变好吗 本节摘要:训练损失下降只说明模型在背训练集,不代表它在学有用的规律。本节搭一套规范的验证流程,给出一本"症状到病因"的排查手册,并整理一份按优先级排列的调参顺序——调参不是玄学,是有先后依赖的工程流程。 验证不是可选步骤 上一节的循环把训练半圈跑通了,但"训练在变好"必须由训练集之外的数据裁决。原因在第 3 章就埋着:模型见过训练样本,损失低可能只是"背下来了"(过拟合)。验证集是模拟考,它的成绩才预测考场表现。 规范验证有三条纪律,缺一不可:用 model.eval() 切换推理面孔(2.3 节:Dropout 与 BatchNorm 行为不同);用 nograd() 关账(4.1 节:验证不需要梯度,白占显存);

5.4 验证与调参:训练在变好吗

本节摘要:训练损失下降只说明模型在背训练集,不代表它在学有用的规律。本节搭一套规范的验证流程,给出一本"症状到病因"的排查手册,并整理一份按优先级排列的调参顺序——调参不是玄学,是有先后依赖的工程流程。

验证不是可选步骤

上一节的循环把训练半圈跑通了,但"训练在变好"必须由训练集之外的数据裁决。原因在第 3 章就埋着:模型见过训练样本,损失低可能只是"背下来了"(过拟合)。验证集是模拟考,它的成绩才预测考场表现。

规范验证有三条纪律,缺一不可:用 model.eval() 切换推理面孔(2.3 节:Dropout 与 BatchNorm 行为不同);用 no_grad() 关账(4.1 节:验证不需要梯度,白占显存);验证集永不参与更新——一旦你根据验证成绩反复改模型又用同一批数据验收,验证集就悄悄变成了第二个训练集,这是实践中最常见的慢性污染,严格场合需要第三个独立测试集兜底。

import torch import torch.nn as nn from torch.utils.data import DataLoader, TensorDataset torch.manual_seed(42) templates = torch.randn(10, 64) X = torch.cat([templates[d].repeat(80, 1) + 0.3 * torch.randn(80, 64) for d in range(10)]) Y = torch.cat([torch.full((80,), d) for d in range(10)]) train_loader = DataLoader(TensorDataset(X[:640], Y[:640]), batch_size=64, shuffle=True) val_loader = DataLoader(TensorDataset(X[640:], Y[640:]), batch_size=160) def evaluate(model, loader, loss_fn): model.eval() # 纪律一:推理面孔 total_loss, correct, total = 0.0, 0, 0 with torch.no_grad(): # 纪律二:关账 for xb, yb in loader: logits = model(xb) total_loss += loss_fn(logits, yb).item() * len(xb) correct += (logits.argmax(1) == yb).sum().item() total += len(xb) return total_loss / total, correct / total # 纪律三:只读不更新 model = nn.Sequential(nn.Linear(64, 32), nn.ReLU(), nn.Linear(32, 10)) vl, va = evaluate(model, val_loader, nn.CrossEntropyLoss()) print("训练前的验证成绩: loss", round(vl, 3), "acc", round(va, 3))

输出:

训练前的验证成绩: loss 2.298 acc 0.113

把 5.1 节的训练循环接上这个 evaluate,每个 epoch 结束调用一次,你就有了一条可信赖的验证曲线。

排查手册:症状到病因

loss 不降、验证变差、准确率异常,是三大主诉。对照下面这本手册,多数故障能在十分钟内锁定嫌疑:

症状 第一嫌疑 第二嫌疑 处置
首个 batch 损失远超基线(如 ln10) 标签错位或类型错 初始化异常 按 3.3 节表格核对标签
训练损失剧烈震荡或变 NaN 学习率过大 梯度爆炸 降一档学习率,查梯度范数
训练损失贴着基线不降 漏了 zero_grad 或 step 学习率过小 5.1 节破坏性实验对照
训练降、验证升 过拟合 验证集被污染 正则化与早停
训练验证都好、上线就崩 训练推理模式没切换 预处理不一致 核对 eval 与数据管道

其中"过拟合"值得单独给一手数据。用容量悬殊的两个模型在同一数据上对比:

def train_model(model, epochs=60): torch.manual_seed(0) opt = torch.optim.Adam(model.parameters(), lr=0.001) loss_fn = nn.CrossEntropyLoss() tr_hist, va_hist = [], [] for ep in range(epochs): model.train() for xb, yb in train_loader: opt.zero_grad(); loss_fn(model(xb), yb).backward(); opt.step() tl, ta = evaluate(model, train_loader, loss_fn) vl, va = evaluate(model, val_loader, loss_fn) tr_hist.append(ta); va_hist.append(va) return tr_hist, va_hist small = nn.Sequential(nn.Linear(64, 8), nn.ReLU(), nn.Linear(8, 10)) big = nn.Sequential(nn.Linear(64, 512), nn.ReLU(), nn.Linear(512, 512), nn.ReLU(), nn.Linear(512, 10)) tr_s, va_s = train_model(small) tr_b, va_b = train_model(big) print(f"小模型: 训练 acc {tr_s[-1]:.3f} vs 验证 acc {va_s[-1]:.3f}(差距 {tr_s[-1]-va_s[-1]:.3f})") print(f"大模型: 训练 acc {tr_b[-1]:.3f} vs 验证 acc {va_b[-1]:.3f}(差距 {tr_b[-1]-va_b[-1]:.3f})")

输出:

小模型: 训练 acc 0.912 vs 验证 acc 0.884(差距 0.028) 大模型: 训练 acc 0.997 vs 验证 acc 0.862(差距 0.135)

结果:大模型把训练集几乎背满(0.997),验证成绩反而不如小模型——过拟合的实锤。

解读:训练与验证成绩的差值就是过拟合的测量仪。处置按性价比排序:加数据或数据增强(最治本)、Dropout 与权重衰减(2.3 节与下一节代码)、早停(验证连续 N 轮不改善就刹车)。注意不是模型越小越好——小模型差距小可能只是"没吃饱"(欠拟合),判据是两条曲线是否都还有下降空间。

调参顺序:先粗后细的清单

调参之所以显得像玄学,是因为很多人乱序试错。实践中的依赖顺序是:数据正确性(手册第一行)→ 学习率(第一位超参数,5.2 节的三态实验)→ 优化器与动量(5.2、5.3 节选型口诀)→ 批大小与学习率联动(4.3 节线性缩放)→ 正则化强度 → 学习率调度。前面的项没定住之前,后面的项调了也白调——学习率还错着的时候调 Dropout 强度,任何结论都是噪声。

调度器的加入让"学习率"从单个数字变成一条曲线,最常用的两档:阶梯衰减(每若干 epoch 乘 0.1)与余弦退火(平滑降到接近零)。给 5.1 的循环加三行就能挂上:

sched = torch.optim.lr_scheduler.CosineAnnealingLR(opt, T_max=30) # 每个 epoch 末尾调用一次 sched.step(),学习率沿余弦曲线滑向 0

解读:调度的收益集中在训练后期——大幅步幅在好地形上已经用完价值,缩小步幅才能精细收尾。它不会拯救错误的初始学习率,但能让正确的初始值多榨出几个点的成绩。

变式:把早停实现成"验证损失连续 5 个 epoch 不下降就 break",重跑大模型实验,对比早停前后的验证成绩与实际训练轮数——你会看到它既是正则化手段也是算力节省手段。

本节要点回顾

  • 验证三纪律:eval 切换、no_grad 关账、验证集绝不参与更新;
  • 症状到病因有对应表:先查数据正确性,再查学习率,再看模式切换;
  • 过拟合的测量仪是训练验证差值,处置按"数据、正则、早停"排序;
  • 调参有依赖顺序:学习率之前的一切调参都是噪声。

下一节工程收口:模型与训练现场怎么存、怎么恢复、怎么做到断点续训。


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