burn 解决什么问题
主线位置:三条主线的外面。本页回答 burn 在「一个张量运算」和「一块硬件」之间加了哪几层、为什么这样分层;三条主线都从这张分层图出发。
flowchart TB user["用户代码 Tensor D K 和 Module"] --> tensor["burn-tensor 张量 API"] tensor --> disp["Dispatch 按设备 match"] disp --> ad["Autodiff 装饰器"] ad --> fus["Fusion 装饰器"] disp --> flex["Flex CPU eager"] ad --> flex disp --> fus fus --> cube["CubeBackend"] cube --> cubek["cubek 内核"] cubek --> cubecl["cubecl 编译 MSL PTX WGSL 等"]
burn 怎么描述自己
README 第一句:「Burn is both a tensor library and a deep learning framework, optimized for numerical computing, training and inference.」接着说它要解决的问题:模型通常在 Python 里训练,再导出成 ONNX 之类交给推理引擎,「This export step is often brittle and lossy」;burn 的回答是「the exact code used for training is the exact code that runs in production」。
怎么做到,README 也说了:「Burn preserves the intuitive ergonomics of PyTorch, with dynamic shapes and graphs, but JIT-compiles streams of tensor operations, performing automatic kernel fusion.」拆开就是三件事,本卷依次讲:
| README 的说法 | 落在哪 | 讲它的页 |
|---|---|---|
| 同一份代码跑在多种硬件上 | 后端 trait(burn-backend)+ 全局后端 Dispatch + 各个实现(Flex、cubecl 的各运行时) | 03 后端与分派 |
| dynamic graphs,可以训练 | Autodiff<B> 装饰器,每个 op 执行时登记反向步骤(define-by-run) | 04 自动微分 |
| JIT-compiles streams of tensor operations, automatic kernel fusion | Fusion<B> 装饰器把 op 记成 IR 攒成流,burn-cubecl-fusion 生成融合内核,cubecl 在运行期编译 | 05 IR 与融合、06 CubeCL 与 GPU |
再往上是模块、优化器、训练循环和模型存取(07 模块与训练)。burn 自己的 crate 文档(crates/burn/src/lib.rs)概括得更平实:「It covers tensors, automatic differentiation, neural network modules, optimizers, training and model storage, and runs the same model code on GPUs (CUDA, ROCm, Metal, Vulkan, WebGPU), CPUs and WebAssembly.」
后端是可以套的装饰器
burn 把「在哪算」和「算的时候多做什么」分开。「在哪算」是一个实现了 Backend 的类型:纯 Rust 的 Flex,或者所有 cubecl 运行时共用的 CubeBackend。「多做什么」是一个以后端为类型参数、本身也实现 Backend 的包装类型:
pub struct Autodiff<B, C = NoCheckpointing> {
_b: PhantomData<B>,
_checkpoint_strategy: PhantomData<C>,
}
pub struct Fusion<B: FusionBackend> {
_backend: PhantomData<B>,
}
(Autodiff、Fusion。)两者都是零大小的标记类型,状态在各自的张量原语里:Autodiff<B> 的浮点张量是 AutodiffTensor<B>(内层原语加图节点),Fusion<B> 的张量是 FusionTensor(张量 id、形状、dtype、所在的流和 fusion 客户端,数据要等流执行之后才有)。每个 op 在装饰器里做完自己的事(登记反向步骤、记一条 IR),再调 B:: 的同名 op。于是自动微分只写一遍,对任何后端都成立;融合只写一遍,对所有 cubecl 运行时都成立。
能套什么,README 写得很具体:「Burn's CubeCL backends (CUDA, ROCm, Metal, Vulkan, WebGPU, CPU) compose with autodiff, fusion and remote-execution decorators, while external and simpler backends (LibTorch and pure-Rust CPU/no_std) compose with autodiff only.」Fusion 要求内层实现 FusionBackend(能执行 IR、能生成融合内核),Flex 没有实现,所以 Flex 只能套 Autodiff。在 Metal 设备上打印后端名,看到的正是这个套娃:dispatch<autodiff<fusion<cubecl<wgpu<msl>>>>>(一次 matmul)。
README 把远程执行也叫装饰器,它的底座 burn-router 却不一样:BackendRouter<R: RouterChannel> 的类型参数是一个通道,不是被包的后端。它把每个 op 记成 burn-ir 送进通道,另一头(另一台机器上的服务端,或者只记录不执行的 capture)再用真正的后端重放。
0.22:装饰器从类型挪到了设备上
0.21 里装饰器是写在用户代码里的类型:type Backend = Autodiff<Wgpu>;,Tensor<Backend, 2>,模型是 Mlp<B: Backend>。0.22 里这些类型还在,但用户看不到了:Tensor<2> 没有后端参数,Device::metal(..).autodiff() 是一个值,Dispatch 在运行期按它 match 到 Autodiff<Fusion<CubeBackend>> 这样的具体类型(见 Dispatch)。
#4717「[Breaking] Remove Tensor backend generic and add high-level Device struct」(2026-05-13,首次发布于 v0.22.0-pre.1,628 个文件,+13 030 / −27 066 行)之前,0.21 的 README 说:「it is impossible to make the mistake of calling backward on a model that runs on a backend that does not support autodiff (for inference), as this method is only offered by an Autodiff backend.」那时 backward 只定义在 impl<const D: usize, B: AutodiffBackend> Tensor<B, D> 上,类型系统替你挡住了错误。#4717 的提交说明里有一行「Carry autodiff intent via checkpointing field」:autodiff 变成了设备值上的一个标记(DispatchDevice::Autodiff { device, checkpointing })。0.22.1 的 README 相应改成「backward() checks graph participation at runtime」,并提供 is_autodiff()、is_tracked()、is_require_grad() 让你在运行期查。换来的是:模型代码不再到处带 <B: Backend>,同一个二进制可以在运行期选设备,训练和推理用同一个 struct。
这个取舍的完整账(编译时间、错误信息、每个 op 多一次 match 的代价)在设计取舍。
和别的框架比
只写能在源码里核实的事实。candle 对照的是它的 0.11.0 tag(2026-06-26)。
| burn 0.22.1 | candle 0.11.0 | tch-rs | PyTorch | |
|---|---|---|---|---|
| 语言 | 全部 Rust,GPU 内核也用 Rust 写(cubecl 的 #[cube]) | Rust;CUDA 和 Metal 内核是手写的 .cu、.metal 文件(candle-kernels 26 个、candle-metal-kernels 17 个) | Rust 绑定 LibTorch(C++) | Python 前端,C++ / CUDA 后端 |
| 选设备 | Device 值,Dispatch 在运行期 match;后端集合由 Cargo feature 决定 | enum Device { Cpu, Cuda(..), Metal(..) },存储是 enum Storage { Cpu(..), Cuda(..), Metal(..) } | 用 LibTorch 的设备 | 用自己的设备 |
| 自动微分 | Autodiff<B> 装饰器,任何后端可套 | 内建在 Tensor 里:每个张量带一个 op: BackpropOp 字段,backward 对节点拓扑排序 | 用 LibTorch 的 | 内建 |
| 融合 | Fusion<B> 装饰器,运行期把 op 流编成融合内核 | 无对应的通用机制(核实范围:candle-core 的设备与存储) | 用 LibTorch 的 | 本卷不核实 |
| 自我定位 | 「both a tensor library and a deep learning framework, optimized for numerical computing, training and inference」 | 「Candle's core goal is to make serverless inference possible」 | — | — |
几处说明:
- candle:
Device是三个变体的 enum,Storage::matmul对(self, rhs)做match:两个都在 CPU 就调 CPU 实现,都在 CUDA 就调 CUDA 实现,不一致返回DeviceMismatchBinaryOp。自动微分不是单独的一层:Tensor::backward直接沿每个张量记下的op走图。candle 的 README 自己也把 burn 列为「a general crate that can leverage multiple backends so you can choose the best engine for your workload」。 - tch-rs:candle 的 README 说它是「Bindings to the torch library in Rust. Extremely versatile, but they bring in the entire torch library into the runtime.」burn 里有一个基于它的后端
burn-tch(依赖tch = "0.22.0",download-libtorchfeature),0.22.0 起标为弃用(#5525),crate 文档建议改用 cubecl 后端或 Flex。 - PyTorch:本卷离线写作,只引用 burn 源码里能看到的关系:README 说 burn「preserves the intuitive ergonomics of PyTorch」;
burn-store用自带的pytorch-reader读.pt/.pth检查点,它的文档写着「without PyTorch or Burn」;burn-tch曾是在 burn 里用 LibTorch 的途径。PyTorch 自身的实现细节本卷不做断言。
问: burn 0.22 的 Dispatch 也是对一个设备 enum 做 match,和 candle 的 match (self, rhs) 有什么不同?
答: match 本身一样,区别在 match 的每个分支后面是什么。candle 的分支后面是这个设备的存储实现,自动微分在分支外面的 Tensor 里。burn 的分支后面是一个实现了整套 Backend trait 的类型,而这个类型可以是 Autodiff<Fusion<CubeBackend>> 这样套出来的:自动微分和融合都是「又一个后端」,分支只多不少(DispatchDevice::Autodiff 包着内层设备,再递归分派一次)。所以在 burn 里加一个新后端,实现 Backend 之后 Autodiff 自动可用;加一种新装饰器,所有后端自动能套。代价是每个 op 都要经过这几层转发,见一次 matmul 里的调用栈。
小结
- burn 的目标是训练和推理用同一份 Rust 代码,跑在 CPU、多种 GPU 和 WebAssembly 上。
- 核心结构:后端 trait + 实现(Flex、
CubeBackend)+ 以后端为参数的装饰器(Autodiff<B>、Fusion<B>);burn-router/burn-remote则是把 IR 送到别处执行。 - cubecl 后端能套 autodiff、fusion、remote;Flex、LibTorch 只能套 autodiff。
- 0.22 把装饰器从用户类型挪到
Device值上:模型代码没有后端参数,backward的合法性改成运行期检查。 - 和 candle 0.11 比:candle 的设备和存储是 enum,自动微分内建在
Tensor里,GPU 内核是手写的.cu/.metal;burn 的内核用 Rust 写、运行期编译,自动微分和融合是可套的装饰器。