您好,登錄后才能下訂單哦!
如何使用ONNX部署深度學習和傳統(tǒng)機器學習模型,針對這個問題,這篇文章詳細介紹了相對應(yīng)的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
開放神經(jīng)網(wǎng)絡(luò)交換ONNX(Open Neural Network Exchange)是一套表示深度神經(jīng)網(wǎng)絡(luò)模型的開放格式,由微軟和Facebook于2017推出,然后迅速得到了各大廠商和框架的支持。通過短短幾年的發(fā)展,已經(jīng)成為表示深度學習模型的實際標準,并且通過ONNX-ML
,可以支持傳統(tǒng)非神經(jīng)網(wǎng)絡(luò)機器學習模型,大有一統(tǒng)整個AI模型交換標準。
ONNX定義了一組與環(huán)境和平臺無關(guān)的標準格式,為AI模型的互操作性提供了基礎(chǔ),使AI模型可以在不同框架和環(huán)境下交互使用。硬件和軟件廠商可以基于ONNX標準優(yōu)化模型性能,讓所有兼容ONNX標準的框架受益。目前,ONNX主要關(guān)注在模型預(yù)測方面(inferring),使用不同框架訓(xùn)練的模型,轉(zhuǎn)化為ONNX格式后,可以很容易的部署在兼容ONNX的運行環(huán)境中。
ONNX規(guī)范由以下幾個部分組成:
一個可擴展的計算圖模型:定義了通用的計算圖中間表示法(Intermediate Representation)。
內(nèi)置操作符集:ai.onnx
和ai.onnx.ml
,ai.onnx
是默認的操作符集,主要針對神經(jīng)網(wǎng)絡(luò)模型,ai.onnx.ml
主要適用于傳統(tǒng)非神經(jīng)網(wǎng)絡(luò)機器學習模型。
標準數(shù)據(jù)類型。包括張量(tensors)、序列(sequences)和映射(maps)。
目前,ONNX規(guī)范有兩個官方變體,主要區(qū)別在與支持的類型和默認的操作符集。ONNX神經(jīng)網(wǎng)絡(luò)變體只使用張量作為輸入和輸出;而作為支持傳統(tǒng)機器學習模型的ONNX-ML
,還可以識別序列和映射,ONNX-ML
為支持非神經(jīng)網(wǎng)絡(luò)算法擴展了ONNX操作符集。
ONNX使用protobuf序列化AI模型,頂層是一個模型(Model)結(jié)構(gòu),主要由關(guān)聯(lián)的元數(shù)據(jù)和一個圖(Graph)組成;圖由元數(shù)據(jù)、模型參數(shù)、輸入輸出、和計算節(jié)點(Node
)序列組成,這些節(jié)點構(gòu)成了一個計算無環(huán)圖,每一個計算節(jié)點代表了一次操作符的調(diào)用,主要由節(jié)點名稱、操作符、輸入列表、輸出列表和屬性列表組成,屬性列表主要記錄了一些運行時常量,比如模型訓(xùn)練時生成的系數(shù)值。
為了更直觀的了解ONNX格式內(nèi)容,下面,我們訓(xùn)練一個簡單的LogisticRegression模型,然后導(dǎo)出ONNX。仍然使用常用的分類數(shù)據(jù)集iris
:
from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.linear_model import LogisticRegression iris = load_iris() X, y = iris.data, iris.target X_train, X_test, y_train, y_test = train_test_split(X, y) clr = LogisticRegression() clr.fit(X_train, y_train)
使用skl2onnx
把Scikit-learn模型序列化為ONNX格式:
from skl2onnx import convert_sklearn from skl2onnx.common.data_types import FloatTensorType initial_type = [('float_input', FloatTensorType([1, 4]))] onx = convert_sklearn(clr, initial_types=initial_type) with open("logreg_iris.onnx", "wb") as f: f.write(onx.SerializeToString())
使用ONNX Python API查看和驗證模型:
import onnx model = onnx.load('logreg_iris.onnx') print(model)
輸出模型信息如下:
ir_version: 5 producer_name: "skl2onnx" producer_version: "1.5.1" domain: "ai.onnx" model_version: 0 doc_string: "" graph { node { input: "float_input" output: "label" output: "probability_tensor" name: "LinearClassifier" op_type: "LinearClassifier" attribute { name: "classlabels_ints" ints: 0 ints: 1 ints: 2 type: INTS } attribute { name: "coefficients" floats: 0.375753253698349 floats: 1.3907358646392822 floats: -2.127762794494629 floats: -0.9207873344421387 floats: 0.47902926802635193 floats: -1.5524250268936157 floats: 0.46959221363067627 floats: -1.2708674669265747 floats: -1.5656673908233643 floats: -1.256540060043335 floats: 2.18996000289917 floats: 2.2694246768951416 type: FLOATS } attribute { name: "intercepts" floats: 0.24828049540519714 floats: 0.8415762782096863 floats: -1.0461325645446777 type: FLOATS } attribute { name: "multi_class" i: 1 type: INT } attribute { name: "post_transform" s: "LOGISTIC" type: STRING } domain: "ai.onnx.ml" } node { input: "probability_tensor" output: "probabilities" name: "Normalizer" op_type: "Normalizer" attribute { name: "norm" s: "L1" type: STRING } domain: "ai.onnx.ml" } node { input: "label" output: "output_label" name: "Cast" op_type: "Cast" attribute { name: "to" i: 7 type: INT } domain: "" } node { input: "probabilities" output: "output_probability" name: "ZipMap" op_type: "ZipMap" attribute { name: "classlabels_int64s" ints: 0 ints: 1 ints: 2 type: INTS } domain: "ai.onnx.ml" } name: "deedadd605a34d41ac95746c4feeec1f" input { name: "float_input" type { tensor_type { elem_type: 1 shape { dim { dim_value: 1 } dim { dim_value: 4 } } } } } output { name: "output_label" type { tensor_type { elem_type: 7 shape { dim { dim_value: 1 } } } } } output { name: "output_probability" type { sequence_type { elem_type { map_type { key_type: 7 value_type { tensor_type { elem_type: 1 } } } } } } } } opset_import { domain: "" version: 9 } opset_import { domain: "ai.onnx.ml" version: 1 }
我們可以看到頂層字段記錄了一些模型的元數(shù)據(jù)信息,代表的含義都比較直觀,字段詳細解釋可以參考文檔Open Neural Network Exchange - ONNX。opset_import
記錄了該模型引入的操作符集??盏?code>domain操作符集表示引入ONNX默認的操作符集ai.onnx
。ai.onnx.ml
代表支持傳統(tǒng)非神經(jīng)網(wǎng)絡(luò)模型操作符集,比如以上模型中的LinearClassifier
、Normalizer
和ZipMap
。圖(graph)中定義了以下元素:
四個計算節(jié)點(node)。
一個輸入變量float_input
,類型為1*4的張量,elem_type
是一個DataType枚舉型變量,1代表FLOAT。
兩個輸出變量output_label
和output_probability
,output_label
類型為維數(shù)為1的INT64(elem_type: 7)張量,代表預(yù)測目標分類; output_probability
類型是映射的序列,映射的鍵是INT64(key_type: 7),值為維數(shù)為1的FLOAT,代表每一個目標分類的概率。
可以使用netron,圖像化顯示ONNX模型的計算拓撲圖,以上模型如下圖:
下面我們使用ONNX Runtime Python API預(yù)測該ONNX模型,當前僅使用了測試數(shù)據(jù)集中的第一條數(shù)據(jù):
import onnxruntime as rt import numpy sess = rt.InferenceSession("logreg_iris.onnx") input_name = sess.get_inputs()[0].name label_name = sess.get_outputs()[0].name probability_name = sess.get_outputs()[1].name pred_onx = sess.run([label_name, probability_name], { input_name: X_test[0].astype(numpy.float32)}) # print info print('input_name: ' + input_name) print('label_name: ' + label_name) print('probability_name: ' + probability_name) print(X_test[0]) print(pred_onx)
打印的模型信息和預(yù)測值如下:
input_name: float_input label_name: output_label probability_name: output_probability [5.5 2.6 4.4 1.2] [array([1], dtype=int64), [{0: 0.012208569794893265, 1: 0.5704444646835327, 2: 0.4173469841480255}]]
完整的程序,可以參考以下Notebook:onnx.ipynb
ONNX和PMML都是與平臺和環(huán)境無關(guān)的模型表示標準,可以讓模型部署脫離模型訓(xùn)練環(huán)境,簡化了部署流程,加速模型快速上線到生產(chǎn)環(huán)境中。這兩個標準都得到了各大廠商和框架的支持,具有廣泛的應(yīng)用。
PMML是一個比較成熟的標準,在ONNX誕生之前,可以說是模型表示的實際標準,對傳統(tǒng)數(shù)據(jù)挖掘模型有豐富的支持,最新 PMML4.4 可以支持多達19種模型類型。但是,目前PMML缺乏對深度學習模型的支持,下一版本5.0有可能會添加對深度神經(jīng)網(wǎng)絡(luò)的支持,但是因為PMML是基于老式的XML格式,使用文本格式來存儲深度神經(jīng)網(wǎng)絡(luò)模型結(jié)構(gòu)和參數(shù)會帶來模型大小和性能的問題,目前該問題還沒有一個完美的解決方案。關(guān)于PMML的詳細介紹,可以參考文章《使用PMML部署機器學習模型》。
ONNX作為一個新的標準,剛開始主要提供對深度神經(jīng)網(wǎng)絡(luò)模型的支持,解決模型在不同框架下互操作和交換的問題。目前通過ONNX-ML
,ONNX已經(jīng)可以支持傳統(tǒng)非神經(jīng)網(wǎng)絡(luò)機器學習模型,但是目前模型類型還不夠豐富。ONNX使用protobuf二進制格式來序列化模型,可以提供更好的傳輸性能。
ONNX和PMML這兩種格式都有成熟的開源類庫和框架支持,PMML有JPMML,PMML4S,PyPMML等。ONNX有微軟的ONNX runtime,NVIDIA TensorRT等。用戶可以根據(jù)自己的實際情況選擇合適的跨平臺格式來部署AI模型。
DaaS(Deployment-as-a-Service)是AutoDeployAI公司推出的AI模型自動部署系統(tǒng),支持多種模型類型的上線部署,以下我們介紹如何在DaaS中使用ONNX格式來部署傳統(tǒng)機器學習模型和深度神經(jīng)網(wǎng)絡(luò)學習模型,DaaS使用ONNX Runtime作為ONNX模型的執(zhí)行引擎,ONNX Runtime是微軟開源的ONNX預(yù)測類庫,提供高性能預(yù)測服務(wù)功能。首先,登陸DaaS系統(tǒng)后,創(chuàng)建一個新的工程ONNX
,下面的操作都在該工程下進行。關(guān)于DaaS的詳細信息,可以參考文章《自動部署PMML模型生成REST API》。
導(dǎo)入模型。選擇上面訓(xùn)練的Logistic Regression模型logreg_iris.onnx
:
導(dǎo)入成功后,頁面轉(zhuǎn)到模型主頁面。可以看到模型有一個輸入字段float_input
,類型是tensor(float)
,維數(shù)(1,4)
。兩個輸出字段:output_label
和output_probability
。
測試模型。點擊標簽頁測試
,輸入預(yù)測數(shù)據(jù)[[5.5, 2.6, 4.4, 1.2]]
,然后點擊提交
命令,輸出頁面顯示預(yù)測測試結(jié)果:
創(chuàng)建默認實時預(yù)測Web服務(wù)。點擊標簽頁部署
,然后點擊添加服務(wù)
命令,輸入服務(wù)名稱,其他使用默認值:
測試Web服務(wù)。服務(wù)創(chuàng)建成功后,頁面轉(zhuǎn)到服務(wù)部署主頁,當服務(wù)副本狀態(tài)為運行中
時,代表Web服務(wù)已經(jīng)成功上線,可以接受外部請求。有兩種方式測試該服務(wù):
在DaaS系統(tǒng)中通過測試頁面。點擊標簽頁測試
,輸入JSON格式的請求正文,點擊提交
命令:
通過任意的RSET客戶端,使用標準的REST API來測試。這里我們使用curl命令行程序來調(diào)用Web服務(wù),點擊生成代碼
命令,彈出顯示使用curl命令調(diào)用REST API的對話框:
復(fù)制該curl命令,打開shell頁面,執(zhí)行命令:
我們嘗試部署ONNX Model Zoo中已經(jīng)訓(xùn)練好的模型,這里我們選擇MNIST-手寫數(shù)字識別CNN模型,下載基于ONNX1.3的模型最新版本:mnist.tar.gz。
導(dǎo)入模型。選擇已下載模型mnist.tar.gz
:
導(dǎo)入成功后,頁面轉(zhuǎn)到模型主頁面??梢钥吹侥P陀幸粋€輸入字段Input3
,類型是tensor(float)
,維數(shù)(1,1,28,28)
。一個輸出字段:Plus214_Output_0
,類型同樣是tensor(float)
,維數(shù)(1,10)
。
測試模型。點擊標簽頁測試
,然后點擊JSON
命令,DaaS系統(tǒng)會自動創(chuàng)建符合輸入數(shù)據(jù)格式的隨機數(shù)據(jù),以方便測試。點擊提交
命令,輸出頁面顯示預(yù)測測試結(jié)果:
創(chuàng)建自定義實施預(yù)測腳本。為了能支持輸入圖像,并且直接輸出預(yù)測值,我們需要創(chuàng)建自定義預(yù)測腳本。點擊標簽頁實時預(yù)測
,然后點擊生成自定義實時預(yù)測腳本
命令,
腳本生成后,點擊命令作為API測試
,進入腳本測試頁面,我們可以自由添加自定義預(yù)處理和后處理功能。添加以下函數(shù)預(yù)處理圖像:
def rgb2gray(rgb): """Convert the input image into grayscale""" import numpy as np return np.dot(rgb[...,:3], [0.299, 0.587, 0.114]) def resize_img(img_to_resize): """Resize image to MNIST model input dimensions""" import cv2 r_img = cv2.resize(img_to_resize, dsize=(28, 28), interpolation=cv2.INTER_AREA) r_img.resize((1, 1, 28, 28)) return r_img def preprocess_image(img_to_preprocess): """Resize input images and convert them to grayscale.""" if img_to_preprocess.shape == (28, 28): img_to_preprocess.resize((1, 1, 28, 28)) return img_to_preprocess grayscale = rgb2gray(img_to_preprocess) processed_img = resize_img(grayscale) return processed_img
在已有preprocess_files
函數(shù)中調(diào)用preprocess_image
,代碼如下:
import matplotlib.image as mpimg for key, file in files.items(): img = mpimg.imread(file) record[key] = preprocess_image(img)
在已有postprocess
函數(shù)中添加如下代碼后處理預(yù)測結(jié)果以獲取最終的預(yù)測值:
def postprocess(result): """postprocess the predicted results""" import numpy as np return [int(np.argmax(np.array(result).squeeze(), axis=0))]
點擊命令保存
,然后在請求頁面中輸入函數(shù)名為predict
,選擇請求正文基于表單
,輸入表單名稱為模型唯一的輸入字段名Input3
,類型選擇文件
,點擊上傳,選擇測試圖像2.png
,最后點擊提交
命令,測試該腳本是否按照我們的期望工作:
創(chuàng)建正式部署Web服務(wù)。當腳本測試成功后,點擊部署
標簽頁,然后點擊添加網(wǎng)絡(luò)服務(wù)
命令,輸入服務(wù)名稱,其他使用默認值:
測試Web服務(wù)。服務(wù)創(chuàng)建成功后,頁面轉(zhuǎn)到服務(wù)部署主頁,當服務(wù)副本狀態(tài)為運行中
時,代表Web服務(wù)已經(jīng)成功上線,可以接受外部請求。有兩種方式測試該服務(wù):
在DaaS系統(tǒng)中通過測試頁面。點擊標簽頁測試
,選擇請求正文基于表單
,選擇輸入測試圖像5.jpg
,點擊提交
命令:
通過任意的RSET客戶端,使用標準的REST API來測試。這里我們使用curl命令行程序來調(diào)用Web服務(wù),點擊生成代碼
命令,彈出顯示使用curl命令調(diào)用REST API的對話框:
復(fù)制該curl命令,打開shell頁面,切換到圖像目錄下,執(zhí)行命令:
關(guān)于如何使用ONNX部署深度學習和傳統(tǒng)機器學習模型問題的解答就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。