Skip to content

排错与 FAQ:新手最常撞的 8 堵墙

遇到报错先别慌着搜答案——本篇每条都给出"报错原文 → 原因 → 解决 → 调试思路"。建议当字典用:撞墙了 Ctrl+F 报错关键词。

Q1:mat1 and mat2 shapes cannot be multiplied (Ax B and CxD)

原因:矩阵乘的中间维度对不上,即进入 nn.Linear 的最后一维 ≠ in_features

解决:沿报错向上追一层,print(x.shape) 找到形状开始"不对味"的位置。常见修法:缺 nn.Flatten() / view 参数算错 / batch 维丢了。

思路:拿草稿纸把每层"输入形状 → 权重形状 → 输出形状"列成表。这道题没有捷径,形状表就是深度世界的堆栈跟踪。

Q2:Expected all tensors to be on the same device

原因:张量在 CPU、模型在 GPU(或反之)。

解决:统一三件套——model.to(device);每个 batch images.to(device);中途手工创建的张量(如 mask)也要 .to(device)

思路:报错信息会给出两边的 device(cuda:0 vs cpu)。顺着"新出现的那个张量是谁创建的"找漏网之鱼。

Q3:loss 不降 / 训练不收敛(不报错的那种)

最阴险的问题,按概率从高到低排查:

  1. zero_grad() —— 梯度累加,参数原地打摆(实战篇踩过)。
  2. 学习率不当 —— 太大:loss 震荡或 NaN;太小:几乎不动。先做 3 档扫描。
  3. 标签或数据管道错位 —— shuffle=True 时 Dataset 的 __getitem__ 返回了不配对的 (x, y)。
  4. 忘了 model.train() / 参数没进优化器 —— 打印 len(opt.param_groups[0]['params']) 核对。

通用杀招:过拟合单个 batch——拿一个 batch 反复训 100 步,loss 不趋近 0 就说明管线有 bug,与数据集无关。

Q4:CUDA out of memory

原因:显存超限。注意:报错时的占用包含其他进程(同事的训练任务、Jupyter 里没释放的旧 notebook)。

解决(按序尝试):

  1. 减小 batch_size(减半试)
  2. 评估代码套 torch.no_grad()(忘记它等于白白存下整张计算图)
  3. 开启 AMP 混合精度
  4. del 大张量; torch.cuda.empty_cache() 手动释放(应急)
  5. 梯度累积模拟大 batch

思路nvidia-smi(Linux 终端 / Windows PowerShell)边训边看,区分"启动就炸"(模型太大)还是"训着训着炸"(内存泄漏,常因把 loss 张量直接 append 进列表——应存 loss.item())。

Q5:Can't call numpy() on Tensor that requires grad... / Converting a tensor with requires_grad=True

原因:带梯度的张量不能直接转 NumPy;GPU 张量也不能直接转。

解决x.detach().cpu().numpy() —— 剪断梯度 → 搬回 CPU → 转数组。

思路:报错第一行通常直接给了解药关键词(detach / cpu)。记住这条流水线,可视化、指标计算全靠它。

Q6:Windows 上运行直接卡死 / 疯狂递归打印 / Attempt to start a new process before booting...

原因DataLoader(num_workers>0) 在 Windows 用 spawn 启动子进程,子进程重新导入主模块,而主逻辑没被保护块拦住。

解决:所有入口代码放进 if __name__ == "__main__":(实战篇的 train.py 从第一天就是这么写的);或先用 num_workers=0 验证逻辑,再加并发。

Q7:Error(s) in loading state_dict for XXX: Missing key(s) ... Unexpected key(s) ...

常见三种情形

报错特征原因解决
Unexpected key "module.xxx"训练用了 DataParallel/DDP,保存的 state_dict 带 module. 前缀加载时去掉前缀,或加载进 model.module
Missing/Unexpected 都是若干层模型结构与权重不匹配(改了网络定义)用同一份模型定义加载;strict=False 只能应急,必须检查差在哪
尺寸不匹配in_features/out_features 对不上对照保存时的结构改回来

思路:先 print(model.state_dict().keys()) 对比权重文件 torch.load(..., weights_only=True).keys(),差异一目了然。

Q8:明明切了评估模式,为什么每次推理结果还不一样?

可能原因

  1. 评估前没 model.eval()(Dropout 还在工作)。
  2. torch.rand 没设种子,数据增强每次不同。
  3. 模型里含 BatchNorm 且在评估时又误调了 model.train()

解决:评估/推理固定套路 model.eval() + with torch.no_grad():;复现实验最前面统一设种(torch.manual_seed,需要更强复现见 torch.use_deterministic_algorithms(True))。

通用调试心法

  1. 缩小规模:模型削到 2 层、数据取 1 个 batch、epoch 设 1——问题还在才好定位。
  2. 打印形状和统计量x.shapex.dtypex.devicex.min()/max(),四个属性覆盖一半 bug。
  3. 梯度体检for n, p in model.named_parameters(): print(n, p.grad is None, p.grad.norm())——None 说明图断了,inf/nan 说明爆炸了。
  4. 读报错从最后往上读到自己写的那一行:PyTorch 的 traceback 很长,但最后一帧指向的才是你的代码。

更多可查:快速参考卡片 或回到 心智模型 检查理解偏差。