大模型能力越来越强,但推理成本也越来越高:参数规模变大,显存占用上升,计算开销增加,长上下文带来更大的 KV Cache,线上服务还要面对延迟、吞吐和并发压力。对于真实业务系统来说,模型不只是“能不能答得好”,还要看它能不能在可接受的成本和延迟下稳定运行。

模型压缩要解决的正是这个问题:在尽量少损失模型能力的前提下,降低参数存储、显存占用、计算开销和生成延迟。它不是单一技术,而是一组面向推理降本提速的系统优化方法,包括量化、剪枝、蒸馏、低秩分解、KV Cache 优化和 Speculative Decoding。

这一篇我们重点看清楚:大模型推理成本到底来自哪里,不同压缩技术分别优化哪一部分,以及在生产环境里应该如何根据瓶颈选择合适的压缩与加速方案。

为什么需要模型压缩

大模型推理成本,主要来自四个部分:模型权重、计算开销、KV Cache 和系统调度开销。模型压缩并不是只把参数文件变小,而是要围绕这几类成本做整体优化。可以先用一张图理解,如下所示:

模型压缩不是只压参数,还要看计算、KV Cache 和系统执行路径

参数显存

模型权重占用可以粗略估算为:

1
权重显存 ≈ 参数量 × 每个参数字节数

例如:

精度 每个参数字节数 13B 模型权重显存
FP32 4 bytes 约 52 GB
FP16 / BF16 2 bytes 约 26 GB
INT8 1 byte 约 13 GB
INT4 0.5 byte 约 6.5 GB

这里算的只是模型权重,不包含 KV Cache、运行时 buffer、batch 调度和框架额外开销。量化最直接的收益,就是让同一个模型用更低精度存储,从而降低权重显存和内存带宽压力。

计算开销

Transformer 推理主要由矩阵乘法构成,尤其是 Attention 投影矩阵和 FFN / MLP 矩阵。推理阶段可以分成两段:

  1. Prefill:处理完整输入上下文,Attention 需要看见整段序列,长上下文下计算和显存压力很高;
  2. Decode:逐 token 生成,每一步都要经过所有层,并访问历史 KV Cache。

可以简化理解为:

1
每 token 计算量 ≈ 层数 × hidden_size² × 常数项

这不是严格公式,但能说明核心趋势:层数越多、hidden size 越大,矩阵计算越重。Dense Transformer 每个 token 通常都会经过完整网络路径,所以大模型推理经常不是“算不出来”,而是“算得太贵、太慢”。

KV Cache

在自回归生成中,模型每生成一个新 token,都需要访问历史 token 的 Key / Value。为了避免重复计算,系统会把每层 Attention 的 K/V 缓存下来,这就是 KV Cache。KV Cache 可以粗略估算为:

1
KV Cache ≈ 2 × layers × tokens × kv_heads × head_dim × bytes × batch_size

其中 2 表示 Key 和 Value。这意味着:上下文越长、batch 越大、并发越高,KV Cache 占用就越大。长上下文场景里,瓶颈经常不是模型权重,而是 KV Cache。

系统调度开销

除了模型权重、计算量和 KV Cache,推理系统本身也会带来额外开销。比如连续批处理、请求调度、kernel 启动、张量并行通信、显存碎片、KV block 管理,都会影响最终的延迟和吞吐。

这也是为什么模型文件变小之后,推理速度不一定线性提升。真实服务里的性能瓶颈,往往是模型计算、内存带宽、缓存管理和调度策略共同作用的结果。因此,模型压缩通常要和推理引擎优化一起看,而不是只看参数量或模型大小。

压缩目标

所以模型压缩可以拆成几类目标:

目标 典型方案
降低权重显存 量化、剪枝、低秩分解
降低计算成本 量化、剪枝、蒸馏
降低 KV Cache 成本 GQA / MQA、KV 量化、Sliding Window / KV Eviction、PagedAttention
降低生成延迟与提升吞吐 Speculative Decoding、Prefix Cache、批处理调度
提升系统执行效率 Continuous Batching、PagedAttention、Prefix Cache、请求调度

