LLM 系列 (二十一):模型压缩,如何降低大模型推理成本
大模型能力越来越强,但推理成本也越来越高:参数规模变大,显存占用上升,计算开销增加,长上下文带来更大的 KV Cache,线上服务还要面对延迟、吞吐和并发压力。对于真实业务系统来说,模型不只是“能不能答得好”,还要看它能不能在可接受的成本和延迟下稳定运行。
模型压缩要解决的正是这个问题:在尽量少损失模型能力的前提下,降低参数存储、显存占用、计算开销和生成延迟。它不是单一技术,而是一组面向推理降本提速的系统优化方法,包括量化、剪枝、蒸馏、低秩分解、KV Cache 优化和 Speculative Decoding。
这一篇我们重点看清楚:大模型推理成本到底来自哪里,不同压缩技术分别优化哪一部分,以及在生产环境里应该如何根据瓶颈选择合适的压缩与加速方案。
为什么需要模型压缩
大模型推理成本,主要来自四个部分:模型权重、计算开销、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 矩阵。推理阶段可以分成两段:
- Prefill:处理完整输入上下文,Attention 需要看见整段序列,长上下文下计算和显存压力很高;
- 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。量化的收益主要来自两点:
- 降低显存占用:同样数量的参数,用更少 bit 存储;
- 降低内存带宽压力:推理时从显存读取的数据更少。
但量化不是“无损压缩”。它本质上是用更低数值精度近似原始浮点数,因此一定会引入量化误差。真正的难点不是把模型变成 INT4,而是控制误差,让模型能力尽量不下降。
量化的基本原理
量化的基本原理,是用低精度数值近似表示原来的高精度浮点数。可以把它理解成:先统计一组浮点数的范围,再用有限的整数刻度去近似表示它们。一个常见的非对称量化形式可以写成:
1 | q = round(x / scale) + zero_point |
其中:
| 符号 | 含义 |
|---|---|
| x | 原始浮点值 |
| q | 量化后的整数值 |
| scale | 缩放因子 |
| zero_point | 零点偏移 |
| x_hat | 反量化后的近似值 |
这里展示的是非对称量化。如果采用对称量化,zero_point 通常为 0,公式可以简化为:
1 | q = round(x / scale) |
在 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 更小,所以一定更快。实际不一定。推理速度不只取决于模型文件大小,还取决于:
- GPU / NPU 是否原生支持对应精度;
- kernel 是否针对 INT4 做了优化;
- 计算时是否需要频繁反量化;
- batch size 和矩阵形状是否适合低精度 kernel;
- 瓶颈到底在计算,还是在内存带宽。
INT4 的主要优势是:
- 权重显存更低;
- 内存带宽压力更小;
- 更容易部署到显存较小的设备上。
但它也可能带来:
- 反量化开销;
- 精度损失;
- kernel 支持不足;
- 小 batch 下收益不稳定;
- 某些层需要保留高精度,实际收益打折。
所以 INT4 更常见的价值是降低显存和部署门槛,而不是在所有场景下都显著提升速度。
PTQ 与 QAT
量化通常分为两类:
| 方法 | 全称 | 核心思路 | 特点 |
|---|---|---|---|
| PTQ | Post-Training Quantization | 训练后量化 | 成本低,常用于推理部署 |
| QAT | Quantization-Aware Training | 量化感知训练 | 效果更稳,但训练成本高 |
实际 LLM 推理里,PTQ 更常见。因为重新训练大模型成本很高,很多系统会用少量校准数据统计权重和激活分布,然后选择合适的量化尺度、分组策略和保留高精度的敏感层。
QAT 则会在训练过程中模拟量化误差,让模型提前适应低精度计算。它通常效果更稳,但成本更高,更适合对精度要求高、部署规模大、值得重新训练的场景。
量化的核心难点:Outlier
LLM 量化最难的地方,是模型里经常存在 outlier,也就是少数特别大的权重值或激活值。量化需要用有限刻度覆盖一个数值范围。如果范围被少数 outlier 拉得很大,大多数普通值就会挤在很小的区间里,表示精度变差。可以简单理解成:
- 没有 outlier:整数刻度集中表示常见数值,误差较小;
- 存在 outlier:刻度被少数极端值拉开,普通值表示变粗糙。
常见解决思路包括:
| 方法 | 作用 |
|---|---|
| 分组量化 | 每组权重单独计算 scale,减少大范围误差 |
| 通道级量化 | 不同 channel 使用不同 scale |
| 激活平滑 | 把 activation outlier 转移或平滑到权重侧处理 |
| 混合精度 | 对敏感层、Embedding、输出层保留 FP16 / BF16 |
| 校准数据 | 使用接近真实业务分布的数据统计量化参数 |
量化最终是一场 trade-off:
1 | 更低精度 -> 更低显存 / 更低带宽 / 更低部署门槛 |
一句话概括:量化是用数值精度换推理成本,核心难点不在“把 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 支持 |
剪枝最难的是“重要性评估”。常见评估信号包括:
- 权重幅度:权重越小,可能越不重要;
- 梯度敏感度:删除后 loss 变化越小,越适合剪;
- 激活统计:长期不活跃的结构可以优先考虑;
- 注意力模式:冗余 head 可能被删除;
- 任务评估:以真实任务性能变化作为最终判断。
但剪枝风险很高。因为模型能力不是线性叠加的,删除一个看起来“不重要”的 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 Distillation 和 Reasoning Distillation。例如用大模型生成高质量问答、代码解释、推理链路、领域任务样本,再用这些数据训练小模型。典型流程是:
1 | 大模型能力强,但推理太贵 |
蒸馏适合这些场景:
- 高频、重复、边界清晰的垂直任务;
- 大模型作为离线 teacher,小模型在线服务;
- 对延迟和成本敏感的业务;
- 希望在端侧或私有化环境部署较小模型;
- 有足够高质量任务数据和评测集。
但蒸馏也有明显边界:
- 小模型容量有限,很难完整继承大模型通用能力;
- teacher 输出如果有幻觉,student 也会学到;
- 蒸馏数据分布太窄,小模型泛化会差;
- 推理过程蒸馏可能学到“形式”,不一定学到真正能力;
- 仍然需要系统评测,不能只看训练集指标。
一句话说:蒸馏不是把大模型无损压成小模型,而是把大模型在特定任务上的行为迁移给更低成本的小模型。
低秩分解:用小矩阵近似大矩阵
Transformer 中大量参数集中在线性层里,例如 Attention 的 q_proj / k_proj / v_proj / o_proj,以及 FFN / MLP 的上投影、下投影矩阵。低秩分解的思路是:用两个更小的矩阵近似一个大矩阵。
1 | W ≈ A × B |
如果原始矩阵是:
1 | W: d_out × d_in |
低秩分解后变成:
1 | A: d_out × r |
当 r 远小于 d_in 和 d_out 时,参数量会明显下降。

