1、模型转换概述:什么是模型转换、为什么需要模型转换、常见转换场景

大家好,我是你们这门课的老朋友。今天咱们正式开篇,聊聊模型转换。

说实话,我刚开始做深度学习那会儿,压根没把模型转换当回事。总觉得训练出一个高精度的模型,任务就完成了。直到有一次,我把一个训练好的 PyTorch 模型直接丢到生产环境的 C++ 推理引擎里……嗯,结果你们应该猜到了,跑不起来。那叫一个尴尬。

从那以后,我养成了一个习惯:训练完模型的第一件事,不是庆祝,而是想清楚它最终要在哪跑、怎么跑。 这就是模型转换要解决的核心问题。

1.1 什么是模型转换?

说白了,模型转换就是把一个框架下训练好的模型,变成另一个框架或平台能认得的格式。

举个例子:你用 PyTorch 写了个图像分类模型,训练完保存成 .pth 文件。但生产环境用的是 TensorFlow Serving,或者要部署到手机端。这时候,你就得把 .pth 转成 .pb 或者 .tflite。这个过程,就是模型转换。

你可能会问:“不就是换个文件后缀吗?有那么复杂?”

还真不是。模型转换不仅仅是格式的变换,它涉及:

  • 算子映射:PyTorch 的 Conv2d 和 TensorFlow 的 Conv2D,底层实现细节不一样
  • 计算图优化:去掉训练时才需要的 dropout、BN 层,合并一些算子
  • 精度调整:从 FP32 降到 FP16 甚至 INT8,速度能快好几倍
  • 内存布局:不同硬件对张量存储顺序的要求不同(NCHW vs NHWC)

核心要点:模型转换不是简单的格式转换,而是一个适配目标运行环境的优化过程。你转换后的模型,不仅要能跑,还要跑得快、跑得稳。

1.2 为什么需要模型转换?

这个问题,我在项目里被问过无数次。其实原因很直接:训练环境和部署环境,天生就是两码事。

我总结了一下,主要有这么几个原因:

  1. 框架差异:训练时用 PyTorch 最顺手,但线上推理可能要求 TensorFlow 或 ONNX。跨框架迁移是家常便饭。
  2. 硬件限制:服务器上有大显存的 GPU,但手机、嵌入式设备资源有限。模型必须压缩、量化才能塞进去。
  3. 推理优化:训练框架(比如 PyTorch)本身不是为高性能推理设计的。TensorRT、OpenVINO 这些推理引擎,能把模型优化到极致。
  4. 部署标准化:ONNX 作为中间格式,能让模型在不同平台间自由流转。我习惯把 ONNX 当作“模型界的通用语言”。

我的经验:如果你只做研究、发论文,那模型转换可能不是刚需。但一旦涉及产品落地,模型转换就是绕不开的一步。我曾经因为没做转换优化,导致模型在端侧推理延迟高达 200ms,用户体验极差。后来做了 INT8 量化,直接降到 30ms。差距就是这么大。

1.3 常见转换场景

在实际工作中,模型转换主要出现在以下三个场景。我一个个说。

场景一:训练到推理

这是最常见的场景。训练好的模型要部署到生产环境,做实时推理。

训练时,模型需要反向传播、计算梯度,所以会保留很多中间变量。但推理时,这些都不需要了。转换过程中,我们会:

  • 去掉 Dropout、BatchNorm 的训练模式
  • 冻结权重,变成只读
  • 合并 Conv + BN 等连续算子,减少计算量

举个例子,PyTorch 模型转 ONNX:

import torch
import torch.onnx

# 假设 model 是训练好的 PyTorch 模型
model = torch.load('model.pth')
model.eval()  # 切换到推理模式

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

# 导出 ONNX
torch.onnx.export(
    model,
    dummy_input,
    'model.onnx',
    opset_version=11,
    input_names=['input'],
    output_names=['output']
)

你看,代码很简单。但背后做了很多事:计算图静态化、算子映射、常量折叠。这些细节,后面章节会深入讲。

场景二:跨框架迁移

团队里有人用 PyTorch,有人用 TensorFlow,还有人用 JAX。模型要共享,怎么办?

我的做法是:统一转成 ONNX 格式。ONNX 就像一个桥梁,连接了各大框架。

源框架 目标框架 常用工具
PyTorch → ONNX TensorFlow onnx-tf
TensorFlow → ONNX PyTorch tf2onnx
Keras → ONNX CoreML onnx-coreml

不过要注意,不是所有算子都能完美映射。有些自定义算子,ONNX 不支持,就得自己写扩展。我在一个项目中就遇到过 PyTorch 的 F.grid_sample 转 ONNX 失败的情况,最后不得不手动实现了一个替代方案。

避坑指南:跨框架迁移时,尽量使用标准算子。自定义算子越多,转换的坑就越多。我曾经因为一个自定义激活函数,折腾了两天才搞定 ONNX 导出。后来学乖了,能用 ReLU 就不用 Swish,能用标准 Conv 就不用 Depthwise Conv。

场景三:端侧部署

把模型部署到手机、摄像头、IoT 设备上,这是最考验模型转换功力的场景。

端侧设备的特点是:算力有限、内存小、功耗敏感。所以转换时,我们通常要做:

  • 量化:FP32 → INT8,模型体积缩小 4 倍,速度提升 2-4 倍
  • 剪枝:去掉不重要的连接,减少参数量
  • 蒸馏:用大模型教小模型,保持精度的同时缩小体积

以 Android 端部署为例,PyTorch 模型要转成 .ptl(PyTorch Lite)或 .tflite

# PyTorch → TorchScript → Android
import torch

model = torch.load('model.pth')
model.eval()

# 转成 TorchScript
scripted_model = torch.jit.script(model)
scripted_model.save('model.ptl')

# 然后放到 Android 项目里,用 PyTorch Android API 加载

如果是 TensorFlow 模型,转 TFLite 更直接:

import tensorflow as tf

# 加载 SavedModel 或 Keras 模型
model = tf.saved_model.load('saved_model')

# 转换并量化
converter = tf.lite.TFLiteConverter.from_saved_model('saved_model')
converter.optimizations = [tf.lite.Optimize.DEFAULT]
tflite_model = converter.convert()

# 保存
with open('model.tflite', 'wb') as f:
    f.write(tflite_model)

我的建议:端侧部署时,先做量化,再考虑剪枝。量化是性价比最高的优化手段,几乎不损失精度,但收益巨大。剪枝和蒸馏需要更多调参,适合对模型大小有极致要求的场景。

小结

好了,这一章我们聊了模型转换是什么、为什么需要它、以及三个最常见的转换场景。

总结一下:

  • 模型转换 = 格式转换 + 计算图优化 + 精度调整 + 内存布局适配
  • 为什么需要:训练环境和部署环境天然不同,框架、硬件、性能要求都不一样
  • 三大场景:训练到推理、跨框架迁移、端侧部署

下一章,我们会深入模型转换的核心——计算图与算子映射。到时候我会拿一个实际项目中的踩坑案例,带大家看看算子映射到底有多坑,以及怎么填坑。

咱们下章见。