赞
踩
本文主要介绍如何将PyTorch模型转换为ONNX模型,为后面的模型部署做准备。转换后的xxx.onnx模型,进行加载和测试。最后介绍使用Netron,可视化ONNX模型,看一下网络结构;查看使用了那些算子,以便开发部署。
目录
将PyTorch模型转换为ONNX模型,通常是使用torch.onnx.export( )函数来转换的,基本的思路是:
下面有一个简单的例子:
- import torch
- import torch.onnx
-
- # 加载 PyTorch 模型
- model = ...
-
- # 设置模型输入,包括:通道数,分辨率等
- dummy_input = torch.randn(1, 3, 224, 224, device='cpu')
-
- # 转换为ONNX模型
- torch.onnx.export(model, dummy_input, "model.onnx", export_params=True)
这里举一个resnet18的例子,基本思路是:
torch.randn()
函数生成了一个随机张量。onnx.export()
函数将 PyTorch 模型转换为 ONNX 格式,并将其保存到指定的输出文件中。程序如下:
- import torch
- import torchvision.models as models
-
- # 加载预训练的 ResNet18 模型
- model = models.resnet18(pretrained=True)
-
- # 将模型设置为评估模式
- model.eval()
-
- # 定义输入张量,需要与模型的输入张量形状相同
- input_shape = (1, 3, 224, 224)
- x = torch.randn(input_shape)
-
-
- # 需要指定输入张量,输出文件路径和运行设备
- # 默认情况下,输出张量的名称将基于模型中的名称自动分配
- device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
-
- # 将 PyTorch 模型转换为 ONNX 格式
- output_file = "resnet18.onnx"
- torch.onnx.export(model, x.to(device), output_file, export_params=True)

举一个resnet18的例子:基本思路是:
onnx.export()
函数将 PyTorch 模型转换为 ONNX 格式;指定参数do_constant_folding=False,不加载模型的权重。- import torch
- import torchvision.models as models
-
- # 加载 PyTorch 模型
- model = models.resnet18()
-
- # 将模型转换为 ONNX 格式但不加载权重
- dummy_input = torch.randn(1, 3, 224, 224)
- torch.onnx.export(model, dummy_input, "resnet18.onnx", do_constant_folding=False)
下面构建一个简单网络结构,并转换为ONNX
- import torch
- import torchvision
- import numpy as np
-
- # 定义一个简单的PyTorch 模型
- class MyModel(torch.nn.Module):
- def __init__(self):
- super(MyModel, self).__init__()
- self.conv1 = torch.nn.Conv2d(3, 32, kernel_size=3, stride=1, padding=1)
- self.relu = torch.nn.ReLU()
- self.maxpool = torch.nn.MaxPool2d(kernel_size=2, stride=2)
- self.conv2 = torch.nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1)
- self.flatten = torch.nn.Flatten()
- self.fc1 = torch.nn.Linear(64 * 8 * 8, 10)
-
- def forward(self, x):
- x = self.conv1(x)
- x = self.relu(x)
- x = self.maxpool(x)
- x = self.conv2(x)
- x = self.relu(x)
- x = self.maxpool(x)
- x = self.flatten(x)
- x = self.fc1(x)
- return x
-
- # 创建模型实例
- model = MyModel()
-
- # 指定模型输入尺寸
- dummy_input = torch.randn(1, 3, 32, 32)
-
- # 将PyTorch模型转为ONNX模型
- torch.onnx.export(model, dummy_input, 'mymodel.onnx', do_constant_folding=False)

看一下这个函数的参数
- torch.onnx.export(
- model,
- args,
- f,
- export_params=True,
- opset_version=10,
- do_constant_folding=True,
- input_names=['input'],
- output_names=['output'],
- dynamic_axes=None,
- verbose=False,
- example_outputs=None,
- keep_initializers_as_inputs=None)
model
:需要导出的 PyTorch 模型args
:PyTorch模型输入数据的尺寸,指定通道数、长和宽。可以是单个 Tensor 或元组,也可以是元组列表。f
:导出的 ONNX 文件路径和名称,mymodel.onnx。export_params
:是否导出模型参数。如果设置为 False,则不导出模型参数。opset_version
:导出的 ONNX 版本。默认值为 10。do_constant_folding
:是否对模型进行常量折叠。如果设置为 True,不加载模型的权重。input_names
:模型输入数据的名称。默认为 'input'。output_names
:模型输出数据的名称。默认为 'output'。dynamic_axes
:动态轴的列表,允许在导出的 ONNX 模型中创建变化的维度。verbose
:是否输出详细的导出信息。example_outputs
:用于确定导出 ONNX 模型输出形状的样本输出。keep_initializers_as_inputs
:是否将模型的初始化器作为输入导出。如果设置为 True,则模型初始化器将被作为输入的一部分导出。
下面是只是一个常用的模板
- import torch.onnx
-
- # 转为ONNX
- def Convert_ONNX(model):
-
- # 设置模型为推理模式
- model.eval()
-
- # 设置模型输入的尺寸
- dummy_input = torch.randn(1, input_size, requires_grad=True)
-
- # 导出ONNX模型
- torch.onnx.export(model, # model being run
- dummy_input, # model input (or a tuple for multiple inputs)
- "xxx.onnx", # where to save the model
- export_params=True, # store the trained parameter weights inside the model file
- opset_version=10, # the ONNX version to export the model to
- do_constant_folding=True, # whether to execute constant folding for optimization
- input_names = ['modelInput'], # the model's input names
- output_names = ['modelOutput'], # the model's output names
- dynamic_axes={'modelInput' : {0 : 'batch_size'}, # variable length axes
- 'modelOutput' : {0 : 'batch_size'}})
- print(" ")
- print('Model has been converted to ONNX')
-
-
- if __name__ == "__main__":
-
- # 构建模型并训练
- # xxxxxxxxxxxx
-
- # 测试模型精度
- #testAccuracy()
-
- # 加载模型结构与权重
- model = Network()
- path = "myFirstModel.pth"
- model.load_state_dict(torch.load(path))
-
- # 转换为ONNX
- Convert_ONNX(model)

