
如今大模型越来越火,不管是企业做业务落地,还是我们作为个人开发者上手体验,都绕不开一个核心问题:大模型虽强,但太笨重,动辄几十上百GB显存占用,普通硬件跑不动,推理延迟还高,根本没法适配边缘设备、实时场景这些实际需求。这时候,轻量化技术就成了破局关键,而量化、蒸馏、剪枝都是最常用的三种方案。但我们又该怎么抉择,哪种合适,或怎么去理解三者的差别,每种方式的存在肯定有它独特的道理和最适用的场景,尽管它们各有侧重,没有绝对的优劣,但对于技术优化选型而言,选对了能少走很多弯路,选错了要么精度崩了,要么落地成本翻倍。今天我们就把它们放在一起拆解对比,就算不分伯仲,我们也要看清每种技术的适配场景、落地门槛和效果边界,明白不同需求该选哪种方案。
大模型轻量化不是越复杂越好,而是适配才最优。不用盲目追求高精度或极致压缩,结合自己的硬件条件、落地周期和精度需求做选择,甚至组合使用,才能在成本、速度和效果之间找到平衡。下面我们就从概念、差异、代码到选型,一步步把这三种技术做通俗易懂的分解,充分理解三者的差异、核心逻辑和使用配置细节。

量化是通过降低模型参数和激活值的数值精度,减少存储字节数与计算开销的技术。大模型默认采用 32 位浮点数(FP32)存储参数,每个参数占 4 字节,量化通过将其转换为低精度格式(如 FP16、INT8、INT4),实现显存占用和计算量的成比例降低,且不改变模型结构。
通俗比喻:如同将一张 1600 万像素的高清图,压缩为 200 万像素的标清图,画面细节略有损失,但存储体积大幅减小,且不改变图片的整体构图,相较而言,模型的参数量减少,但对应模型结构不变。
训练后量化(Post-Training Quantization, PTQ):是在模型训练完成后直接进行的量化方法。它不对模型结构或训练过程做任何修改,而是利用少量(通常几百个)无标签的校准数据,统计激活值的分布(如最小/最大值、直方图等),从而确定合适的量化参数(如缩放因子和零点)。权重通常直接从浮点(如 FP32)转换为整型(如 INT8)。
这种方法的主要优点包括:
量化感知训练(Quantization-Aware Training, QAT):是在训练阶段就引入量化模拟操作,将前向传播中的权重和激活“假装”量化为低比特形式(实际仍用浮点计算),使模型在训练过程中学会补偿量化带来的信息损失。训练完成后,再将模型真正转换为低精度格式(如 INT8)用于推理。
这种方法的主要优点包括:
动态量化(Dynamic Quantization):是一种在模型推理阶段应用的量化技术,其核心思想是:模型参数(如权重)在部署前被静态地量化为低比特表示(如 INT8),而激活值则在推理过程中根据每一批输入数据的分布动态地进行量化和反量化。
这种方法的主要优点包括:
蒸馏是一种知识迁移技术,通过高精度大模型“老师模型”指导轻量化小模型“学生模型”训练,让小模型学习大模型的隐性知识,最终实现“小模型精度接近大模型,速度和显存远超大模型”的效果。
传统小模型训练仅学习“硬标签”(如文本分类的“0/1”类别),而蒸馏让学生模型同时学习老师模型的“软标签”(如预测“类别 1”的概率 92%、“类别 0”的概率 8%),软标签中包含大模型对数据的深层理解(如“语义相似性”),这是蒸馏精度优于直接训练小模型的核心原因。
通俗比喻:如同大学教授(老师模型)给小学生(学生模型)讲课,教授不仅告诉学生“标准答案”(硬标签),还讲解“解题思路和逻辑”(软标签),让小学生在知识储备有限的情况下,也能达到接近教授的解题准确率。
逻辑蒸馏(Logits Distillation):是最经典、最基础的知识蒸馏形式,利用教师模型输出的 logits(即 softmax 前的原始分数)作为“软标签”,引导学生模型学习更平滑、信息更丰富的输出分布,而不仅限于硬标签(如 one-hot 编码),常配合温度缩放(Temperature Scaling)使用,使教师输出更柔和,便于学生学习。
特征蒸馏(Feature Distillation):特征蒸馏不再只关注最终输出,而是让学生模型模仿教师模型在中间某一层(或多层)的特征表示(如 CNN 的卷积特征图、Transformer 的隐藏状态)。通常通过最小化两者特征之间的 L2 距离、余弦相似度或注意力图差异来实现。需对齐教师与学生的特征维度,可通过投影层或适配器,否则难以直接比较。
自蒸馏(Self-Distillation):自蒸馏是一种无需外部教师模型的蒸馏策略。它利用同一个模型的不同部分(如深层 vs 浅层、主干 vs 分支、不同训练阶段的快照)互为师生:例如用深层输出指导浅层,或用完整模型指导其剪枝/量化后的子模型。
剪枝是通过识别并移除模型中的冗余参数/结构,实现模型精简的技术。大模型中存在大量权重接近 0 的参数,这些参数对模型输出影响极小(如同大树的枯枝),剪枝后模型参数数量减少,结构更简洁,从而降低显存占用、提升推理速度。
剪枝的核心是“保留关键参数、移除冗余参数”,需通过“参数重要性评估”(如权重绝对值、L2 范数)判断哪些参数可移除,且剪后需微调模型,恢复因剪枝损失的部分精度。
通俗比喻:如同给大树修剪枝叶,剪掉枯萎、冗余的枝条(权重接近 0 的参数),保留粗壮的主枝和健康枝叶(关键参数),让大树(模型)生长更高效,同时不影响整体形态(核心能力)。
结构化剪枝(Structured Pruning):以规则的结构单元为单位进行裁剪,如移除整个神经元、删除完整的卷积核、剪掉整个注意力头或前馈层、甚至直接删减整层网络
结构化剪枝的优点:
结构化剪枝的缺点:
非结构化剪枝(Unstructured Pruning):非结构化剪枝逐元素地移除权重,只保留绝对值较大的参数,其余置零,形成高度稀疏的权重矩阵。
非结构化剪枝优点:
非结构化剪枝缺点:
混合剪枝:结合结构化与非结构化剪枝,保精度对核心层做非结构化剪枝,提速度对非核心层做结构化剪枝。
混合剪枝的优点:
混合剪枝的缺点:





