news 2026/9/15 22:59:47

LMCache 中的 KV Cache 压缩:CacheGen 编解码原理、配置方式与源码解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LMCache 中的 KV Cache 压缩:CacheGen 编解码原理、配置方式与源码解析

LMCache 中的 KV Cache 压缩:CacheGen 编解码原理、配置方式与源码解析

【免费下载链接】LMCacheLMCache: Supercharge Your LLM with the Fastest KV Cache Layer项目地址: https://gitcode.com/GitHub_Trending/lm/LMCache

KV Cache 在长上下文、多轮对话等场景下会迅速占据大量显存与远端存储,直接制约缓存命中率与加载速度。LMCache 在docs/source/kv_cache_optimizations/compression/index.rst中正式引入了基于 KV Cache 分布特性的压缩算法 CacheGen,将 KV Cache 编码为更紧凑的比特流,并以可忽略的解码开销换取存储/内存占用与加载速度的大幅改善。读完本文,你将掌握 CacheGen 在 LMCache 中的启用方式(离线与在线两种配置)、底层"量化—CDF 估计—算术编码"完整链路,以及如何在仓库中验证其压缩效果。

为什么需要 KV Cache 压缩

KV Cache 压缩能够显著减小缓存体积,这对以下两方面都有直接收益:

  • 存储 / 内存占用:压缩后的 KV Cache 可以更少地占用本地 CPU 内存、本地磁盘或远端缓存服务(Redis、Mooncake 等)的空间,让同样的容量容纳更多 token 的缓存;
  • 加载速度:更小的字节流意味着在远端缓存读取(cache hit 场景)时更少的网络传输时间与反序列化开销,从而缩短首 Token 延迟。

在 LMCache 当前的压缩功能矩阵中,官方支持的压缩算法为 CacheGen(对应docs/source/kv_cache_optimizations/compression/index.rst中的列表):

  • CacheGenCacheGen: KV Cache Compression and Streaming for Fast Large Language Model Serving(SIGMETRICS 论文)

docs/source/kv_cache_optimizations/compression/cachegen.rst对 CacheGen 做了如下定位:CacheGen 利用 KV Cache 的分布特性(distributional properties),将其编码为更紧凑的比特流表示(bitstream),且解码开销可以忽略不计(negligible decoding overhead)。

需要注意,上述文档描述的是 LMCache 的 in-process 模式(已标记为 deprecated)行为。LMCache 更推荐使用 LMCache MP 模式 以获得更完善的功能支持与性能;MP 模式下的 CacheGen 支持尚未实现(见 MP 模式 CacheGen 文档,其内容为 "not implemented yet (coming soon)"),原始 in-process 实现被保留在 Legacy 部分,即本文所对应的 compression/index.rst。

启用 CacheGen:离线与在线两种配置

CacheGen 的配置与 LMCache 的 naive KV cache sharing 几乎完全一致,只需做少量改动即可启用。也就是说,它作用于"远端缓存读写"这一条链路上,对 KV Cache 进行压缩后写入远端、读取时解压还原。

离线推理场景(环境变量方式)

在离线推理(offline inference)中,通过设置环境变量LMCACHE_REMOTE_SERDE来启用:

# Enable cachgen compression in LMCache os.environ["LMCACHE_REMOTE_SERDE"] = "cachegen"

在线推理场景(配置文件方式)

在在线推理(online inference,例如与 vLLM 集成的部署)中,需要在 LMCache 的配置 YAML 中设置remote_serde字段:

# Enable cachgen compression in LMCache remote_serde: "cachegen"

配置项在源码中的落点

remote_serdeLMCacheEngineConfig的一个标准配置项,定义于 lmcache/v1/config.py:

  • 类型:Optional[str]
  • 默认值:"naive"(即默认使用朴素序列化,不启用压缩)
  • 环境变量转换器:str

从 lmcache/v1/storage_backend/naive_serde/init.py 的CreateSerde工厂函数可以看到,serde_type支持naivekivicachegen三种取值,其中:

elif serde_type == "cachegen": s, d = ( CacheGenSerializer(config, metadata), CacheGenDeserializer(config, metadata), )

