0.8MB 跑通 Qwen|第 5-3 篇:推理引擎的参考实现对拍——怎么读懂 rel err 的数量级

简介: 本系列《0.8MB跑通Qwen》聚焦ARM端零依赖纯C推理引擎开发,实测适配Qwen3-VL多模型,在RK3588上完成Q8/Q4量化与NEON加速。核心创新在于“两把尺子”误差分析法:内核一致性(1e-7)验证手写代码正确性,量化损失(1e-2)界定精度边界,实现可验证、可调试、可落地的轻量级LLM部署。(239字)

系列:《0.8MB 跑通 Qwen:从零实现 ARM 零依赖纯 C 推理引擎》(30 天 × 90 篇) | 适配模型:Qwen3-VL-8B-Instruct(千问3_VL_8B_Instruct)· Qwen3-VL-2B-Instruct · Qwen3-30B-A3B | 测试设备:RK3588(4×Cortex-A76 + 4×Cortex-A55,aarch64)

系列总纲:《0.8MB 跑通 Qwen》30 天 90 篇 · 总纲(阿里云社区)

上一篇:5-2《Q8 对称量化:scale 从哪来》 | 下一篇:第 6 天《NEON 手写 GEMM》

真机实测通过:本文实验已在 RK3588 板端实测完成(2026-09;方法学与原始记录见仓库 docs 与《实验脚本》目录)

一句话导读:推理引擎参考实现对拍的误差量纲:把量化代码算得对不对落到两把尺子上,分清内核一致性期望的 1e-7 与量化损失天然的 1e-2,落点在改坏内核后看 rel err 数量级爆表的回归实验。

关键词:手搓 Qwen 推理引擎、千问大模型推理、参考对拍、rel err、相对误差、内核一致性、量化损失、Qwen3-VL、零依赖纯 C

导语:「误差」两个字不能一概而论。本篇把参考对拍量纲化:引擎里其实有两把尺子——内核一致性看 1e-7,量化损失看 1e-2。先从 --test-l3 的 7.68e-08 读懂「算的是同一件事」,再把内核改坏一次,看 rel err 如何一步爆到 1e-1 量级。

5-2 把量化的"标定"讲完了,可量化后的代码到底算得对不对?Day 1 我们说过引擎靠"参考对拍"自证——今天把这件事量纲化:rel err = 1e-7 意味着什么?1e-2 又意味着什么?先会读误差的数量级,才谈得上写加速内核。

1. 知识点:引擎里其实有"两把尺子"

很多人看到"误差"就紧张,其实引擎里对拍在量两种完全不同的东西:

尺子 比什么 期望数量级 回答的问题
内核一致性 手写内核 vs 朴素 C 参考 1e-7(fp32 逐位级) "我写的快版和慢版算的是不是同一件事"
量化损失 量化后 vs 原始浮点 1e-2(Q8 量化粒度) "我用 8bit 换的带宽,精度上亏了多少"

两把尺子不能混:内核一致性要的是"几乎逐位一致"(1e-7),而量化损失天生就是"差几个百分点"(1e-2 上下)。如果你拿 1e-2 的标准去验收内核对拍,一个累计方向上的小 bug 会被放行;拿 1e-7 去要求量化,则永远无法落地。先分清在比哪把尺子,再谈误差大小。

2. 对应代码:两把尺子在引擎里的落点

尺子一(内核对拍):--test-l3 里 Q4 点积的标量参考对拍(Day 1 主角)。板端实测(RK3588 / Release / 2026-09 当日重跑):

$ ./build-rk3588/vllm_kestrel --test-l3 | grep scalar
[PASS] q4 dot vs scalar reference (rel 7.68e-08)

7.68e-08 ≈ 1e-7 量级:NEON 点积路径与朴素 C 参考路径在 fp32 累加里只有最后一位的舍入差——它们算的是同一个东西,只是累加顺序略不同(这就是 Day 1 说的"及格线 1e-5 内 PASS"为何敢用)。

尺子二(混合精度门):--bench-mixed 用同一份合成权重同时准备 Q4_0 与 Q8_0 双份("Weights: dual Q8_0+Q4_0 copies (273 MB)"),把两种量化路径的核都真跑一遍,最后打印 Q4 vs Q8 的数值差距并收尾。板端实测当日运行:

$ ./build-rk3588/vllm_kestrel --bench-mixed
=== Mixed-Precision Kernel Benchmark (Q4_0 vs Q8_0) ===
  dim=4096 ... batch=32 | pool threads=4
  Weights: dual Q8_0+Q4_0 copies (273 MB)
  ... (decode / prefill / DRAM 探针,见 5-1) ...
=== Mixed-Precision benchmark done ===          (exit 0 = 全路径跑通)

这里输出的 Q4 vs Q8 gate+up numerical gap 一行数值巨大(max|Q8| = inf 出现)——别慌,也别忽略:它比的是"两条不同量化路径的输出"(Q4 与 Q8 的量化误差本就不同,量级天然大),是诊断信息不是 PASS/FAIL 线。真正能当"门"的是:exit code = 0、全部内核跑完不崩、以及 5-2 里量化往返误差落在预期量级。这就是"诚实读误差"的现场教学:看到大数字先问'它在比什么'。

量化的"本征误差":5-2 的往返实验给出 Q8 一档的往返误差 0.033(相对输入幅度 ~3,约 1%),这就是"尺子二"的正常地板——量化必然损失 ~1e-2,不可消除,只能控制。

3. 改动后果:改坏内核,看 1e-7 怎么变成 1

"内核一致性"这把尺子的价值在于:它能把你无意中改坏的累加顺序或越界从"静默错误"变成"数字爆表"。Day 1 我们做过"把参考实现改坏"的实验;反过来改坏被测内核效果一样:把 NEON 点积里某条 lane 的累加注释掉,rel 会从 1e-7 直接跳到接近 0.25(少了 1/4 的贡献)甚至更大——一亿分之一的差 vs 百分之几十的差,一眼可辨。

实际动手姿势(板端):改 vllm_l3.c 的 l3_q4_dot64_neon,让它少累加一段,./build_rk3588.sh 重建后跑 --test-l3 | grep scalar,你会看到 [FAIL] q4 dot vs scalar reference (rel 2.5e-01) 之类——然后 git checkout -- src/core/vllm_l3.c 还原。

# 改动后预期(示意):rel 从 7.68e-08 爆到 ~2.5e-01
./build-rk3588/vllm_kestrel --test-l3 | grep scalar

这就是"对拍"作为开发工具的用法:它不是上线前的仪式,而是每次改内核后 3 秒内给答案的回归。

4. 学员调试任务

  • A 档(板端动手):
    1. 跑 --test-l3 与 --bench-mixed,分别记录"内核对拍 rel"与"混合精度门 exit code";
    2. 故意改坏一次内核(少累加一段),重建后看 rel 从 1e-7 量级爆到多少,再还原;
    3. 用自己的话写三句话:1e-7、1e-2、1e-1 分别在你眼里代表"代码处于什么状态"。
  • B 档(纯读源码):在 vllm_l3.c 里找出"参考实现"与"被测内核"各一段,数清两者的累加顺序差异,解释为什么顺序不同却只差 1e-7。

预期输出:你能分清"内核一致性(1e-7)"与"量化损失(1e-2)"两把尺子,并在 3 秒内读懂一条 rel 输出意味着什么。

收尾

  • 本篇源码点名:vllm_safetensors.c(--bench-mixed 混合精度门)、vllm_l3.c(scalar reference 对拍)。
  • 开源仓库:Kestrel-LLM (Gitee)(AGPL-3.0-or-later 或商业许可,二选一)
  • 下篇预告:对拍证明"算得对"了,可 CPU 标量路径每秒只能算几十 GFLOPS——想要几百 GFLOPS,只能让 NEON 向量指令上。第 6 天进 NEON 手写 GEMM:vdotq_s32 一条指令做 4 个点积。
