
从我们日常接触的电脑存储开始理解,我们可以先回忆一下手机、电脑里的数据存储规则:大模型的核心是海量参数,可以理解为模型学到的知识,像一本超级厚的字典,这些参数在计算机里默认是用 32 位浮点数(FP32) 存储的,简单说,就是用 32 个二进制位来记录一个数字,能精确表示很大范围的小数。
但这样我们会面临核心的问题:
量化的本质:把模型参数的“数据精度降低”,比如从 32 位降到 16 位、8 位,甚至 4 位、2 位。大模型量化就是牺牲一点点精度,换取模型体积缩小、运行速度提升、硬件门槛降低”的技术。
类比一下:我们原本用精密天平称东西,比如精确到 0.001 克,现在改用只能精确到 1 克的厨房秤,虽然精度降了,但秤更便宜、称重更快,日常做饭完全够用。

模型训练时的默认精度,FP32 精度最高,FP16 是半精度,体积和计算量减半。
量化后的精度,INT 代表整数,数字越小,精度越低,模型体积越小。
在模型训练阶段就考虑量化的影响,训练出本身就适合量化的模型,精度损失最小。
对已经训练好的模型直接做量化,不用重新训练,操作简单,适合初次接触和快速部署。
量化后模型预测能力的下降程度,好的量化方法能让损失几乎可以忽略。
假设模型某参数的范围是[-10, 10](FP32),要转成 INT8(范围[-128, 127]):
量化最核心的价值,直接决定了大模型能不能走进千家万户:
3.1 降低硬件门槛
3.2 提升运行速度
3.3 减少存储和带宽成本
3.4 降低功耗
一句话总结:量化是大模型从实验室走向实际应用的关键技术。
我们以最常用的后训练量化(PTQ) 为例,拆解量化的完整流程,这个流程不需要重新训练模型,适合初次接触理解。

步骤 1:确定量化目标
首先明确两个问题:
步骤 2:数据校准(核心步骤)
量化的关键是找到 “全精度数据” 和 “低精度数据” 的对应关系 ,这个过程叫 “校准”。举个 INT8 量化的例子:
通俗理解:校准就像给地图做比例尺 —— 把真实世界的大范围(全精度数据)缩小到一张小地图上(低精度数据),比例尺就是缩放因子。
步骤 3:模型量化转换
用步骤 2 得到的缩放因子,把模型的所有权重从全精度转换成低精度整数,保存成新的量化模型文件。这个过程可以用现成的工具(比如 PyTorch 的torch.quantization、TensorRT、GPTQ 等)自动完成,不需要手动计算。
步骤 4:推理时的 “量化 - 反量化”
量化后的模型运行时,会多两步操作:
整个过程对用户是透明的,我们可以看到的还是正常的模型输出,但背后的计算已经 “轻量化” 了。
步骤 5:精度评估与调优
量化后必须做测试:用测试数据集对比全精度模型和量化模型的输出结果(比如准确率、困惑度等指标)。如果精度损失太大,有两个解决办法:
流程精简总结:

快速轻量化的入门选择,后训练量化是一种对已完成训练的全精度模型进行直接量化的技术。其核心思想是在不重新训练模型的前提下,通过校准数据集的统计信息,计算出最优的量化参数,实现模型的轻量化转换。
技术特点:
适用场景扩展:
PTQ特别适合需要快速部署和资源受限的环境。例如:
追求极致精度的专业方案,量化感知训练通过在模型训练阶段引入量化模拟,让模型在学习过程中适应低精度表示,从而在真正量化时最大限度保持性能。
技术特点:
适用场景扩展:
QAT适用于对精度要求极为严格且有足够训练资源的场景:
边缘计算的极致优化,极低精度量化将模型压缩到极致,通常需要结合创新的量化算法和专用硬件支持,是对资源极度受限环境的针对性解决方案。
技术特点:
适用场景扩展:
极低精度量化专为资源极度受限和功耗敏感的场景设计:
实际应用中,量化方法的选择应基于四维权衡:
现代最佳实践常采用混合策略:
第一步加深基础理解,不涉及完整大模型,先理解“全精度→低精度”的转换本质,就像先学数学基础1+1=2,再学高等数学。
import torch
# ===================== 1. 定义一个全精度张量(模拟模型参数) =====================
# 模拟模型中的一个权重张量,FP32精度(32位浮点数)
fp32_tensor = torch.tensor([1.23, -4.56, 7.89, -0.12], dtype=torch.float32)
print("原始全精度张量(FP32):", fp32_tensor)
print("原始张量占用内存:", fp32_tensor.element_size() * fp32_tensor.numel(), "字节") # 4字节/元素 × 4元素=16字节
# ===================== 2. 手动实现INT8量化核心逻辑 =====================
# 步骤1:计算缩放因子(Scale)——把FP32范围映射到INT8范围(-128~127)
max_val = torch.max(torch.abs(fp32_tensor)) # 取绝对值最大值,避免正负偏移
scale = max_val / 127.0 # INT8最大值是127,最小值-128,这里简化用127
# 步骤2:量化(FP32→INT8):除以缩放因子后取整
int8_tensor = torch.round(fp32_tensor / scale).to(torch.int8)
print("\n量化后INT8张量:", int8_tensor)
print("量化后张量占用内存:", int8_tensor.element_size() * int8_tensor.numel(), "字节") # 1字节/元素 ×4=4字节(缩小4倍)
# 步骤3:反量化(INT8→FP32):还原成近似的全精度值(推理时输出用)
fp32_recovered = int8_tensor.to(torch.float32) * scale
print("\n反量化后的近似FP32张量:", fp32_recovered)
print("量化前后误差:", torch.mean(torch.abs(fp32_tensor - fp32_recovered))) # 误差很小,几乎可忽略输出结果:
原始全精度张量(FP32): tensor([ 1.2300, -4.5600, 7.8900, -0.1200]) 原始张量占用内存: 16 字节 量化后INT8张量: tensor([ 20, -73, 127, -2], dtype=torch.int8) 量化后张量占用内存: 4 字节 反量化后的近似FP32张量: tensor([ 1.2425, -4.5352, 7.8900, -0.1243]) 量化前后误差: tensor(0.0104)
示例解析:
大模型量化对 CPU 来说,是让一般的硬件设备也能调试运行大模型的核心技术:
import torch
import torch.nn as nn
from torch.quantization import QuantStub, DeQuantStub, get_default_qconfig, prepare, convert
# 确保全程在CPU运行
torch.set_default_device('cpu')
# 定义模拟大模型结构的简单网络(CPU友好)
class SimpleModel(nn.Module):
def __init__(self):
super(SimpleModel, self).__init__()
# 量化/反量化节点(老版本PyTorch必需,CPU适配)
self.quant = QuantStub() # 输入量化:FP32→INT8
self.dequant = DeQuantStub() # 输出反量化:INT8→FP32
# 模拟大模型的核心层(线性层+激活层)
self.fc1 = nn.Linear(in_features=16, out_features=32) # 输入16维,输出32维
self.relu1 = nn.ReLU() # 激活函数
self.fc2 = nn.Linear(in_features=32, out_features=16) # 输出16维
self.relu2 = nn.ReLU()
def forward(self, x):
# 量化节点:CPU上执行输入量化
x = self.quant(x)
# 模型前向计算(全程CPU)
x = self.fc1(x)
x = self.relu1(x)
x = self.fc2(x)
x = self.relu2(x)
# 反量化节点:CPU上执行输出反量化
x = self.dequant(x)
return x
# 初始化模型并设为评估模式(量化仅用于推理,CPU运行)
model_fp32 = SimpleModel()
model_fp32.eval()
print("===== 全精度模型初始化完成(CPU)====")
print(f"模型结构:\n{model_fp32}")# 校准数据要求:少量、和模型输入匹配、贴近真实场景(CPU生成)
# 生成100条校准数据,每条16维(和模型输入维度一致),CPU存储
calibration_data = [torch.randn(1, 16) for _ in range(100)]
print(f"\n===== 校准数据准备完成(CPU)====")
print(f"校准数据数量:{len(calibration_data)}条")
print(f"单条数据形状:{calibration_data[0].shape}(匹配模型输入)")
# 测试全精度模型是否能在CPU正常推理
test_input = torch.randn(1, 16)
with torch.no_grad(): # 关闭梯度计算,节省CPU算力
fp32_output = model_fp32(test_input)
print(f"\n===== 全精度模型CPU推理测试 =====")
print(f"输入值:{test_input[0][:5]}(前5个值)")
print(f"输出值:{fp32_output[0][:5]}(前5个值)")# 配置CPU量化后端(fbgemm适配x86 CPU,qnnpack适配ARM CPU)
qconfig = get_default_qconfig('fbgemm')
# 给模型绑定量化配置(CPU上执行)
model_fp32.qconfig = qconfig
# 准备量化:CPU上分析模型结构,插入量化节点
model_prepared = prepare(model_fp32)
print(f"\n===== 模型量化准备完成(CPU)====")
print(f"量化配置:{model_prepared.qconfig}")print(f"\n===== 开始CPU校准(统计数据分布)====")
# 用校准数据跑模型,统计权重/激活值的分布(CPU计算)
with torch.no_grad():
for data in calibration_data:
model_prepared(data) # 仅前向推理,不训练
print(f"校准完成!CPU已统计出缩放因子(Scale)")# 转换为INT8量化模型(CPU上执行)
model_int8 = convert(model_prepared)
print(f"\n===== 量化模型生成完成(CPU·INT8)====")
print(f"量化模型结构:\n{model_int8}")
# 测试量化模型CPU推理
with torch.no_grad():
int8_output = model_int8(test_input)
print(f"\n===== 量化模型CPU推理测试 =====")
print(f"量化输出值:{int8_output[0][:5]}(前5个值)")# 1. 精度对比:计算平均绝对误差(CPU)
abs_error = torch.mean(torch.abs(fp32_output - int8_output))
print(f"\n===== 量化精度评估(CPU)====")
print(f"全精度输出:{fp32_output[0][:5]}")
print(f"量化输出:{int8_output[0][:5]}")
print(f"平均绝对误差:{abs_error.item()}(<0.1即无感知)")
# 2. 内存对比(CPU)
def calculate_model_size(model):
"""计算模型参数在CPU上的内存占用(字节)"""
total_size = 0
for param in model.parameters():
# 每个参数的内存:元素大小 × 元素数量
param_size = param.element_size() * param.numel()
total_size += param_size
return total_size
fp32_size = calculate_model_size(model_fp32)
int8_size = calculate_model_size(model_int8)
print(f"\n===== 量化性能评估(CPU)====")
print(f"全精度模型内存:{fp32_size} 字节")
print(f"INT8量化模型内存:{int8_size} 字节")
print(f"内存节省:{1 - int8_size/fp32_size:.2f}(即{int((1 - int8_size/fp32_size)*100)}%)")
# 3. 速度对比(CPU)
import time
# 全精度模型推理耗时(CPU)
start_time = time.time()
with torch.no_grad():
for _ in range(100):
model_fp32(test_input)
fp32_time = time.time() - start_time
# 量化模型推理耗时(CPU)
start_time = time.time()
with torch.no_grad():
for _ in range(100):
model_int8(test_input)
int8_time = time.time() - start_time
print(f"\n===== 量化速度评估(CPU)====")
print(f"全精度模型100次推理耗时:{fp32_time:.4f} 秒")
print(f"INT8量化模型100次推理耗时:{int8_time:.4f} 秒")
print(f"推理速度提升:{fp32_time/int8_time:.2f} 倍")输出结果:
===== 全精度模型初始化完成(CPU)==== 模型结构: SimpleModel( (quant): QuantStub() (dequant): DeQuantStub() (fc1): Linear(in_features=16, out_features=32, bias=True) (relu1): ReLU() (fc2): Linear(in_features=32, out_features=16, bias=True) (relu2): ReLU() ) ===== 校准数据准备完成(CPU)==== 校准数据数量:100条 单条数据形状:torch.Size([1, 16])(匹配模型输入) ===== 全精度模型CPU推理测试 ===== 输入值:tensor([ 1.9764, -0.5861, 0.1155, -1.5267, -0.7654])(前5个值) 输出值:tensor([0.4386, 0.0205, 0.0000, 0.0000, 0.0000])(前5个值) ===== 模型量化准备完成(CPU)==== 量化配置:QConfig(activation=functools.partial(<class 'torch.ao.quantization.observer.HistogramObserver'>, reduce_range=True){'factory_kwargs': <function _add_module_to_qconfig_obs_ctr.<locals>.get_factory_kwargs_based_on_module_device at 0x0000015A77BBC310>}, weight=functools.partial(<class 'torch.ao.quantization.observer.PerChannelMinMaxObserver'>, dtype=torch.qint8, qscheme=torch.per_channel_symmetric){'factory_kwargs': <function _add_module_to_qconfig_obs_ctr.<locals>.get_factory_kwargs_based_on_module_device at 0x0000015A77BBC310>}) ===== 开始CPU校准(统计数据分布)==== 校准完成!CPU已统计出缩放因子(Scale) ===== 量化模型生成完成(CPU·INT8)==== 量化模型结构: SimpleModel( (quant): Quantize(scale=tensor([0.0594]), zero_point=tensor([70]), dtype=torch.quint8) (dequant): DeQuantize() (fc1): QuantizedLinear(in_features=16, out_features=32, scale=0.03623142093420029, zero_point=66, qscheme=torch.per_channel_affine) (relu1): ReLU() (fc2): QuantizedLinear(in_features=32, out_features=16, scale=0.01594831421971321, zero_point=74, qscheme=torch.per_channel_affine) (relu2): ReLU() ) ===== 量化模型CPU推理测试 ===== 量化输出值:tensor([0.4466, 0.0159, 0.0000, 0.0000, 0.0000])(前5个值) ===== 量化精度评估(CPU)==== 全精度输出:tensor([0.4386, 0.0205, 0.0000, 0.0000, 0.0000]) 量化输出:tensor([0.4466, 0.0159, 0.0000, 0.0000, 0.0000]) 平均绝对误差:0.003916075453162193(<0.1即无感知) ===== 量化性能评估(CPU)==== 全精度模型内存:4288 字节 INT8量化模型内存:0 字节 内存节省:1.00(即100%) ===== 量化速度评估(CPU)==== 全精度模型100次推理耗时:0.0070 秒 INT8量化模型100次推理耗时:0.0320 秒 推理速度提升:0.22 倍
量化的结果分析:
建议:对于小模型,量化可能不会带来明显的性能提升,甚至可能降低速度。但对于大模型,量化通常可以显著减少内存占用并提升推理速度。另外,可以尝试在支持整数运算加速的硬件(如某些ARM处理器或GPU)上运行量化模型,以获得更好的性能。
注意:由于本地配置环境有限,过程做了针对CPU的专门处理,实际可以根据配置来做优化调整。
大模型量化的核心逻辑非常简单:用“精度的小妥协”换“部署的大便利”。它不是高深莫测的黑科技,而是让大模型接地气的实用技术,没有量化,我们就不可能在手机上用本地 AI、在普通电脑上跑大模型。
对于我们初次接触来说,从后训练量化(PTQ) 入手,用现成的工具跑一遍量化流程,就能直观感受到它的效果。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。