举个简单例子:
1 | 原矩阵 W: 4096 × 4096 |
参数量大约变成原来的 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 的压力主要体现在四个方面:
- 显存占用变高;
- 内存带宽压力变大;
- batch 调度更困难;
- 长上下文下缓存碎片和复用更复杂。
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_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 | 用一个更小、更快的 draft model 先生成多个候选 token |
如果候选 token 被接受,就可以一次推进多个 token,从而减少大模型逐 token 解码的次数。

它能加速的原因是:大模型验证多个 token 时可以并行计算,而不是每次只生成一个 token。理想情况下,如果 draft model 提出的候选和 target model 分布接近,大模型一次 forward 就能接受多个 token。
Speculative Decoding 的关键指标
Speculative Decoding 的收益取决于几个核心指标:
| 指标 | 含义 | 影响 |
|---|---|---|
| Draft 速度 | 小模型生成候选是否足够快 | draft 太慢会抵消收益 |
| Acceptance Rate | target 接受候选 token 的比例 | 接受率越高,加速越明显 |
| 验证成本 | target 验证候选 token 的开销 | 验证过重会降低收益 |
| 输出一致性 | 是否保持 target model 的分布 | 影响生成质量和稳定性 |
| 系统复杂度 | 多模型调度、KV 管理、失败处理 | 影响工程落地成本 |
它适合的场景:
- 大模型 Decode 延迟较高;
- 输出长度较长;
- draft model 足够便宜;
- draft 和 target 分布足够接近;
- 系统可以承受多模型调度复杂度。
不适合的场景:
- 输出很短,draft 还没带来收益就结束;
- draft 质量太差,大量 token 被拒绝;
- target 本身已经很快,瓶颈不在 Decode;
- 系统无法承担额外模型部署和调度成本。
简单总结一下: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 成本和生成延迟。真正有效的压缩方案,一定要从线上瓶颈出发,并通过任务质量、延迟、吞吐、显存和安全能力一起评估。
一句话概括:模型压缩的目标,是让大模型在真实业务里以更低成本、更低延迟和更低部署门槛稳定运行。
