📑 本页目录(点开跳转)
PyTorch这个框架本身 · 按问题查阅
从屏幕上的报错出发,不用从第一页读起。
先找到稳定的报错片段,再看原因与对应章节。没有报错,也有单独的症状入口。
先做这一步
先看 traceback 最后一行;搜索不含个人变量名的短片段,例如 size mismatch for。
输入关键词定位条目;正文不会被隐藏。
附录A · 速查
⏱ 62 分钟 | ⭐ 按「你屏幕上那句话」反查原因 —— 每一条都是本机 torch 2.13.0+cpu 真触发出来、逐字抄的
🎯 一句话
这一页不讲道理,只回答一个问题:我看到了这句报错,它是什么意思、该去哪一章。
正文各章负责让你懂,这一页负责让你快。
先定位,不用通读
所有原始报错、原因和章节链接保留;搜索只提供定位,不隐藏正文。
🚦 怎么用这一页
⭐ 搜索的时候只搜报错里【不含你自己变量名】的那一段。 比如你看到的是
RuntimeError: Error(s) in loading state_dict for MyBackbone:
size mismatch for encoder.layer3.attn.qkv.weight: copying a param with shape torch.Size([2304, 768]) …
要搜的是 size mismatch for,不是 encoder.layer3.attn.qkv.weight。
⚠️ 另一条:PyTorch 的报错经常在最后一行才说真话,前面几十行是框架内部的调用栈。先看最后一行,再往上找你自己的文件名。
梯度与就地操作
先找稳定的报错片段,再沿右侧链接回到机制解释。
🧨 一、autograd 与梯度
| 报错原文(片段) | 常见原因 | 去哪 |
|---|---|---|
Trying to backward through the graph a second time (or directly access saved tensors after they have already been freed). |
⭐ 图默认用完就扔。多半是同一个 loss 调了两次 backward(),或者把上一步的图挂在了这一步上(RNN 的 hidden 忘了 detach())。真需要就 retain_graph=True,但先想想是不是漏了 detach |
02 |
element 0 of tensors does not require grad and does not have a grad_fn |
⚠️ 成因至少四种:①忘了 requires_grad=True ②在 no_grad() 里算的 ③中途绕出框架(numpy / .item() / 外部库)④自定义 Function 的 backward 里忘了 with torch.enable_grad(): |
02 · 04 · 09 |
grad can be implicitly created only for scalar outputs |
对一个非标量调了 backward()。要么 .sum() / .mean() 成标量,要么显式传 backward(torch.ones_like(y)) |
02 |
Can't call numpy() on Tensor that requires grad. Use tensor.detach().numpy() instead. |
⭐ 报错自带修法。注意 .detach() 之后还是共享内存的 |
01 · 04 |
UserWarning: The .grad attribute of a Tensor that is not a leaf Tensor is being accessed. |
⚠️ 这是 warning 不是报错,你会拿到 None。中间结果默认不留梯度,要留就 y.retain_grad() |
02 |
Inference tensors cannot be saved for backward. |
在 torch.inference_mode() 里造的张量流进了要求导的计算。报错自带两个修法:.clone() 一份,或者改用 torch.no_grad() |
04 |
🔧 二、就地操作
| 报错原文(片段) | 常见原因 | 去哪 |
|---|---|---|
a leaf Variable that requires grad is being used in an in-place operation. |
⭐ 直接改参数/叶子张量(w += 1、w.mul_(0.9))。要改就包在 with torch.no_grad(): 里,或者改 w.data(不推荐) |
03 |
a view of a leaf Variable that requires grad is being used in an in-place operation. |
同上,只是隔了一层 view / 切片(x.view(2,2).add_(1)、x[0] = 1) |
03 |
one of the variables needed for gradient computation has been modified by an inplace operation: […], which is output 0 of Sigmoid, is at version 1; expected version 0 instead. |
⭐ 前向存下来给反向用的中间结果被改了。which is output 0 of Xxx 直接点名了是哪个算子的输出,从那里往后找 _ 结尾的调用或 inplace=True |
03 · 09 |
上面那条后面跟着 Hint: enable anomaly detection …set_detect_anomaly(True, check_nan=False) |
照做。开了之后 Hint 会变成 the backtrace further above shows the operation that failed…,上方多出的那段栈才是真凶所在 |
03 |
形状、类型与模型状态
不要只让报错消失,还要核对输入与模型原来的约定。
📏 三、形状与 dtype
| 报错原文(片段) | 常见原因 | 去哪 |
|---|---|---|
mat1 and mat2 shapes cannot be multiplied (3x4 and 5x2) |
矩阵乘的内维对不上。⭐ 括号里两个形状按顺序就是左右操作数,4 != 5 一眼可见 |
01 |
mat1 and mat2 must have the same dtype, but got Double and Float |
⚠️ 十有八九是数据是 float64、模型是 float32。源头常在 DataLoader:__getitem__ 返回了 python float |
01 · 08 |
The size of tensor a (3) must match the size of tensor b (4) at non-singleton dimension 0 |
广播对不齐。从右往左逐维看,只有相等或其中一个是 1 才行 | 01 |
view size is not compatible with input tensor's size and stride (at least one dimension spans across two contiguous subspaces). Use .reshape(...) instead. |
⭐ 转置/切片之后内存不连续了。报错自带修法(.reshape),想要真连续用 .contiguous() |
01 |
Boolean value of Tensor with more than one value is ambiguous |
把一个多元素张量当成了 if 的条件。想问「有没有」用 .any(),「是不是全都」用 .all() |
01 |
a Tensor with 2 elements cannot be converted to Scalar |
.item() / float() 只能用在单元素张量上 |
01 |
Expected more than 1 value per channel when training, got input size torch.Size([1, 2]) |
⭐ BatchNorm 在 train() 模式下拿到了只有 1 条样本的 batch。最常见的成因是 drop_last=False 时最后一个 batch 只剩 1 条。修法:drop_last=True,或者推理时记得 .eval() |
07 · 08 |
IndexError: Target 5 is out of bounds. |
cross_entropy 的标签超出了 num_classes。⚠️ 类别从 0 开始编号 |
01 |
expected target dtype to be Long or Byte, but got Float |
分类标签必须是整型(.long()),别喂 one-hot 也别喂 float |
01 |
Expected input batch_size (4) to match target batch_size (2). |
输入和标签的第 0 维不一样长。常见于忘了 squeeze / 多算了一次切分 |
01 |
🧱 四、nn.Module 与 state_dict
| 报错原文(片段) | 常见原因 | 去哪 |
|---|---|---|
cannot assign module before Module.__init__() call |
⭐ __init__ 里忘了写 super().__init__(),而这一行正是让 nn.Module 的注册机制活起来的那一行 |
05 |
cannot assign 'torch.FloatTensor' as parameter 'w' (torch.nn.Parameter or None expected) |
想给一个已经是 Parameter 的属性赋一个普通张量。要改值用 w.data.copy_(...) 或 with torch.no_grad(): w.copy_(...) |
05 |
ValueError: optimizer got an empty parameter list |
⭐ 参数没被注册。最常见的是把子模块装进了 python list(要用 nn.ModuleList)或 dict(要用 nn.ModuleDict) |
05 |
AttributeError: 'Linear' object has no attribute 'fc3' |
名字写错,或者那个子模块在另一个分支里才创建 | 05 |
Error(s) in loading state_dict for X: size mismatch for 0.weight: copying a param with shape torch.Size([8, 4]) from checkpoint, the shape in current model is torch.Size([16, 4]). |
⭐ 结构超参对不上(隐层宽度、类别数、词表大小)。⚠️ 光有权重不够,构造超参必须一起交付 | 06 · 10 |
Missing key(s) in state_dict: "1.weight", "1.bias". |
模型比 checkpoint 多了层。strict=False 能放过,但放过的就是没被加载的 |
06 |
Unexpected key(s) in state_dict: "_orig_mod.fc1.weight", … |
⭐ 所有 key 都多了同一个前缀 = 你存的是包装过的模型。_orig_mod. 来自 torch.compile,module. 来自 DataParallel / DDP。✅ 存 model._orig_mod.state_dict() / model.module.state_dict() |
06 · 10 |
数据加载与自定义算子
先分清外层错误和内部真正出错的位置。
🚚 五、DataLoader 与多进程
| 报错原文(片段) | 常见原因 | 去哪 |
|---|---|---|
An attempt has been made to start a new process before the current process has finished its bootstrapping phase. |
⭐ Windows / spawn 下忘了 if __name__ == "__main__":。把建 DataLoader 和跑循环的代码放进去 |
08 |
Caught RuntimeError in DataLoader worker process 0. + Original Traceback (most recent call last): |
⚠️ 这不是错误本身,是一个信封。 真正的报错在下面那段 Original Traceback 的最后一行。💡 排查时先把 num_workers=0,栈就干净了 |
08 |
stack expects each tensor to be equal size, but got [3] at entry 0 and [4] at entry 1 |
⭐ 样本变长(文本 / 音频 / 点云)。自己写 collate_fn 用 pad_sequence 补齐,并且一定要把真实长度也返回,否则下游造不出 mask |
08 |
default_collate: batch must contain tensors, numpy arrays, numbers, dicts or lists; found <class '…'> |
__getitem__ 返回了自定义对象(PIL.Image、dataclass、spaCy 的 Doc)。在 __getitem__ 里就转成张量,或者自己写 collate |
08 |
🛠️ 六、自定义算子
| 报错原文(片段) | 常见原因 | 去哪 |
|---|---|---|
Legacy autograd function with non-static forward method is deprecated. Please use new-style autograd function with static forward method. |
💀 报错指错了方向:你的 forward 很可能已经写了 @staticmethod,真正的原因是你实例化了(Square()(x))。正确写法是 Square.apply(x) |
09 |
function XxxBackward returned an incorrect number of gradients (expected 2, got 1) |
⭐ backward 返回值的个数必须等于 forward 的入参个数。非张量入参返回 None 占位 |
09 |
GradcheckError: Jacobian mismatch for output 0 with respect to input 0, 后面跟着 numerical: / analytical: 两个矩阵 |
numerical 可信、analytical 是你写的。⭐ 先看两者的比值:差常数倍是系数写错,差符号是正负反了。⚠️ 但第一件事是确认输入是不是 torch.double —— float32 下正确的实现也会失败 |
09 |
UserWarning: Input #0 requires gradient and is not a double precision floating point or complex. |
就是上一条那个 dtype 问题的提醒,很容易被淹没在输出里 | 09 |
保存、导出与编译
把成功导出与交付后行为一致分开验收。
📦 七、保存、导出、编译
| 报错原文(片段) | 常见原因 | 去哪 |
|---|---|---|
ModuleNotFoundError: No module named 'xxx'(发生在 torch.load 里) |
💀 这个 checkpoint 是 torch.save(model) 存的,文件里写着你的模块路径。改过目录结构 / 改过类名 / 对方没有你的代码,都会撞上。✅ 只存 state_dict |
10 |
UnpicklingError: Weights only load failed. + WeightsUnpickler error: Unsupported global: GLOBAL xxx was not an allowed global by default. |
⭐ PyTorch 2.6 起 torch.load 默认 weights_only=True。⚠️ 最容易中招的是 checkpoint 里塞了 numpy 数组(GLOBAL numpy._core.multiarray._reconstruct)或配置对象(GLOBAL argparse.Namespace)。修法优先级:别塞对象 → torch.serialization.safe_globals([...]) → weights_only=False(仅限文件是自己产的) |
10 |
TracerWarning: Converting a tensor to a Python boolean might cause the trace to be incorrect. |
💀💀 这是 warning,但它意味着你的导出模型是错的:torch.jit.trace 把数据相关的 if 写死成了常量。✅ 改用 torch.jit.script 或 torch.export |
10 |
TracerWarning: torch.from_numpy results are registered as constants in the trace. |
💀💀💀 更狠的一种:forward 里绕出去用 numpy 算了,整段计算被折成一个常量。实测导出的 ONNX 图会没有输入、永远返回同一个值 |
09 · 10 |
ModuleNotFoundError: No module named 'onnxscript'(发生在 torch.onnx.export 里) |
PyTorch 2.9 起 ONNX 导出默认走新的 torch.export 导出器。装 onnxscript,或者 dynamo=False 退回老路(会收到一条 legacy TorchScript-based ONNX export 的 DeprecationWarning) |
10 |
GuardOnDataDependentSymNode: Could not guard on data-dependent expression … |
⭐ torch.export 遇到了数据相关的分支。这是好事 —— trace 会悄悄给你一个错模型,它选择报错 |
10 |
AssertionError: Guard failed: x.size()[0] == 2 |
torch.export 默认把形状写死了。用 torch.export.Dim("batch") 声明动态维。⚠️ 样例输入的 batch 别用 1(0/1 会被特化,会报 Constraints violated) |
10 |
InductorError: InvalidCxxCompiler: Compiler: cl is not found. |
torch.compile 的 CPU 后端要生成 C++ 再编译,Windows 上需要 MSVC 的 cl.exe(GPU 上则需要 Triton)。它不是纯 Python 的东西 |
10 |
不报错,却算错了
这里没有错误字符串可搜:按症状找下一步检查。
💀 八、不报错、但是错的(最贵的一类)
⭐ 这一节没有报错原文可搜 —— 正因为如此,它比上面所有条目加起来都值钱。
| 症状 | 真相 | 去哪 |
|---|---|---|
| loss 下降得比预期慢,或者收敛到一个稍差的点 | ⭐ 忘了 optimizer.zero_grad()。梯度是累加的:实测同一个 w 连做三次 backward(),w.grad 从 2 变成 6 |
02 |
| 验证集精度莫名其妙比训练时差 | 忘了 model.eval()(Dropout 还在丢、BN 还在更新 running 统计量) |
07 |
| 训练正常,但 GPU 上「开了混合精度却没提速」 | ⚠️ __getitem__ 返回了 python float,默认 collate 把它变成 float64,整条 loss 链路被静默提升成双精度 |
08 |
| 数据增强「看起来是随机的」,但训练效果就是差一点 | 💀 把随机数发生器存进了 self,每个 worker 拿到同一份副本。实测 num_workers=2 时 8 条样本去重后只剩 4 条 |
08 |
| 一个 epoch 变长了,每条数据被重复训练 | IterableDataset 在多 worker 下没分片:实测 6 条的数据集在 num_workers=3 下吐出 18 条 |
08 |
| 自定义算子的梯度大了一个整数倍 | 💀 用 ctx.x = x 而不是 ctx.save_for_backward(x):前者只存引用、没有版本检查,实测前向存的张量被就地改之后梯度从 [2,4,6] 变成 [20,40,60] 且不报错 |
09 |
| 导出的模型在你测的那条样例上完全正确,上线之后胡说八道 | 💀💀 trace / 老 ONNX 导出器把数据相关的分支写死了。实测负样例 PyTorch 给 [1.0, 2.0]、导出模型给 [-2.0, -4.0] |
10 |
⭐ 对付这一整类,只有一招通用:
导出/交付之后,拿一批(不是一条)真实数据,逐条比对原模型和交付物的输出。
覆盖边界与检查点
本页的环境限制、跨章导航和答案保持可见或可展开。
🗓️ 九、本页没有实跑的部分
⚠️ 本页所有报错原文都来自 torch 2.13.0+cpu,而本机 CUDA 不可用。 所以下面这几类故意没有收录,免得抄错一个字反而误导你:
| 类别 | 为什么没收 |
|---|---|
CUDA out of memory / Expected all tensors to be on the same device / CUDA error: device-side assert triggered |
🗓️ 未实跑 —— 需要 GPU。它们的报错文本里带具体显存数字和设备编号,抄不得 |
| NCCL / 分布式训练的超时与卡死 | 同上,且属于 《AI基础设施》 的范围 |
torch.compile 编译成功之后的行为(重编译、graph break 日志) |
🗓️ 本机连 cl.exe 都没有,只跑到了 InvalidCxxCompiler 那一步 |
🔗 这一章连到哪里
| 相关的地方 | 为什么 |
|---|---|
| 00 · 怎么用这份教程 | 章节地图和几条读法路线 |
| 《机器学习与深度学习基础》15 · PyTorch 实战手册 | ⭐ 「十分钟跑通一个训练循环」和六个高频 Bug 在那里 —— 本板块刻意不重复那一层 |
| 《机器学习与深度学习基础》附录C · 手撕代码速查 | 面试要手写的那批实现(含 .contiguous() 的急救写法) |
| 《AI基础设施》附录A · 速查 | 显存账、并行策略、推理优化那一侧的速查 |
| 《Python 会咬你的地方》 | 进程模型、GIL、pickle 代价 —— DataLoader 那几条报错的下一层 |
| 《框架底下是 C++》 | 报错栈掉进 C++ 之后怎么读、算子在那一侧怎么注册 |
✅ 检查点
- 搜报错的时候,该搜哪一段、不该搜哪一段?为什么说「先看最后一行」?
element 0 of tensors does not require grad and does not have a grad_fn至少有哪四种成因?which is output 0 of Sigmoid, is at version 1这句话里,哪个信息对定位最有用?- 看到
Unexpected key(s)且所有 key 都多了同一个前缀,是什么情况?_orig_mod.和module.分别来自谁? Caught RuntimeError in DataLoader worker process 0为什么说它「不是错误本身」?排查第一步做什么?Legacy autograd function with non-static forward method为什么说它指错了方向?GradcheckError出现时,第一件该做的事是什么(不是改代码)?- 哪两条
TracerWarning意味着「你的导出模型已经错了」? - 第八节里那七条「不报错但是错的」,有没有一招通用的对付办法?
- 本页为什么不收录
CUDA out of memory这类报错?
👀 答案
- 搜不含你自己变量名的那一段(
size mismatch for而不是encoder.layer3.attn.qkv.weight)。PyTorch 的报错经常最后一行才说真话,前面几十行是框架内部调用栈 —— 先看最后一行,再往上找你自己的文件名。 - ①忘了
requires_grad=True②在no_grad()里算的 ③中途绕出框架(numpy /.item()/ 外部库)④自定义Function的backward里忘了with torch.enable_grad():。 output 0 of Sigmoid—— 它直接点名了被改掉的是哪个算子的输出,从那里往后找_结尾的调用或inplace=True就行。(version 1 / expected 0只说明被改过一次。)另外这条报错的 Hint 建议开set_detect_anomaly(True),开了之后 Hint 会变成「上方的 backtrace 里有真凶」。- 你存的是包装过的模型的
state_dict。_orig_mod.来自torch.compile,module.来自DataParallel/DDP。✅ 存model._orig_mod.state_dict()或model.module.state_dict()。 - 因为它只是个信封 —— 真正的报错在下面那段
Original Traceback的最后一行。排查第一步:把num_workers设成 0,栈就干净了(⚠️ 但这招会掩盖「发生器存进self」那个随机数 bug)。 - 因为你的
forward很可能已经写了@staticmethod—— 真正的原因是你实例化了(Square()(x)),正确写法是Square.apply(x)。看到这条先去找多出来的那对括号。 - 先确认输入是不是
torch.double。float32下即使实现完全正确也会失败(有限差分在单精度下没有效位剩下),PyTorch 会给一条UserWarning: Input #0 requires gradient and is not a double precision…,但很容易被淹没。dtype 没问题之后,再看numerical和analytical的比值找线索。 - ①
Converting a tensor to a Python boolean might cause the trace to be incorrect.(数据相关的if被写死成常量)②torch.from_numpy results are registered as constants in the trace.(整段计算被折成常量 —— 实测导出的 ONNX 图没有输入,永远返回同一个值)。⚠️ 两条都是 warning,不是报错。 - 有:导出/交付之后,拿一批(不是一条)真实数据,逐条比对原模型和交付物的输出。 这一整类的共同点就是「在你测的那一条上完全正确」。
- 因为本页所有报错都来自 torch 2.13.0+cpu,本机 CUDA 不可用,而这类报错的文本里带具体显存数字和设备编号 —— 🗓️ 抄错一个字反而误导。分布式那一侧属于《AI基础设施》。
🛑 可以停在这里
⚡ 走神救援
- 先看 traceback 最后一行,搜索不含个人变量名的报错片段。
- 梯度异常先查图是否断了;就地操作报错里,算子的输出名称能帮助定位。
- state_dict 的形状与前缀要和模型结构、包装方式一起核对;DataLoader 的 worker 报错还要看内部原始栈。
- 没有报错不等于行为正确;按第八节症状排查,并对照原模型与交付物的批量输出。
下一节 👉 回到板块索引