Rust in Everything
基于 candle 0.11.0

从 PyTorch 到 candle

这一卷写给已经会写 PyTorch、用过 HuggingFace transformers,想改用 candle(HuggingFace 的 Rust 机器学习框架)的读者。主线只有一条:把 transformers 里的一个模型搬到 candle 上做推理,从读 config 和权重开始,到 logits 两边对上、带 KV 缓存生成、量化和部署。张量和训练只讲和 PyTorch 习惯冲突的地方。

每章只做一件事,给出 PyTorch / transformers 和 candle 两份都能跑的程序,再贴两边的真实输出。先说两边概念上相同的部分,再说哪里不同、为什么不同。说「两边对得上」的地方,都给出实测的最大绝对误差、输出的量级和容差。

candle 内部怎么实现,这一卷不重讲,candle 源码解析那一卷讲过的机制,这里只给链接。和 burn 相比的同类问题,链到从 PyTorch 到 burn。

项版本说明
PyTorch2.15.0Python 3.13.18、numpy 2.5.4;macOS 上的 wheel,对照默认在 CPU 上做
transformers5.22.0tokenizers 0.23.3、safetensors 0.8.0;离线运行(HF_HUB_OFFLINE=1)
candle0.11.0candle-core、candle-nn、candle-transformers,features metal 和 accelerate
burn0.22.1只在个别地方一句话对照

三条主线

  • 推理主线(本卷的主轴):读 config 和权重 → 建模块 → 前向,logits 对上 → 带 KV 缓存生成 → 量化与部署。模型是 SmolLM2-135M-Instruct(Llama 结构,135M 参数),prompt The capital of France is。对应 04 到 09,以及 11。
  • 张量主线:建张量 → 计算 → 读回主机。对应 01 张量、02 错误与所有权。
  • 训练主线:forward → loss → backward → 优化器一步。模型是一个两层 MLP(8→16→4,ReLU,MSE)。对应 03 自动求导与训练。

每个内容页开头的「主线位置」说明这一页在哪条线的哪一步。每一步落在哪一页,见怎么读这一卷。

flowchart TB
  intro[00 导读] --> tensor[01 张量]
  tensor --> res[02 错误与所有权]
  res --> ad[03 自动求导]
  res --> module[04 模块]
  module --> weights[05 权重]
  weights --> llm[06 搬一个 LLM]
  llm --> gen[07 生成]
  gen --> quant[08 量化]
  quant --> deploy[09 部署]
  deploy --> pit[10 常见坑]
  ad --> pit
  pit --> hands[11 动手]

实验环境

每个对照是一对程序:一个 .py 和一个 cargo crate,输出同样结构的 JSON,再用一个几十行的 compare.py 逐个数比较。平台是 M2 Max、macOS 27、rustc 1.99.0。candle 依赖锁定 0.11.0,一律离线构建;transformers 只读本地的 SmolLM2-135M-Instruct 权重。比速度的地方用 release 构建,固定 PyTorch 的线程数,取多次运行的最小值,并写明当时机器的负载;Metal 上还写明着色器库的缓存是冷是热。

各部分

  1. 00 导读:版本、对照程序怎么跑、logits「对得上」的标准;同一个 SmolLM2 推理两边的体积、启动时间、内存,以及什么时候不该选 candle。
  2. 01 张量:torch.tensor 对 Tensor::new;浮点字面量是 F64、没有类型提升;+ 不广播;argmax 返回 U32;整数运算;设备。
  3. 02 错误与所有权:几乎每个方法返回 Result;运算接引用,张量不可变。
  4. 03 自动求导与训练:requires_grad 对 Var;没有 no_grad;SGD 和 AdamW 一步对一步。
  5. 04 模块:nn.Module 对「结构体 + Module trait」和 VarBuilder;常用层;逐层对数。
  6. 05 权重:from_pretrained 对 from_mmaped_safetensors;读 .bin / .pt;键名对不上。
  7. 06 搬一个 LLM:LlamaForCausalLM 对 candle_transformers::models::llama;KV 缓存;半精度。
  8. 07 生成:model.generate 对手写循环;取样参数;分词与对话模板。
  9. 08 量化:GGUF;自己量化。
  10. 09 性能与部署:prefill 和 decode 的速度;一个二进制的交付形态。
  11. 10 常见坑:从 PyTorch / transformers 的写法出发的坑,每条有报错原文或静默的错误结果和最小复现。
  12. 11 动手:不用 candle-transformers,只用 candle-core 和 candle-nn 手写 SmolLM2 的前向,和 transformers 对到同样的误差。

适合谁读

  • 会写 PyTorch、用过 transformers,能读懂 Rust 代码。这一卷不讲 Rust 语法。
  • 只想知道值不值得换:先读什么时候选 candle,那一页同时写了不该选的情况。
  • 手上有一个 transformers 模型要搬:从怎么读这一卷看对照的标准,然后直接去 04 到 06。

💬 关联讨论

发起讨论
加载中...