2026年4月19日

模型压缩(剪枝 / 蒸馏 / 量化)

模型压缩是解决"大模型在有限资源下部署"的标准方法。三个方向解决的问题不同:

知识库机器学习machine-learningmodel-compressionpruningdistillationquantization

模型压缩(剪枝 / 蒸馏 / 量化)

先把结论放前面

模型压缩是解决"大模型在有限资源下部署"的标准方法。三个方向解决的问题不同:

  • 剪枝:减少模型参数量(哪些权重不重要,可以去掉)
  • 知识蒸馏:用小模型学习大模型的行为(小模型从大模型学到"软标签")
  • 量化:降低权重和计算的精度(FP32 → INT8 → INT4)

三者可以叠加:蒸馏后的模型再做量化,通常能再压缩 2-4 倍。

剪枝(Pruning)

核心思想

神经网络的权重不是同等重要的。很多权重接近零,或者对最终输出的影响极小。剪枝把这些"不重要"的权重去掉,减少参数量和计算量。

结构化剪枝 vs 非结构化剪枝

非结构化剪枝:随机把单个权重设为零。

优点:压缩率高,可以剪掉任意比例的参数
缺点:稀疏矩阵需要专门的稀疏矩阵计算库才能加速(通常硬件不支持)

结构化剪枝:按结构单位(神经元、通道、注意力头)批量剪枝。

常见单位:
- Channel Pruning(去掉整个卷积通道)
- Head Pruning(去掉 Transformer 的某个注意力头)
- Layer Pruning(去掉整个 Transformer 层)
- Neuron Pruning(去掉 FC 层的神经元)

优点:硬件友好(不需要稀疏矩阵库)
缺点:压缩率有限(每次只能剪掉一个 Channel/Head)

Magnitude Pruning(幅度剪枝)

最简单的方法:把绝对值最小的权重剪掉。

# 保留 top-k% 最大的权重,其余设为零
threshold = np.percentile(np.abs(weights), prune_percentile)
mask = np.abs(weights) > threshold
pruned_weights = weights * mask

Lottery Ticket Hypothesis(彩票假说)

一个很有趣的理论:任何一个随机初始化的稠密网络,都包含一个子网络,当它被单独训练时能达到和原网络一样的精度。

这个子网络就叫"中奖彩票"(Lottery Ticket)。

找到它的方法:训练一个大网络 → 剪枝 → 把剪枝后的结构单独重新训练(用原始随机初始化)→ 如果精度恢复,就找到中奖彩票了。

Practical Pruning 流程(工程实践)

# 1. 训练一个大网络(Teacher)
model = train_large_model()

# 2. 评估每个权重的重要性
# 常用方法:L1 norm / Taylor expansion / gradient-based
importance = torch.sum(torch.abs(model.weight), dim=0)  # channel importance

# 3. 按重要性排序,剪掉最低的 p%
prune_threshold = torch.kthvalue(importance, k=int(len(importance) * 0.3)).values
mask = importance > prune_threshold

# 4. 微调恢复精度(通常 1-3 个 epoch)
model = fine_tune_pruned_model(mask, train_loader)

剪枝的比例(Pruning Rate)

通常需要做实验确定。经验值:

  • 保留参数 50-70%:精度几乎不下降
  • 保留参数 30-50%:可能需要更多微调
  • 保留参数 < 20%:精度下降明显,需要更复杂的微调策略

知识蒸馏(Knowledge Distillation)

核心思想

大模型(Teacher)学到的不仅是"正确答案",还有"正确答案的概率分布"——比如"这张图 70% 是猫,20% 是狗",这个"软标签"比硬标签包含更多信息。

知识蒸馏让小模型(Student)同时学习:

  1. 硬标签(真实标签,hard target)
  2. 软标签(Teacher 的输出概率,soft target)

蒸馏温度(Temperature)

软标签除以一个温度参数 T 再做 softmax,增大类间差异:

# 普通 softmax
probs = softmax(logits / 1.0)

# 高温 softmax(T > 1,概率分布更平滑)
probs_soft = softmax(logits / T)

温度 T 的作用:T 越高,概率分布越平滑,小模型越容易学到类间关系。常用 T = 2~5。

蒸馏 Loss

loss = alpha * CE_loss(student_preds, hard_labels) \
       + (1 - alpha) * KL_loss(softmax(student_logits/T), softmax(teacher_logits/T))
  • 第一项:学硬标签(普通交叉熵)
  • 第二项:学软标签(KL 散度)

自蒸馏(Self-Distillation)

不需要单独训练 Teacher。常见做法:

  • 用当前模型的 EMA(指数移动平均)版本作为 Teacher
  • 或用深层的 Layer 作为 Teacher 教浅层(Depth Distillation)

中间层蒸馏

有些方法不仅让学生学习 Teacher 的最终输出,还让学生学习 Teacher 的中间层表示(如 Hidden Activation、BERT 的 [CLS] token)。

量化(Quantization)

核心思想

神经网络权重和激活值通常用 FP32(32位浮点)存储。量化把它们映射到低位宽(INT8、INT4、FP16、BF16),减少存储和计算。

量化精度级别