"cachegen"会创建CacheGenSerializerCacheGenDeserializer这对编解码器;传入其他非法值会抛出ValueError

另外两点值得注意:

  • 在 lmcache/v1/cache_engine.py 与 lmcache/v1/cache_engine.py 中,创建远端序列化器的分支要求method必须为"cachegen",进一步印证了 CacheGen 是当前 in-process 模式下唯一受支持的远端压缩算法(其余压缩能力走 MP 模式的 legacy 代码路径)。
  • 远端后端在创建时会断言config.remote_serde is not None(见 lmcache/v1/storage_backend/remote_backend.py),也就是说使用远端缓存(如 Redis、Mooncake)时remote_serde是必经之路,而默认值"naive"保证未显式配置时也能正常工作。

前置条件:先完成跨实例 KV Cache 共享

由于 CacheGen 是"远端 KV Cache 共享"链路中的序列化器,正式启用前需要先按照 share_kv_cache 文档 配置好跨实例 KV Cache 共享。LMCache 支持两类共享方式:

  • centralized_sharing:通过集中式缓存服务器共享 KV Cache;
  • p2p_sharing:通过点对点缓存传输共享 KV Cache。

CacheGen 的配置与这两种共享方式的配置"非常相似",只需在既有共享配置之上追加remote_serde: "cachegen"(或设置环境变量)即可,无需调整其他参数。

CacheGen 底层原理:源码级编解码链路

CacheGen 的核心思想是:先对 KV Cache 做按层分组的低位宽量化,再基于量化值的统计分布估计累积分布函数(CDF),最后用 CDF 驱动的算术编码把量化值压成紧凑比特流。编码、解码两条路径分别实现在:

  • lmcache/storage_backend/serde/cachegen_encoder.py:CacheGenSerializer.to_bytes()
  • lmcache/storage_backend/serde/cachegen_decoder.py:CacheGenDeserializer.from_bytes()

1. 按层分组的量化配置(QuantizationSpec)

量化规格由QuantizationSpec描述(cachegen_basics.py),包含三个字段:

字段含义
start_layer该量化区间的起始层号(含)
end_layer该量化区间的结束层号(不含)
bins量化 bin 数量,bin 数越大量化越精细

CacheGenConfig聚合了nlayers(总层数)、kspecs(K 的量化区间列表)、vspecs(V 的量化区间列表),并通过from_model_name()按模型族自动推导默认配置:

  • 7B 系mistralai/Mistral-7B-Instruct-v0.2lmsys/longchat-7b-16kQwen/Qwen-7B):32 层,K 前 10 层用 32 bins、其余 16 bins;V 前 2 层用 32 bins、其余 16 bins;
  • 8B 系meta-llama/Llama-3.1-8B-Instruct):同为 32 层,量化分段与 7B 一致;
  • 9B 系THUDM/glm-4-9b-chat):40 层,K 前 10 层 32 bins、其余 16 bins;V 前 2 层 32 bins、其余 16 bins(源码注释标明该配置 "needs tuning for better quality");
  • 其他模型:通过AutoConfig.from_pretrained(model_name)读取num_hidden_layers动态生成:层数 < 10 时 K/V 全部用 32 bins;否则按"前 10 层 / 前 2 层用 32 bins、其余用 16 bins"的规则生成;无法识别时抛出ValueError

从配置语义可以看出,CacheGen 的量化策略偏好是:浅层(靠近输入)的 K/V 分布更"重要"或更复杂,给予更多 bin(32),深层则用更少的 bin(16),从而在保真度与压缩率之间取得平衡。

2. 量化(Quantization)

编码器入口to_bytes()接收形状为[num_layers, 2, num_tokens, num_heads, head_size]的 blob KV 张量,先通过_split_kv()拆成 K 与 V(reshape 后按第 1 维 unbind),得到[num_layers, num_tokens, num_channels]形式。

核心量化函数torch_quant_vectorized()(cachegen_encoder.py)逐层按各自 bin 数做对称量化:

