MiniCPM5-1B 验证: 4.7× 压缩, 44ms 推理, 1.3GB 显存, INT8 无损还原
摘要
INT8 量化将大语言模型 (LLM) 权重压缩 2× (16→8 bit/w), 但 INT8 字节流本身仍存在显著冗余 — 全局信息熵仅 4.66 bit/w。现有无损压缩方案 (Huffman, ANS) 虽可逼近熵极限, 但变长编码导致 GPU 上无法高效并行解码。我们提出 INT8-X (3,5,8): 一种基于嵌套 bitmap 的三级定长编码方案, 通过将 INT8 权重按绝对值分为三级 (3-bit / 5-bit / 8-bit), 在保持完全并行的前提下实现 5.50 bit/w 的有效位宽。关键创新是将 bitmap 前缀扫描 (cumsum)、位流提取和权重重建融合进单个 Triton 内核, 利用tl.cumsum在内核内完成变长流定位。在 MiniCPM5-1B (1B 参数, 168 层) 上, INT8-X 实现 463MB 存储 (4.7× vs bf16)、1.3GB GPU 显存 (省 41%)、44ms 推理 (仅 1.26× bf16 开销), 且 INT8 权重 100% 无损还原。
关键词: 模型量化, 无损压缩, Triton, bitmap 编码, LLM 部署
1. 引言
INT8 量化是 LLM 部署的标准压缩手段, 将 bf16 权重 (16 bit/w) 压缩为 INT8 (8 bit/w), 实现 2× 存储/显存节省。然而, INT8 量化后的权重分布高度集中在零附近 (图 1), 其 Shannon 熵仅 4.66 bit/w — 意味着 INT8 字节流本身仍有 42% 的冗余空间。
进一步无损压缩 INT8 数据的现有方案存在根本性矛盾:
变长编码 (Huffman/ANS): 可逼近熵极限 (4.66 bit/w), 但每个符号的码长不同, 解码时元素间存在数据依赖, GPU 无法高效并行化。实测块并行 Huffman 解码需 442ms (12.6× bf16)。
定长块编码: GPU 友好, 但每块需覆盖块内最大值, 导致位宽浪费。实测最优块方案仅达 6.5 bit/w。
我们提出 INT8-X, 通过多级定长 + 嵌套 bitmap架构解决这一矛盾, 并通过Triton 内核融合实现接近零开销的实时解码。
2. 方法
2.1 三级定长编码
将 INT8 权重按绝对值分为三级:
Level 1 (3-bit): |v| ≤ 3 → 55.5% 权重 ← 主体 Level 2 (5-bit): |v| ≤ 15 → 40.4% 权重 Level 3 (8-bit): |v| > 15 → 4.1% 权重 ← 稀疏离群点每级使用定长编码, 存储为三个独立的位打包流:
L1 流: n1 × 3 bits (打包成 int32 位流) L2 流: n2 × 5 bits (打包成 int32 位流) L3 流: n3 × 8 bits (原始 uint8 字节)2.2 嵌套 Bitmap 定位
三级元素的全局位置通过两层 bitmap 编码:
Bitmap 1 (N bit): 0 = Level 1, 1 = 检查 Bitmap 2 Bitmap 2 (0.445N bit): 0 = Level 2, 1 = Level 3Bitmap 开销: 1 + 0.445 =1.445 bit/w
解码时, 通过 cumsum(bitmap) 计算每个元素在其级别流中的位置, 实现精确定位。
2.3 有效位宽计算
flag (bitmap): 1.445 bit/w data (L1+L2+L3): 0.555×3 + 0.404×5 + 0.041×8 = 4.013 bit/w ──────────────────────────────────────────────── 总计: 5.46 bit/w → 2.93× vs bf16 (纯权重) 含 scale 共享: 5.50 bit/w → 4.7× vs bf16 (含 embedding)2.4 Triton 融合内核
核心创新: 将以下操作融合进单个 Triton 内核:
@triton.jitdef_ix358_fused_kernel(out,b1,b2,l1,l2,l3,b1_blk,b2_blk,scale,N,BLK):# 1. 读取 B1 bitmap 位is_l1_bit=(b1[word]>>bit)&1# 2. 块内 cumsum → 计算 L1 流位置l1_local_rank=tl.cumsum(is_l1_bit,axis=0)-1l1_rank=l1_before+l1_local_rank# 3. 从 L1 位流提取 3-bit 值 (跨字条件)val=extract_bits(l1,l1_rank*3,3)# 4. 非 L1: 读 B2 → cumsum → L2 流位置# 5. 从 L2 位流提取 5-bit 值# 6. L3: 直接读 uint8# 7. 选择: val = where(is_l1, l1_val, where(is_l2, l2_val, l3_val))# 8. 重建: w = val × scale关键:tl.cumsum在 Triton 3.7+ 中原生支持, 允许内核内完成前缀扫描, 避免了 PyTorch 层面的多次 cumsum 调用和临时数组分配。
块间前缀和 (block-level prefix sum) 在编码时预计算, 存储为 int32 数组 (每 1024 元素 1 个值 = 0.001 bit/w 开销)。
2.5 编码流程 (离线, 一次性)
bf16 权重 → INT8 量化 (per-tensor scale) → 按绝对值分级 (L1/L2/L3) → 打包: L1(3b stream) + L2(5b stream) + L3(raw) + B1(bitmap) + B2(bitmap) → 预计算: 块级前缀和 (b1_blk, b2_blk)3. 实验
3.1 实验设置
| 参数 | 值 |
|---|---|
| 模型 | MiniCPM5-1B (168 层, 679M Linear 权重) |
| 量化 | INT8 per-tensor symmetric |
| GPU | RTX 4090 24GB |
| 框架 | PyTorch 2.13 + Triton 3.7.1 |
| 基线 | bf16 原始模型 |
3.2 推理性能
| 模式 | Fwd | GPU 显存 | 存储 | vs bf16 速度 | vs bf16 压缩 |
|---|---|---|---|---|---|
| bf16 | 35ms | 2.2GB | 2161MB | 1.0× | 1.0× |
| INT8 (per-tensor) | — | — | 679MB | — | 3.2× |
| INT8-X (3,5,8) | 44ms | 1.3GB | 463MB | 0.80× | 4.7× |
| Huffman-INT8 (block) | 442ms | 1.5GB | 389MB | 0.08× | 5.6× |
INT8-X 仅比 bf16 慢 26% (44ms vs 35ms), 但存储压缩 4.7×、显存节省 41%。
3.3 无损验证
INT8-X 对 INT8 量化值实现 100% 精确还原:
原始 INT8 → INT8-X 编码 → Triton 解码 → 还原 INT8 匹配率: 100.0% (679M 权重逐元素验证)端到端质量等价于 INT8 量化 (bf16 → INT8 的量化误差不在本文范围内)。
3.4 版本演进
| 版本 | 技术 | Fwd | GPU | 关键改进 |
|---|---|---|---|---|
| v7 | Python 逐 bit 解包 | 676ms | 1.6GB | 基线 |
| v8 | PyTorch 向量化解包 | 446ms | 1.8GB | 消除 Python 循环 |
| v9 | Triton + PyTorch cumsum | 175ms | 1.6GB | Triton bit 提取 |
| v10 | Triton 融合 (tl.cumsum) | 44ms | 1.3GB | 全融合单 kernel |
v10 相比 v7 加速15.4×, 核心来自tl.cumsum的内核内前缀扫描。
3.5 方案对比
| 方案 | bit/w | Fwd | GPU | 无损? | GPU 解码 |
|---|---|---|---|---|---|
| bf16 | 16 | 35ms | 2.2GB | — | — |
| BF16X (bf16无损) | 12.4 | 105ms | 2.0GB | ✅ bf16 | 快 (Triton) |
| INT8 plain | 8.0 | — | — | — | 极快 |
| DG 4-bit (QAT) | 4.5 | 50ms | 1.2GB | ❌ (可恢复) | 快 (Triton) |
| INT8-X (3,5,8) | 5.5 | 44ms | 1.3GB | ✅ INT8 | 快 (Triton融合) |
| Huffman | 4.66 | 442ms | 1.5GB | ✅ INT8 | 慢 (串行) |
INT8-X 在速度 (44ms)、压缩 (4.7×) 和无损性 (INT8) 之间取得最优 Pareto 平衡。
4. 级别选择分析
4.1 穷举搜索
对 2~5 级嵌套 bitmap 的所有 bit 组合进行穷举搜索:
| 方案 | bit/w | vs bf16 | 备注 |
|---|---|---|---|
| (3,4,5,6,8) 5级 | 5.33 | 3.00× | 最优但复杂 |
| (3,4,5,8) 4级 | 5.40 | 2.96× | |
| (3,5,8) 3级 | 5.50 | 2.93× | Pareto 最优 |
| (2,4,6,8) 4级 | 5.70 | 2.81× | 2b 覆盖太少 |
4.2 第一级位宽的甜点分析
第一级 bit 数 覆盖率 bitmap开销 数据位宽 总计 1-bit 13.8% 1.86 b/w 3.91 b/w 5.77 b/w 2-bit 27.6% 1.72 b/w 4.14 b/w 5.86 b/w 3-bit 55.5% 1.49 b/w 4.01 b/w 5.50 b/w ← 最优 4-bit 82.8% 1.18 b/w 4.35 b/w 5.53 b/w 5-bit 95.9% 1.04 b/w 4.96 b/w 6.00 b/w3-bit 是甜点: 覆盖过半 (55.5%) 权重, 同时数据位宽足够低 (3b), bitmap 二次查询开销适中 (44.5% 需查 B2)。
5. 讨论
5.1 为什么不定长更低位?
定长方案的天花板在 ~5.3 bit/w (5 级)。低于此需变长编码 (Huffman = 4.66 bit/w), 但 GPU 串行解码代价高昂 (442ms vs 44ms)。
INT8-X (3,5,8) 在 5.50 bit/w 处取得速度-压缩最优平衡。
5.2 与 DFloat11 的关系
DFloat11 [Zhang et al., 2025] 对 bf16 指数做 Huffman 编码, GPU 解码需分层 LUT + 块内串行扫描。INT8-X 改用定长多级 + bitmap 定位, 避免了变长解码的串行依赖, 实现全并行 Triton 内核。
5.3 局限
- 仅验证 MiniCPM5-1B, 需扩展到 7B/13B
- L3 (8-bit raw) 未进一步压缩, 占 4.1% 但贡献 0.33 bit/w
- 块级前缀和预计算增加编码复杂度
6. 结论
我们提出 INT8-X (3,5,8): 一种基于多级定长 + 嵌套 bitmap 的 INT8 无损压缩方案, 配合 Triton 融合内核实现接近零开销的实时解码。在 MiniCPM5-1B 上实现 4.7× 压缩、1.3GB 显存、44ms 推理, 且 INT8 权重 100% 无损还原。tl.cumsum内核内前缀扫描是关键加速技术, 将解码从 676ms 降到 44ms (15.4× 加速)。
开源代码: https://www.modelscope.cn/models/dfytensor/MiniCPM5-1B-DG-INT4
参考文献
[1] Zhang et al. “70% Size, 100% Accuracy: Lossless LLM Compression for Efficient GPU Inference via Dynamic-Length Float (DFloat11).” NeurIPS 2025.
[2] Frantar et al. “GPTQ: Accurate Post-Training Quantization for Generative Pre-trained Transformers.” ICLR 2023.
[3] Lin et al. “AWQ: Activation-aware Weight Quantization for LLM Compression and Acceleration.” MLSys 2024.
[4] Tillet et al. “Triton: an intermediate language and compiler for tiled neural network computations.” 2019.