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 为什么需要模型转换?
这个问题,我在项目里被问过无数次。其实原因很直接:训练环境和部署环境,天生就是两码事。
我总结了一下,主要有这么几个原因:
- 框架差异:训练时用 PyTorch 最顺手,但线上推理可能要求 TensorFlow 或 ONNX。跨框架迁移是家常便饭。
- 硬件限制:服务器上有大显存的 GPU,但手机、嵌入式设备资源有限。模型必须压缩、量化才能塞进去。
- 推理优化:训练框架(比如 PyTorch)本身不是为高性能推理设计的。TensorRT、OpenVINO 这些推理引擎,能把模型优化到极致。
- 部署标准化: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)
我的建议:端侧部署时,先做量化,再考虑剪枝。量化是性价比最高的优化手段,几乎不损失精度,但收益巨大。剪枝和蒸馏需要更多调参,适合对模型大小有极致要求的场景。
小结
好了,这一章我们聊了模型转换是什么、为什么需要它、以及三个最常见的转换场景。
总结一下:
- 模型转换 = 格式转换 + 计算图优化 + 精度调整 + 内存布局适配
- 为什么需要:训练环境和部署环境天然不同,框架、硬件、性能要求都不一样
- 三大场景:训练到推理、跨框架迁移、端侧部署
下一章,我们会深入模型转换的核心——计算图与算子映射。到时候我会拿一个实际项目中的踩坑案例,带大家看看算子映射到底有多坑,以及怎么填坑。
咱们下章见。