Rust in Everything
基于 candle-core 0.11.0

神经网络层

前面几部分讲的是 candle-core:张量、后端、自动微分。这一部分讲建在它上面的 candle-nn(约 1 万行),也就是推理主线里 safetensors 那条路的前半段:权重从文件到张量,张量组成层,层在生成时怎么缓存过去的键和值。candle-nn 不定义模型,具体模型在 candle-transformers,见模型。GGUF 和量化权重走的是另一条路,见量化。

  1. VarBuilder:模型按名字和形状要权重,VarBuilder 把前缀拼上、交给后端;后端可以是 VarMap(训练时新建)、mmap 的 safetensors、npz、PyTorch .pth;名字或形状不对时的报错原文;to_dtype 和 get_unchecked 对 dtype 的理解不一致。
  2. safetensors 与 mmap:8 字节长度、JSON 头、原始数据;MmapedSafetensors 只在建立时解析头部,取张量时 CPU 和 Metal 上都复制一次,不是零拷贝;实测 SmolLM2 的加载时间、RSS 和 Metal 显存,以及 BF16 转 F32 的代价。
  3. 常用层:Linear 的权重和 PyTorch 一样是 [out, in];softmax_last_dim、rms_norm、layer_norm、rope 是每个设备一个内核的融合算子,都不记反向;和拼出来的版本对比数值和时间;CPU 上 BF16 的 softmax 在长行上算错。
  4. KV 缓存与注意力:KvCache 预分配再 slice_set,ConcatKvCache 每步 cat,还有滚动、散列、交错几种;增长策略;quantized_llama 用自己的 cat;attention/ 里 CPU flash attention 的在线 softmax,只有 Qwen3 和 SmolLM3 在用。
flowchart TB
  file["model.safetensors"] --> mm["MmapedSafetensors"]
  mm --> vb["VarBuilder pp get"]
  vb --> layers["Linear Embedding RmsNorm"]
  layers --> model["candle-transformers 模型"]
  model --> kv["KvCache 或 cat"]
  ops["ops 融合算子"] -.-> layers
  ops -.-> model

第一、二页是加载,第三页是前向时每层做什么,第四页是生成时的状态。四页的实验都在 M2 Max、macOS 27、rustc 1.99.0 上跑,用的是本地的 SmolLM2-135M-Instruct(model.safetensors,BF16)。

💬 关联讨论

发起讨论
加载中...