最近在社区里经常看到这样的提问:模型明明只有 7B、8B 参数,为什么放到本机部署时显存直接爆掉?推理一句话要等好几秒,GPU 利用率还不到 50%;想上生产环境,又担心带宽和成本扛不住。这类问题的背后,都绕不开大模型轻量化部署。
轻量化这个词看起来高大上,落到工程上无非两条路径:蒸馏和量化。蒸馏是让模型“变小变聪明”,量化是让模型“变瘦跑得快”。两者可以单独使用,也可以组合成一套流水线。本文就用一篇教程的篇幅,把两条路径的原理、常见做法、代码示例、踩坑点都过一遍,适合刚接触大模型部署的读者,也会给出一些生产环境层面的建议。
1. 大模型部署的核心瓶颈
1.1 显存、延迟和成本从哪里来
先看一组粗略估算。假设一个 8B 参数的大模型,用 FP16(半精度,每个参数占 2 字节)保存权重:
- 权重显存需求大约为 8B × 2B ≈ 16GB。
- 如果加载到 24G 显存的显卡上,看起来刚好能装下,但推理过程中还需要分配 KV Cache、激活值、临时算子缓冲区,再叠加这些开销以后,16G 显存会很紧张。
- 如果用 INT8 量化(每个参数占 1 字节),权重只需要 8GB;如果用 INT4 量化(每个参数占 0.5 字节),权重只需要 4GB 左右。
这只是一个简化模型,真实工程里还要考虑批处理大小和序列长度,但结论已经足够明显:参数量越大,存储和计算的开销越大,对部署环境的要求越苛刻。
推理延迟也是一个核心指标。大模型是逐 token 生成的,每个 token 都要走一次完整前向计算。模型越大,单次前向计算越慢,用户感受到的“打字机式输出”也就越考验耐心。很多场景对时延有硬性要求,比如客服机器人、代码补全、实时翻译,这些场景里模型大小和推理速度必须被当成第一优先级去优化。
成本则是另一个维度。显存更贵的服务器、更高的功耗、更大的 GPU 集群,最终都变成账单。轻量化部署要做的事情,就是在保住效果底线的前提下,把显存、延迟和成本压下来。
1.2 轻量化手段不只有蒸馏和量化
常见的模型压缩手段其实有好几类,先做一个整体对比:
| 手段 | 核心思路 | 优点 | 难点 |
|---|---|---|---|
| 蒸馏 | 用小模型学习大模型的输出行为 | 显著降低参数量,推理速度提升明显 | 需要训练数据和训练算力;学生模型能力上限受限 |
| 量化 | 降低权重和激活值的数值精度 | 无需重新训练(PTQ 场景),部署改动小 | 精度可能下降,需要校准和评测 |
| 剪枝 | 删除冗余参数或注意力头 | 模型结构稀疏化,减少计算量 | 结构改动复杂,微调成本高 |
| 稀疏化 | 只保留部分非零权重 | 理论上压缩率极高 | 实际硬件加速支持有限,落地困难 |
从 2023 年到 2025 年的大模型生态来看,蒸馏和量化是落地范围最广、生态最成熟的两条路径。剪枝和稀疏化更多出现在学术研究和特定硬件方案里。所以本文把重点放在蒸馏和量化上,完全对应实际生产中最常被问到的需求。
1.3 先弄清楚:蒸馏和量化不是互斥关系
很多新人会把蒸馏和量化当成两种对立的方案,实际上它们是两个维度上的优化:
- 蒸馏改变的是模型架构和参数量。典型路径是从 70B 蒸馏出 7B 模型,参数量变小,结构也变了。
- 量化改变的是参数的存储和计算精度。它不改变参数量,只改变每个参数用多少位来表示。
所以完全可以把一个大模型先蒸馏成一个小模型,再对小模型做量化。比如先训练一个 1.5B 的学生模型,再对它做 4bit 量化,最终得到一个“又小又快”的部署单元。这也是很多端侧、边缘侧方案的实际做法。
2. 知识蒸馏:让“大老师”教会“小学生”
2.1 蒸馏到底在蒸馏什么
知识蒸馏(Knowledge Distillation,KD)最早由 Hinton 等人在 2015 年系统提出,核心思想非常直观:用一个已经训练好的大模型(教师模型)去指导一个小模型(学生模型)的训练。
学生模型的目标不是直接学习数据里的硬标签,而是学习教师模型对数据“怎么看”。比如一张图片里有一只猫,硬标签是“猫”,但教师模型可能输出 0.7 的概率是猫、0.2 的概率是狗、0.1 的概率是狐狸。这些软化的概率分布里包含大量类间关系信息,学生模型能从中学到更平滑、更丰富的语义。
放到大模型场景里也一样。一个 7B 模型在某个指令上的回答,包含的不只是最终答案,还有回答的措辞风格、思考路径、对边界的处理方式。蒸馏可以有效传递这些“暗知识”。
2.2 软标签、温度和蒸馏损失
蒸馏中有一个关键参数叫温度(Temperature,通常记为 T)。教师模型输出的 logits 先除以 T,再做 softmax,就得到了软化的概率分布。T 越大,分布越平滑;T 越小,分布越接近 one-hot 硬标签。训练学生模型时,一般用两个损失:
- 蒸馏损失:学生模型和教师模型软化输出之间的 KL 散度。
- 常规任务损失:学生模型和真实标签之间的交叉熵。
最后再把两个损失加权相加。一个典型的 PyTorch 风格蒸馏训练循环可以是这样的:
import torch import torch.nn as nn import torch.optim as optim # 假设已经有 teacher_model 和 student_model teacher_model = TeacherModel() student_model = StudentModel() temperature = 4.0 alpha = 0.7 def distillation_loss(student_logits, teacher_logits, labels): # 教师模型软化输出 teacher_soft = torch.nn.functional.softmax(teacher_logits / temperature, dim=-1) # 学生模型软化输出 student_soft = torch.nn.functional.log_softmax(student_logits / temperature, dim=-1) # KL 散度蒸馏损失,乘 T^2 是为了让梯度尺度与温度无关 kd_loss = torch.nn.functional.kl_div( student_soft, teacher_soft, reduction="batchmean" ) * (temperature ** 2) # 常规交叉熵损失 ce_loss = torch.nn.CrossEntropyLoss()(student_logits, labels) return alpha * kd_loss + (1 - alpha) * ce_loss optimizer = optim.Adam(student_model.parameters(), lr=1e-4) for batch_x, batch_y in dataloader: with torch.no_grad(): t_logits = teacher_model(batch_x) s_logits = student_model(batch_x) loss = distillation_loss(s_logits, t_logits, batch_y) optimizer.zero_grad() loss.backward() optimizer.step()这段代码只是最小示例,实际项目中还需要考虑:
- 教师模型 logits 和学生模型 logits 的维度要对齐,尤其是输出层类别数不一致时,需要加一个投影层。
- 大模型场景往往不是直接对 logits 蒸馏,而是对下一 token 的概率分布做 KL 散度蒸馏,公式类似但输入是 token 序列。
- 蒸馏训练的数据量不需要和预训练一样大,但质量要求很高,尤其是希望学生模型继承推理能力时,需要精心构造指令数据。
2.3 多种蒸馏变体:在线、离线、自蒸馏、黑盒蒸馏
随着蒸馏被用到更多场景,衍生出了很多变体:
- 离线蒸馏:教师模型先冻结,离线生成大量 soft label,学生模型再训练。优点是实现简单,缺点是教师模型不更新,数据分布可能和学生实际遇到的不同。
- 在线蒸馏:教师模型和学生模型一起更新,两边同时变强。适合数据分布动态变化的场景。
- 自蒸馏:教师模型和学生模型同结构,用同一模型的历史迭代版本当老师,比如 BEiT 系列中使用过类似思想。
- 黑盒蒸馏:访问不到教师模型的参数和 logits,只能拿到教师模型生成的文本。这种场景下,通常会要求学生模型去拟合教师模型的输出文本,甚至通过打分反馈来强化对齐。当前许多已发布小模型的“数据蒸馏”流程,很多都可以归入黑盒蒸馏范畴,同时也常被与“合成数据训练”混在一起讨论。
2.4 蒸馏在 CV、大模型、控制任务里的典型应用
蒸馏并不是大模型专属技术。在目标检测领域,YOLO 系列论文经常讨论用大检测器蒸馏小检测器,教师模型输出特征图或者分类边界分布,学生模型在相似位置对齐。这样做之后,小模型的 mAP 往往能明显高于直接从头训练。
在控制与策略学习领域,也有人把行为克隆和运动蒸馏结合起来,教师策略给出一组轨迹和动作分布,学生策略去拟合。这样做出来的学生策略往往更轻量、推理更快,适合部署在机器人或边缘设备上,热词里的“运动蒸馏”指的就是这类方向。
在大模型领域,蒸馏更倾向于“指令蒸馏”。比如把 300B 教师模型在 100 万条指令上的回答整理成数据集合,再训练一个 7B 学生模型。这也是很多开源小模型可以追平甚至接近大模型效果的原因之一。
3. 模型量化:降低数值精度,释放部署红利
3.1 什么是模型量化
模型量化是指把模型权重和激活值从高精度数值类型(如 FP32、FP16)转换为低精度数值类型(如 INT8、INT4)的过程。量化后,模型参数占用的存储空间变小,推理时参与计算的位宽变低,还能利用硬件上的低精度加速指令,因此推理速度往往也有明显提升。
一个最直接的例子:FP32 的 1B 模型权重约 4GB,INT8 后约 1GB,INT4 后约 0.5GB。这种压缩效果对显存受限的本地部署场景几乎可以说是“救命级别”的优化。
在搜资料时,你可能会看到“量化交易”“量化比赛”“比特币量化”等关键词,它们属于金融领域,指的是用量化模型做交易决策,和本文讨论的模型参数量化完全是两回事。搜“大模型量化”时很容易混入这些内容,需要留意甄别。
3.2 PTQ 和 QAT:两种主流量化路线
根据是否需要训练,量化可以分成两条路线:
- 训练后量化(Post-Training Quantization,PTQ):模型训练完成后,直接对权重做量化。优点是快、不需要训练,缺点是精度损失相对较大,通常需要一小部分校准数据来确定量化范围。
- 量化感知训练(Quantization-Aware Training,QAT):在训练过程中就模拟量化误差,让模型逐步适应低精度表示。优点是精度更好,缺点是需要重新训练、付出额外算力。
对于大模型来说,大部分开源社区方案偏好 PTQ,因为训练成本太高。常见的 GPTQ、AWQ 都属于 PTQ 路线的代表。
3.3 常见精度档位:FP16、INT8、INT4、NF4
不同精度档位代表了不同的“性价比”:
| 精度 | 每参数位数 | 显存占用(以 7B 模型粗略估算) | 说明 |
|---|---|---|---|
| FP32 | 32 bit | 约 28GB | 极少用于推理部署,主要出现在训练阶段 |
| FP16 / BF16 | 16 bit | 约 14GB | 大多数在线服务的默认精度 |
| INT8 | 8 bit | 约 7GB | 速度较好,精度损失可控 |
| INT4 | 4 bit | 约 3.5GB | 适合本地和端侧部署 |
| NF4 | 4 bit | 约 3.5GB | QLoRA 中提出的归一化 4bit 格式,分布更适配权重 |
实际显存还要考虑缓存和激活,远不止权重大小。但上面的表已经足够帮新手建立直观认知。
3.4 大模型量化生态:GGUF、GPTQ、AWQ、bitsandbytes
大模型领域目前有几种主流量化生态,它们服务于不同的推理框架:
- GGUF:由 llama.cpp 社区推广的格式,适合 CPU 和混合推理,支持 Q4_0、Q4_K_S、Q4_K_M、Q5_K_M 等档位。很多“下载 GGUF 模型本地部署”的教程都是基于这个格式。
- GPTQ:一种训练后量化方法,利用二阶信息补偿量化误差,常用于 GPU 上推理。HuggingFace 上很多模型会提供 GPTQ 版本。
- AWQ:基于激活感知的量化方法,不是简单按权重绝对值分组,而是结合激活分布来挑选保护的重要通道,效果在部分任务上优于 GPTQ。
- bitsandbytes:提供便捷的
load_in_4bit、load_in_8bit接口,主要配合 transformers 使用,适合快速尝试。
如果你用的是 transformers 加载一个 4bit 量化模型,常见写法如下:
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig import torch quantization_config = BitsAndBytesConfig( load_in_4bit=True, bnb_4bit_quant_type="nf4", bnb_4bit_use_double_quant=True, bnb_4bit_compute_dtype=torch.bfloat16, ) model_id = "your-model-id" tokenizer = AutoTokenizer.from_pretrained(model_id) model = AutoModelForCausalLM.from_pretrained( model_id, quantization_config=quantization_config, device_map="auto", torch_dtype=torch.bfloat16, ) inputs = tokenizer("介绍一下大模型轻量化部署", return_tensors="pt").to("cuda") output = model.generate(**inputs, max_new_tokens=100) print(tokenizer.decode(output[0], skip_special_tokens=True))这段代码中的load_in_4bit=True会自动把权重映射到 4bit 位宽。nf4是 QLoRA 论文中推荐的 NF4 量化类型。bnb_4bit_use_double_quant表示对量化常数做二次量化,进一步省显存。
注意:不同 transformers 版本对 BitsAndBytesConfig 的参数名可能有改动,如果你用的版本较新,遇到参数不识别时,优先查看官方文档;示例思路不变,具体 API 以你的实际版本为准。
3.5 GGUF 的本地化部署
GGUF 格式在 Windows、Linux、Mac 本地部署里非常流行。整体流程一般是:
- 下载模型仓库中的
.gguf文件,或者用转换脚本把自己的 HuggingFace 模型转换成 GGUF。 - 用 llama.cpp 或者支持 GGUF 的推理前端加载模型。
- 启动本地 API 服务,然后通过 OpenAI 风格接口调用。
典型的转换命令如下:
# 先安装 llama.cpp 相关依赖,再执行转换 python convert_hf_to_gguf.py /path/to/your_hf_model_dir \ --outfile model_f16.gguf \ --outtype f16转换完成后可以做量化:
llama-quantize model_f16.gguf model_q4_k_m.gguf Q4_K_Mllama-quantize是 llama.cpp 项目提供的命令行工具,Q4_K_M是质量和体积比较均衡的档位之一。需要强调,llama.cpp 的命令行参数在持续演进,版本不同可能略有差异;这里给出的是最常见的用法,实际环境以官方 README 为准。
4. 从 PyTorch 到 ONNX INT8 量化:一套完整实操流程
如果不想局限于大模型生态,想把普通的 PyTorch 模型也做一次量化,ONNX Runtime 是一条很成熟的路径。下面这套流程适合做一次完整的“量化初体验”:准备模型、导出 ONNX、动态量化、对比推理结果。
4.1 环境准备
本文示例基于以下常见环境,你不需要完全一致,重点看思路:
- 操作系统:Windows 10/11 或 Ubuntu 20.04 均可
- Python:3.8 及以上
- PyTorch:2.x 版本(版本差异不影响整体流程)
- onnx:1.14 及以上
- onnxruntime:1.16 及以上
安装依赖:
pip install torch onnx onnxruntime如果你的模型还用了其他预处理库,也要一并安装。示例模型用 resnet18 这种结构,一是小巧,二是方便验证。
4.2 导出 ONNX 模型
导出 ONNX 本质上是把 PyTorch 模型的计算图冻结成静态图,只保留推理所需的信息。需要注意的是控制流:如果模型中包含依赖数据来改变执行路径的逻辑,导出会受限。
import torch import torchvision.models as models model = models.resnet18(pretrained=True) model.eval() dummy_input = torch.randn(1, 3, 224, 224) torch.onnx.export( model, dummy_input, "resnet18.onnx", input_names=["input"], output_names=["output"], opset_version=17, ) print("ONNX 模型导出完成")这里使用opset_version=17,不同 ONNX Runtime 版本对算子集的支持不同,如果导出时提示算子不支持,可以调低 opset 版本。
4.3 对 ONNX 模型做 INT8 动态量化
动态量化只量化权重,激活值仍在推理时动态决定范围,优点是不需要额外准备校准数据,适合快速验证。
from onnxruntime.quantization import quantize_dynamic, QuantType model_path = "resnet18.onnx" quantized_model_path = "resnet18_int8.onnx" quantize_dynamic( model_input=model_path, model_output=quantized_model_path, weight_type=QuantType.QInt8, ) print("INT8 动态量化完成")动态量化简单,但精度通常不如静态量化。静态量化需要准备一批有代表性的校准数据,先统计每层激活的数值范围,再执行量化。以下是一个静态量化的简化示意:
from onnxruntime.quantization import quantize_static, QuantType from onnxruntime.quantization import CalibrationDataReader class MyCalibrationDataReader(CalibrationDataReader): def __init__(self, calibration_samples): self.data = iter(calibration_samples) def get_next(self): try: return next(self.data) except StopIteration: return None # calibration_samples 是一个包含字典的列表,字典格式为 {"input": numpy 数组} calibration_data = [{"input": sample.astype("float32")} for sample in samples] quantize_static( model_input=model_path, model_output="resnet18_int8_static.onnx", calibration_data_reader=MyCalibrationDataReader(calibration_data), quant_format=QuantType.QInt8, )这里需要注意CalibrationDataReader的get_next必须返回一个字典或 None,不能直接返回 numpy 数组,这是新手最容易写错的地方。
4.4 推理对比与结果验证
把原始 ONNX 和量化 ONNX 分别跑一遍,对比推理结果和耗时:
import numpy as np import time import onnxruntime as ort def run_inference(onnx_path, input_data): session = ort.InferenceSession(onnx_path, providers=["CPUExecutionProvider"]) start = time.time() outputs = session.run(None, {"input": input_data}) cost = time.time() - start return outputs, cost sample = np.random.randn(1, 3, 224, 224).astype(np.float32) outputs_fp32, cost_fp32 = run_inference("resnet18.onnx", sample) outputs_int8, cost_int8 = run_inference("resnet18_int8.onnx", sample) print(f"FP32 推理耗时: {cost_fp32:.4f} s") print(f"INT8 推理耗时: {cost_int8:.4f} s") print("输出维度:", outputs_fp32[0].shape, outputs_int8[0].shape)如果你的机器 CPU 不支持相关优化指令,可能看到 INT8 的速度提升不明显。这个结果受硬件影响较大,但不影响理解整体流程。
4.5 关于大模型场景的补充
上述 ONNX 流程主要面向普通 CV 模型。大模型转 ONNX 会更复杂,因为存在动态序列长度、KV Cache、缓存管理等算子,很多时候直接导出会报算子不兼容。所以大模型量化更常走 bitsandbytes、llama.cpp、vLLM 等专用链路,而不是通用 ONNX 流程。理解 ONNX 量化流程的重点,是为了搞懂“量化是做什么、数据校准是做什么、量化后精度怎么验证”这套通用方法论。
5. 蒸馏 + 量化的组合实战思路
5.1 为什么推荐先蒸馏再量化
蒸馏负责把模型“从大变小”,量化负责把模型“从小变省”。两者叠加的收益非常可观:
- 一个 70B 的教师模型被蒸馏成 1.5B 学生模型,参数量减少约 98%。
- 把 1.5B 学生模型再做 4bit 量化,显存需求进一步下降。
- 最终部署时,模型体积可能只有教师模型的 1/40 到 1/50,而效果依然能保持一部分能力。
如果直接用 70B 模型做 INT4 量化,模型体积虽然变小了,但推理时每 token 的计算量仍然很大,小显存和低延迟要求依然难以满足。所以很多端侧场景的完整链路是“蒸馏 → 量化”,而不是“直接量化”。
5.2 流程怎么设计
一个典型的组合流程可以分成这样几步:
- 用部署目标确定算力上限,例如“必须在 8G 显存 GPU 上运行”。
- 从教师模型蒸馏出合适参数量的学生模型,例如 1.5B 或 3B。
- 对蒸馏后的学生模型做量化评估,确定合适的量化档位。
- 构建评测集,验证量化后的效果,如果效果不达标,考虑 QAT 或降低量化倍数。
- 部署推理服务,记录线上指标,持续监控。
5.3 QAT:把量化误差也放进训练里
如果训练资源允许,建议在量化阶段考虑 QAT。QAT 的思想是在训练中模拟量化噪声,让模型参数适应低精度表示。这样得到的结果通常比 PTQ 更稳定。
在大模型场景,完全的 QAT 成本很高,但可以退一步做“部分 QAT”:例如只对敏感层应用量化感知训练,其余层用普通 PTQ。很多工程实践表明,敏感层的识别是关键,通常看哪些层受到量化扰动后损失变化最大。
5.4 一个粗暴但有效的部署对照表
| 部署场景 | 显存预算 | 推荐思路 |
|---|---|---|
| 消费级显卡 16G | 2B~7B 模型 INT4 | 优先下载已量化模型,直接部署 |
| 服务器显卡 24G~48G | 7B~30B 模型 INT8/FP16 | 优先评估 FP16,显存不足再量化 |
| 端侧或手机 | 0.5B~1.5B 量化模型 | 优先走蒸馏减小参数量,再做低比特量化 |
| CPU 本地推理 | 任意模型量化版 | 使用 GGUF 等 CPU 友好格式 |
这张表只是经验参考,不是硬性规则。实际效果必须基于你自己的评测集来定。
6. 常见问题与排查思路
6.1 本地部署时报显存不足
现象:模型刚加载就 OOM,或者推理到一半崩溃。
常见原因:
- 权重本身占太多显存。
- KV Cache 随着序列长度增加而膨胀。
- 同时打开了多个推理进程。
排查步骤:
# Linux 下查看 GPU 显存占用 nvidia-smi解决思路:
- 切换更低 bit 位宽,例如从 INT8 降到 INT4。
- 减少上下文长度
max_length。 - 升级推理框架,使用支持 PagedAttention 的框架,例如 vLLM,减少 KV Cache 碎片。
- 如果可以接受性能下降,关闭部分扩展功能,如长上下文。
6.2 量化后维度不匹配
现象:加载量化模型后,发现 embedding 或输出维度对不上,报 shape mismatch。
典型例子是:原始模型某个隐藏层大小是 5120,量化版配置文件里却写成了 4096,导致加载时报错。这个问题在社区热词里也很常见,比如“minimax h3量化版 clip5120 与 4096 不匹配”。
常见原因:
- 下载的量化模型与原始 config.json 版本不一致。
- 量化过程中改了模型隐藏层大小但没有同步配置文件。
- 使用了不同的 tokenizer 或头文件。
解决思路:
- 先检查 config.json 里的
hidden_size、num_attention_heads、num_hidden_layers是否与模型文件匹配。 - 如果不一致,优先重新下载官方原版量化包,不要手动改配置。
- 如果必须自定义投影层,需要重新跑蒸馏或微调,而不是直接硬加载。
6.3 量化后效果明显变差
现象:模型回答质量下降,出现语法错误、逻辑断裂或重复内容。
原因分析:
- 量化档位过低,例如直接用 2bit 但模型敏感层没做保护。
- 校准数据集覆盖不够,PTQ 的激活统计失准。
- 量化器不支持某些算子,导致部分层没有真正量化反而产生错误。
解决思路:
- 换用 Q4_K_M 或 Q5_K_M 等更高 bit 档位。
- 换用 AWQ、GPTQ 等更先进的量化方法。
- 引入 QAT 做量化感知训练。
- 用一批多样化的业务数据做校准。
6.4 转换 GGUF 失败或推理速度慢
现象:转换过程中报算子不支持,或量化后推理速度没有提升甚至变慢。
解决思路:
- 检查 llama.cpp 是否升级到最新版本,老的构建可能不支持最新模型架构。
- 确认 CPU 是否支持 AVX、AVX2 指令集,不支持时低比特量化收益不明显。
- 如果目标是 GPU 推理,优先用适合 GPU 的量化格式,而不是只盯着 GGUF。
6.5 搜索资料时概念混淆
大模型量化在中文互联网里很容易和金融量化交易混淆。搜索“量化”时经常能看到股票、比特币、量化策略、夏普比率等内容,这些与本文讨论的模型量化不是一回事。建议搜索时带上前缀,例如“大模型量化部署”“模型 int8 量化”“GGUF 量化”,能显著减少无关信息。
7. 最佳实践与工程建议
7.1 先定部署目标,再选方案
不要一上来就问“用蒸馏还是用量化”。先回答三个问题:
- 最终跑在什么硬件上?
- 期望的单 token 延迟是多少?
- 可以接受的精度损失上限是多少?
答案决定方案。如果硬件是手机,必须蒸馏 + 低比特量化;如果硬件是 80G A100,很多场景直接 FP16 就是最优解,完全没必要折腾量化。
7.2 构建自己的评测集
模型量化后的精度变化,不能只看一两条测试用例。建议从业务数据里抽取 200 到 1000 条样本,形成一个固定评测集,量化前后都跑一遍,用相同指标对比。
评测集要覆盖:
- 常见指令。
- 长文本输入。
- 多轮对话。
- 边缘案例和对抗样本。
- 中文与英文场景比例,取决于业务。
7.3 量化前备份、量化后验证
这是最容易忽略的安全边界。量化是对文件做覆盖性操作,如果直接替换生产模型的权重,出现精度问题时很难快速回滚。推荐做法:
- 用独立的实验目录存放原始权重、量化脚本、量化产物。
- 量化产物命名带清晰档位标记,例如
model_q4_k_m.gguf,不要只写model_new.gguf。 - 生产替换前先在预发布环境跑完整回归。
- 保留上一个可用的模型版本,至少一周后再清理。
7.4 日志与监控
上线后也要持续关注模型行为。推理日志里至少记录:
- 输入 token 数量。
- 输出 token 数量。
- 首 token 延迟和总耗时。
- 显存峰值。
- 无响应或请求失败数量。
当线上指标出现明显波动时,可以用这些日志快速定位问题是否与量化精度、上下文长度或者显存分配相关。
7.5 注意框架版本管理
量化生态迭代很快,不同版本的 transformers、llama.cpp、onnxruntime 对同一模型的行为可能有差异。建议在项目里固定依赖版本:
pip freeze > requirements-deploy.txt git tag deploy-2025这样即使半年后重新部署,也能通过同一份依赖还原当时的环境。
8. 总结与学习路线
到这一步,你应该已经搞清楚蒸馏和量化分别解决什么问题、如何组合、有哪些常见坑。用一句话概括:蒸馏改的是模型结构,量化改的是数值表示,两者共同服务于“用更少资源跑起来一个效果够用的模型”这个目标。
接下来可以按自己的方向继续深入:
- 如果对蒸馏感兴趣,下一步可以研究教师模型如何选择、温度如何调、蒸馏数据的配比,以及 LLM 里的指令蒸馏。
- 如果对量化感兴趣,下一步可以研究 GPTQ 的误差补偿原理、AWQ 的激活感知机制、GGUF 的分块量化方式。
- 如果想直接动手落地,建议先从“下载一个 Q4_K_M 量化模型,用 llama.cpp 本地跑通服务”开始,把流程走通后再尝试蒸馏方案。
实操中还有一个很现实的建议:不要追求“最先进”,先追求“能跑通”。大部分项目失败的原因不是技术选型不够好,而是在最初的流程验证上花的时间太少。把一个小模型完整走完“部署 → 评测 → 优化 → 监控”这一圈,比囤一堆前沿论文要有效得多。
如果这篇教程对你有帮助,可以先收藏备用,等实际部署时再翻出蒸馏和量化这两张“王牌”对症下药。