MAX = (bins // 2 - 1)[:, None, None] # [nlayers, 1, 1] max1 = torch.amax(torch.abs(input_groups), dim=-1, keepdim=True) factor = MAX / max1 xq = torch.round(input_groups * factor + MAX).to(torch.int8)

即对每个通道维度取绝对值的最大值作为缩放因子max1,将张量缩放到[-MAX, MAX]区间并 round 成int8max1作为反量化所需的缩放系数随编码结果一并保存。

3. CDF 估计与归一化

量化完成后,编码器基于量化值的直方图统计每个 (层, 通道) 的符号分布,并用torch.cumsum计算累积分布函数(CDF)。为了让浮点 CDF 能安全喂给整数算术编码器,_convert_to_int_and_normalize()(cachegen_encoder.py)做了关键处理:

  • 将 CDF 从[0, 1)放大到2^16(16 位精度)量级;
  • 若需要归一化,先乘2^16 - (Lp - 1)再叠加一个arange(Lp)斜坡,保证 CDF严格单调递增——算术编码器要求 CDF 单调,否则相同符号会出现重复区间导致解码失败。

4. 算术编码与 GPU Kernel

真正把量化符号压成比特流的是 GPU 端的算术编码 kernel。编码器按CACHEGEN_GPU_MAX_TOKENS_PER_CHUNK = 256(cachegen_basics.py)将 token 分批处理,调用:

  • device_ops.calculate_cdf(...):GPU 上直接计算 CDF(对应 csrc/cuda/cal_cdf.cu);
  • device_ops.encode_fast_new(...):GPU 算术编码(对应 csrc/cuda/ac_enc.cu)。

每批编码结果以CacheGenGPUBytestreambytestream+bytestream_lengths+ntokens)组织,最终封装为CacheGenGPUEncoderOutput,并通过 pickle 序列化成bytes写入远端。

5. 解码与反量化

解码路径(CacheGenDeserializer.from_bytes())是编码的逆过程:

  1. 反序列化得到CacheGenGPUEncoderOutput
  2. 调用device_ops.decode_fast_prefsum(...)(对应 csrc/cuda/ac_dec.cu)按 CDF 与长度前缀和还原每个 (层, 通道) 的量化符号;
  3. decode_function_gpu()将解码结果 reshape 回[2, nlayers, ntokens, nchannels]并拆出 K/V;
  4. do_dequantize()(cachegen_decoder.py)用保存的max_tensors_key/max_tensors_value与各层 bin 数做逆缩放:t = (t - C) / C * maxtensors
  5. 最后重新 stack 成[nlayers, 2, ntokens, num_heads, head_size]并转回原始 dtype。

解码器内部还复用了get_output_buffer()的预分配缓冲来降低反复分配的抖动,并对key_bins/value_bins做设备同步(源码注释 #83 记录了多 worker 设备隐式绑定问题的临时修复)。

6. 与 vLLM 集成时的注意点

在 vLLM 集成路径中,lmcache/integration/vllm/utils.py 存在如下约束:

if use_mla and (config.remote_serde != "naive" and config.remote_serde is not None):

即当模型使用 MLA(Multi-head Latent Attention)且remote_serde被设置为非naive时会有额外的检查逻辑。这意味着在启用 CacheGen 前,需要确认目标模型架构(尤其 MLA 类模型)与 CacheGen 的兼容性约束。

如何验证压缩效果:仓库自带的端到端 Benchmark

仓库在 tests/benchmarks/test_cachegen.py 提供了 CacheGen 编码/解码的端到端基准测试,可以直观验证压缩率与耗时。运行方式:

pytest tests/benchmarks/test_cachegen.py --benchmark-only

该测试的关键设计:

  • 使用_generate_kv()构造 32 层、8 头、head_size 128 的 bfloat16 合成 KV blob;
  • 编解码器通过LMCacheEngineConfig.from_defaults(chunk_size=...)LMCacheMetadata(model_name="mistralai/Mistral-7B-Instruct-v0.2", ...)构建,即走 7B 模型的默认量化配置;
  • 编码测试对chunk_size分别取[64, 128, 256, 768]四档,测量to_bytes()耗时,并打印raw / compressed的压缩率;
  • 解码测试测量from_bytes()耗时;
  • 测试要求当前 torch 运行时可用(torch_dev.is_available()),否则整模块 skip——因为 CacheGen 依赖手写的 GPU kernel(CUDA/XPU 等)。

此外,tests/test_serde.py 等单测覆盖了序列化器的一致性校验,可用于确认 CacheGen 编码-解码往返(round-trip)的正确性。

使用建议与限制小结

  1. 适用路径:CacheGen 作用于远端 KV Cache 读写的序列化链路,启用前请先完成 KV Cache 跨实例共享 的配置;
  2. 模式限制:本文档对应的 in-process 模式已被标记为 deprecated;MP 模式 的 CacheGen 尚未实现,生产环境建议关注 MP 模式路线并留意后续版本;
  3. 硬件依赖:CacheGen 的 CDF 计算与算术编解码均在 GPU kernel 中完成(csrc/cuda 下的ac_enc.cuac_dec.cucal_cdf.cu),启用前需确认推理设备具备对应运行时;
  4. 模型适配:默认量化配置针对常见 7B/8B/9B 模型族做了手工调优,其他模型会基于num_hidden_layers自动推导;如需更优的精度/压缩权衡,可关注后续对量化规格可配置化的演进;
  5. 架构约束:MLA 类模型与remote_serde非默认值存在联动检查,使用前应核对 vllm 集成代码 中的约束条件。

整体来看,CacheGen 是 LMCache 在"KV Cache 压缩"方向上的核心实现,其"分布感知的按层量化 + 算术编码"思路在压缩率与解码开销之间做了精心取舍;通过remote_serde: "cachegen"一行配置即可接入,配合仓库自带的 benchmark 可以快速量化其在目标硬件上的实际收益。

【免费下载链接】LMCacheLMCache: Supercharge Your LLM with the Fastest KV Cache Layer项目地址: https://gitcode.com/GitHub_Trending/lm/LMCache

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/15 22:59:44

深圳网站建设公司评论避坑指南:保姆级建站教程解析

深圳网站建设公司评论避坑指南:保姆级建站教程解析 域名注册完卡在服务器配置,SSL证书申请下来却忘了配置,这种“域名服务器搞不懂”的困境,几乎是深圳中小企业主建站时的第一道坎。很多人以为找个深圳网站建设公司就能一劳永逸,结果上线后发现代码烂、SEO差、备案难,悔之晚矣。这篇保姆级建站教程,不聊虚的,…

作者头像 李华
网站建设 2026/9/15 22:59:28

技术专家转型项目负责人的实战经验与敏捷管理

1. 从技术专家到项目负责人的角色转变十年前&#xff0c;当我第一次被任命为软件项目负责人时&#xff0c;我以为这只是个"高级程序员"的头衔变化。直到第一次项目进度会议上&#xff0c;看着十几双期待的眼睛&#xff0c;我才意识到自己需要完全不同的技能树。技术专…

作者头像 李华
网站建设 2026/9/15 22:58:10

无线对讲系统选型实战:盯紧核心参数避开营销陷阱

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/15 22:57:12

Flutter跨端实战:OpenHarmony上开发MD5/SHA1摘要工具

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/15 22:56:38

mysql数据迁移

背景&#xff1a;随着时间的推移&#xff0c;交易系统中的订单表越来越大&#xff0c;目前达到500w数据。为了防止数据量过大导致的查询性能问题&#xff0c;现将订单表进行拆分&#xff0c;分为实时库和历史库。实时库保留近6个月的数据&#xff0c;用于退款业务需求&#xff…

作者头像 李华
网站建设 2026/9/15 22:56:10

开源大模型技术手册:原理、实践与优化全解析

1. 开源大模型技术手册的价值解析《大模型基础》这本由浙江大学团队推出的开源技术书籍&#xff0c;近期在开发者社区引发了热烈讨论。作为一本系统讲解大语言模型&#xff08;LLM&#xff09;技术原理与实践指南的公开资料&#xff0c;它的出现正好填补了当前中文技术文档生态…

作者头像 李华