一句话概括:模型压缩不是简单把模型文件变小,而是围绕推理成本,对权重、计算、缓存和系统执行路径做整体优化。

量化:用更低精度表示模型

量化是大模型压缩里最常见、最实用的一类方法。它的核心思想是:不再总是用 FP16 / BF16 存储和计算模型权重,而是用 INT8、INT4、FP8 等更低精度表示权重、激活值或 KV Cache。量化的收益主要来自两点:

  1. 降低显存占用:同样数量的参数,用更少 bit 存储;
  2. 降低内存带宽压力:推理时从显存读取的数据更少。

但量化不是“无损压缩”。它本质上是用更低数值精度近似原始浮点数,因此一定会引入量化误差。真正的难点不是把模型变成 INT4,而是控制误差,让模型能力尽量不下降。

量化的基本原理

量化的基本原理,是用低精度数值近似表示原来的高精度浮点数。可以把它理解成:先统计一组浮点数的范围,再用有限的整数刻度去近似表示它们。一个常见的非对称量化形式可以写成:

1
2
q = round(x / scale) + zero_point
x_hat = scale × (q - zero_point)

其中:

符号 含义
x 原始浮点值
q 量化后的整数值
scale 缩放因子
zero_point 零点偏移
x_hat 反量化后的近似值

这里展示的是非对称量化。如果采用对称量化,zero_point 通常为 0,公式可以简化为:

1
2
q = round(x / scale)
x_hat = scale × q

在 LLM 权重量化中,更常见的是分组量化或通道级量化:不同 group 或 channel 使用不同的 scale,以减少 outlier 对整体量化范围的影响。不同实现会在精度、速度和显存之间做取舍。

量化通过低精度表示减少权重显存和内存带宽压力

例如,对于 INT8 来说,通常只有 256 个可表示刻度;对于 INT4,则只有 16 个刻度。刻度越少,压缩率越高,但表示误差也越大。

量化主要压哪里

量化可以作用在不同对象上:

类型 量化对象 说明 难度
Weight-only Quantization 权重 只量化模型权重,激活仍用 FP16 / BF16 相对简单,常见于 INT4 / INT8 推理
Weight + Activation Quantization 权重 + 激活 权重和激活都量化,计算加速潜力更大 更难,需要更细致校准
KV Cache Quantization KV Cache 用低精度存储 Key / Value 适合长上下文和高并发
FP8 Quantization 权重 / 激活 使用 FP8 做训练或推理 依赖硬件和框架支持

其中 Weight-only Quantization 最常见,因为它对模型结构侵入较小,也更容易落地。
Weight + Activation Quantization 理论上加速潜力更大,但激活值随输入变化,分布更不稳定,所以更难做好。

为什么 INT4 不一定比 INT8 快

很多人会直觉认为:INT4 比 INT8 更小,所以一定更快。实际不一定。推理速度不只取决于模型文件大小,还取决于:

  1. GPU / NPU 是否原生支持对应精度;
  2. kernel 是否针对 INT4 做了优化;
  3. 计算时是否需要频繁反量化;
  4. batch size 和矩阵形状是否适合低精度 kernel;
  5. 瓶颈到底在计算,还是在内存带宽。

INT4 的主要优势是:

  1. 权重显存更低;
  2. 内存带宽压力更小;
  3. 更容易部署到显存较小的设备上。

但它也可能带来:

  1. 反量化开销;
  2. 精度损失;
  3. kernel 支持不足;
  4. 小 batch 下收益不稳定;
  5. 某些层需要保留高精度,实际收益打折。

所以 INT4 更常见的价值是降低显存和部署门槛,而不是在所有场景下都显著提升速度。

PTQ 与 QAT

量化通常分为两类:

方法 全称 核心思路 特点
PTQ Post-Training Quantization 训练后量化 成本低,常用于推理部署
QAT Quantization-Aware Training 量化感知训练 效果更稳,但训练成本高

实际 LLM 推理里,PTQ 更常见。因为重新训练大模型成本很高,很多系统会用少量校准数据统计权重和激活分布,然后选择合适的量化尺度、分组策略和保留高精度的敏感层。

