ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

FP8 KV Cache:先证明 E4M3 解码,再讨论容量收益

FP8 KV Cache:先证明 E4M3 解码,再讨论容量收益

FP8 KV Cache 不只是把数组元素从两字节改为一字节。尺度怎么校准、按张量还是按 head、后端是否支持相应计算路径,都会影响结果。更基础的一关是格式解码本身:合法的 256 不能因为指数分支写错就变成 448。

vLLM 的量化 KV 文档分别说明每张量、每注意力头的尺度与校准方式,并指出后端限制。OCP OFP8 规范给出这些编码边界。这里聚焦 E4M3FN 的非负码字:指数全 1 并不意味着所有值都饱和;最高有限值是 448,特定尾数码表示 NaN。

KV 载荷、尺度与数值解码都属于量化缓存的实现。

import math def decode_e4m3fn(byte): if not 0<=byte<=255: raise ValueError("one byte required") sign=-1. if byte&128 else 1. exp=(byte>>3)&15; mant=byte&7 if exp==15 and mant==7: return float('nan') value=(mant/8)*2**(-6) if exp==0 else (1+mant/8)*2**(exp-7) return sign*value assert decode_e4m3fn(0x78)==256. assert decode_e4m3fn(0x7e)==448. assert math.isnan(decode_e4m3fn(0x7f)) assert decode_e4m3fn(0x01)==2**(-9) assert decode_e4m3fn(0xf8)==-256. print("E4M3FN: normal, subnormal, sign and NaN cases passed")

这只是解码,不包含编码舍入、饱和策略和尺度应用。不能用几个解码断言宣称量化器完整可用。若要实现编码,最好枚举全部可表示值,再用明确的 ties-to-even 或其他约定检查边界,而不是凭指数判断粗暴截断。

容量要按 KV 头数计算

对于常见全注意力层,一个请求的原始 KV 载荷可按2*layers*tokens*kv_heads*head_dim*bytes估算。GQA 应用 KV 头数,不能把 query 头数直接代入。还要加入页尾、尺度和分配器元数据;混合模型与滑窗层需要按层计算。

NVIDIA Transformer Engine 的 FP8 资料说明了不同 FP8 格式的数值范围。格式相同也不保证校准相同,错误尺度可能让一整块值变得过大或过小。

用枚举建立格式参考的价值

八位格式只有有限数量的码字,解码器很适合做全码枚举。除了已列出的几个边界,还可以检查正负对称、正常数与次正规数的接合,以及零和 NaN 的分类。这样的参考表不需要真实模型,却能给硬件实现或向量解码提供稳定对照。

编码器的困难则不同。两个相邻可表示值的中点该向哪边舍入,超过范围是否饱和,NaN 是否保留某种载荷,都需要明确。若编码与解码来自同一份错误表,往返测试也可能通过,因此还应与规范中的独立编码边界比较,而不是只测自己能否把自己的字节读回来。

KV 量化的尺度还要跟着缓存一起走。若缓存块被搬到主机、重排或跨请求复用,尺度与数据必须保持同一身份;漏传尺度不会引发读取越界,却会让整块数值错误。按 head 校准与按张量校准,也需要不同的元数据布局,不能只在配置字符串上切换。

容量收益和质量检查可以分开记录。先核对块池实际分配量,确认元数据和页尾没有被漏计;再用固定模型与数据检查输出偏差,特别关注长上下文与敏感层。量化格式解析通过,只能让后续实验具有可解释的起点,不能替代这些模型与系统层面的验证。

校准集的身份也会影响重现。只写使用了校准数据,却没有固定来源、预处理和长度分布,后续很难比较尺度变化是否合理。真实部署可以先保存校准配置和尺度摘要,再在相同评估条件下比较不同粒度。若某些层保留高精度,应在容量和质量报告里如实说明,不能把混合方案写成全层 FP8。本文的解码参考没有承担这些校准工作,它只是帮助排除最基础的格式解释错误。

本文没有运行 vLLM、没有测困惑度和长上下文任务。完成解码与容量核算后,还需比较真实模型输出、缓存命中以及端到端 ITL;显存减少不能直接换算成速度提升。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进