格式 位宽 动态范围 精度 硬件支持
FP32 32bit 3.4e38 最高 通用
FP16 16bit 65504 GPU 原生
BF16 16bit 3.4e38 新 GPU
INT8 8bit ±127/±255 CPU/GPU/NPU
INT4 4bit ±7/±15 专用硬件
INT2 2bit ±1/±3 极低 专用硬件

BF16 vs FP16:BF16 的指数范围和 FP32 相同(避免溢出),但尾数精度较低。LLM 训练推荐 BF16,推理可用 INT8。

训练后量化(PTQ,Post-Training Quantization)

模型训练好后直接量化,不需要重新训练。最简单,精度损失通常在 1-3%。

# PyTorch 训练后量化
import torch.quantization

model = load_model("model.pth")
model.eval()
model_int8 = torch.quantization.quantize_dynamic(
    model, {torch.nn.Linear}, dtype=torch.qint8
)

常见方法

  • Dynamic Quantization:权重实时量化, activations 动态量化(最快,精度损失中)
  • Static Quantization:需要校准数据,确定 activations 的范围(精度更好,需要校准数据)

量化感知训练(QAT,Quantization-Aware Training)

在训练时模拟量化效果,让模型适应低位宽表示。

训练时:
  Forward: weights → quantized(weights) → activation
  Backward: gradients computed through "fake quantization"

推理时:
  用真实量化

QAT 精度比 PTQ 高(通常 1-2% 提升),但需要重新训练或微调,成本高。

GPTQ / AWQ(LLM 专用量化)

GPTQ:单样本量化,对每个权重块做一次奇异值分解,精度接近 FP16 但只需 4-8bit。适合 100B+ 的大模型。

AWQ(Activation-Aware Weight Quantization):不只看权重分布,还看激活值分布,对高激活的权重做更低量化(保护关键权重)。

# AutoAWQ 示例
from awq import AutoAWQForCausalLM
from transformers import AutoTokenizer

quant_config = {"zero_point": True, "q_group_size": 128, "w_bit": 4}
model = AutoAWQForCausalLM.from_pretrained("model_name")
model.quantize(tokenizer, quant_config=quant_config)

llama.cpp 量化

llama.cpp 是最流行的 LLM 本地推理框架,支持 GGUF 格式(GGML 的继任者)。

GGUF 格式特点:

  • 把 LLM 的权重和 Tokenizer 打包成一个文件
  • 支持多种量化级别(Q4_K_M、Q5_K_S、Q8_0 等)
  • 可以在 CPU 和 GPU 上运行
  • 模型文件可以直接分发,不需要额外的推理框架

常用量化级别对比:

量化级别 内存压缩 精度保留 速度
Q8_0 ~4bit/param 极高(基本无损) 最慢
Q5_K_M ~3.5bit/param
Q4_K_M ~3bit/param 中高(主流推荐)
Q3_K_M ~2.5bit/param 中(效果明显下降) 很快
Q2_K ~2bit/param 最快

三者的对比与叠加

维度 剪枝 知识蒸馏 量化
压缩对象 参数数量 模型容量 权重精度
精度损失 中等 较低 中等(取决于方法)
计算量 减少 不变 显著减少
硬件友好度 结构化剪枝友好 友好 最友好(INT8 有硬件支持)
实现难度 中等(需要微调) 中等 低(PTQ)或高(QAT)
适用场景 CV 模型、CNN Teacher-Student 蒸馏 LLM、边缘部署

三者叠加

大模型 (FP32)
  → 剪枝(保留 30-50% 参数)
  → 知识蒸馏(用原模型教小模型)
  → INT8 量化(降低精度)
  → 最终模型:原大小 5-10%

如果放到面试里怎么讲

"模型压缩有哪些方法?"

我会从三个方向说:剪枝去掉不重要的参数或结构单元,知识蒸馏用大模型教小模型学习软标签,量化降低权重精度。其中量化是最通用的,剪枝和蒸馏可以叠加。

"大模型怎么在有限显存里跑起来?"

首先看量化:INT8 量化通常能把模型体积压缩到 1/4,精度损失在 1-2% 可接受。如果还不够,用 GPTQ 或 AWQ 做 4bit 量化。另一个方向是用 llama.cpp 跑 GGUF 格式,在 CPU 上也能运行。

最后记几个点

  1. 剪枝分结构化(硬件友好)和非结构化(压缩率高),结构化剪枝按 Channel/Head/Layer 单位剪
  2. 知识蒸馏的核心是让 Student 学习 Teacher 的软标签,用温度 T 控制软化程度
  3. 量化三层次:FP32 → FP16/BF16 → INT8 → INT4,越低压缩越大,精度损失也越大
  4. BF16 是 LLM 训练的推荐精度(避免溢出),INT8 是推理的主流精度
  5. GPTQ/AWQ 是 LLM 专用的 4bit 量化方法,比普通 INT8 效果更好
  6. llama.cpp + GGUF 格式是目前最流行的本地 LLM 推理方案
  7. 三者可以叠加:剪枝 → 蒸馏 → 量化,通常能压缩到原模型的 5-10%

跨库关联

本文件的量化/蒸馏部分是通用视角,LLM 专项内容在 大模型知识库 中: