训练模式和推理模式有什么区别?为什么要切换?
简化版
train() 与 eval() 切换的是模块行为,不是是否计算梯度:Dropout 在训练态随机屏蔽、评估态关闭;BatchNorm 训练态用批统计并更新滑动量、评估态用固定统计。推理通常还需 no_grad() 或 inference mode 节省计算图。
详细版
-
model.eval()不会自动禁用 autograd。 -
torch.no_grad()不会自动关闭 Dropout 或切换 BN。 -
验证前切 eval,结束后若继续训练必须切回 train。
-
Monte Carlo Dropout 可有意在推理时保留 Dropout,但 BN 策略应单独控制。
-
冻结参数与模块模式是两个独立维度。
完整版教学
一、模式开关控制层语义,梯度开关控制图记录
某些层在训练与评估必须使用不同随机性或统计量,框架用 module.training 递归传递模式。
普通线性层通常不受影响。
autograd 则决定是否保存反向依赖。
评估态下仍可计算输入梯度做攻击或解释,训练态下也可临时 no_grad 做教师前向。
二、底层机制与公式
training: Dropout(x)=mask*x/(1-p); BN uses batch stats
eval: Dropout(x)=x; BN uses running stats
mode switch != gradient switch
三、带数字的推演
Dropout p=0.5 时,训练态保留单元会乘 2,使期望不变;评估态不再随机且不乘 2。
同一输入若忘记 eval,多次输出会不同,准确率也会抖动。
四、方案对比
| 方案/对象 | 核心特点 | 代价或边界 |
|---|---|---|
| train + grad | 标准训练 | 更新参数和 BN 统计 |
| eval + no_grad | 标准验证/推理 | 确定且省显存 |
| eval + grad | 解释/输入梯度 | 层固定但仍建图 |
五、执行流程
训练循环: model.train -> forward/backward/update
验证阶段: model.eval -> no_grad -> metrics
返回训练: model.train -> 下一 epoch
六、边界条件与工程代价
只冻结 BN 的 γ/β 不会阻止 running stats 更新;要固定统计量需让对应 BN 保持 eval。
反过来 eval 也不会让参数 requires_grad=False。
分布式验证要聚合所有 rank 的指标和样本数。
模式正确只保证层行为,不能修复指标只统计单卡的问题。
记忆钩子:用两只开关记忆:train/eval 管“层怎么做”,grad/no_grad 管“图记不记”。
七、常见误区与追问
-
误区:model.eval() 等于 no_grad()。 前者改模块行为,后者控制计算图。
-
追问:忘记 eval 会影响哪些层? 典型是 Dropout 和 BatchNorm。
-
误区:no_grad 下模型自动使用 running mean。 BN 是否用滑动统计只由模式决定。
-
追问:验证后为何要 train()? eval 状态会保留,后续 Dropout/BN 否则继续按推理方式运行。
-
追问:何时 eval 仍需梯度? Grad-CAM、输入优化和对抗评估等场景。
八、加强记忆
用两只开关记忆:train/eval 管“层怎么做”,grad/no_grad 管“图记不记”。
标准推理两者都要切,但概念不能合并。