QAT 则会在训练过程中模拟量化误差,让模型提前适应低精度计算。它通常效果更稳,但成本更高,更适合对精度要求高、部署规模大、值得重新训练的场景。

量化的核心难点:Outlier

LLM 量化最难的地方,是模型里经常存在 outlier,也就是少数特别大的权重值或激活值。量化需要用有限刻度覆盖一个数值范围。如果范围被少数 outlier 拉得很大,大多数普通值就会挤在很小的区间里,表示精度变差。可以简单理解成:

  1. 没有 outlier:整数刻度集中表示常见数值,误差较小;
  2. 存在 outlier:刻度被少数极端值拉开,普通值表示变粗糙。

常见解决思路包括:

方法 作用
分组量化 每组权重单独计算 scale,减少大范围误差
通道级量化 不同 channel 使用不同 scale
激活平滑 把 activation outlier 转移或平滑到权重侧处理
混合精度 对敏感层、Embedding、输出层保留 FP16 / BF16
校准数据 使用接近真实业务分布的数据统计量化参数

量化最终是一场 trade-off:

1
2
更低精度 -> 更低显存 / 更低带宽 / 更低部署门槛
更低精度 -> 更大量化误差 / 更高能力退化风险

一句话概括:量化是用数值精度换推理成本,核心难点不在“把 FP16 变成 INT4”,而在如何控制量化误差,让模型在更低显存和更低带宽下仍然保持能力稳定。

剪枝、蒸馏与低秩分解:从结构上变小

量化主要改变的是参数表示精度,模型结构本身通常还在;而剪枝、蒸馏和低秩分解更进一步,目标是让模型在结构上变小,或者让一个更小的模型继承大模型的能力。其区分如下表:

方法 核心思路 压缩对象
剪枝 删除低重要性结构 权重、head、channel、layer
蒸馏 让小模型学习大模型行为 模型能力和任务分布
低秩分解 用小矩阵近似大矩阵 Attention / FFN 线性层

它们比量化更“激进”:不仅改变模型怎么存储,还可能改变模型结构、参数路径和能力分布。因此这类方法通常需要额外微调、蒸馏或评估来恢复能力。

剪枝:删掉低重要性结构

剪枝的核心思想是:模型里并不是所有参数、通道、注意力头和层都同等重要。可以先评估不同结构对输出的影响,再删除影响较小的部分,从而减少参数量和计算量。

剪枝通过评估重要性、删除低重要性结构并微调恢复能力来压缩模型

剪枝可以分成两类:

类型 做法 工程效果
非结构化剪枝 删除单个权重,把部分权重置零 参数稀疏,但不一定真实加速
结构化剪枝 删除 head、channel、FFN hidden、layer 更容易减少真实计算量

对 LLM 来说,结构化剪枝通常更有工程价值。因为如果只是把一些权重置零,但推理 kernel 仍然按完整矩阵计算,实际延迟可能不会明显下降。常见剪枝对象包括:

剪枝对象 含义 可能影响
Attention Head 删除部分注意力头 影响上下文交互能力
FFN Hidden Dimension 减少 MLP 中间维度 影响非线性表达能力
Transformer Layer 删除部分层 影响整体推理深度
Vocabulary / Embedding 裁剪词表或 embedding 影响语言覆盖范围
Sparse Block 删除稀疏矩阵块 依赖硬件和 kernel 支持

剪枝最难的是“重要性评估”。常见评估信号包括:

  1. 权重幅度:权重越小,可能越不重要;
  2. 梯度敏感度:删除后 loss 变化越小,越适合剪;
  3. 激活统计:长期不活跃的结构可以优先考虑;
  4. 注意力模式:冗余 head 可能被删除;
  5. 任务评估:以真实任务性能变化作为最终判断。

但剪枝风险很高。因为模型能力不是线性叠加的,删除一个看起来“不重要”的 head 或 layer,可能对推理、代码、数学等能力产生放大影响。因此剪枝后通常需要 SFT、蒸馏或继续训练来恢复能力。

