专栏算法工具链【LLM量化技术介绍-3】KV Cache量化技术介绍

【LLM量化技术介绍-3】KV Cache量化技术介绍

momo(社区版)2025-10-27
84
0

前言

笔者在前面两篇文章【LLM量化技术介绍 - 1】LLM量化技术概述及AWQ和GPTQ介绍【LLM量化技术介绍 - 2】SmoothQuant原理及量化技术详解 中,重点介绍了大语言模型(LLM)中激活和权重的量化原理与方案。LLM中的键值缓存(KV Cache)虽然大大减少了重复计算,但它同样带来了巨大的显存和带宽开销。为了节省显存、降低带宽、提高吞吐率,研究者自然想到对 KV Cache 进行量化,比如:从 FP16 到 INT4,KV Cache 大小缩小 4 倍。

本文将对KV Cache量化技术进行介绍。

KV Cache量化技术介绍

KV Cache 是随上下文动态生成、长期存储、反复读取的激活。它既不是固定权重,也不是短期中间结果,因此量化后误差会“积累”。其与普通权重量化的不同可以总结为:

对象

特点

量化挑战

权重 (Weights)

固定不变,可离线量化、校准

量化噪声可被模型学习到

激活 (Activations)

每次前向变化大

SmoothQuant、AWQ 等方法

KV Cache

激活的一部分(注意力Key/Value)且跨 token 持续使用

分布动态、层间差异大,不能重新校准

KVQuant

KVQuant: Towards 10 Million Context Length LLM Inference with KV Cache Quantization

现有LLM量化方法虽然有做 activations 或 weights 的量化,但专门针对 KV Cache、并且做到亚 4 位(比如 3-bit、2-bit)却效果不好/几乎没有/存在明显精度损失。

因而,KVQuant希望 专门为 KV Cache 的特性 设计量化方案,从而支持“超长上下文(例如百万、千万级 token)”的推理。论文标题里就强调 “Towards 10 Million Context Length” 。

论文提出了一系列创新,主要针对 Key 和 Value 的激活缓存的特点设计。下面将按方法点逐个说明。

方法细节

Per-Channel Key Quantization

观察到 Key 缓存(Key activations)在不同通道(channel,通常指 head_dim 维度中的一个索引)上分布差异大,某些通道有强极值/outlier。因此他们不只是对所有通道统一量化,而是对 Key 做 按通道(per-channel) 量化,即为每个通道或者通道组设定独立的 scale/zero-point。

这样做的好处:对 outlier 较严重的通道可以给出较大范围,而通道分布较窄的可以用更窄的量化范围/更细的刻度,从而整体量化误差更小。

Pre-RoPE Key Quantization

在 Transformer 架构中,很多模型使用 RoPE(Rotary Positional Embedding)来给 Key/Query 注入位置编码。RoPE 会导致通道维度之间的“旋转”/混合关系。

论文提出:在 RoPE 应用之前对 Key 激活进行量化,即「Pre-RoPE Quantization」。原因在于:如果先做 RoPE,再量化,那么 RoPE 会把通道之间的分布和极值情况搞得更复杂,不利于量化;而如果先量化,再做 RoPE,则可以利用通道原本的分布结构。这意味着缓存 Key 时,先把未加位置信息的 Key 做量化,随后在解量化(或使用量化形式)再应用 RoPE/Attention。

Non-Uniform KV Cache Quantization

对于 Value 缓存、或者整个 KV Cache,他们发现统一的 “线性均匀量化(uniform quantization)”并不能很好地匹配激活分布,因为激活分布往往非对称、存在尖峰/尾部。因此提出 “非均匀量化(non-uniform quantization)”,即根据层(layer)或者通道敏感度(sensitivity)来设计不同的量化格式/刻度。

换而言之:某些层或通道如果对量化误差敏感,经校准后可能使用更多刻度(或更大位宽),而其他低敏感的可用更粗糙的量化,这样整体在给定比特预算下误差更小。

