Rust in Everything
基于 candle 0.11.0

常见坑

每一章对着一个 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 与整数

  1. dtype mismatch in mul, lhs: F32, rhs: F64:浮点字面量是 F64,没有类型提升;Metal 上 F64 能上传、不能运算。
  2. shape mismatch in add / matmul / where_cond:+ 不广播,matmul 不收一维,where_cond 不收标量。
  3. unsupported dtype F32 for op index-select:整数字面量是 I32,报错报的却是被索引张量的 dtype;U8 下标不是掩码。
  4. 整数张量配浮点数:掩码全变成 0:整数张量乘加浮点标量,CPU 和 Metal 各算各的。
  5. 数掩码里的 1:290 个加出 34:U8 求和不提升,release 回绕、debug panic;整数除零 panic。

形状与索引

  1. invalid index 18446744073709551516:没有 ignore_index;-1 转成 U32 静默读出 0。
  2. narrow invalid args start + len > dim_len:切片超出长度不截断,没有负下标和步长。
  3. logits 里有 NaN,贪心选了别的 token:max / argmax 遇到 NaN,CPU 看位置,Metal 跳过。

Metal 与上游问题

  1. Metal 上越界下标不报错:index_select 截到最后一行,gather 读相邻行。
  2. expand 之后 matmul,后几批算错:不开 accelerate 的 CPU 上,左边批维广播时静默算错。

训练

  1. clone 出来的快照跟着参数变:clone、detach 共享存储,Metal 上 copy 也是。
  2. conv1d 的卷积核梯度不对:batch 大于 1、输出通道大于 1 时静默算错,附一个 im2col 的绕法。

模块

  1. F.gelu 搬成 x.gelu(),隐状态差 1.93e-2:candle 的 gelu 是 tanh 近似。
  2. unknown variant quick_gelu:Activation 只认一部分 transformers 的激活函数名。

权重

  1. from_pth 读到 0 个张量:嵌套检查点、整个模型、TorchScript 都不报错。
  2. invalid Zip archive: Could not find EOCD:旧格式打不开,bool / int32 被跳过。
  3. cannot find tensor model.embed_tokens.weight:save_model 留下的是 lm_head.weight;分片的 index.json 不是权重文件。
  4. rename_f 之后前缀出现两次:先 pp 再 rename_f 时前缀加了两遍。
  5. unsupported dtype BF16 for op matmul:CPU 上的半精度:BF16 报错,F16 要么报错要么误差大一个量级。

LLM 与 KV 缓存

  1. rope_theta 静默变成 10000:transformers 5 重存的 config 把它放进 rope_parameters。
  2. cannot broadcast [5, 5] to [1, 9, 5, 29]:位置不从缓存推断;复用缓存换 prompt。
  3. dtype mismatch in rope BF16 F32 F32:模型和 Cache 的 dtype 要一致。
  4. Llama::load 和 forward 会 panic:缺层、没开 flash-attn、位置超过 8192。

算子

  1. SDPA has no cpu impl:融合注意力只有 Metal 版,头维度有白名单。
  2. no method named topk found:topk、masked_fill、nonzero、einsum 都没有。

生成

  1. 同样的取样参数,分布不一样:do_sample=True 隐含 top_k=50;top-k 加 top-p 的归一化不同。
  2. 重复惩罚罚的范围不同:公式一样,HF 罚整个上下文,candle 的例子只罚最后一段。
  3. 第一个 token 就是 <|im_end|>:没套对话模板、不查 eos。
  4. 流式输出的中文全是 �:一个汉字跨几个 token,要增量解码。

💬 关联讨论

发起讨论
加载中...