Rust in Everything
基于 burn 0.22.1

后端与分派

张量那一部分把调用一路送到 Dispatch 门口。这一部分讲门后:一个后端要实现什么,Dispatch 这个唯一的全局后端怎么把调用分给 Flex、Cube(所有 GPU 运行时)或 Autodiff,以及 CPU 上那一支 Flex 怎么真正把数算出来。

代码在三个 crate:burn-backend(trait 定义,约 1.3 万行,多半是文档注释)、burn-dispatch 加上生成分派代码的过程宏 crate burn-backend-extension(合计约 1.1 万行)、burn-flex(约 3.7 万行,本部分只读存储、逐元素、归约、矩阵乘)。

  1. Backend trait:BackendTypes 是设备加四种张量原语,Backend 是九个 op trait 的合集;197 个方法必须实现,239 个有用别的 op 拼出来的默认实现,各后端按自己的理由挑着覆盖;DeviceOps::defaults 决定默认 dtype;读数据返回 future,因为 GPU 和 wasm 不能原地等。
  2. Dispatch:Dispatch 是空结构体,后端信息在每个 DispatchTensor 的变体上;变体由 build.rs 算出的 cfg 裁剪,一个后端都不开时只剩不可构造的 NoBackend;#[backend_dispatch] 给每个 op 生成一段 match,跨后端搬运经主机中转;实测分派层让 Flex 上一个小 op 多 19 到 40 纳秒。
  3. Flex:CPU 后端:Arc<Bytes> 加带符号步长的 Layout,视图类 op 不复制;逐元素运算优先原地写,f32 走 macerator SIMD,矩阵乘交给 gemm,大张量才用 rayon;和弃用的 NdArray 比矩阵乘。
flowchart TB
  bridge["BridgeTensor"] --> disp["Dispatch"]
  disp -->|"kind 是 Flex"| flex["Flex"]
  disp -->|"kind 是 Cube"| cube["Fusion CubeBackend"]
  disp -->|"带 autodiff"| ad["Autodiff B C"]
  ad --> flex
  ad --> cube
  trait["burn-backend 的 op trait"] -.->|实现| flex
  trait -.->|实现| cube
  trait -.->|实现| ad
  trait -.->|实现| disp

第一页是契约,后两页是契约的两个实现者:一个只转发,一个真算。Cube 那一支先进 burn-fusion 攒操作,见 IR 与融合;再进 cubecl,见 burn-cubecl 后端。Autodiff 那一支在自动微分。

💬 关联讨论

发起讨论
加载中...