常见坑
每一章对着一个 PyTorch 或 transformers 的习惯:先写出 PyTorch 那边的写法和输出,再照搬到 candle,给出现象(报错原文或静默的错误结果),然后到 0.11.0 的源码里找原因,最后给出改法和检查办法。机制在前面几部分讲过的,这里只链过去;candle 卷的常见坑从 candle 自身出发,和这里互补。
复现环境都是 M2 Max、macOS 27、rustc 1.99.0、PyTorch 2.15.0、transformers 5.22.0、candle 0.11.0;没有特别说明时 candle 用 CPU(开 accelerate),PyTorch 用 CPU。
flowchart TB habit["PyTorch 的写法"] --> port["照搬到 candle"] port --> ce["编译不过"] port --> err["运行时 Err"] port --> pn["panic"] port --> silent["静默得到错的数"] ce --> fix["改法"] err --> fix pn --> fix silent --> chk["怎么检查"] chk --> fix
最危险的是不报错的那几类:整数和浮点混算(4、5)、Metal 上的越界下标(9)、几个上游问题(10、12),以及 config、缓存和取样上的静默偏差(20、21、26、27)。它们只能靠和 PyTorch 逐个数对照才能发现,方法见怎么读这一卷。
dtype 与整数
- dtype mismatch in mul, lhs: F32, rhs: F64:浮点字面量是 F64,没有类型提升;Metal 上 F64 能上传、不能运算。
- shape mismatch in add / matmul / where_cond:
+不广播,matmul不收一维,where_cond不收标量。 - unsupported dtype F32 for op index-select:整数字面量是 I32,报错报的却是被索引张量的 dtype;U8 下标不是掩码。
- 整数张量配浮点数:掩码全变成 0:整数张量乘加浮点标量,CPU 和 Metal 各算各的。
- 数掩码里的 1:290 个加出 34:U8 求和不提升,release 回绕、debug panic;整数除零 panic。
形状与索引
- invalid index 18446744073709551516:没有
ignore_index;-1 转成 U32 静默读出 0。 - narrow invalid args start + len > dim_len:切片超出长度不截断,没有负下标和步长。
- logits 里有 NaN,贪心选了别的 token:
max/argmax遇到 NaN,CPU 看位置,Metal 跳过。
Metal 与上游问题
- Metal 上越界下标不报错:
index_select截到最后一行,gather读相邻行。 - expand 之后 matmul,后几批算错:不开
accelerate的 CPU 上,左边批维广播时静默算错。
训练
- clone 出来的快照跟着参数变:
clone、detach共享存储,Metal 上copy也是。 - conv1d 的卷积核梯度不对:batch 大于 1、输出通道大于 1 时静默算错,附一个 im2col 的绕法。
模块
- F.gelu 搬成 x.gelu(),隐状态差 1.93e-2:candle 的
gelu是 tanh 近似。 - unknown variant
quick_gelu:Activation只认一部分 transformers 的激活函数名。
权重
- from_pth 读到 0 个张量:嵌套检查点、整个模型、TorchScript 都不报错。
- invalid Zip archive: Could not find EOCD:旧格式打不开,bool / int32 被跳过。
- cannot find tensor model.embed_tokens.weight:
save_model留下的是lm_head.weight;分片的 index.json 不是权重文件。 - rename_f 之后前缀出现两次:先
pp再rename_f时前缀加了两遍。 - unsupported dtype BF16 for op matmul:CPU 上的半精度:BF16 报错,F16 要么报错要么误差大一个量级。
LLM 与 KV 缓存
- rope_theta 静默变成 10000:transformers 5 重存的 config 把它放进
rope_parameters。 - cannot broadcast [5, 5] to [1, 9, 5, 29]:位置不从缓存推断;复用缓存换 prompt。
- dtype mismatch in rope BF16 F32 F32:模型和
Cache的 dtype 要一致。 - Llama::load 和 forward 会 panic:缺层、没开 flash-attn、位置超过 8192。
算子
- SDPA has no cpu impl:融合注意力只有 Metal 版,头维度有白名单。
- no method named
topkfound:topk、masked_fill、nonzero、einsum都没有。
生成
- 同样的取样参数,分布不一样:
do_sample=True隐含top_k=50;top-k 加 top-p 的归一化不同。 - 重复惩罚罚的范围不同:公式一样,HF 罚整个上下文,candle 的例子只罚最后一段。
- 第一个 token 就是
<|im_end|>:没套对话模板、不查 eos。 - 流式输出的中文全是 �:一个汉字跨几个 token,要增量解码。
💬 关联讨论
发起讨论加载中...