推理精度下降主因是加载上下文未对齐:设备需用map_location指定、必须调用model.eval()和torch.no_grad()、预处理须与训练一致、state_dict加载后应校验键匹配,且需固定随机种子。

不是模型本身坏了,而是加载时的上下文断了。 推理精度下降几乎从不源于 torch.save 或 torch.load 本身出错,而是设备、模式、预处理或状态这几个环节中某一个没对齐。
设备不一致:GPU训练,CPU加载却没设 map_location
模型在 GPU 上训练后,state_dict 中的张量默认带有 CUDA 设备标记。如果直接用 torch.load("model.pth") 加载到 CPU 环境,PyTorch 会尝试把张量挪到 CPU,但这个过程可能触发隐式类型转换(如 float16 → float32 强制降级),或在某些旧版本中引发数值异常。
- 错误写法:
model.load_state_dict(torch.load("model.pth"))(无map_location) - 正确写法:
device = torch.device("cuda" if torch.cuda.is_available() else "cpu"),然后model.load_state_dict(torch.load("model.pth", map_location=device)) - 加载后务必调用
model.to(device),否则部分缓冲区(如 BatchNorm 的 running_mean)可能仍留在 CPU
训练/推理模式未切换:model.eval() 和 torch.no_grad() 缺一不可
Dropout 层在 train() 模式下会随机置零,在 eval() 模式下才恒等输出;BatchNorm 在 eval() 下使用统计的 running_mean/running_var,而非当前 batch 统计值。漏掉 model.eval(),模型行为就和训练时一样不稳定。
- 必须显式调用:
model.eval()(不是靠load_state_dict自动恢复) - 推理时务必包裹
with torch.no_grad():,否则梯度计算开销大,且某些算子(如 Dropout)在有 grad context 下行为异常 - 若模型含自定义层,检查其
forward中是否依赖self.training分支
预处理 pipeline 不一致:输入分布偏移比权重误差更致命
训练时用了 transforms.Normalize([0.485,0.456,0.406], [0.229,0.224,0.225]),推理时却忘了归一化,或顺序颠倒(先 resize 再 normalize vs 先 normalize 再 resize),都会让模型收到“没见过的数据”。尤其对 GCN 类模型,节点标签顺序因 set(labels) 无序导致编码映射错位,精度直接归零。
SkillSub Pro - Python 题解与代码注释双功能技能功能概述SkillSub Pro - Python 题解与代码注释双功能技能是一项面向实际任务的技能,主要用于SkillSub Pro 是一个 Python 题解生成与代码注释的 双功能合体技能 ,专为学生、算法学习者和开发者设计;✅ 一个技能,两种用途 :;核心要点📝 题解模式 :输入题目/题号,自动生成完整 Python 题解(含详细注释、解题思路、复杂度分析);💬 注释模式 :输入 Python 代码,自动添加详细中。它将相关步骤、
立即学习“Python免费学习笔记(深入)”;
- 检查图像通道顺序:训练是 RGB,部署脚本是否误用了 BGR?
- 确认 resize 尺寸与训练一致,且插值方式相同(
cv2.INTER_CUBICvsPIL.Image.BILINEAR数值微差可累积) - 对分类任务,验证 label 映射字典是否硬编码、是否依赖
os.listdir顺序(应排序后再构建)
state_dict 加载失败但没报错:键名不匹配静默跳过
load_state_dict(..., strict=True) 是默认行为,但一旦模型结构微调(比如加了新层、改了层名、删了 BN 缓冲区),它会直接抛 RuntimeError: Error(s) in loading state_dict。而很多人为了“不报错”改成 strict=False,结果是缺失的键被忽略、多余的键被丢弃——模型实际加载的参数少了一半,还浑然不知。
- 加载后务必验证:
assert len(model.state_dict()) == len(checkpoint),或打印不匹配键:missing, unexpected = model.load_state_dict(checkpoint, strict=False) - 若用
torch.load("model.pth")加载整个模型对象(不推荐),需确保 PyTorch 版本、模型类定义、__init__和forward完全一致,否则反序列化可能失败或加载错误对象 - 量化模型额外注意:校准后的 observer 状态(如 min/max)必须随
state_dict一起保存,否则加载后所有量化层退回到 FP32 fallback
最常被忽略的是:即使所有代码都写了,只要测试时没固定随机种子,Dropout 和 BatchNorm 的微小波动就能让单次准确率浮动 1–2 个百分点——这不是 bug,是没关掉随机性的正常表现。

















