File size: 8,695 Bytes
f0ad681 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 | # 🧠 纯文本 LLM KV 缓存压缩 — 详细定制方案
> **版本**: v1.0
> **日期**: 2026-08-06
> **适用**: 纯文本大语言模型推理(对话/长文/代码/文档)
> **目标**: 显存 -50%+、吞吐 +2x、精度损失 < 0.5 PPL
---
## 一、方案总览
### 1.1 核心思路
纯文本 LLM 的 KV 缓存压缩采用**分层正交叠加**策略:
```
┌─────────────────────────────────────────────────────┐
│ Layer 1: INT8 量化 (per-channel) → 显存 -50% │
│ Layer 2: StreamingLLM (attention sink) → 长上下稳定 │
│ Layer 3: H2O 驱逐 (重击者+近邻) → 再省 40% │
│ Layer 4: K/V 分离存储 (可选) → 显存换质量 │
└─────────────────────────────────────────────────────┘
每层独立开关, 可按场景组合
```
### 1.2 三层正交性
| 维度 | 压缩对象 | 对应层 | 说明 |
|------|----------|--------|------|
| 特征维度 | 每个 token 的 K/V 精度 | Layer 1 量化 | 与长度无关 |
| 序列维度 | 不重要的历史 token | Layer 3 驱逐 | 与精度无关 |
| 存储维度 | 冷数据放慢速介质 | Layer 4 分离 | 与上面都正交 |
| 结构维度 | 首 token 保留 | Layer 2 保底 | 免费防护 |
---
## 二、Layer 1: INT8 KV 量化(必做)
### 2.1 原理
```python
# per-channel 量化 (K/V 每通道一个 scale)
scale_k = max_abs(K, dim=channel) / 127
K_int8 = round(K / scale_k)
# 反量化在注意力计算时做
K_deq = K_int8 * scale_k
```
### 2.2 技术选型
| 方案 | 精度 | 速度 | 复杂度 | 推荐 |
|------|------|------|--------|------|
| **per-channel INT8** | 掉点 <0.3 | 快 | 低 | ✅ 首选 |
| per-token INT8 | 更稳 | 快 | 中 | ✅ 精度敏感时 |
| FP8 (E4M3) | 几乎无损 | 最快 | 高 | ⚠️ 需 H100/L40S 支持 |
| INT4 | 掉点 1-2 | 最快 | 高 | ❌ 纯文本不值当 |
### 2.3 实现要点
```
1. 量化时机: 每 token 写入 KV 缓存时即时量化 (不重算)
2. scale 计算: per-channel (head 维度), 避免 per-token 额外开销
3. 反量化位置: 在 FlashAttention 内核内融合, 不额外访存
4. 溢出处理: 用动态 scale (max-abs), 比固定 scale 稳
5. 特殊 token: attention sink 的 K/V 保持 FP16 (防精度损失)
```
### 2.4 预期收益
- 显存: K/V 从 FP16 → INT8, **-50%**
- 速度: 缓存命中率提升, decode 吞吐 **+30~50%**
- 精度: PPL 变化 < 0.3, 实际对话几乎无感
---
## 三、Layer 2: StreamingLLM 滑窗保底(必做)
### 3.1 原理
```
保留集合 = [attention_sink(前4个token)] + [最近 N 个token]
旧 token 滑出窗口后被丢弃, 但 sink 永不动
```
### 3.2 参数推荐
| 参数 | 默认 | 说明 |
|------|------|------|
| sink_tokens | 4 | 首 4 个 token 永存 |
| window_size | 2048 | 滑动窗口长度 |
| 触发时机 | 序列 > window 时 | 之前不启用 |
### 3.3 与 Layer 1 叠加
```
Layer 1 (量化) 对窗口内所有 token 生效
Layer 2 (滑窗) 决定哪些 token 保留
→ 实际显存 = window_size × 量化后大小
→ 长对话显存从 O(seq_len) 降到 O(window)
```
---
## 四、Layer 3: H2O 驱逐(可选, 按场景)
### 4.1 适用判定
| 场景 | 是否启用 | 原因 |
|------|----------|------|
| 多轮对话 | ⚠️ 谨慎 | 回头翻旧账可能丢信息 |
| 单轮长文 | ✅ 启用 | 注意力集中, 效果好 |
| RAG 检索 | ❌ 禁用 | 检索需全量上下文 |
| 代码补全 | ✅ 启用 | 代码局部性强 |
### 4.2 H2O 算法
```python
def h2o_evict(kv_cache, budget, attention_scores):
"""
1. 统计每个 token 的累计注意力分数 (heavy hitter 分数)
2. 保留 top-k 重击者 token
3. 加上最近 budget 内 token
4. 其余驱逐
"""
scores = cumulative_attention(attention_scores)
heavy = topk(scores, k=budget * 0.3) # 30% 重击者
recent = last_n_tokens(kv_cache, budget * 0.7) # 70% 最近
return heavy ∪ recent
```
### 4.3 参数
| 参数 | 默认 | 说明 |
|------|------|------|
| budget | 1024 | 驱逐后保留的 token 数 |
| heavy_ratio | 0.3 | 重击者占比 |
| 驱逐频率 | 每 64 token | 避免频繁计算 |
### 4.4 与推理模型的区别(重要)
```
⚠️ 推理模型 (DeepSeek-R1) 禁用 H2O:
思考链长且信息密度高, 驱逐会破坏推理连贯性
纯文本模型 (对话/总结/代码) 可用:
注意力集中, 驱逐掉低分 token 影响极小
```
---
## 五、Layer 4: K/V 分离存储(高级定制)
### 5.1 原理(HCAttention 思路)
```
┌─────────────────────────────────────────┐
│ GPU 高速显存 │
│ K_int8 (量化后, 只用来打分) ← 全保留 │
│ 最近窗口的 V (FP16) │
├─────────────────────────────────────────┤
│ CPU 内存 │
│ 旧 token 的完整 V (FP16) ← 按需调取 │
└─────────────────────────────────────────┘
```
### 5.2 工作流
```python
# 打分阶段 (GPU, 只要 K)
scores = Q @ K_int8.T / sqrt(d) # 全局近似打分
# 取用阶段 (按需)
if token 在 GPU 窗口: V = V_gpu
else: V = V_cpu[token] # 从 CPU 拉取
# 输出
out = softmax(scores) @ V
```
### 5.3 适用场景
| 场景 | 是否启用 | 原因 |
|------|----------|------|
| 多轮对话(客户翻旧账) | ✅ 启用 | 旧信息可回溯, 不丢 |
| 单轮长文 | ❌ 不必 | 滑窗够用 |
| 显存紧张 (24G 卡) | ✅ 启用 | 把显存让给 batch |
### 5.4 代价
- 冷 V 从 CPU 拉取: 延迟 +5~15ms(首 token 感知)
- 实现复杂度: 中高(需要 CPU/GPU 内存管理)
---
## 六、场景定制矩阵
| 业务场景 | Layer1 | Layer2 | Layer3 | Layer4 | 预期压缩 |
|----------|--------|--------|--------|--------|----------|
| **客服对话** | ✅ | ✅ | ⚠️ | ✅ | 4~6x |
| **长文总结** | ✅ | ✅ | ✅ | ❌ | 6~8x |
| **代码生成** | ✅ | ✅ | ✅ | ❌ | 6~8x |
| **RAG 问答** | ✅ | ✅ | ❌ | ✅ | 3~4x |
| **推理模型** | ✅ | ✅ | ❌ | ✅ | 3~4x |
| **批量离线** | ✅ | ❌ | ✅ | ❌ | 8x+ |
---
## 七、实现路线图(L40S 实测)
### Phase 1: Baseline(1 天)
```
1. 搭 vLLM 或自研推理脚本 (支持 7B/14B)
2. 跑通 FlashAttention 2
3. 记录 baseline: PPL / 吞吐 / 显存
```
### Phase 2: INT8 量化(1-2 天)
```
1. 实现 per-channel KV 量化
2. 内核融合反量化
3. 对比 PPL / 显存 / 吞吐
```
### Phase 3: StreamingLLM + H2O(1-2 天)
```
1. 实现滑窗 + attention sink
2. 实现 H2O 驱逐
3. 长上下文压力测试 (4k/8k/16k/32k)
```
### Phase 4: K/V 分离(2 天, 可选)
```
1. CPU 内存池管理
2. 冷热 V 迁移
3. 多轮回溯测试
```
### Phase 5: 评测 + 交付(1 天)
```
1. 三张核心曲线: 压缩率 vs PPL / 压缩率 vs 吞吐 / 压缩率 vs 延迟
2. 生成对比报告 (HTML, 类似 kv_cache_report)
3. 封装成可复用的推理加速模块
```
---
## 八、评测方案
### 8.1 精度指标
| 指标 | 工具 | 目标 |
|------|------|------|
| PPL | wikitext-2/4 | 变化 < 0.5 |
| 任务准确率 | MMLU / GSM8K | 掉点 < 1% |
| 长文检索 | LongBench | 保持 |
| 对话一致性 | 人工抽测 | 无明显劣化 |
### 8.2 性能指标
| 指标 | 定义 | 目标 |
|------|------|------|
| 显存占用 | KV 缓存峰值 | -50% |
| decode 吞吐 | tokens/s | +50% |
| TTFT | 首 token 延迟 | 不变 |
| 长上下文极限 | 可处理最大序列 | 2x 提升 |
---
## 九、交付物
```
1. 推理加速模块 (可插拔: kv_compress.py)
2. 四层开关配置 (yaml)
3. 评测报告 (HTML 带曲线)
4. 场景接入示例 (对话/长文/代码/RAG)
5. 文档: 参数调优指南
```
---
## 十、风险与对策
| 风险 | 概率 | 对策 |
|------|------|------|
| INT8 掉点超预期 | 低 | 回退 per-token 量化 / 关键层保 FP16 |
| H2O 在特定任务崩 | 中 | 按场景开关, 提供安全默认值 |
| K/V 分离延迟超标 | 中 | 预取 / 双缓冲 / LRU 热 V 常驻 |
| 长上下文 OOM | 低 | 滑窗兜底 + 显存监控自动降级 |
---
*本方案为纯文本 LLM KV 缓存压缩定制版, 基于 H2O / StreamingLLM / HCAttention / INT8 量化等技术路线综合设计。*
|