相关文章
|
1天前
|
存储 容器
0.8MB 跑通 Qwen|第 17-2 篇:GGUF → VQF——推理引擎的 Q4_0…Q8_K 反量化再量化
本系列《0.8MB跑通Qwen》聚焦ARM零依赖纯C推理引擎,适配Qwen3-VL多版本模型,在RK3588平台实测。本文详解GGUF→VQF的“反量化再量化”路径:将llama.cpp已量化权重(Q4_0/Q8_0等)先还原为F32,再经统一量化与重排固化为VQF格式,确保内核兼容性与可验证性。(239字)
|
1天前
|
安全 索引
0.8MB 跑通 Qwen|第 12-2 篇:推理引擎的磁盘 KV 快照格式——0.47 GB 从哪来
本系列《0.8MB跑通Qwen》聚焦ARM端零依赖纯C推理引擎,实测RK3588上部署Qwen3-VL多模态模型。本文详解0.47GB磁盘KV快照格式:64字节头+token IDs+28层F32原样KV,逐字段对账到字节级,诠释“宁大勿错”的可靠性设计。(239字)
|
1天前
|
C++
0.8MB 跑通 Qwen|第 10-3 篇:推理引擎里诚实的坑——哪些场景稀疏无收益,甚至负优化
本篇实测揭示稀疏注意力的真相:短上下文(<1K)开`--sparse-attn`反成负优化!RK3588板端验证,详列8条“禁用清单”,每条附源码行号与实测数据。明确边界:q4 KV、推测解码、L3驱逐等均与稀疏互斥,并坦承`test-sparse`自检崩溃缺陷。(239字)
|
1天前
|
编解码 缓存 计算机视觉
0.8MB 跑通 Qwen|第 19-1 篇:ViT 编码——推理引擎里图片是怎么变成视觉 token 的
本系列《0.8MB跑通Qwen》用纯C手写零依赖推理引擎,实现在RK3588(aarch64)上部署Qwen3-VL多模态模型。真机实测:64×64图经24层ViT编码得4个视觉token,耗时仅295.3ms,支持图文理解与视频分析。(239字)
|
1天前
|
算法 定位技术 C语言
0.8MB 跑通 Qwen|第 16-3 篇:推理引擎的 tensor 目录与布局重排的落盘顺序
《0.8MB跑通Qwen》系列实录:30天手搓零依赖纯C推理引擎,适配Qwen3-VL多模态模型(2B/8B/30B-A3B),真机跑通RK3588(aarch64)。详解VQFTensor目录结构、64字节对齐落盘、FNV校验及mmap加载机制,含零依赖Python解析器。
|
1天前
|
存储 缓存 C++
0.8MB 跑通 Qwen|第 9-1 篇:推理引擎的 KV 也量化——q8 KV 把缓存与 decode 带宽压到一半
本系列手搓零依赖纯C推理引擎,仅0.8MB即可在RK3588上跑通Qwen3-VL多模型。本文详解q8 KV量化:将f16 KV压至INT8,按token每头独立定标,缓存与decode带宽降低约48%,兼顾精度与效率,f32仅作调试探针。
|
1天前
|
调度 C++
0.8MB 跑通 Qwen|第 7-2 篇:推理引擎的混合精度路由——flags 决定谁用 Q8、谁用 Q4
本系列《0.8MB跑通Qwen》聚焦ARM端零依赖纯C推理引擎,适配Qwen3-VL多模态模型,在RK3588上实现实测。核心创新是混合精度路由:prefill阶段用Q8保精度,decode阶段用Q4省带宽,通过flags比特位动态调度,兼顾速度与质量。(239字)
|
1天前
|
缓存 NoSQL 区块链
0.8MB 跑通 Qwen|第 15-3 篇:推理引擎单步走一次生成——token 循环与 KV 追加
本系列《0.8MB跑通Qwen》用纯C手搓零依赖推理引擎,实测RK3588板端运行Qwen3-VL多模型;本文以gdb单步追踪decode循环,直观展示“采样→前向→KV追加→停判”全过程,将大模型逐token生成钉在胶片上。(239字)
|
1天前
|
API 调度 C++
0.8MB 跑通 Qwen|第 14-1 篇:大模型推理的连续批处理——iteration-level 调度思想
本系列《0.8MB跑通Qwen》聚焦ARM端零依赖纯C推理引擎,适配Qwen3-VL多模态模型,在RK3588上实测落地。本文详解iteration-level连续批处理:动态聚合多请求的decode步,单次前向服务多人,兼顾并发与确定性。(239字)
|
1天前
|
JSON 网络协议 前端开发
0.8MB 跑通 Qwen|第 20-3 篇:SSE 流式——推理引擎响应怎么写一半就发给客户端
本系列《0.8MB跑通Qwen》用纯C手搓零依赖推理引擎,适配Qwen3-VL多尺寸模型,在RK3588(aarch64)实测SSE流式响应:首token延迟130ms,后续约50ms/token,支持标准+自定义事件,真正实现端侧“打字机”体验。(239字)

热门文章

最新文章