pytorch模型转ONNX、并进行比较推理

pytorch模型转ONNX、并进行比较推理


在这里插入图片描述

pytorch模型转ONNX

概述

ONNX(Open Neural Network Exchange)是一种开放式的深度学习模型交换格式,旨在促进不同深度学习框架之间的互操作性。通过将深度学习模型转换为ONNX格式,可以将其从一个深度学习框架移植到另一个框架中,而无需重新训练模型或手动重新实现模型结构。

ONNX是由微软和Facebook于2017年联合发布的,目前得到了众多公司和社区的支持和贡献。ONNX格式支持多种深度学习模型类型,包括卷积神经网络(CNN)、循环神经网络(RNN)和变换器(Transformer)等。

在使用ONNX时,通常需要两个步骤:模型的导出和模型的导入。首先,将模型从一个深度学习框架中导出到ONNX格式。导出后,可以使用ONNX运行时(ONNX Runtime)或其他支持ONNX格式的深度学习框架将模型导入到所需的平台中进行推理。

在导出模型时,需要注意确保模型的兼容性。由于每个框架实现深度学习算法的方式不同,因此在转换模型时可能会出现一些限制或不兼容性。此外,由于ONNX不支持某些框架特有的操作或层,因此在导出模型时可能需要进行一些自定义操作或调整模型结构,以便使模型兼容ONNX格式。

总的来说,ONNX是一个非常有用的工具,可以简化深度学习模型的转换和部署过程,促进不同框架之间的互操作性和合作。

PT转ONNX

import torch
import onnx
import onnxruntime
from efficient_net import build_model


# Step 1: 加载 PyTorch 模型
# model = EfficientNet.from_pretrained('efficientnet-b0')
model = build_model(model_name="efficientnet-b2",weights_path="ef_classify/models/best.pt", num_classes=2)
model.eval()

# Step 2: 将模型转换为 ONNX 格式(包含动态批次)
output_path = "efficientnet-b2.onnx"  # ONNX 模型保存路径

# 导出 ONNX 模型
dummy_input = torch.randn(1, 3, 260, 260)
dynamic_axes = {
    
    'input': {
    
    0: 'batch_size'}, 'output': {
    
    0: 'batch_size'}}
torch.onnx.export(model, dummy_input, output_path, verbose=True, input_names=['input'], output_names=['output'],
                  dynamic_axes=dynamic_axes)

比较PT和ONNX

要比较转换后的ONNX模型和原始的PyTorch模型之间的差异,可以使用ONNX Runtime工具包。

  1. 加载模型:在使用ONNX Runtime进行模型比较之前,您需要加载PyTorch模型和转换后的ONNX模型。您可以使用PyTorch或ONNX Runtime加载模型。
# 加载 PyTorch 模型
import torch
from efficient_net import build_model
# model_pt = torch.load('model.pt')
model_pt = build_model(model_name="efficientnet-b2",weights_path="ef_classify/models/best.pt", num_classes=2)

# 加载转换后的 ONNX 模型
import onnxruntime as ort
model_onnx = ort.InferenceSession('efficientnet-b2.onnx',providers=['CUDAExecutionProvider', 'CPUExecutionProvider'])
  1. 输入数据:为了比较模型,需要提供相同的输入数据。可以生成一些随机数据并将其提供给模型进行比较。
import numpy as np
input_shape = (1, 3, 260, 260)
input_data = np.random.random(input_shape).astype(np.float32)
  1. 推理和比较:使用PyTorch和ONNX Runtime对相同的输入数据进行推理并比较输出结果。如果输出相同,则说明两个模型在这些输入数据上是等价的。
# 使用 PyTorch 进行推理
model_pt.eval()
with torch.no_grad():
    output_pt = model_pt(torch.tensor(input_data))

# 使用 ONNX Runtime 进行推理
output_onnx = model_onnx.run(None, {
    
    'input': input_data})[0]

# 比较输出结果
if np.allclose(output_pt.numpy(), output_onnx, rtol=1e-3, atol=1e-5):
    print("模型输出相同!")
else:
    print("模型输出不同!")

使用这种方法,可以比较转换后的ONNX模型和原始的PyTorch模型在相同输入数据上的输出结果是否相同,从而评估模型的差距。

ONNX批量推理图片

在下面的代码中,我们使用了一个批处理的方式来进行推理。我们首先获取了所有图像文件的路径,然后将其分成了多个大小为batch_size的批次进行推理。在每个批次中,我们将多张图像一次性输入模型进行推理,并将输出结果保存在outputs列表中。最后,我们将所有输出结果合并并输出每个图像的预测结果。

import os
import cv2
import numpy as np
import onnxruntime as ort

# 加载ONNX模型
model_path = "efficientnet-b2.onnx"
session =  ort.InferenceSession(model_path,providers=['CUDAExecutionProvider', 'CPUExecutionProvider'])

input_name = session.get_inputs()[0].name

# 获取所有图像文件的路径
images_path = "ef_classify/dataset/dog"
image_paths = [os.path.join(images_path, f) for f in os.listdir(images_path) if os.path.isfile(os.path.join(images_path, f))]


# 批量读取、预处理和推理图像
batch_size = 8
outputs = []
for i in range(0, len(image_paths), batch_size):
    batch_images = []
    for image_path in image_paths[i:i+batch_size]:
        # 读取图像并进行预处理
        image = cv2.imread(image_path)
        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        image = cv2.resize(image, (260, 260))
        img = image.astype(np.float32)
        
        img /= 255.0
        img_mean = (0.485,0.456,0.406)
        img_std = (0.229,0.224,0.225)
        img = img - img_mean
        img = (img/img_std)

        image = img.transpose((2, 0, 1))
        image = np.expand_dims(image, axis=0).astype(np.float32)
        batch_images.append(image)

    # 进行推理并保存输出结果
    batch_images = np.concatenate(batch_images, axis=0)
    batch_outputs = session.run(None, {
    
    input_name: batch_images})
    outputs.append(batch_outputs[0])

# 将所有输出结果合并并输出每个图像的预测结果
outputs = np.concatenate(outputs, axis=0)
for i, image_path in enumerate(image_paths):
    predicted_class = np.argmax(outputs[i])
    print(f"Image: {
      
      image_path} - Predicted Class: {
      
      predicted_class}")

猜你喜欢

转载自blog.csdn.net/qq128252/article/details/129792240