动手
前面各部分读的是 candle 的源码。这一部分反过来:只用标准库和 half,把推理主线里「读 GGUF、取出量化权重、反量化、量化点积」这一段自己写一遍。写完之后让 candle 处理同样的数据,两边逐字节、逐位对一对。
- 写一个迷你 Q8_0 量化:库 325 行代码。Q8_0 每 32 个值一块,一个 f16 scale 加 32 个 i8;量化结果和 candle 的
BlockQ8_0逐字节相同,SmolLM2 的 211 个 Q8_0 张量反量化和QTensor::dequantize逐位相同,标量点积和vec_dot_unopt逐位相同、和 neon 版差在累加顺序。同一次矩阵乘向量,CPU 的QMatMul先量化输入,Metal 不量化,误差差四个数量级。读头部时测出 candle 在BufReader<File>上调了 98384 次lseek,general.alignment = 0会让它 panic。最后一张表列出 candle 多出来的东西(SIMD、K-quants、Metal 内核、QMatMul的三种形态、分配上限)和讲它们的页。
flowchart TB gguf["GGUF 头部"] --> raw["张量原始字节"] raw --> blk["BlockQ8_0"] blk --> deq["反量化"] blk --> dot["量化点积"] deq --> cmp["和 candle 逐位比"] dot --> cmp
💬 关联讨论
发起讨论加载中...