知识复习 - Pytorch导出ONNX模型以及使用Netron进行ONNX模型的可视化

目录

1. 什么是ONNX格式?为什么要使用ONNX格式的模型?

2. Pytorch模型导出ONNX格式的基本方法

2.1. 使用Pytorch构建一个简单的CNN

2.2. 导出ONNX格式的CNN

2.3. 验证导出的ONNX模型

3. 使用Netron可视化导出的ONNX模型


1. 什么是ONNX格式?为什么要使用ONNX格式的模型?

Open Neural Network Exchange(ONNX)是一种开放的深度学习模型交换格式。ONNX格式可以实现不同框架(比如Pytorch和Tensorflow)之间的模型互操作和跨平台部署。使用ONNX格式可以还可以提高模型的推理效率,并有广泛的社区支持。

2. Pytorch模型导出ONNX格式的基本方法

2.1. 使用Pytorch构建一个简单的CNN

首先,用Pytorch定义一个简单的 CNN 模型,该模型包含两个卷积层、两个池化层和一个全连接层。将文件命名为SimpleCNN.py,代码如下:

import torch
import torch.nn as nn
 
# 定义一个简单的卷积神经网络
class SimpleCNN(nn.Module):
    def __init__(self):
        super(SimpleCNN, self).__init__()
        self.conv1 = nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1)  # 输入1通道(灰度图),输出32通道
        self.conv2 = nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1)  # 输入32通道,输出64通道
        self.fc1 = nn.Linear(64 * 7 * 7, 128)  # 64个7x7特征图展平后传入全连接层
        self.fc2 = nn.Linear(128, 10)  # 最终输出10个类别
 
    def forward(self, x):
        x = torch.relu(self.conv1(x))
        x = torch.max_pool2d(x, 2)  # 池化层,2x2
        x = torch.relu(self.conv2(x))
        x = torch.max_pool2d(x, 2)
        x = x.view(x.size(0), -1)  # 展平操作
        x = torch.relu(self.fc1(x))
        x = self.fc2(x)
        return x

这是非常基本的Pytorch编程,这里不再赘述。不明白的小伙伴可以参考Pytorch的入门教程,网络上有很多。

2.2. 导出ONNX格式的CNN

Pytorch模型导出ONNX格式有很多细节与注意事项,比如是否有多个输入,是否有动态维度等等。这里暂时只考虑有单个输入和输出的静态模型,更复杂的情况在之后的文章中讨论。注意这里需要建立一个伪输入张量(dummy_input)来模拟模型的输入。

import torch.onnx
from SimpleCNN import SimpleCNN

# 创建CNN模型
model = SimpleCNN()

# 将模型设置为评估模式(至关重要)
model.eval()

# 创建一个输入张量(假设输入为 1 个 28x28 的灰度图像)
dummy_input = torch.randn(1, 1, 28, 28)  # batch_size=1, 1通道,28x28的图像
 
# 导出为 ONNX 格式
onnx_file_path = "simple_cnn.onnx"
torch.onnx.export(model,               # 要导出的模型
                dummy_input,         # 模型的输入
                onnx_file_path,      # 导出文件的路径
                export_params=True,  # 是否导出模型参数
                opset_version=12,    # ONNX 的操作集版本
                input_names=["input"],  # 输入层名称
                output_names=["output"],
                dynamic_axes={"input": {0: "batch_size"},  # 支持动态 batch_size
                              "output": {0: "batch_size"}})  # 输出层名称

如代码中所示,torch.onnx.export() 方法有很多参数。这里我们需要注意的是 opset_version 和 dynamic_axes 参数。前者决定了 ONNX 操作集的版本,最新版为13;后者决定了导出的 ONNX 模型使用的是静态的还是动态的输入与输出。当然,我们可以把所有的输入和输出都设置为动态的,这样在使用起来很方便。但是这样会影响 ONNX 模型的推理速度,所以还是需要根据实际的情况谨慎选择。

