1. PyTorch模型量化基础
任务目标
使用PyTorch对预训练ResNet-18执行动态量化(Dynamic Quantization),将模型权重从FP32压缩为INT8,并对比量化前后的模型文件大小与CPU推理速度。
环境依赖
- Python 3.8+
- PyTorch ≥ 1.8(含torchvision)
- CPU环境即可(动态量化主要面向CPU推理优化)
核心实现
import torch
import torchvision.models as models
import time
import copy
# 1. 加载预训练模型并设为评估模式
model_fp32 = models.resnet18(weights=models.ResNet18_Weights.IMAGENET1K_V1)
model_fp32.eval()
# 2. 深拷贝一份用于量化
model_quantized = copy.deepcopy(model_fp32)
# 3. 动态量化:仅量化Linear层(ResNet-18的FC层)
model_quantized = torch.ao.quantization.quantize_dynamic(
model_quantized, {torch.nn.Linear}, dtype=torch.qint8
)
# 4. 模型大小对比(保存后查看文件字节数)
import os
def get_model_size_mb(model, filename):
torch.save(model.state_dict(), filename)
size_bytes = os.path.getsize(filename)
os.remove(filename)
return size_bytes / (1024 * 1024)
size_fp32 = get_model_size_mb(model_fp32, "resnet18_fp32.pth")
size_int8 = get_model_size_mb(model_quantized, "resnet18_int8.pth")
print(f"FP32模型大小: {size_fp32:.2f} MB")
print(f"INT8动态量化模型大小: {size_int8:.2f} MB")
print(f"压缩比: {size_fp32 / size_int8:.2f}x")
# 5. CPU推理速度对比(使用随机输入)
batch_size = 1
dummy_input = torch.randn(batch_size, 3, 224, 224)
def measure_inference_time(model, input_tensor, num_runs=50):
# 预热
with torch.no_grad():
for _ in range(10):
model(input_tensor)
# 计时
torch.cuda.synchronize() if torch.cuda.is_available() else None
start = time.time()
with torch.no_grad():
for _ in range(num_runs):
model(input_tensor)
end = time.time()
return (end - start) / num_runs * 1000 # 毫秒
# 限制线程数保证公平对比
torch.set_num_threads(4)
time_fp32 = measure_inference_time(model_fp32, dummy_input)
time_int8 = measure_inference_time(model_quantized, dummy_input)
print(f"FP32平均推理耗时: {time_fp32:.2f} ms")
print(f"INT8动态量化平均推理耗时: {time_int8:.2f} ms")
print(f"加速比: {time_fp32 / time_int8:.2f}x")
# 6. 验证输出一致性(量化前后预测差异)
with torch.no_grad():
out_fp32 = model_fp32(dummy_input)
out_int8 = model_quantized(dummy_input)
# 比较最大误差
max_diff = (out_fp32 - out_int8).abs().max().item()
print(f"量化前后输出最大误差: {max_diff:.6f}")
print("验证完成:量化模型可正常推理且输出与FP32模型接近。")
运行方式
# 安装依赖
pip install torch torchvision
# 运行脚本
python quantize_resnet18.py
验证方法与判定标准
- 模型大小:量化后模型文件应显著小于FP32模型(通常压缩比约3~4倍,因仅量化全连接层,ResNet-18卷积层仍为FP32)。
- 推理速度:量化后模型在CPU上的推理耗时应当低于或接近FP32模型(动态量化主要优化全连接层计算,若整体耗时下降不明显,可观察FC层占比高的输入场景)。
- 输出一致性:量化前后模型对同一输入的输出最大误差应小于0.1(典型值在1e-3~1e-2量级),说明量化精度损失在可接受范围。
- 功能正确性:脚本无报错,且打印出上述对比指标即视为运行成功。
关键说明
- 动态量化仅对
torch.nn.Linear层生效,ResNet-18的卷积层仍保持FP32,因此压缩比和加速比有限。若需更大压缩,可改用静态量化(需校准数据)或量化感知训练。 - 推理速度受CPU型号、线程数影响,建议固定
torch.set_num_threads()以保证对比公平。 - 若需部署到移动端或边缘设备,可进一步导出为ONNX并量化,但本案例聚焦PyTorch原生动态量化流程。