从 PyTorch 到 candle
这一卷写给已经会写 PyTorch、用过 HuggingFace transformers,想改用 candle(HuggingFace 的 Rust 机器学习框架)的读者。主线只有一条:把 transformers 里的一个模型搬到 candle 上做推理,从读 config 和权重开始,到 logits 两边对上、带 KV 缓存生成、量化和部署。张量和训练只讲和 PyTorch 习惯冲突的地方。
每章只做一件事,给出 PyTorch / transformers 和 candle 两份都能跑的程序,再贴两边的真实输出。先说两边概念上相同的部分,再说哪里不同、为什么不同。说「两边对得上」的地方,都给出实测的最大绝对误差、输出的量级和容差。
candle 内部怎么实现,这一卷不重讲,candle 源码解析那一卷讲过的机制,这里只给链接。和 burn 相比的同类问题,链到从 PyTorch 到 burn。
| 项 | 版本 | 说明 |
|---|---|---|
| PyTorch | 2.15.0 | Python 3.13.18、numpy 2.5.4;macOS 上的 wheel,对照默认在 CPU 上做 |
| transformers | 5.22.0 | tokenizers 0.23.3、safetensors 0.8.0;离线运行(HF_HUB_OFFLINE=1) |
| candle | 0.11.0 | candle-core、candle-nn、candle-transformers,features metal 和 accelerate |
| burn | 0.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 上还写明着色器库的缓存是冷是热。
各部分
- 00 导读:版本、对照程序怎么跑、logits「对得上」的标准;同一个 SmolLM2 推理两边的体积、启动时间、内存,以及什么时候不该选 candle。
- 01 张量:
torch.tensor对Tensor::new;浮点字面量是 F64、没有类型提升;+不广播;argmax返回 U32;整数运算;设备。 - 02 错误与所有权:几乎每个方法返回
Result;运算接引用,张量不可变。 - 03 自动求导与训练:
requires_grad对Var;没有no_grad;SGD 和 AdamW 一步对一步。 - 04 模块:
nn.Module对「结构体 +Moduletrait」和VarBuilder;常用层;逐层对数。 - 05 权重:
from_pretrained对from_mmaped_safetensors;读.bin/.pt;键名对不上。 - 06 搬一个 LLM:
LlamaForCausalLM对candle_transformers::models::llama;KV 缓存;半精度。 - 07 生成:
model.generate对手写循环;取样参数;分词与对话模板。 - 08 量化:GGUF;自己量化。
- 09 性能与部署:prefill 和 decode 的速度;一个二进制的交付形态。
- 10 常见坑:从 PyTorch / transformers 的写法出发的坑,每条有报错原文或静默的错误结果和最小复现。
- 11 动手:不用
candle-transformers,只用candle-core和candle-nn手写 SmolLM2 的前向,和 transformers 对到同样的误差。
适合谁读
- 会写 PyTorch、用过 transformers,能读懂 Rust 代码。这一卷不讲 Rust 语法。
- 只想知道值不值得换:先读什么时候选 candle,那一页同时写了不该选的情况。
- 手上有一个 transformers 模型要搬:从怎么读这一卷看对照的标准,然后直接去 04 到 06。
💬 关联讨论
发起讨论加载中...