一句话说:剪枝的核心不是“删得越多越好”,而是删掉真实冗余、同时让推理 kernel 能真正少算。

蒸馏:让小模型学习大模型

蒸馏的核心思想是:用一个能力更强的 teacher model 作为“老师”,生成高质量监督信号,让更小的 student model 学习它的输出行为、推理方式和任务偏好。

蒸馏把大模型能力迁移到更小模型上

蒸馏不是简单训练“小模型回答标准答案”,而是让小模型学习大模型的输出分布、回答风格、推理过程或偏好行为。常见方式包括:

蒸馏方式 学习目标 说明
Logits Distillation 概率分布 学 teacher 对各 token 的偏好
Response Distillation 最终回答 学 teacher 的高质量输出
Reasoning Distillation 推理过程 学中间步骤和解题路径
Feature Distillation 中间表示 学 teacher 的隐藏层特征
Preference Distillation 偏好排序 学 teacher 或人类偏好的选择

在 LLM 场景里,最常见的是 Response DistillationReasoning Distillation。例如用大模型生成高质量问答、代码解释、推理链路、领域任务样本,再用这些数据训练小模型。典型流程是:

1
2
3
4
5
大模型能力强,但推理太贵
-> 用大模型生成高质量数据
-> 清洗、过滤、去重、构造训练集
-> 训练小模型
-> 小模型服务高频低成本场景

蒸馏适合这些场景:

  1. 高频、重复、边界清晰的垂直任务;
  2. 大模型作为离线 teacher,小模型在线服务;
  3. 对延迟和成本敏感的业务;
  4. 希望在端侧或私有化环境部署较小模型;
  5. 有足够高质量任务数据和评测集。

但蒸馏也有明显边界:

  1. 小模型容量有限,很难完整继承大模型通用能力;
  2. teacher 输出如果有幻觉,student 也会学到;
  3. 蒸馏数据分布太窄,小模型泛化会差;
  4. 推理过程蒸馏可能学到“形式”,不一定学到真正能力;
  5. 仍然需要系统评测,不能只看训练集指标。

一句话说:蒸馏不是把大模型无损压成小模型,而是把大模型在特定任务上的行为迁移给更低成本的小模型。

低秩分解:用小矩阵近似大矩阵

Transformer 中大量参数集中在线性层里,例如 Attention 的 q_proj / k_proj / v_proj / o_proj,以及 FFN / MLP 的上投影、下投影矩阵。低秩分解的思路是:用两个更小的矩阵近似一个大矩阵。

1
W ≈ A × B

如果原始矩阵是:

1
W: d_out × d_in

低秩分解后变成:

1
2
A: d_out × r
B: r × d_in

r 远小于 d_ind_out 时,参数量会明显下降。

低秩分解用两个小矩阵近似一个大矩阵

举个简单例子:

1
2
3
4
5
6
7
原矩阵 W: 4096 × 4096
参数量 = 16,777,216

低秩分解 r = 64:
A: 4096 × 64
B: 64 × 4096
参数量 = 524,288

参数量大约变成原来的 1/32。低秩分解的核心假设是:大矩阵里存在冗余,可以用更低维的子空间近似。这个假设在很多线性层中是有意义的,但并不代表所有层都适合低秩化。rank 太小会明显损伤模型能力,rank 太大则压缩收益有限。

低秩分解和 LoRA 形式相似,但目标不同:

技术 公式视角 目标
LoRA W' = W + B × A 冻结原模型,用低秩增量做任务适配
低秩分解 W ≈ A × B 直接用低秩矩阵近似并替换原权重

所以 LoRA 更像“低成本适配”,低秩分解更像“结构压缩”。

三类方法如何选择

方法 主要收益 主要风险 适合场景
剪枝 减少真实结构和计算 能力非线性下降 对结构可控、可重新微调的模型
蒸馏 小模型替代大模型 上限受 student 容量限制 高频垂直任务、低成本服务
低秩分解 压缩大矩阵参数 rank 选择困难、近似误差 线性层冗余明显的模型

