模型
前几部分讲的是零件:张量和后端(candle-core)、层和缓存(candle-nn)、量化格式和 GGUF(candle-core/src/quantized)。这一部分讲 candle-transformers 怎么用这些零件搭出模型。candle-transformers 有 8.3 万行、124 个模型模块,本卷只读两个,正好对应推理主线的两条路:BERT 走 safetensors + VarBuilder,一次前向算完整个句子;量化 llama 走 GGUF + QMatMul,一个 token 一个 token 地生成,最后由取样决定下一个 token。
- BERT:
bert.rs一个结构体对一个 Python 类,没有 pooler;加载 bert-base-chinese 要把 LayerNorm 的gamma/beta改名,失败时报错里的名字是误导;mean pooling 给中文句子算向量;with_tracing的 span 必须在建模型前装 subscriber,CPU 上量出gelu_erf占一半时间;CPU 与 Metal 的批处理时间。 - 量化 llama 的一次前向:
from_gguf只认llama.*元数据键,RoPE 约定按架构名选;forward里 mask 何时建、按什么缓存;按 span 和逐个 op 拆开一个 decode 步;prefill 与 decode 的吞吐;index_pos传错和不清缓存各会怎样。 - 取样:
LogitsProcessor的六种取法哪些在设备上、哪些读回主机;温度为 0 的报错;top-p 和 top-k-then-top-p 的真实语义;每次取样的耗时;种子复现什么、Gumbel 为什么不受种子控制、Metal 的set_seed为什么不起作用;重复惩罚。
flowchart TB st["safetensors"] --> vb["VarBuilder"] vb --> bert["BertModel"] bert --> pool["mean pooling 句向量"] gg["GGUF"] --> mw["ModelWeights from_gguf"] mw --> fwd["forward input pos"] fwd --> lp["LogitsProcessor"] lp -->|下一个 token| fwd
三页的实验都在 M2 Max、macOS 27、rustc 1.99.0 上跑,模型是本地的 bert-base-chinese 和 SmolLM2-135M-Instruct 的 GGUF。生成一个 token 的分段计时(读 GGUF、建模型、prefill、decode、冷热缓存)在生成一个 token,本部分不重复。
💬 关联讨论
发起讨论加载中...