分别对应三者量化方式的场景示例,对最重要的配置部分做详细说明;
采用 PyTorch 动态量化,针对全连接层进行 INT8 量化,无需重新训练,短时间内可完成,精度损失控制在 3%-5%,适合快速部署。
import torch
import torch.nn as nn
from transformers import BertForSequenceClassification, BertTokenizer
# 1. 加载预训练模型和分词器
model = BertForSequenceClassification.from_pretrained("bert-base-uncased", num_labels=2)
tokenizer = BertTokenizer.from_pretrained("bert-base-uncased")
model.eval() # 量化前需切换至评估模式,避免训练状态干扰
# 2. 配置动态量化参数(INT8量化,仅量化全连接层)
quantized_model = torch.quantization.quantize_dynamic(
model,
{nn.Linear}, # 指定要量化的层类型(BERT核心权重集中在全连接层)
dtype=torch.qint8, # 量化精度:INT8(比FP32节省75%显存)
inplace=False
)
# 3. 保存量化模型(体积仅为原始模型的1/4左右)
torch.save(quantized_model.state_dict(), "quantized_bert.pth")
# 加载量化模型(需先初始化模型结构,再加载量化权重)
# quantized_model.load_state_dict(torch.load("quantized_bert.pth"))
# 4. 量化模型推理测试
text = "This is a test sentence for quantized model inference."
inputs = tokenizer(text, return_tensors="pt", padding=True, truncation=True)
with torch.no_grad(): # 推理时关闭梯度计算,节省显存
outputs = quantized_model(**inputs)
logits = outputs.logits
pred = torch.argmax(logits, dim=1).item()
print(f"量化模型推理结果:类别 {pred}")
print(f"量化模型显存占用:{torch.cuda.memory_allocated() / 1024**2:.2f} MB")量化突出的重点:
- 1. 采用动态量化(Dynamic Quantization)
- 2. 仅量化全连接层(nn.Linear)
- 3. 使用 qint8(有符号 INT8)
- 4. 显存与模型体积显著压缩
以 BERT-large(老师模型,高精度)蒸馏到 BERT-base(学生模型,轻量化)为例,核心是让学生学习老师的软标签知识,精度损失控制在 1%-2%,适配高精度轻量化场景。
import torch
import torch.nn as nn
import torch.optim as optim
from transformers import BertForSequenceClassification, BertTokenizer, Trainer, TrainingArguments
from datasets import Dataset # 用于构建简单数据集
# 超参数配置(蒸馏核心参数)
TEMPERATURE = 5 # 温度系数,控制软标签平滑度(2-10为常用范围)
ALPHA = 0.3 # 硬标签损失权重,软标签权重为 1-ALPHA
EPOCHS = 3
BATCH_SIZE = 8
# 1. 加载老师模型(大模型,仅用于推理输出软标签)和学生模型(小模型,需训练)
teacher_model = BertForSequenceClassification.from_pretrained("bert-large-uncased", num_labels=2)
student_model = BertForSequenceClassification.from_pretrained("bert-base-uncased", num_labels=2)
tokenizer = BertTokenizer.from_pretrained("bert-base-uncased")
teacher_model.eval() # 老师模型固定参数,不参与训练
# 2. 构建简单数据集(实际场景替换为真实业务数据)
data = {
"text": ["I love this movie", "This movie is terrible", "Great film", "Worst experience ever"],
"label": [1, 0, 1, 0] # 硬标签(真实类别)
}
dataset = Dataset.from_dict(data)
# 数据预处理函数
def preprocess_function(examples):
return tokenizer(examples["text"], padding="max_length", truncation=True, max_length=128)
tokenized_dataset = dataset.map(preprocess_function, batched=True)
# 3. 定义蒸馏损失函数(硬标签损失 + 软标签损失)
class DistillationLoss(nn.Module):
def __init__(self):
super().__init__()
self.hard_loss = nn.CrossEntropyLoss() # 硬标签损失(真实类别)
self.soft_loss = nn.KLDivLoss(reduction="batchmean") # 软标签损失(老师输出)
def forward(self, student_logits, teacher_logits, labels):
# 软标签计算(老师输出经温度缩放后归一化)
teacher_soft = torch.softmax(teacher_logits / TEMPERATURE, dim=-1)
# 学生输出经温度缩放后取对数(适配KL散度输入)
student_soft = torch.log_softmax(student_logits / TEMPERATURE, dim=-1)
# 总损失 = 硬标签损失*ALPHA + 软标签损失*(1-ALPHA)*温度平方(补偿缩放影响)
loss = ALPHA * self.hard_loss(student_logits, labels) + \
(1 - ALPHA) * self.soft_loss(student_soft, teacher_soft) * (TEMPERATURE ** 2)
return loss
# 4. 自定义训练循环(简化版,实际可使用Trainer封装)
loss_fn = DistillationLoss()
optimizer = optim.Adam(student_model.parameters(), lr=2e-5)
for epoch in range(EPOCHS):
student_model.train()
total_loss = 0.0
for batch in tokenized_dataset.iter(batch_size=BATCH_SIZE):
# 转换为张量并移动到设备(CPU/GPU)
inputs = {k: torch.tensor(v).to("cpu") for k, v in batch.items() if k != "text"}
labels = inputs.pop("label")
# 老师模型输出软标签(关闭梯度计算)
with torch.no_grad():
teacher_logits = teacher_model(**inputs).logits
# 学生模型输出
student_logits = student_model(**inputs).logits
# 计算损失并反向传播
loss = loss_fn(student_logits, teacher_logits, labels)
optimizer.zero_grad()
loss.backward()
optimizer.step()
total_loss += loss.item() * batch["label"].__len__()
avg_loss = total_loss / len(tokenized_dataset)
print(f"Epoch {epoch+1}/{EPOCHS}, Average Loss: {avg_loss:.4f}")
# 5. 保存蒸馏后的学生模型
torch.save(student_model.state_dict(), "distilled_bert.pth")蒸馏突出的重点:
- 1. 经典的知识蒸馏框架
- 2. 教师-学生架构清晰分离
- 3. 损失函数设计符合标准实践
关键细节配置:
- 1. 温度系数 TEMPERATURE = 5
- 2. 损失权重 ALPHA = 0.3
- 3. KL 散度使用 reduction="batchmean"
- 4. 学生与教师使用不同 BERT 变体
采用结构化剪枝(按列剪枝,保留模型结构完整性,适配硬件部署),剪掉 30% 冗余权重,剪后通过微调恢复精度,适合专用硬件与极致压缩场景。
import torch
import torch.nn.utils.prune as prune
from transformers import BertForSequenceClassification, BertTokenizer
# 1. 加载预训练模型和分词器
model = BertForSequenceClassification.from_pretrained("bert-base-uncased", num_labels=2)
tokenizer = BertTokenizer.from_pretrained("bert-base-uncased")
# 2. 选择剪枝目标层(BERT编码器第1-3层的全连接层,可扩展至所有层)
target_layers = [
model.bert.encoder.layer[i].output.dense for i in range(3) # 选取前3层全连接层
]
# 3. 结构化剪枝:剪掉每层30%的权重(按列剪枝,即移除整个神经元)
prune_ratio = 0.3
for layer in target_layers:
# ln_structured:按L2范数判断权重重要性,dim=1表示按列剪枝(结构化剪枝核心)
prune.ln_structured(
layer,
name="weight", # 剪枝参数名(权重)
amount=prune_ratio,
n=2, # 用L2范数评估权重重要性
dim=1
)
# 4. 移除剪枝掩码,固化剪枝后的模型结构(剪枝后必须执行,否则权重会恢复)
for layer in target_layers:
prune.remove(layer, "weight")
# 5. 剪枝后微调(恢复精度,简化版,实际需用数据集训练)
optimizer = torch.optim.Adam(model.parameters(), lr=1e-5)
loss_fn = nn.CrossEntropyLoss()
model.train()
# 模拟微调(实际替换为真实数据集训练5-10轮)
text = "This is a fine-tuning sentence for pruned model."
inputs = tokenizer(text, return_tensors="pt", padding=True, truncation=True)
labels = torch.tensor([1])
for _ in range(5):
outputs = model(**inputs)
loss = loss_fn(outputs.logits, labels)
optimizer.zero_grad()
loss.backward()
optimizer.step()
print(f"微调损失: {loss.item():.4f}")
# 6. 保存剪枝后的模型
torch.save(model.state_dict(), "pruned_bert.pth")
# 7. 剪枝模型推理测试
model.eval()
with torch.no_grad():
outputs = model(**inputs)
pred = torch.argmax(outputs.logits, dim=1).item()
print(f"剪枝模型推理结果:类别 {pred}")
print(f"剪枝后模型参数数量(粗略):{sum(p.numel() for p in model.parameters()) / 1e6:.2f} M")剪枝突出的重点:
- 1. 采用结构化剪枝
- 2. 聚焦 BERT 的关键可剪枝模块
- 3. 基于 L2 范数的重要性评估
- 4. 显式固化剪枝结果(prune.remove)
- 5. 包含剪枝后微调(Fine-tuning)
关键细节配置:
- 1. 剪枝粒度:dim=1 的含义
- 2. 剪枝比例 prune_ratio = 0.3
- 3. 微调配置合理性
- 4. 模型保存方式正确
- 5. 参数量统计有效

其实大模型轻量化就这三种核心玩法,大家可以根据自己的需求选,不用盲目追求复杂方案。量化是最适合新手入门的,不用重新训练,几小时就能搞定,显存直接省七成多,边缘设备、预算有限的情况选它准没错,就是精度会略有损失,日常业务完全能接受。如果对精度要求特别高,比如医疗、金融场景,就选蒸馏,虽然要用到大模型当“老师”,耗时也久一点,但小模型能学到大模型的精髓,精度损失控制在2%以内,速度还能提3倍。
剪枝就适合有专用硬件、想极致压缩模型的场景,能精简模型结构,但难度最高,剪完还得微调恢复精度,初次接触不建议一开始就试。最推荐的还是组合模式,先蒸馏保精度,再量化提速度,兼顾效果和效率。总的来说,快速落地选量化,高精度需求选蒸馏,极致压缩选剪枝,根据自己的硬件、周期和精度容忍度挑,就能少走很多弯路,这三种方案基本能覆盖大部分轻量化场景了。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。