一句话概括:剪枝是删结构,蒸馏是迁移能力,低秩分解是近似矩阵。它们都能让模型变小,但也更容易改变模型能力边界,因此必须配合微调、蒸馏和系统评测一起使用。

KV Cache 优化与 Speculative Decoding

权重被压缩之后,推理瓶颈并不会自动消失。尤其在长上下文、高并发和长输出场景下,系统压力往往会从“模型权重太大”,转向两个更现实的问题:KV Cache 占用大量显存,以及 Decode 阶段逐 token 生成带来的延迟。

因此,这一节重点看两个方向:KV Cache 优化 和 Speculative Decoding。

  • 前者通过减少 KV 数量、降低存储精度、提升缓存管理与复用效率,降低长上下文和高并发推理成本;
  • 后者通过 draft model 预生成、target model 批量验证,减少大模型串行解码等待时间。

需要注意的是,KV Cache 优化不完全等同于“压缩”。GQA / MQA 更像架构层面的 KV 数量减少,KV 量化是存储精度压缩,PagedAttention 和 Prefix Cache 则更偏缓存管理与复用。它们路径不同,但目标一致:让模型在更长上下文、更高并发下以更低成本完成推理。

KV Cache 为什么贵

在自回归生成中,模型每生成一个新 token,都需要基于历史上下文计算注意力。为了避免每一步都重新计算历史 token 的 Key / Value,推理系统会把每层 Attention 的 K/V 缓存下来,这就是 KV Cache。

KV Cache 的大小可以粗略估算为:

1
KV Cache ≈ 2 × layers × tokens × kv_heads × head_dim × bytes × batch_size

其中:

变量 含义
2 Key 和 Value 两份缓存
layers Transformer 层数
tokens 上下文长度
kv_heads KV heads 数量
head_dim 每个 head 的维度
bytes 每个元素占用字节数
batch_size 并发 batch 大小

这个公式说明了一个关键事实:KV Cache 会随着上下文长度和并发数线性增长。当上下文从 8K 扩展到 128K,或者 batch size 提高时,KV Cache 很容易成为主要显存瓶颈。KV Cache 的压力主要体现在四个方面:

  1. 显存占用变高;
  2. 内存带宽压力变大;
  3. batch 调度更困难;
  4. 长上下文下缓存碎片和复用更复杂。

KV Cache 的优化方向

常见优化方向可以分成四类:

技术 优化点 说明
MQA / GQA 减少 KV heads 多个 Query head 共享 K/V,直接降低 KV Cache
KV Cache Quantization 降低单元素字节数 用 INT8 / INT4 存储 K/V
Sliding Window / KV Eviction 减少保留 token 数 只保留局部窗口或重要历史 token
Prefix Cache / PagedAttention 提升缓存管理效率 复用前缀、分页管理 KV,减少碎片和重复计算

这里要注意,PagedAttention 严格来说不是压缩技术。它不会让单个 KV 元素变小,也不一定减少 token 数量;它更像一种 KV Cache 内存管理机制,通过分页方式提高显存利用率,减少长上下文和高并发下的内存碎片。

长上下文场景下,KV Cache 优化和权重量化同样重要

可以把这些方案对应到 KV Cache 公式里:

公式变量 优化方式
kv_heads MQA / GQA
bytes KV Cache Quantization
tokens Sliding Window、KV Eviction
batch_size 下的碎片问题 PagedAttention、Prefix Cache、调度优化

所以 KV Cache 优化不是单一技术,而是从 head 数量、数值精度、保留长度、内存管理 四个方向同时降低成本。

Speculative Decoding:用小模型加速大模型

KV Cache 优化解决的是“缓存太贵”,但自回归模型还有另一个瓶颈:Decode 阶段必须逐 token 生成

大模型每生成一个 token,都要经过一次完整 forward。即使单次 forward 很快,长输出任务里,逐 token 串行生成也会带来明显延迟。Speculative Decoding 的核心思想是:

1
2
用一个更小、更快的 draft model 先生成多个候选 token
再让大模型 target model 一次性验证这些候选 token

如果候选 token 被接受,就可以一次推进多个 token,从而减少大模型逐 token 解码的次数。