2.3. 验证导出的ONNX模型

在模型导出后,可以使用 onnx 库(注意不是torch.onnx)加载和验证 ONNX 格式的模型,代码如下:

import onnx

# 加载 ONNX 模型
onnx_model = onnx.load('./simple_cnn.onnx')

# 验证模型
onnx.checker.check_model(onnx_model)
print("ONNX 模型验证通过!")

onnx.checker.check_model 检查导出的 ONNX 模型的一致性,即模型在结构、格式和配置方面的正确性和完整性。

3. 使用Netron可视化导出的ONNX模型

ONNX格式并不像Pytorch源代码一样可以直接解读,需要额外的工具来进行模型可视化。Netron是一款非常好用的模型可视化工具,支持ONNX格式。Netron工具可以在线运行https://netron.app/。打开主页,直接加载导出的ONNX文件,ONNX模型的结构便会显示出来。

我们可以看到,Netron显示的ONNX模型结构和Pytorch源代码构造的模型结构完全一样。 

### 使用ONNX生成模型预测结果的可视化热力图 对于YOLOv8这样的目标检测模型,其可视化热力图可以将预测边界框和置信度以图形形式展现出来[^1]。然而,在处理通用ONNX模型时,为了生成类似的可视化热力图,通常采用特定的技术手段。 #### 方法一:基于Grad-CAM实现热力图 一种流行的方式是利用梯度加权类激活映射(Grad-CAM),这种方法能够突出显示输入图像中哪些部分对网络决策贡献最大。具体来说: - 首先加载预训练好的ONNX模型并准备测试数据集; - 接着计算选定类别得分相对于最后一层卷积特征图的梯度; - 计算全局平均池化后的权重向量并与相应位置处的特征响应相乘得到重要性分数矩阵; - 将上述矩阵上采样至原图尺寸即获得最终热力图表示; 以下是Python环境下使用`onnxruntime`库配合PyTorch框架来执行此过程的一个简单例子: ```python import torch from torchvision import models, transforms import onnxruntime as ort import numpy as np import cv2 def preprocess_image(img_path): transform = transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ]) img = Image.open(img_path).convert('RGB') input_tensor = transform(img) return input_tensor.unsqueeze(0) model_onnx = "path_to_your_model.onnx" img_path = 'test.jpg' session = ort.InferenceSession(model_onnx) input_name = session.get_inputs()[0].name output_names = ["output"] preprocessed_img = preprocess_image(img_path) outputs = session.run(output_names, {input_name: preprocessed_img.numpy()}) # Assuming the model outputs logits directly without softmax activation. logits = torch.tensor(outputs[0]) target_class_idx = int(torch.argmax(logits)) grad_cam = GradCAM(model=session, target_layer='last_conv_layer', use_cuda=True if 'CUDAExecutionProvider' in ort.get_available_providers() else False) heatmap = grad_cam(preprocessed_img, class_idx=target_class_idx)[0] original_img = cv2.imread(img_path) overlayed_heatmap = overlay_heatmap(original_img, heatmap) cv2.imshow("Heat Map", overlayed_heatmap) cv2.waitKey() ``` 注意这段代码假设读者已经安装好了必要的依赖包,并且熟悉基本的操作流程。此外,“last_conv_layer”的名称需根据实际使用的神经网络架构调整为最后一个卷基层的名字。 #### 方法二:直接解析ONNX文件结构 另一种途径涉及直接分析ONNX文件内部结构,找到负责输出分类概率分布的那个节点及其前置运算单元——通常是全连接层之前的某个卷积层。一旦定位到这些组件,则可以通过读取它们之间的中间状态来进行后续处理,比如构建热力图等视觉效果。 不过这种方式相对复杂一些,因为它不仅要求使用者具备较强的编程能力,还需要深入了解所研究的具体深度学习算法原理以及对应的ONNX表达方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

方博士AI机器人

您的鼓励将是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值