加载ONNX模型,通常需要用到ONNX、ONNX Runtime,所以需要先安装。
pip install onnx
pip install onnxruntime
加载ONNX模型可以使用ONNX Runtime库,以下是一个加载ONNX模型的示例代码:
- import onnxruntime as ort
-
- # 加载 ONNX 模型
- ort_session = ort.InferenceSession("model.onnx")
-
- # 准备输入信息
- input_info = ort_session.get_inputs()[0]
- input_name = input_info.name
- input_shape = input_info.shape
- input_type = input_info.type
-
-
- # 运行ONNX模型
- outputs = ort_session.run(input_name, input_data)
-
- # 获取输出信息
- output_info = ort_session.get_outputs()[0]
- output_name = output_info.name
- output_shape = output_info.shape
- output_data = outputs[0]
-
- print("outputs:", outputs)
- print("output_info :", output_info )
- print("output_name :", output_name )
- print("output_shape :", output_shape )
- print("output_data :", output_data )

以下是一个示例程序,将 resnet18 模型从 PyTorch 转换为 ONNX 格式,然后加载和测试 ONNX 模型的过程:
- import torch
- import torchvision.models as models
- import onnx
- import onnxruntime
-
- # 加载 PyTorch 模型
- model = models.resnet18(pretrained=True)
- model.eval()
-
- # 定义输入和输出张量的名称和形状
- input_names = ["input"]
- output_names = ["output"]
- batch_size = 1
- input_shape = (batch_size, 3, 224, 224)
- output_shape = (batch_size, 1000)
-
- # 将 PyTorch 模型转换为 ONNX 格式
- torch.onnx.export(
- model, # 要转换的 PyTorch 模型
- torch.randn(input_shape), # 模型输入的随机张量
- "resnet18.onnx", # 保存的 ONNX 模型的文件名
- input_names=input_names, # 输入张量的名称
- output_names=output_names, # 输出张量的名称
- dynamic_axes={input_names[0]: {0: "batch_size"}, output_names[0]: {0: "batch_size"}} # 动态轴,即输入和输出张量可以具有不同的批次大小
- )
-
- # 加载 ONNX 模型
- onnx_model = onnx.load("resnet18.onnx")
- onnx_model_graph = onnx_model.graph
- onnx_session = onnxruntime.InferenceSession(onnx_model.SerializeToString())
-
- # 使用随机张量测试 ONNX 模型
- x = torch.randn(input_shape).numpy()
- onnx_output = onnx_session.run(output_names, {input_names[0]: x})[0]
-
- print(f"PyTorch output: {model(torch.from_numpy(x)).detach().numpy()[0, :5]}")
- print(f"ONNX output: {onnx_output[0, :5]}")

上述代码中,首先加载预训练的 resnet18 模型,并定义了输入和输出张量的名称和形状。
然后,使用 torch.onnx.export() 函数将模型转换为 ONNX 格式,并保存为 resnet18.onnx 文件。
接着,使用 onnxruntime.InferenceSession() 函数加载 ONNX 模型,并使用随机张量进行测试。
最后,将 PyTorch 模型和 ONNX 模型的输出进行比较,以确保它们具有相似的输出。
使用Netron,可视化ONNX模型,看一下网络结构;查看使用了那些算子,以便开发部署。
这里简单介绍一下
Netron是一个轻量级、跨平台的模型可视化工具,支持多种深度学习框架的模型可视化,包括TensorFlow、PyTorch、ONNX、Keras、Caffe等等。它提供了可视化网络结构、层次关系、输出尺寸、权重等信息,并且可以通过鼠标移动和缩放来浏览模型。Netron还支持模型的导出和导入,方便模型的分享和交流。
Netron的网页在线版本,直接在网页中打开和查看ONNX模型Netron
支持多种操作系统:
macOS: Download
Linux: Download
Windows: Download
Browser: Start
Python Server: Run pip install netron
and netron [FILE]
or netron.start('[FILE]')
.
下面是可视化模型截图:
还能查看某个节点(运算操作)的信息,比如下面MaxPool,点击一下,能看到使用的3x3的池化核,是否有填充pads,步长strides等参数。
分享完毕~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。