Speculative Decoding 用小模型提出候选,大模型负责验证

它能加速的原因是:大模型验证多个 token 时可以并行计算,而不是每次只生成一个 token。理想情况下,如果 draft model 提出的候选和 target model 分布接近,大模型一次 forward 就能接受多个 token。

Speculative Decoding 的关键指标

Speculative Decoding 的收益取决于几个核心指标:

指标 含义 影响
Draft 速度 小模型生成候选是否足够快 draft 太慢会抵消收益
Acceptance Rate target 接受候选 token 的比例 接受率越高,加速越明显
验证成本 target 验证候选 token 的开销 验证过重会降低收益
输出一致性 是否保持 target model 的分布 影响生成质量和稳定性
系统复杂度 多模型调度、KV 管理、失败处理 影响工程落地成本

它适合的场景:

  1. 大模型 Decode 延迟较高;
  2. 输出长度较长;
  3. draft model 足够便宜;
  4. draft 和 target 分布足够接近;
  5. 系统可以承受多模型调度复杂度。

不适合的场景:

  1. 输出很短,draft 还没带来收益就结束;
  2. draft 质量太差,大量 token 被拒绝;
  3. target 本身已经很快,瓶颈不在 Decode;
  4. 系统无法承担额外模型部署和调度成本。

简单总结一下:KV Cache 优化解决“历史信息存得太贵”,Speculative Decoding 解决“未来 token 生成得太慢”。前者降低显存和带宽压力,后者减少大模型逐 token 解码次数。

工程选型与总结

模型压缩没有一招通吃。不同技术优化的对象不同:有的降低权重显存,有的减少计算路径,有的优化 KV Cache,有的降低逐 token 解码延迟。生产环境里,真正重要的不是“用了哪种压缩技术”,而是先判断系统瓶颈在哪里。

技术 主要优化对象 主要收益 主要风险 适合场景
量化 权重、激活、KV Cache 降低显存和带宽 精度下降、kernel 依赖 通用推理部署
剪枝 Head、Channel、Layer 减少参数和计算 能力非线性下降 结构可控、可重新微调的模型
蒸馏 模型能力迁移 小模型替代大模型 上限受 student 容量限制 高频垂直任务
低秩分解 Attention / FFN 矩阵 压缩线性层参数 rank 选择困难 矩阵冗余明显的模型
KV Cache 优化 K/V 缓存 降低长上下文显存 可能影响长程依赖 长上下文、高并发
Speculative Decoding Decode 过程 降低生成延迟 draft 接受率依赖 长输出、低延迟服务

生产环境里,可以按目标选择方案:

模型压缩方案应该从真实瓶颈出发,而不是为了压缩而压缩

上线前一定要做评估。压缩带来的收益通常很直观:显存更低、模型更小、吞吐可能更高;但损失往往更隐蔽,比如任务准确率下降、长上下文能力变弱、工具调用不稳定,或者安全拒答能力退化。因此至少要同时评估任务质量、推理延迟、吞吐能力、显存占用、长上下文稳定性,以及 RAG、Function Calling、Agent 等真实应用链路中的表现。

还要注意,模型变小并不等于推理一定更快。推理性能同时受权重大小、内存带宽、计算 kernel、batch size、KV Cache、调度策略和硬件支持影响。比如 INT4 权重更小,但如果 kernel 不成熟、反量化开销高,实际延迟未必优于 INT8 或 FP16;PagedAttention 不会减少模型参数,却可能显著改善高并发长上下文下的显存利用率。

更合理的压缩流程是:

1
定位瓶颈 -> 选择方案 -> 离线评测 -> 压测验证 -> 灰度上线 -> 持续监控

最终来看,模型压缩的核心不是单纯追求模型文件更小,而是在质量可接受的前提下,系统性降低权重显存、计算开销、KV Cache 成本和生成延迟。真正有效的压缩方案,一定要从线上瓶颈出发,并通过任务质量、延迟、吞吐、显存和安全能力一起评估。

一句话概括:模型压缩的目标,是让大模型在真实业务里以更低成本、更低延迟和更低部署门槛稳定运行。