4. PyTorch模型直接转换为TFLite
任务目标
将PyTorch训练好的模型转换为TFLite格式,以便在移动端或边缘设备上部署。本案例以经典CNN分类模型为例,走通 PyTorch → ONNX → TensorFlow → TFLite 的完整转换链路,并验证转换后的TFLite模型推理结果与原始PyTorch模型一致。
环境依赖
- PyTorch ≥ 1.10(含
torch.onnx.export) - ONNX ≥ 1.12(
onnx与onnx2tf) - TensorFlow ≥ 2.8(含
tf.lite.TFLiteConverter) - 安装:
pip install onnx onnx2tf tensorflow
实现步骤与代码
核心思路:先用 torch.onnx.export 将PyTorch模型固化为ONNX,再用 onnx2tf 将ONNX转为TensorFlow SavedModel,最后用 TFLiteConverter 生成TFLite文件。以下代码一次完成全流程,并包含输入输出张量形状对齐与推理验证。
import torch
import torch.nn as nn
import numpy as np
import onnx
import tensorflow as tf
import os
# ---------- 1. 定义并训练一个极简PyTorch模型(演示用) ----------
class SimpleCNN(nn.Module):
def __init__(self):
super().__init__()
self.conv = nn.Conv2d(1, 4, kernel_size=3, padding=1)
self.fc = nn.Linear(4 * 8 * 8, 10)
def forward(self, x):
x = torch.relu(self.conv(x))
x = torch.max_pool2d(x, 2) # 8x8
x = x.view(x.size(0), -1)
return self.fc(x)
model = SimpleCNN()
model.eval()
# 固定输入尺寸:batch=1, channel=1, H=W=16
dummy_input = torch.randn(1, 1, 16, 16)
# ---------- 2. PyTorch → ONNX ----------
onnx_path = "simple_cnn.onnx"
torch.onnx.export(
model, dummy_input, onnx_path,
input_names=["input"], output_names=["output"],
dynamic_axes=None, # 固定shape,便于TFLite转换
opset_version=13
)
# 验证ONNX模型结构完整性
onnx_model = onnx.load(onnx_path)
onnx.checker.check_model(onnx_model)
print("ONNX export OK")
# ---------- 3. ONNX → TensorFlow SavedModel ----------
# onnx2tf会保留输入输出名,并自动处理NHWC/NCHW转换
saved_model_dir = "saved_model"
os.makedirs(saved_model_dir, exist_ok=True)
os.system(f"onnx2tf -i {onnx_path} -o {saved_model_dir} -nuo 1")
# ---------- 4. TensorFlow → TFLite ----------
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.target_spec.supported_ops = [
tf.lite.OpsSet.TFLITE_BUILTINS,
tf.lite.OpsSet.SELECT_TF_OPS # 允许部分TF算子回退
]
tflite_model = converter.convert()
tflite_path = "simple_cnn.tflite"
with open(tflite_path, "wb") as f:
f.write(tflite_model)
print("TFLite conversion OK")
# ---------- 5. 推理验证:对比PyTorch与TFLite输出 ----------
# 准备相同输入
test_input = torch.randn(1, 1, 16, 16)
# PyTorch推理
with torch.no_grad():
pt_output = model(test_input).numpy()
# TFLite推理
interpreter = tf.lite.Interpreter(model_path=tflite_path)
interpreter.allocate_tensors()
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()
# 检查输入张量形状(TFLite通常为NHWC)
print("TFLite input shape:", input_details[0]['shape'])
tflite_input = test_input.numpy().transpose(0, 2, 3, 1) # NCHW→NHWC
interpreter.set_tensor(input_details[0]['index'], tflite_input)
interpreter.invoke()
tflite_output = interpreter.get_tensor(output_details[0]['index'])
# 比较输出(softmax前logits)
diff = np.abs(pt_output - tflite_output).max()
print(f"Max absolute difference: {diff:.6f}")
assert diff < 1e-4, "Output mismatch too large"
print("Verification PASSED: PyTorch and TFLite outputs match")
运行方式
- 将上述代码保存为
convert_pytorch_to_tflite.py,直接执行python convert_pytorch_to_tflite.py。 - 脚本运行结束后,当前目录应生成
simple_cnn.onnx、saved_model/目录和simple_cnn.tflite三个产物。
验证方法与判定标准
- 转换链路完整性:脚本依次打印
ONNX export OK和TFLite conversion OK,且无异常抛出。 - 推理一致性:脚本最后输出
Max absolute difference数值,并断言其小于1e-4。若断言通过,打印Verification PASSED,说明TFLite模型与原始PyTorch模型在相同输入下的输出误差在可接受范围内。 - 产物可用性:可用
Netron打开simple_cnn.tflite查看计算图结构,确认输入形状为[1, 16, 16, 1](NHWC),输出形状为[1, 10]。
常见问题
- 算子不支持:若转换时报错,可在
converter.target_spec.supported_ops中保留SELECT_TF_OPS(代码已包含),或尝试降低ONNX opset版本。 - 动态维度:本案例固定了batch和输入尺寸。若需动态batch,需在
torch.onnx.export中设置dynamic_axes,并在TFLite转换时确认推理引擎支持动态shape。 - 输入布局:PyTorch默认NCHW,TFLite通常使用NHWC。代码中已通过
transpose手动对齐,若使用onnx2tf的默认参数,其内部已处理布局转换,此处显式转置仅为确保一致性。