🔢 第2课:INT4 量化——把 32 位"压缩"成 4 位

MiniCpm5 的核心技术:三种精度混合量化(INT4权重 + INT8输入 + Q8.8 scale),以及 HLS 怎么实现它。

🎯 本课目标

理解为什么需要量化、INT4/INT8/Q8.8 三种格式各自的作用、反量化公式的含义、HLS preload cache 为什么快。

一、三种数据的"精密度"

三种数据类型的协作

flowchart LR H["hidden向量
INT8 (有符号8位)
范围: -128~127
BRAM: 32bit=4个INT8"] --> MAC["32路并行MAC
(乘加器)"] W["weight权重
INT4 (有符号4位)
范围: -8~7
BRAM: 128bit=32个INT4"] --> DEQ["反量化
deq = ((INT4 - zp) × Q8.8) >> 8"] S["scale/zero_point
Q8.8 (16位定标)
zp: 4位有符号
每row每pass独立"] --> DEQ DEQ --> MAC MAC --> ACC["累加器 INT32
1536项累加
范围足够大"] ACC --> TOP1["top1 argmax
选最大logit"] style H fill:#3987e5,color:#fff style W fill:#199e70,color:#fff style S fill:#c98500,color:#000

为什么三种不同的精度?

二、反量化——从4位恢复到"够用"的精度

反量化公式拆解

flowchart TB INT4["原始INT4值
例: 5 (二进制0101)"] --> SUB["减去zero_point
5 - (-2) = 7"] SUB --> MUL["乘以Q8.8 scale
7 × 0.375 (Q8.8=0x0060)"] MUL --> SHIFT["右移8位
(除以256)"] SHIFT --> CLAMP["钳位
限制在合理范围"] CLAMP --> RESULT["反量化结果
约等于原始float32值"] style INT4 fill:#3987e5,color:#fff style RESULT fill:#199e70,color:#fff

一句话解释:INT4 存的是"压缩编码",需要乘以一个 scale 因子(告诉你在原始浮点世界里"1"代表多大的值)再加上零点偏移(zero_point),才能恢复到接近原始浮点值的精度。每个 pass 的每个 row 有自己独立的 scale 和 zero_point——这样不同的权重行可以有不同的数值范围。

三、权重存储布局——128bit 塞 32 个 INT4

一个 weight BRAM word 的内容

flowchart LR subgraph WORD["weight_words 元素: ap_uint<128>"] L0["lane0
bits[3:0]"] --- L1["lane1
bits[7:4]"] --- L2["..."] --- L31["lane31
bits[127:124]"] end WORD --> PARALLEL["32路并行!
一个BRAM读 = 32个乘法的权重输入"] style WORD fill:#3987e5,color:#fff

这就是 HLS 32-lane 并行架构的数据基础——一次 128bit 的 BRAM 读取,就拿到了 32 个并行乘法器需要的全部权重。配合 preload cache 把 hidden 数据也准备好,就能做到 II=1(每个周期完成 32 次乘法+累加)。

四、HLS Preload Cache 原理

为什么需要 Preload?

sequenceDiagram participant BRAM as hidden BRAM
(384个32bit字) participant CACHE as Preload Cache
(用FF实现的高速缓存) participant LANE as 32路MAC Note over BRAM,LANE: Direct BRAM: 32路同时读 → 冲突 → II=4 Note over BRAM,LANE: Preload Cache: 先一次性加载 → 各读各的 → II=1 BRAM->>CACHE: 第1步: 预加载全部hidden数据
(24 passes × 16 words = 384次读) loop 每个pass的每个tile CACHE->>LANE: 第2步: 32路同时从Cache读
(无冲突!) LANE->>LANE: 第3步: 32个乘法同时算 end

代价:FF(触发器)从 1,322 个暴增到 15,431 个(+11.7×)。收获:延迟从 207,873 降到 59,781 cycles(-3.4×)。VU19P 有大量 FF 资源,这个 trade-off 完全值得。