0.8MB 跑通 Qwen|第 5-1 篇:为什么必须 Q4/Q8——边缘推理的带宽瓶颈

简介: 本系列手搓零依赖纯C推理引擎,仅0.8MB即可在RK3588上跑通Qwen3-VL/30B等大模型。本文聚焦“带宽瓶颈”:decode每生成一词需重读全部权重,推理时间≈权重字节数÷内存带宽。实测表明,Q4/Q8量化+紧凑布局可提升有效带宽3倍,是边缘部署的生存前提。(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 篇 · 总纲(阿里云社区)

上一篇:4-3《核绑定实验:为什么"勿设 8 线程"》 | 下一篇:5-2《Q8 对称量化:scale 从哪来》

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

一句话导读:推理引擎的边缘推理带宽瓶颈:以 decode 每生成一个词都要重读全部权重为起点,讲清推理时间近似等于权重字节数除以内存带宽的墙,落点在真实模型文件按量化类型的字节分解与紧凑排布的有效带宽实测。

关键词:手搓 Qwen 推理引擎、千问大模型推理、Q4/Q8 量化、带宽瓶颈、decode、内存带宽、RK3588、Qwen3-VL、零依赖纯 C

导语:推理引擎卡住的往往不是算力,而是带宽——decode 每生成一个词都要重读全部权重。本篇从「时间≈权重字节÷内存带宽」这堵墙出发,用真实模型文件的量化字节分解,与紧凑排布对 64B 对齐排布的有效带宽实测,说明 Q4/Q8 为何是边缘推理的生存前提。

第 4 天我们把算力调度清楚了,可推理引擎真正卡住的往往不是算力,是带宽——权重要从内存喂给 CPU,喂得慢,核再快也空转。这一篇讲清楚:为什么量化(Q4/Q8)不是"可选的压缩技巧",而是边缘推理的生存前提。

1. 知识点:decode 是"每 token 重读全部权重"的机器

先看 decode(生成一个 token)在做什么:要把整个网络从前到后跑一遍——每一层的 Q/K/V、gate/up/down 权重都要被读一次。也就是说:

decode 的时间 ≈ 全部权重的字节数 ÷ 内存带宽。

举例:一个 2B 模型若以 fp16 存权重(每元素 2 字节),每生成一个 token 至少要读约 4.2 GB 权重。哪怕内存带宽有 30 GB/s,光喂权重就要 ~0.14 秒/词——这就是"带宽墙":多核并行救不了它,因为它不是算不过来,是"吃不下"。

那怎么办?两条路一起走:

  1. 降字节:把每元素从 2 字节(fp16)降到 1 字节(Q8)甚至半字节(Q4),decode 每词要搬的字节数直接砍半/砍到 1/4;
  2. 紧凑布局:数据排得越密,一次突发传输能用的有效字节越多(第 3 节实测:同样的数据,紧凑排 vs 对齐大步长排,有效带宽差 3 倍)。

量化就是"用精度换字节"的工程:多花一点点数值误差,把内存与带宽需求砍到能塞进边缘设备。

2. 对应代码:真实模型文件里,量化到底省了多少

直接看板端真实的 2B 模型。同源权重两个文件并排躺着:

model.safetensors   4,255,140,312 B   (4.25 GB,源权重)
model.vqf           2,331,316,232 B   (2.33 GB,引擎格式 = Q8/Q4 混合 + F16 embed)

2.33 GB 只是 4.25 GB 的 ~55%——但这是"混合档"。我们用一段 20 行 Python 解析 VQF 头部目录(41 个张量),按量化类型统计真实字节占比(板端实测,2026-09):

n_tensors=41
  token_embed   F16   622.3 MB   (151936 词表 × 2048 维,F16 半精度)
  norm 层        F32   ~13 MB     (attn/ffn/q/k norm 合计,量小不值得量化)
  q4_q          Q4_0   66.1 MB   ... 28 层 × Q/K/V/O/gate/up/down
  q8_*          Q8_0  320.9 MB   (attention 的 Q8 副本)
  q4_*          Q4_0  967.8 MB   (FFN 为主的 Q4 副本)
  v_* (视觉塔)   F32   420.4 MB   (vision tower 仍是 F32)
TOTAL bytes by qtype: {F32: 420.4, Q8_0: 320.9, Q4_0: 967.8, F16: 622.3} MB
grand total MB: 2331.3   (≈ 文件大小 2331316232 B,对得上)

这张表本身就是"量化策略":大头(FFN 的 gate/up/down)用 Q4 最省;attention 用 Q8 保精度;embedding 是查表密集、用 F16;视觉塔暂留 F32。要是全 fp32,光文本部分就是 ~8 GB——板上根本放不下。量化不是"要不要",是"哪部分用几 bit"的分配问题。

3. 改动后果:布局决定你能用多少带宽

量化把字节数降下来了,但同样的字节,排法不同,有效带宽能差 3 倍。引擎的 --bench-mixed 里内置了一个"真实 DRAM 探测":在板上扫 131072 行 × 128 块的数据,比较三种块排布能达到的有效吞吐(板端实测):

--- Real-DRAM wall probe (131072 rows x 128 blocks/row) ---
compact 18B/block  :   19.6 ms  ->  15.4 GB/s payload
compact 34B/block  :   36.1 ms  ->  15.8 GB/s payload
64B-aligned/block  :   58.2 ms  ->   5.2 GB/s payload (raw 18.5 GB/s)

读同样的数据总量,紧凑排布 ~15.5 GB/s 有效,而"每个块都从 64B 边界取"的排布只有 5.2 GB/s——因为你读 64 字节只用到其中 18 字节,约 70% 的带宽被"跳格"浪费了(原始突发带宽 18.5 GB/s 其实差不多)。这就是 Q4_0 每 32 个权重只占 18 字节({f16 scale; 16 字节 nibble})这种紧凑格式的价值:省字节 + 不浪费突发传输,两个维度一起省。

顺带一提:同一次 bench 还给出引擎两种量化路径的真实内核吞吐(合成 4K 权重,273MB 双份):decode 档 Q8 fused QKV 1.695ms(29.7 GFLOPS)、Q4 3.566ms(14.1 GFLOPS)等——这些数字在第 6–7 天我们逐行拆解时会反复引用。

4. 学员调试任务

  • A 档(板端动手):跑 ./build-rk3588/vllm_kestrel --bench-mixed,找到 Real-DRAM wall probe 三行,确认你板上的紧凑 vs 64B 对齐排布的有效带宽差;再用第 2 节的小脚本(读 VQF 头目录按 qtype 求和)复现你模型文件的体积分解。
  • B 档(纯读源码):读 vllm_safetensors.c 第 2907–2956 行的格式注释(Q8_0/Q4_0 的 block 定义),写出"32 个 f32 → Q8_0 34 字节 / Q4_0 18 字节"的换算公式。

预期输出:你能解释"decode 每词重读全部权重"为什么让带宽成为瓶颈、Q4/Q8 各砍到多少字节/元素,以及紧凑布局为什么能再多榨一倍有效带宽。

收尾

  • 本篇源码点名:vllm_safetensors.c(Q8_0/Q4_0 格式注释第 2907–2956 行、--bench-mixed 的 DRAM 探针)、真实 model.vqf(41 张量按 qtype 分解)。
  • 开源仓库:Kestrel-LLM (Gitee)(AGPL-3.0-or-later 或商业许可,二选一)
  • 下篇预告:Q4/Q8 把字节砍了,可"还原"靠的是一个叫 scale 的标量——这个标量从哪来、存成什么样?下一篇 5-2 拆 Q8 对称量化的标定公式。
相关文章
|
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仅作调试探针。
|
2天前
|
JSON Java Linux
0.8MB 跑通 Qwen|第 3-3 篇:推理引擎的零依赖自研 util——"不引第三方也能活"的边界感
本文实测验证“零第三方依赖”的务实边界:OS已支持的(如Linux原生UTF-8路径)仅薄封装为宏;OS缺失且轻量关键的功能(FNV-1a校验、小端memcpy、平台工具宏)才自研。RK3588真机验证(2026-09),代码简洁、可移植、无冗余。
0.8MB 跑通 Qwen|第 3-3 篇:推理引擎的零依赖自研 util——"不引第三方也能活"的边界感
|
3天前
|
移动开发 编译器 Linux
0.8MB 跑通 Qwen|第 2-2 篇:推理引擎的平台层——一个头文件守住全部平台契约(vllm_platform.h)
本文实测于RK3588(2026-09),提出“平台层契约”设计:将NEON、mmap、绑核等平台依赖统一收口至`vllm_platform.h`,通过`ST_HAVE_NEON`等宏提供唯一真相,配合`#error`门闩实现错误前移——有守卫仅报1行错,无守卫则引发46处误导性编译失败。
0.8MB 跑通 Qwen|第 2-2 篇:推理引擎的平台层——一个头文件守住全部平台契约(vllm_platform.h)
|
1天前
|
调度 C++
0.8MB 跑通 Qwen|第 13-2 篇:草稿 + 验证——推理引擎里 spec decode 的实现
本系列《0.8MB跑通Qwen》聚焦ARM端零依赖纯C推理引擎,实测RK3588上运行Qwen3-VL多模态模型;详解speculative decode实现——基于n-gram草稿、批量验证与无损回放,确保输出位级一致,兼顾 correctness 与工程可控性。(239字)
|
1天前
|
JSON 移动开发 Java
0.8MB 跑通 Qwen|第 20-1 篇:极简 HTTP——推理引擎的 socket/bind/select 轮询
本系列《0.8MB跑通Qwen》聚焦ARM端零依赖纯C推理引擎,适配Qwen3-VL多模态模型,在RK3588芯片实测通过。核心亮点:单文件`vllm_http.c`实现socket监听、select轮询、有界线程池与SSE流式响应,不依赖任何第三方库,专为板端轻量服务而生。(239字)
|
1天前
|
NoSQL C语言 C++
0.8MB 跑通 Qwen|第 15-1 篇:推理引擎入口架构——参数 → 分发(serve/自检)→ 退出
本系列《0.8MB跑通Qwen》聚焦ARM端零依赖纯C推理引擎,实测适配Qwen3-VL-2B/8B及30B-A3B模型,在RK3588板端完成真机验证。本文详解`main()`入口如何通过命令行参数分发至serve、离线转换或自检三种命运,并用GDB抓取真实调用链,厘清初始化与退出逻辑。(239字)
|
1天前
|
缓存 C语言 内存技术
0.8MB 跑通 Qwen|第 8-2 篇:在线 softmax——推理引擎的注意力为什么不能先算完 e^x 再除
本系列手搓0.8MB零依赖纯C推理引擎,适配Qwen3-VL多模型,在RK3588(aarch64)真机实测。本文详解softmax溢出陷阱:fp32下exp>88.7即inf,剖析朴素/稳定/在线三版实现,揭示“减max”数学等价性与在线rescale的流式优势。(239字)
|
1天前
|
机器学习/深度学习 区块链 C++
0.8MB 跑通 Qwen|第 10-1 篇:大模型推理的长上下文为什么必须稀疏——O(n²) 的注意力 vs O(n·k) 的"只看该看的"
本系列手搓0.8MB纯C推理引擎,零依赖跑通Qwen3-VL多模型。本文聚焦长上下文瓶颈:RK3588实测显示,注意力耗时占比从18%飙升至71%。提出块稀疏方案——将O(n²)注意力压至O(n·k),实现每词成本与上下文长度无关,为端侧大模型长文本推理提供关键路径。(239字)
|
1天前
|
编译器 C++
0.8MB 跑通 Qwen|第 6-3 篇:推理引擎的 4x4 asm 内核——从 llama.cpp 提取的 MIT 代码
本系列《0.8MB跑通Qwen》聚焦ARM端零依赖纯C推理引擎,适配Qwen3-VL多模态模型,在RK3588上实测部署。核心采用llama.cpp中450行MIT许可NEON汇编内核,通过机械提取实现零转录风险,并严守许可署名规范,诠释开源合规与工程严谨的统一。(239字)
|
1天前
|
JSON 数据格式 Python
0.8MB 跑通 Qwen|第 18-2 篇:tokenizer.json → vocab.bin——推理引擎的 build_vocab_bin.py 在干嘛
本系列《0.8MB跑通Qwen》聚焦ARM端零依赖纯C推理引擎,适配Qwen3-VL多模态模型(2B/8B/30B),在RK3588平台实测通过。本文详解词表编译:将7MB tokenizer.json编译为1.95MB可审计vocab.bin,精准处理byte-level解码(如0xAD/0x7F等历史坑),实现板端逐位一致、冷启动仅约2秒。(239字)

热门文章

最新文章