建設(shè)網(wǎng)站策劃書鄭州seo顧問外包公司
文章目錄
- 1 背景介紹
- 2 實(shí)驗(yàn)環(huán)境
- 3 paddle.onnx.export函數(shù)簡介
- 4 代碼實(shí)操
- 4.1 PaddlePaddle與ONNX模型導(dǎo)出
- 4.2 ONNX正確性驗(yàn)證
- 4.3 PaddlePaddle與ONNX的一致性檢查
- 4.4 多輸入的情況
- 5 ONNX模型可視化
- 6 ir_version和opset_version修改
- 7 致謝
原文來自于地平線開發(fā)者社區(qū),未來會(huì)持續(xù)發(fā)布深度學(xué)習(xí)、板端部署的相關(guān)優(yōu)質(zhì)文章與視頻,如果文章對(duì)您有幫助,麻煩給點(diǎn)個(gè)贊,如果您有興趣一起學(xué)習(xí),歡迎點(diǎn)個(gè)關(guān)注:尋找永不遺憾(CSDN用戶名)
1 背景介紹
使用深度學(xué)習(xí)開源框架Pytorch訓(xùn)練完網(wǎng)絡(luò)模型后,在部署之前通常需要進(jìn)行格式轉(zhuǎn)換,地平線工具鏈模型轉(zhuǎn)換目前支持Caffe1.0和ONNX(opset_version=10/11 且 ir_version≤7)兩種。ONNX(Open Neural Network Exchange)格式是一種常用的開源神經(jīng)網(wǎng)絡(luò)格式,被較多推理引擎支持,例如Pytorch、PaddlePaddle、TensorFlow等。本文將詳細(xì)介紹如何將PaddlePaddle格式的模型導(dǎo)出到ONNX格式。
2 實(shí)驗(yàn)環(huán)境
本教程的實(shí)驗(yàn)環(huán)境如下:
Python庫 | Version |
---|---|
paddlepaddle | 2.4.1 |
paddle2onnx | 1.0.5 |
onnx | 1.13.0 |
onnxruntime | 1.14.0 |
3 paddle.onnx.export函數(shù)簡介
paddle.onnx.export函數(shù)可以將PaddlePaddle模型導(dǎo)出為ONNX模型,函數(shù)介紹如下,其中x_spec用于配置paddle.onnx.export的input_spec參數(shù)。
x_spec = paddle.static.InputSpec(shape=None, dtype='float32', name=None)
#shape: 聲明維度信息,默認(rèn)為 None
#dtype: 數(shù)據(jù)類型,默認(rèn)為 float32
#name: 網(wǎng)絡(luò)輸入節(jié)點(diǎn)名稱paddle.onnx.export(layer, path, input_spec=[x_spec], opset_version=11, **configs)
#layer: 導(dǎo)出的Layer對(duì)象,即需要轉(zhuǎn)換的網(wǎng)絡(luò)模型
#path: 存儲(chǔ)模型的路徑前綴,導(dǎo)出后會(huì)自動(dòng)添加后綴“.onnx”
#input_spec: 用于配置模型輸入屬性
#opset_version: 默認(rèn)為9,請(qǐng)手動(dòng)配置10或11
關(guān)于paddle.onnx.export的更多詳細(xì)介紹,可以查閱PaddlePaddle的API文檔:
https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/onnx/export_cn.html
4 代碼實(shí)操
4.1 PaddlePaddle與ONNX模型導(dǎo)出
以下代碼展示了搭建一個(gè)簡單分類模型并以PaddlePaddle和ONNX格式保存的過程。
import paddle
import paddle.nn as nnclass MyNet(nn.Layer):def __init__(self, num_classes=10):super(MyNet, self).__init__()self.num_classes = num_classesself.features = nn.Sequential(nn.Conv2D(in_channels=1, out_channels=2,kernel_size=3, stride=1, padding=1),nn.ReLU())self.linear = nn.Sequential(nn.Linear(98, num_classes))def forward(self, inputs):x = self.features(inputs)x = paddle.flatten(x, 1)x = self.linear(x)return xmodel = MyNet()#準(zhǔn)備輸入數(shù)據(jù)
x_spec = paddle.static.InputSpec([1, 1, 7, 7], 'float32', 'input1')
#將模型以PaddlePaddle的格式保存,以驗(yàn)證和ONNX模型推理的一致性
paddle.jit.save(layer=model, path='./pd_model/pdmodel',input_spec=[x_spec])
#將模型導(dǎo)出為ONNX格式保存
paddle.onnx.export(layer=model, path='./model',input_spec=[x_spec], opset_version=11)
4.2 ONNX正確性驗(yàn)證
可以用以下代碼驗(yàn)證ONNX模型的正確性,會(huì)檢查模型的版本,圖的結(jié)構(gòu),節(jié)點(diǎn)及輸入輸出。若輸出為 Check: None 則表示無報(bào)錯(cuò)信息,模型導(dǎo)出正確。
import onnxonnx_model = onnx.load("./model.onnx")
check = onnx.checker.check_model(onnx_model)
print('Check: ', check)
4.3 PaddlePaddle與ONNX的一致性檢查
可以使用以下代碼檢查導(dǎo)出的ONNX模型和原始的PaddlePaddle模型是否有相同的計(jì)算結(jié)果。
import numpy as np
import onnxruntime
import paddleinput1 = np.random.random((1, 1, 7, 7)).astype('float32')ort_sess = onnxruntime.InferenceSession("./model.onnx")
ort_inputs = {ort_sess.get_inputs()[0].name: input1}
ort_outs = ort_sess.run(None, ort_inputs)model = paddle.jit.load("./pd_model/pdmodel")
model.eval()
paddle_input = paddle.to_tensor(input1)
paddle_outs = model(paddle_input)print(ort_outs[0])
print(paddle_outs.numpy())
np.testing.assert_allclose(tf_outs.numpy(), ort_outs[0], rtol=1e-03, atol=1e-05)
print("onnx model check finsh.")
4.4 多輸入的情況
若您的模型存在多輸入,則可參考下方代碼保存成PaddlePaddle和ONNX格式。ONNX的正確性驗(yàn)證和PaddlePaddle與ONNX的一致性檢查不再贅述,仿照上述代碼編寫即可。
import paddle
import paddle.nn as nnclass MyNet(nn.Layer):def __init__(self, num_classes=10):super(MyNet, self).__init__()self.num_classes = num_classesself.features_1 = nn.Sequential(nn.Conv2D(in_channels=1, out_channels=2,kernel_size=3, stride=1, padding=1),nn.ReLU())self.features_2 = nn.Sequential(nn.Conv2D(in_channels=1, out_channels=2,kernel_size=3, stride=1, padding=1),nn.ReLU())self.linear = nn.Sequential(nn.Linear(98, num_classes))def forward(self, inputs1, inputs2):x = self.features_1(inputs1)y = self.features_2(inputs2)z = paddle.concat((x, y), 1)z = paddle.flatten(z, 1)z = self.linear(z)return zmodel = MyNet()x_spec = paddle.static.InputSpec([1, 1, 7, 7], 'float32', 'input1')
y_spec = paddle.static.InputSpec([1, 1, 7, 7], 'float32', 'input2')
paddle.jit.save(layer=model, path='./pd_model/pdmodel',input_spec=[x_spec, y_spec])
paddle.onnx.export(layer=model, path='./model',input_spec=[x_spec, y_spec], opset_version=11)
5 ONNX模型可視化
導(dǎo)出成ONNX模型后,可以使用開源可視化工具Netron來查看網(wǎng)絡(luò)結(jié)構(gòu)及相關(guān)配置信息。Netron的使用方式主要分為兩種,一種是使用在線網(wǎng)頁版 https://netron.app/ ,另一種是下載安裝程序 https://github.com/lutzroeder/netron 。此教程中模型的可視化效果為:
6 ir_version和opset_version修改
地平線工具鏈支持的ONNX模型需要滿足 opset_version=10/11 且 ir_version≤7,當(dāng)拿到的ONNX模型不滿足這兩個(gè)要求時(shí),可以修改代碼重新導(dǎo)出,或者嘗試編寫腳本直接修改ONNX模型的對(duì)應(yīng)屬性,第二種方式的示例代碼如下:
import onnxmodel = onnx.load("./model.onnx")
model.ir_version = 6
model.opset_import[0].version = 10
onnx.save_model(model, "./model_version.onnx")
**注意:**高版本向低版本切換時(shí)可能會(huì)出現(xiàn)問題,這里只是一種可嘗試的解決方案。
調(diào)整結(jié)束后,使用Netron可視化model_version.onnx,如下圖所示:
此時(shí),ONNX模型的ir_version=6,opset_version=10,滿足地平線工具鏈的轉(zhuǎn)換條件。
7 致謝
原文來自于地平線開發(fā)者社區(qū),未來會(huì)持續(xù)發(fā)布深度學(xué)習(xí)、板端部署的相關(guān)優(yōu)質(zhì)文章與視頻,如果文章對(duì)您有幫助,麻煩給點(diǎn)個(gè)贊,如果您有興趣一起學(xué)習(xí),歡迎點(diǎn)個(gè)關(guān)注:尋找永不遺憾(CSDN用戶名)