Q
什么是ONNX?
ONNX(Open Neural Network Exchange)- 開(kāi)放神經(jīng)網(wǎng)絡(luò)交換格式,作為框架共用的一種模型交換格式,使用protobuf 二進(jìn)制格式來(lái)序列化模型,可以提供更好的傳輸性能我們可能會(huì)在某一任務(wù)中Pytorch或者TensorFlow模型轉(zhuǎn)化為ONNX模型(ONNX模型一般用于中間部署階段),然后再拿轉(zhuǎn)化后的ONNX模型進(jìn)而轉(zhuǎn)化為我們使用不同框架部署需要的類(lèi)型,ONNX相當(dāng)于一個(gè)翻譯的作用。
Q
為什么要用ONNX?
深度學(xué)習(xí)算法大多通過(guò)計(jì)算數(shù)據(jù)流圖來(lái)完成神經(jīng)網(wǎng)絡(luò)的深度學(xué)習(xí)過(guò)程。一些框架(例如CNTK,Caffe2,Theano和TensorFlow)使用靜態(tài)圖形,而其他框架(例如PyTorch和Chainer)使用動(dòng)態(tài)圖形。但是這些框架都提供了接口,使開(kāi)發(fā)人員可以輕松構(gòu)建計(jì)算圖和運(yùn)行時(shí),以優(yōu)化的方式處理圖。這些圖用作中間表示(IR),捕獲開(kāi)發(fā)人員源代碼的特定意圖,有助于優(yōu)化和轉(zhuǎn)換在特定設(shè)備(CPU,GPU,FPGA等)上運(yùn)行。假設(shè)一個(gè)場(chǎng)景:現(xiàn)在某組織因?yàn)橹饕_(kāi)發(fā)用TensorFlow為基礎(chǔ)的框架,現(xiàn)在有一個(gè)深度算法,需要將其部署在移動(dòng)設(shè)備上,以觀測(cè)變現(xiàn)。傳統(tǒng)地我們需要用Caffe2重新將模型寫(xiě)好,然后再訓(xùn)練參數(shù);試想下這將是一個(gè)多么耗時(shí)耗力的過(guò)程。此時(shí),ONNX便應(yīng)運(yùn)而生,Caffe2,PyTorch,Microsoft Cognitive Toolkit,Apache MXNet等主流框架都對(duì)ONNX有著不同程度的支持。這就便于我們的算法及模型在不同框架之間的遷移。
ONNX結(jié)構(gòu)分析
ONNX將每一個(gè)網(wǎng)絡(luò)的每一層或者說(shuō)是每一個(gè)算子當(dāng)作節(jié)點(diǎn)Node,再由這些Node去構(gòu)建一個(gè)Graph,相當(dāng)于是一個(gè)網(wǎng)絡(luò)。最后將Graph和這個(gè)ONNX模型的其他信息結(jié)合在一起,生成一個(gè)Model,也就是最終的.onnx的模型。構(gòu)建一個(gè)簡(jiǎn)單的ONNX模型,實(shí)質(zhì)上,只要構(gòu)建好每一個(gè)node,然后將它們和輸入輸出超參數(shù)一起塞到Graph,最后轉(zhuǎn)成Model就可以了。
graph{
node{
input: "1"
input: "2"
output: "12"
op_type: "Conv"
}
attribute{
name: "strides"
ints: 1
ints: 1
}
attribute{
name: "pads"
ints: 2
ints: 2
}
...
}
我們查看ONNX網(wǎng)絡(luò)結(jié)構(gòu)和參數(shù)(查看網(wǎng)址:https://netron.app/)

ONNX安裝、使用
安裝ONNX環(huán)境,在終端中執(zhí)行以下命令,環(huán)境中需要提前準(zhǔn)本 python3.6. 以下流程以u(píng)bunt 20.04 為例。
模型轉(zhuǎn)換流程
超分辨率是一種提高圖像、視頻分辨率的算法,廣泛用于圖像處理或視頻編輯。首先,讓我們?cè)赑yTorch中創(chuàng)建一個(gè)SuperResolution 模型。該模型使用描述的高效子像素卷積層將圖像的分辨率提高了一個(gè)放大因子。該模型將圖像的YCbCr的Y分量作為輸入,并以超分辨率輸出放大的Y分量。
# Some standard imports
import io
import numpy as np
from torch import nn
import torch.utils.model_zoo as model_zoo
import torch.onnx
# Super Resolution model definition in PyTorch
import torch.nn as nn
import torch.nn.init as init
class SuperResolutionNet(nn.Module):
def __init__(self, upscale_factor, inplace=False):
super(SuperResolutionNet, self).__init__()
self.relu = nn.ReLU(inplace=inplace)
self.conv1 = nn.Conv2d(1, 64, (5, 5), (1, 1), (2, 2))
self.conv2 = nn.Conv2d(64, 64, (3, 3), (1, 1), (1, 1))
self.conv3 = nn.Conv2d(64, 32, (3, 3), (1, 1), (1, 1))
self.conv4 = nn.Conv2d(32, upscale_factor ** 2, (3, 3), (1, 1), (1, 1))
self.pixel_shuffle = nn.PixelShuffle(upscale_factor)
self._initialize_weights()
def forward(self, x):
x = self.relu(self.conv1(x))
x = self.relu(self.conv2(x))
x = self.relu(self.conv3(x))
x = self.pixel_shuffle(self.conv4(x))
return x
def _initialize_weights(self):
init.orthogonal_(self.conv1.weight, init.calculate_gain('relu'))
init.orthogonal_(self.conv2.weight, init.calculate_gain('relu'))
init.orthogonal_(self.conv3.weight, init.calculate_gain('relu'))
init.orthogonal_(self.conv4.weight)
# Create the super-resolution model by using the above model definition.
torch_model = SuperResolutionNet(upscale_factor=3)
1
模型下載
由于本教程以演示為目的,因此采用下載預(yù)先訓(xùn)練好的權(quán)重。在導(dǎo)出模型之前調(diào)用torch_model.eval()或torch_model.train(False)將模型轉(zhuǎn)換為推理模式很重要。因?yàn)閐ropout或batchnorm等運(yùn)算符在推理和訓(xùn)練模式下的行為不同。
# Load pretrained model weights model_url = 'https://s3.amazonaws.com/pytorch/test_data/export/superres_epoch100-44c6958e.pth' batch_size = 1 # just a random number # Initialize model with the pretrained weights map_location = lambda storage, loc: storage if torch.cuda.is_available(): map_location = None torch_model.load_state_dict(model_zoo.load_url(model_url, map_location=map_location)) # set the model to inference mode torch_model.eval()
2
模型導(dǎo)出
要導(dǎo)出模型,我們調(diào)用該torch.onnx.export()函數(shù)。這將執(zhí)行模型,記錄用于計(jì)算輸出的運(yùn)算符。因?yàn)閑xport運(yùn)行模型,我們需要提供一個(gè)輸入張量x。只要它是正確的類(lèi)型和大小,其中的值可以是隨機(jī)的。請(qǐng)注意,除非指定為動(dòng)態(tài)軸,否則所有輸入維度的導(dǎo)出ONNX圖中的輸入大小將是固定的。在此示例中,我們使用batch_size 1的輸入導(dǎo)出模型,但隨后在dynamic_axes參數(shù)中將第一個(gè)維度指定為動(dòng)態(tài) torch.onnx.export() . 因此,導(dǎo)出的模型將接受大小為[batch_size, 1, 224, 224]的輸入,其中batch_size可以是可變的。
# Input to the model
x = torch.randn(batch_size, 1, 224, 224, requires_grad=True)
torch_out = torch_model(x)
# Export the model
torch.onnx.export(torch_model, # model being run
x, # model input (or a tuple for multiple inputs)
"super_resolution.onnx", # where to save the model (can be a file or file-like object)
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 = ['input'], # the model's input names
output_names = ['output'], # the model's output names
dynamic_axes={'input' : {0 : 'batch_size'}, # variable length axes
'output' : {0 : 'batch_size'}})
3
導(dǎo)出模型測(cè)試
在使用ONNX Runtime驗(yàn)證模型的輸出之前,我們將使用ONNX的 API檢查ONNX 模型。首先,onnx.load("super_resolution.onnx")將加載保存的模型并輸出 onnx.ModelProto結(jié)構(gòu)(用于捆綁 ML 模型的頂級(jí)文件/容器格式)。然后,onnx.checker.check_model(onnx_model)將驗(yàn)證模型的結(jié)構(gòu)并確認(rèn)模型具有有效的架構(gòu)。ONNX 圖的有效性通過(guò)檢查模型的版本、圖的結(jié)構(gòu)以及節(jié)點(diǎn)及其輸入和輸出來(lái)驗(yàn)證。
import onnx
onnx_model = onnx.load("super_resolution.onnx")
onnx.checker.check_model(onnx_model)
import onnxruntime
ort_session = onnxruntime.InferenceSession("super_resolution.onnx")
def to_numpy(tensor):
return tensor.detach().cpu().numpy() if tensor.requires_grad else tensor.cpu().numpy()
# compute ONNX Runtime output prediction
ort_inputs = {ort_session.get_inputs()[0].name: to_numpy(x)}
ort_outs = ort_session.run(None, ort_inputs)
# compare ONNX Runtime and PyTorch results
np.testing.assert_allclose(to_numpy(torch_out), ort_outs[0], rtol=1e-03, atol=1e-05)
print("Exported model has been tested with ONNXRuntime, and the result looks good!")
1.加載處理前圖片,使用標(biāo)準(zhǔn)PIL python庫(kù)對(duì)其進(jìn)行預(yù)處理。 2.調(diào)整圖像大小以適應(yīng)模型輸入的大小 (224x224)。
-
神經(jīng)網(wǎng)絡(luò)
+關(guān)注
關(guān)注
42文章
4838瀏覽量
107750 -
模型
+關(guān)注
關(guān)注
1文章
3751瀏覽量
52099 -
Graph
+關(guān)注
關(guān)注
0文章
36瀏覽量
9718
原文標(biāo)題:【技術(shù)基礎(chǔ)】使用ONNX使模型通用化
文章出處:【微信號(hào):FPGA創(chuàng)新中心,微信公眾號(hào):FPGA創(chuàng)新中心】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
將yolov5s的模型轉(zhuǎn)成.onnx模型,進(jìn)行cube-ai分析時(shí)報(bào)錯(cuò)的原因?
STM CUBE AI錯(cuò)誤導(dǎo)入onnx模型報(bào)錯(cuò)的原因?
導(dǎo)入keras或者onnx模型到cubeai進(jìn)行分析,為什么會(huì)報(bào)錯(cuò)?
為什么無(wú)法在OpenVINO? 2021.3源中使用CMAKE編譯ONNX模型?
深度探索ONNX模型部署 精選資料分享
ONNX的相關(guān)資料分享
如何使用Paddle2ONNX模型轉(zhuǎn)換工具將飛槳模型轉(zhuǎn)換為ONNX模型?
怎么解決rknntoolkit1.7.1轉(zhuǎn)onnx報(bào)錯(cuò)的問(wèn)題呢?
yolov7 onnx模型在NPU上太慢了怎么解決?
將TensorFlow Lite模型轉(zhuǎn)換為ONNX
手工優(yōu)化ncnn模型結(jié)構(gòu)
基于ONNX結(jié)構(gòu)分析
評(píng)論