引言
大语言模型(LLM)推理时,KV Cache 是显存消耗的主要来源之一。以 LLaMA-70B 为例,在 4096 上下文长度下,KV Cache 占用超过 40 GB 显存。传统的 FP16 KV Cache 每个 token 需要 2 × head_dim × num_heads × 2 bytes = 大量显存。如果能将 KV Cache 压缩到 3-4 bit,就可以将显存占用降低到原来的 1/4 到 1/5,从而支持更长的上下文、更大的 batch size,或在更少的 GPU 上运行同一模型。
TurboQuant(Zandieh et al., ICLR 2026)正是为此而生——它是 vLLM 中实现的一种极低比特 KV Cache 量化方法,通过 Hadamard 旋转 + Lloyd-Max 最优标量量化 + Norm Correction 的组合,将 KV Cache 压缩至 3-4 bit,最高实现 4.9× 压缩比。
为什么需要 TurboQuant?
在 TurboQuant 之前,vLLM 已经支持了 FP8 KV Cache(2× 压缩,几乎无损)。但 2× 压缩在某些场景下仍然不够:
- 超长上下文:当上下文长度达到 128K、256K 甚至 1M 时,即使是 FP8 KV Cache 也会迅速耗尽显存。
- 大批量推理:需要同时服务大量用户时,每个请求的 KV Cache 累积起来成为瓶颈。
- GPU 显存受限:在 24 GB 或 48 GB 的 GPU 上运行大模型(如 70B+ 参数量)时,KV Cache 压缩到极致是防止 OOM 的关键。
TurboQuant 的目标就是在保持可接受精度的前提下,将压缩比从 FP8 的 2× 提升到 3.8×–4.9×。
核心原理
TurboQuant 的算法流程包含四个关键步骤,下面逐一详细拆解。
1. Walsh-Hadamard 旋转
对每个 key 向量 $k \in \mathbb{R}^d$,首先对其做归一化,然后应用随机正交旋转:
$$\tilde{k} = H_d \cdot \frac{k}{\|k\|}$$其中 $H_d$ 是 $d \times d$ 的 Walsh-Hadamard 矩阵。Hadamard 矩阵是正交矩阵的变体,满足 $H H^T = dI$,可以通过递归方式定义:
$$H_1 = [1], \quad H_{2n} = \begin{bmatrix} H_n & H_n \\ H_n & -H_n \end{bmatrix}$$为什么需要这一步?
原始 key 向量的各个坐标往往具有非均匀的分布——某些维度方差大(出现 outlier),某些维度方差小。直接对标量进行低比特量化时,outlier 会占据主要的量化范围,导致其他维度的精度严重损失。
Hadamard 旋转的魔力在于:通过随机正交变换,将能量均匀散布到所有坐标上。根据中心极限定理,旋转后的向量 $\tilde{k}$ 的各坐标近似独立同分布,服从 $N(0, 1/d)$。这意味着所有坐标有了相同的方差,量化时可以为每个坐标使用相同的量化器,大大简化了量化过程。
更重要的是,Hadamard 变换可以用快速 Walsh-Hadamard 变换(FWHT)在 $O(d \log d)$ 时间内完成,远比一般矩阵乘法 $O(d^2)$ 高效。
2. Lloyd-Max 最优标量量化
旋转后的坐标 $x \sim N(0, 1/d)$ 服从高斯分布。对于已知的概率分布,Lloyd-Max 算法可以找到均方误差(MSE)最优的标量量化器。
给定量化水平数 $L = 2^b$($b$ 为比特数),Lloyd-Max 找最优的质心 $c_l$ 和边界 $b_l$ 来最小化 MSE:
$$\min_{c_l, b_l} \sum_{l=1}^L \int_{b_{l-1}}^{b_l} (x - c_l)^2 p(x) \, dx$$其中 $p(x)$ 是 $N(0, 1/d)$ 的概率密度函数。这是一个经典的最优化问题,可以通过迭代求解:
- 初始化:在 $(-3.5\sigma, 3.5\sigma)$ 区间内均匀取 $L$ 个质心
- 每轮迭代:
- 更新边界:$b_l = (c_l + c_{l+1}) / 2$
- 更新质心(条件期望):$c_l = \int_{b_{l-1}}^{b_l} x \, p(x) \, dx \;/\; \int_{b_{l-1}}^{b_l} p(x) \, dx$
- 重复直到收敛
收敛后得到的质心是非均匀分布的——在高概率区域(靠近 0)质心更密集,在低概率区域(尾部)质心更稀疏。这本质上是在信息论意义下的最优量化器。
vLLM 中的实现使用数值积分(梯形法则,200 个采样点)来计算质心和边界,结果通过 @lru_cache 缓存,以 (head_dim, bits) 为 key。
3. 量化存储
Key 的量化存储:
对于 3-bit 或 4-bit 模式,每个坐标存储的是 centroid index(索引指向 Lloyd-Max 质心表),后面附加一个 fp16 的向量范数。对于 head_dim=128、4-bit 配置,每个 key 向量的存储布局为:
[coord_0_idx (4-bit) | coord_1_idx (4-bit) | ... | coord_127_idx (4-bit) | vec_norm (fp16)]
= 64 bytes (索引) + 2 bytes (范数) = 66 bytes
对于 FP8 模式(k8v4),key 的存储很简单——每个坐标直接存 fp8:
[k0_fp8 | k1_fp8 | ... | k127_fp8] = 128 bytes
Value 的量化存储:
Value 向量使用标准的均匀量化(非对称),而不是 Lloyd-Max:
$$v_q = \text{round}((v - \min(v)) / s)$$$$s = (\max(v) - \min(v)) / (2^b - 1)$$每个 value 向量的存储布局:
[coord_0_idx | ... | coord_{d-1}_idx | scale_fp16 | zero_fp16]
Value 用均匀量化而不用 Lloyd-Max 的原因:value 向量的分布不像 key 那样在旋转后服从高斯分布,均匀量化在实际测试中效果已经足够好。
4. 反量化与 Norm Correction
在 attention 计算前,需要对压缩的 KV Cache 进行反量化:
- 解包索引:从 packed bits 中恢复每个坐标的 centroid index
- 查表:根据索引从 centroids 表中恢复量化后的坐标值
- Norm Correction(可选):将向量的范数校正回原始值
Norm Correction 是 TurboQuant 中的一个关键技巧。量化过程会改变向量的范数——因为每个坐标独立量化,量化误差在不同坐标上是随机的,导致 $\|\tilde{k}_q\| \neq \|\tilde{k}\|$。而 attention 计算中 $q \cdot k$ 的值对向量范数非常敏感(softmax 中的指数会放大范数差异)。Norm Correction 的公式很简单:
$$\tilde{k}_{\text{corrected}} = \tilde{k}_q \cdot \frac{\|k\|}{\|\tilde{k}_q\|}$$即在反量化后将向量缩放到原始范数。实验表明,Norm Correction 在 4-bit 下可以带来约 0.8 PPL 的改善。
- 逆 Hadamard 旋转:应用 $H_d^{-1}$ 将向量恢复到原始空间
五种预设配置
TurboQuant 在 vLLM 中通过 --kv-cache-dtype 参数选择,共有五种预设:
turboquant_k8v4(FP8 Key + 4-bit Value)
| 项目 | 值 |
|---|---|
| Key 格式 | FP8 e4m3(无旋转/量化) |
| Value 格式 | 4-bit 均匀量化 |
| 每 slot 字节 | ~196 bytes |
| 压缩比 | ~2.6× |
| 精度影响 | 几乎无损 |
这个预设本质上是"轻量版 TurboQuant"——key 直接存 FP8(已有 2× 压缩),只对 value 做 4-bit 压缩。相比标准 FP8 KV Cache 的优势不大,因为 key 和 value 各占大约一半。
turboquant_4bit_nc(4-bit Key + 4-bit Value + Norm Correction)
| 项目 | 值 |
|---|---|
| Key 格式 | 4-bit Lloyd-Max MSE + Hadamard |
| Value 格式 | 4-bit 均匀量化 |
| Norm Correction | 启用 |
| 每 slot 字节 | ~136 bytes |
| 压缩比 | ~3.8× |
| 精度影响 | +1–4% PPL |
这是最实用的预设。4-bit 对大多数模型来说精度退化可控,3.8× 压缩比意味着同样显存下可以支持近 4 倍长的上下文。
turboquant_k3v4_nc(3-bit Key + 4-bit Value + Norm Correction)
| 项目 | 值 |
|---|---|
| Key 格式 | 3-bit Lloyd-Max MSE + Hadamard |
| Value 格式 | 4-bit 均匀量化 |
| 每 slot 字节 | ~120 bytes |
| 压缩比 | ~4.3× |
| 精度影响 | 较大退化(复杂任务可能掉 10+ 点) |
turboquant_3bit_nc(3-bit Key + 3-bit Value + Norm Correction)
| 项目 | 值 |
|---|---|
| Key 格式 | 3-bit Lloyd-Max MSE + Hadamard |
| Value 格式 | 3-bit 均匀量化 |
| 每 slot 字节 | ~104 bytes |
| 压缩比 | ~4.9× |
| 精度影响 | 显著退化(需充分验证) |
这是压缩比最高的预设,接近 5× 压缩。在数学推理任务(如 GSM8K)上可能掉 20+ 个点,需要针对具体任务验证。
存储对比总表
| 预设 | Key 存储 | Value 存储 | 总 bytes/slot | 压缩比 |
|---|---|---|---|---|
| FP16(基线) | 256 | 256 | 512 | 1× |
| FP8 | 128 | 128 | 256 | 2× |
| k8v4 | 128 (fp8) | 68 (4-bit) | 196 | 2.6× |
| 4bit_nc | 66 (MSE) | 68 (4-bit) | 136 | 3.8× |
| k3v4_nc | 50 (MSE) | 68 (4-bit) | 120 | 4.3× |
| 3bit_nc | 50 (MSE) | 52 (3-bit) | 104 | 4.9× |
边界保护(Boundary Skip Layers)
实践中发现,对模型的第一层和最后几层的 KV Cache 做 TurboQuant 压缩会导致显著精度下降。例如 Qwen3-4B 在 GSM8K 上如果不跳过边界层,精度会下降约 30 个点。
TurboQuant 因此实现了边界跳过机制——默认跳过第一层和最后 2 层,这些层的 KV Cache 以 FP16 存储。对 hybrid 模型(如 Attention + Mamba 混合架构),边界保护自动禁用,因为 Mamba 层没有 KV Cache。
def get_boundary_skip_layers(num_layers, n=2):
first_n = list(range(min(n, num_layers)))
last_n = list(range(max(0, num_layers - n), num_layers))
return sorted(set(first_n + last_n))
与 FP8 KV Cache 的对比
FP8 KV Cache 是 vLLM 中另一个常用的 KV Cache 量化方案。以下是两者的全面对比:
| 对比维度 | FP8 KV Cache | TurboQuant |
|---|---|---|
| 比特数 | 8-bit | 3-4 bit |
| 压缩比 | 2× | 2.6×–4.9× |
| 精度损失 | 基本无损(< 0.5% PPL) | 依赖预设:k8v4 无损,4bit 有 +1–4% PPL |
| 量化方式 | 直接 cast 到 FP8(线性) | Hadamard + Lloyd-Max(非线性最优) |
| 计算模式 | 直接在 FP8 上做 attention(FP8 Tensor Core) | 解压回 BF16 再做 attention |
| 吞吐影响 | 无额外开销 | 增加 10–68% 延迟(解压开销) |
| 硬件要求 | H100+(需要 FP8 Tensor Core) | 任意 GPU(CUDA kernel 解压) |
| Scale 策略 | Per-tensor / per-token-head | 每坐标质心表 + 每向量范数 |
| 是否需校准 | Per-tensor 模式需校准集 | 否(质心表理论计算) |
关键区别:
计算方式:FP8 KV Cache 是"量化存储 + 量化计算"——attention 的 QK^T 矩阵乘直接在 FP8 上完成,无需反量化。TurboQuant 是"量化存储 + 反量化后计算"——attention 计算前需要先解压回 BF16。这意味着 TurboQuant 一定会引入额外的延迟开销。
精度-压缩权衡:FP8 在 2× 压缩时几乎完全无损。TurboQuant 将压缩比推到 3.8×–4.9×,但需要容忍一定程度的精度损失。
适用场景:
- 如果显存充足,FP8 仍是最佳默认选择——2× 压缩,零额外延迟,基本无损。
- 如果显存极度受限且需要更长上下文或更大 batch,TurboQuant(尤其是 4bit_nc)是有价值的备选方案。
- k8v4 相比 FP8 没有明显优势,不建议使用。
算法渊源
TurboQuant 的核心模式——随机正交旋转 + 确定性标量量化 + 重归一化——并非全新发明。这一组合可以追溯到以下工作:
- DRIVE(NeurIPS 2021):首次提出将随机旋转用于量化前的分布整形
- EDEN(ICML 2022):将 DRIVE 的思路扩展到分布式场景
- HIGGS(Malinovskii et al., NAACL 2025):将这种模式用于 LLM 权重量化,数学上等价于 TurboQuant 标量量化的情况
TurboQuant 的主要贡献是将这一范式系统性地应用到了 KV Cache 压缩场景,并针对 key/value 的不同特性设计了不同的量化策略(Key 用 Lloyd-Max MSE,Value 用均匀量化)。
实践建议
根据 vLLM 官方博客和社区测试结果,以下是一般性的实践建议:
默认选择 FP8:如果 GPU 支持 FP8(H100+)且显存压力不大,FP8 KV Cache 是最安全的选择。
显存不足时用 4bit_nc:如果 FP8 仍会导致 OOM,
turboquant_4bit_nc是下一个最佳选项,精度退化在多数场景下可控。避免 k8v4:这个预设相比 FP8 压缩比提升不大,但复杂度增加。
谨慎使用 3-bit 变体:
k3v4_nc和3bit_nc在数学推理、代码生成等任务上可能导致显著精度下降,务必在目标任务上充分验证。务必开启 Norm Correction:所有 4-bit 和 3-bit 预设都应该配合 Norm Correction 使用(
_nc后缀)。
总结
TurboQuant 是 vLLM 中面向极致显存压缩场景的 KV Cache 量化方案。通过 Hadamard 旋转将 key 向量的坐标分布整形为高斯分布,再用 Lloyd-Max 算法求解信息论最优的标量量化器,配合 Norm Correction 补偿量化失真,TurboQuant 在 3-4 bit 的极低比特上实现了可用的 KV Cache 压缩。
它的核心价值在于:当 2× 压缩(FP8)不够用、但又无法接受更大幅度的模型退化时,TurboQuant 提供了从 2.6× 到 4.9× 的灵活选择,帮助 LLM 推理在显存受限的场景下突破瓶颈。