Per-Vector Dense-and-Sparse Quantization

即使做了上面几个优化,依旧可能遇到极端 outlier 元素(比如某个 token/某个 head 在某维度出非常大值),这些极端值会主导量化范围,导致大部分数据只能用很粗的量化刻度。为此,论文提出将每个向量(vector)分成 “dense” 部分(普通分布)和 “sparse” 部分(outlier 元素)。把 outlier 单独处理(可能更高位宽或不同策略),剩下普通分布用低位宽量化。如此可以 隔离 异常值,避免它们拖累整体量化设计。这种方式有点类似 “以混合精度 + 分段策略” 来应对长尾/极端分布。

Q-Norm 与其他细节

在 reddit/摘要中还提及 “Q-Norm” 的名字:虽然在主方法里可能不是核心标题,但确实是一种细化策略,用于确保量化之后激活分布偏移(shift)控制得更好。

此外,论文还在系统层面:做了 自定制 CUDA kernels 来支持量化后 KV Cache 的访问/解量化,以在实际部署中获得速度提升。

实验结果与意义

  1. KVQuant在多个模型(如 LLaMA‑7B、Llama‑2、Llama‑3、Mistral)上进行了测试。

  2. 在标准语言模型 benchmark(如 Wikitext‑2、C4)上:使用 3-bit 量化 的 KV Cache,困惑度(perplexity) 的退化控制在 < 0.1。在部署上,他们声称实现了:单张 A100-80GB GPU 上用 LLaMA-7B 支持 1 百万(1 M)token 上下文长度,8 GPU 系统支持 10 百万(10 M)token
  3. 在速度方面,在 LLaMA-7B 模型上配合自定义 kernel,实现最大约 1.7× 加速(相比 FP16 baseline 的 matrix-vector)理想。

KVQuant提供了将 KV Cache 从传统 FP16/FP32 精度降低到极低位宽(如 3-bit)而几乎不损失质量的方法,为「超长上下文」LLM 推理(数百万、数千万 token)提供了实用的内存/带宽优化路径,铺垫了后续更多 KV Cache 量化、压缩、系统层部署优化工作的基础。

KVQuant在Hugging Face 中使用示例

在 Hugging Face 中启用 KV Cache 量化(KVQuant 思路) 的整个流程如下所示:

Quanto

Quanto 对 KV cache 的量化是 Hugging Face 最近(从 Transformers v4.43 起)引入的一项关键特性,用来在推理时显著降低 KV 缓存显存开销。它的特点有:

  • 支持 动态量化(activations, KV cache)
  • 支持 静态量化(权重)
  • 支持多种 bit 宽:2 / 4 / 8-bit

  • 提供 PyTorch 张量级 API(无需修改模型结构)
  • Transformers + Accelerate 完全兼容

Quanto 的量化原理(以 4-bit 为例)

对于每个注意力头的 KV 矩阵:

  1. 分块量化(block-wise quantization)

      将矩阵切分为小块(默认 32 或 64 行),每块单独量化。这样做的优点是局部统计更准确;支持快速 dequant以及兼容 int kernel。其工作流程如下:

 

  1. Per-block scale + zero-point

    1.   每块保存一个 scale 和 zero_point,用于还原:
    1.   INT4 仅需 4 bit 存储,外加少量 scale 元数据。

  2. 实时反量化访问

    1.   推理时(如 torch.matmul),Quanto 提供高效 CUDA kernel,直接在量化表示上完成部分计算(避免完全解码)。

其核心代码为:

Quanto Hugging Face 中使用示例

从 Transformers v4.43 起,可以直接在 generate() 调用中启用:

 

参考链接

https://zhuanlan.zhihu.com/p/5932153295

https://arxiv.org/abs/2401.18079

算法工具链
技术深度解析社区征文前沿技术
评论0
0/1000