日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

PyTorch?模型?onnx?文件導出及調用詳情_python

作者:荷碧·TongZJ ? 更新時間: 2022-09-17 編程語言

前言

Open Neural Network Exchange (ONNX,開放神經網絡交換) 格式,是一個用于表示深度學習模型的標準,可使模型在不同框架之間進行轉移

PyTorch 所定義的模型為動態圖,其前向傳播是由類方法定義和實現的

但是 Python 代碼的效率是比較底下的,試想把動態圖轉化為靜態圖,模型的推理速度應當有所提升

PyTorch 框架中,torch.onnx.export 可以將父類為 nn.Module 的模型導出到 onnx 文件中,

最重要的有三個參數:

  • model:父類為 nn.Module 的模型
  • args:傳入 model 的 forward 方法的變量列表,類型應為
  • tuplef:onnx 文件名稱的字符串
import torch
from torchvision.models import resnet50
 
file = 'resnet.onnx'
# 聲明模型
resnet = resnet50(pretrained=False).eval()
image = torch.rand([1, 3, 224, 224])
# 導出為 onnx 文件
torch.onnx.export(resnet, (image,), file)

onnx 文件可被 Netron 打開,以查看模型結構

基本用法

要在 Python 中運行 onnx 模型,需要下載 onnxruntime

# 選其一即可
pip install onnxruntime        # CPU 版本
pip install onnxruntime-gpu    # GPU 版本

推理時需要借助其中的 InferenceSession,其中較為重要的實例方法有:

  • get_inputs():得到輸入變量的列表 (變量屬性:name、shape、type)
  • get_outputs():得到輸入變量的列表 (變量屬性:name、shape、type)run(output_names, input_feed):輸入變量為 numpy.ndarray (注意 dtype 應為 float32),使用模型推理并返回輸出

可得出 onnx 模型的基本用法:

import onnxruntime as ort
import numpy as np
file = 'resnet.onnx'
# 找到 GPU / CPU
provider = ort.get_available_providers()[
    1 if ort.get_device() == 'GPU' else 0]
print('設備:', provider)
# 聲明 onnx 模型
model = ort.InferenceSession(file, providers=[provider])
# 參考: ort.NodeArg
for node_list in model.get_inputs(), model.get_outputs():
    for node in node_list:
        attr = {'name': node.name,
                'shape': node.shape,
                'type': node.type}
        print(attr)
    print('-' * 60)
 
# 得到輸入、輸出結點的名稱
input_node_name = model.get_inputs()[0].name
ouput_node_name = [node.name for node in model.get_outputs()]
image = np.random.random([1, 3, 224, 224]).astype(np.float32)
print(model.run(output_names=ouput_node_name,
                input_feed={input_node_name: image}))

高級 API

為了簡化使用步驟,使用類進行封裝:

class Onnx_Module(ort.InferenceSession):
    ''' onnx 推理模型
        provider: 優先使用 GPU'''
    provider = ort.get_available_providers()[
        1 if ort.get_device() == 'GPU' else 0]
 
    def __init__(self, file):
        super(Onnx_Module, self).__init__(file, providers=[self.provider])
        # 參考: ort.NodeArg
        self.inputs = [node_arg.name for node_arg in self.get_inputs()]
        self.outputs = [node_arg.name for node_arg in self.get_outputs()]
 
    def __call__(self, *arrays):
        input_feed = {name: x for name, x in zip(self.inputs, arrays)}
        return self.run(self.outputs, input_feed)

在 PyTorch 中,對于卷積神經網絡 model 與圖像 image,推理的代碼為 "model(image)",而使用這個封裝的類也是類似:

import numpy as np
file = 'resnet.onnx'
model = Onnx_Module(file)
image = np.random.random([1, 3, 224, 224]).astype(np.float32)
print(model(image))

為了方便觀察 Torch 模型與 onnx 模型的速度差異,同時檢查兩個模型的輸出是否一致,又編寫了 test 函數

test 方法的參數與 torch.onnx.export 一致,其基本流程為:

  • 得到 Torch 模型的輸出,并 print 推斷耗時
  • 將 Torch 模型導出為 onnx 文件,將輸入變量中的 torch.tensor 轉化為 numpy.ndarray
  • 初始化 onnx 模型,得到 onnx?模型的輸出,并 print 推斷耗時
  • 計算 Torch 模型與 onnx 模型輸出的絕對誤差的均值
  • 將 onnx 模型 return
class Timer:
    repeat = 3
 
    def __new__(cls, fun, *args, **kwargs):
        import time
        start = time.time()
        for _ in range(cls.repeat): fun(*args, **kwargs)
        cost = (time.time() - start) / cls.repeat
        return cost * 1e3  # ms
 
 
class Onnx_Module(ort.InferenceSession):
    ''' onnx 推理模型
        provider: 優先使用 GPU'''
    provider = ort.get_available_providers()[
        1 if ort.get_device() == 'GPU' else 0]
 
    def __init__(self, file):
        super(Onnx_Module, self).__init__(file, providers=[self.provider])
        # 參考: ort.NodeArg
        self.inputs = [node_arg.name for node_arg in self.get_inputs()]
        self.outputs = [node_arg.name for node_arg in self.get_outputs()]
    def __call__(self, *arrays):
        input_feed = {name: x for name, x in zip(self.inputs, arrays)}
        return self.run(self.outputs, input_feed)
 
    @classmethod
    def test(cls, model, args, file, **export_kwargs):
        # 測試 Torch 的運行時間
        torch_output = model(*args).data.numpy()
        print(f'Torch: {Timer(model, *args):.2f} ms')
        # model: Torch -> onnx
        torch.onnx.export(model, args, file, **export_kwargs)
        # data: tensor -> array
        args = tuple(map(lambda tensor: tensor.data.numpy(), args))
        onnx_model = cls(file)
        # 測試 onnx 的運行時間
        onnx_output = onnx_model(*args)
        print(f'Onnx: {Timer(onnx_model, *args):.2f} ms')
        # 計算 Torch 模型與 onnx 模型輸出的絕對誤差
        abs_error = np.abs(torch_output - onnx_output).mean()
        print(f'Mean Error: {abs_error:.2f}')
        return onnx_model

對于 ResNet50 而言,Torch 模型的推斷耗時為 172.67 ms,onnx 模型的推斷耗時為 36.56 ms,onnx 模型的推斷耗時僅為 Torch 模型的 21.17%

原文鏈接:https://blog.csdn.net/qq_55745968/article/details/125965503

欄目分類
最近更新