第二章:模型部署基础

2.1 模型部署流程概览

模型部署这件事,说白了就是把训练好的模型搬到生产环境里跑起来。我见过不少团队,模型在GPU上跑得飞快,一上手机或者边缘设备就卡成PPT。为什么会这样?因为部署不是简单的「复制粘贴」。

我个人习惯把部署流程拆成四个阶段:

  1. 模型导出:把PyTorch/TensorFlow的模型转成中间格式
  2. 格式转换:针对目标硬件做优化(比如转成TensorRT)
  3. 量化压缩:把FP32变成INT8,体积变小速度变快
  4. 运行时优化:内存管理、流水线调度这些工程细节

嗯,这里要注意:每个阶段都可能踩坑。我在项目中遇到过最典型的问题——模型导出时一个算子不支持,结果整个流程卡了两天。所以我的建议是:先跑通最小闭环,再逐步优化。

核心原则:部署不是训练的终点,而是工程化的起点。你想想看,一个模型在训练时精度再高,部署后跑不起来等于零。

2.2 模型格式转换

2.2.1 ONNX:模型界的通用语言

ONNX是什么?它就是个中间格式。好比你把中文文档翻译成英文,再让不同国家的人都能看懂。ONNX就是那个「英文」。

我建议所有部署项目都先走ONNX。原因很简单:生态最全。不管你是PyTorch、TensorFlow还是PaddlePaddle,都能导出ONNX。而且TensorRT、OpenVINO这些推理引擎都优先支持ONNX。

来个实际例子。PyTorch转ONNX的代码长这样:

import torch
import torch.onnx

# 假设你有个训练好的模型
model = torch.load('resnet50.pth')
model.eval()

# 构造一个虚拟输入
dummy_input = torch.randn(1, 3, 224, 224)

# 导出ONNX
torch.onnx.export(
    model,
    dummy_input,
    'resnet50.onnx',
    opset_version=11,  # 我一般用11或13
    input_names=['input'],
    output_names=['output'],
    dynamic_axes={'input': {0: 'batch_size'}}  # 支持动态batch
)

小技巧:导出时加上dynamic_axes参数,这样你的模型就能处理不同batch size的输入。我在做视频分析项目时,就因为没加这个参数,结果每帧都要重新导出模型,效率极低。

2.2.2 TensorRT:NVIDIA的加速神器

TensorRT是NVIDIA推出的推理优化引擎。它做了三件事:层融合、精度校准、内存优化。说白了就是把模型里能合并的计算合并,能降低精度的降低精度,让GPU跑得更快。

我曾经在一个自动驾驶项目里,把ResNet-50从ONNX转成TensorRT,推理速度提升了3倍。怎么做到的?

import tensorrt as trt

# 创建builder
logger = trt.Logger(trt.Logger.WARNING)
builder = trt.Builder(logger)

# 创建网络定义
network = builder.create_network(
    1 << int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH)
)

# 解析ONNX模型
parser = trt.OnnxParser(network, logger)
with open('resnet50.onnx', 'rb') as f:
    parser.parse(f.read())

# 构建引擎
config = builder.create_builder_config()
config.set_memory_pool_limit(trt.MemoryPoolType.WORKSPACE, 1 << 30)  # 1GB
serialized_engine = builder.build_serialized_network(network, config)

避坑指南:我曾经因为没设置EXPLICIT_BATCH标志,结果模型推理时batch size死活不对。后来查文档才发现,TensorRT 8.0之后必须显式指定batch维度。嗯,这个坑我替你们踩过了。

2.3 模型量化与压缩

2.3.1 为什么要量化?

你想想看,一个FP32的模型参数占4个字节,INT8只占1个字节。量化就是把模型从FP32变成INT8,体积直接缩小4倍,推理速度也能提升2-4倍。代价是什么?精度会掉一点点,但通常可以接受。

我个人的经验是:大部分CV模型量化后精度损失在1%以内。但NLP模型就比较敏感,尤其是BERT这类,量化后可能掉3-5个点。

2.3.2 量化的两种方式

方式 原理 适用场景 精度损失
训练后量化(PTQ) 用少量校准数据统计量化参数 大部分场景 较小
量化感知训练(QAT) 在训练中模拟量化误差 精度要求高的场景 极小

我在项目中遇到过这种情况:PTQ量化后模型精度掉了2%,客户不接受。后来换成QAT,精度只掉了0.3%,顺利交付。所以我的建议是:先试PTQ,不行再上QAT

2.3.3 模型压缩的其他手段

除了量化,还有几种压缩方法:

  • 剪枝:去掉不重要的权重连接。我试过剪掉30%的参数,精度几乎不变。
  • 知识蒸馏:用大模型教小模型。说白了就是「师傅带徒弟」。
  • 权重共享:让多个层共用同一组参数。

实战建议:别一上来就搞剪枝和蒸馏。先做量化,通常能解决80%的性能问题。如果还不够,再考虑更复杂的手段。我曾经在一个项目里,光量化就把推理速度从30ms降到了8ms,客户直接说「够了够了」。

2.4 本章小结

模型部署这件事,说难不难,说简单也不简单。核心就三点:

  1. 格式转换:ONNX是中间桥梁,TensorRT是加速利器
  2. 量化压缩:INT8量化是性价比最高的优化手段
  3. 工程思维:先跑通,再优化,别一上来就追求极致

我记得刚入行时,总觉得部署就是「调个API就完事」。后来被现实教育了——模型部署涉及硬件、框架、算子、内存管理一堆东西。但别怕,跟着这门课一步步来,你也能成为部署高手。

下章预告:我们会深入TensorRT的算子融合和动态shape处理,这些都是实战中绕不开的硬骨头。


公众号:蓝海资料掘金营,微信deep3321