第二章?OpenVINO? 的核心組件
在上篇中我們了解到OpenVINO??是為加速人工智能應(yīng)用和解決方案開發(fā)而生的工具包,基于最新一代的深度學(xué)習(xí)人工神經(jīng)網(wǎng)絡(luò)-包括卷積神經(jīng)網(wǎng)絡(luò) (CNN)、遞歸神經(jīng)網(wǎng)絡(luò)(RNN),能夠部署于從邊緣到云端的各種架構(gòu)中,從而實(shí)現(xiàn)包括機(jī)器視覺、自動(dòng)語音識(shí)別、自然語言處理和推薦系統(tǒng)等多種人工智能應(yīng)用。
我們知道如果從零開始進(jìn)行人工智能應(yīng)用及方案開發(fā)將是一項(xiàng)巨大的工程,搜集數(shù)據(jù)、清洗數(shù)據(jù)、框架選擇、模型訓(xùn)練、調(diào)教模型、應(yīng)用開發(fā)、測(cè)試驗(yàn)證、部署運(yùn)營(yíng),需要投入大量的人力、物力、財(cái)力才能完成這一復(fù)雜的項(xiàng)目。在上一篇中我們也提到,利用OpenVINO? 工具包,開發(fā)者在不了解算法細(xì)節(jié)的前提下同樣可以快速完成人工智能應(yīng)用開發(fā),是如何實(shí)現(xiàn)的呢?在下面的章節(jié)中,我們結(jié)合OpenVINO? 筆記一一解密。在本章節(jié)中我們依舊遵循實(shí)訓(xùn)原則,邊學(xué)邊練,少說多練,不斷鞏固知識(shí)點(diǎn)學(xué)習(xí)。
2.1、核心組件與工作流程
知其然,知其所以然。我們先來了解OpenVINO? 工具包核心組件以及組件之間是如何配合相互完成全部工作流程。推理引擎 Inferece Engine、模型優(yōu)化器Model Optimizer、優(yōu)是加速人工智能應(yīng)用開發(fā)的利劍。
推理引擎管理經(jīng)過優(yōu)化的神經(jīng)網(wǎng)絡(luò)模型的加載和編譯,進(jìn)行推理運(yùn)算,并輸出結(jié)果;推理引擎提供統(tǒng)一API接口可以在英特爾多種硬件上進(jìn)行高性能推理。
模型優(yōu)化器是一個(gè)跨平臺(tái)命令行工具,將經(jīng)過訓(xùn)練的神經(jīng)網(wǎng)絡(luò)從源框架轉(zhuǎn)換為與 nGraph 兼容的開源中間表示 (IR),用于推理運(yùn)算。模型優(yōu)化器支持Caffe、TensorFlow、MXNet、Kaldi 、Pytorch、PaddlePaddle和 ONNX等常用框架預(yù)訓(xùn)練的模型輸入,進(jìn)行一些優(yōu)化,去除冗余的層,并在可能的情況下將操作分組為更簡(jiǎn)單、更快速的圖層用于加速推理運(yùn)算。
下圖展示的是OpenVINO??從準(zhǔn)備模型至完成推理完整的工作流程:
圖2-1? 先導(dǎo)步驟準(zhǔn)備模型
圖2-2? 模型優(yōu)化至推理部署流程
圖2-3? 推理引擎與模型優(yōu)化器協(xié)同工作
通過以上介紹我們已了解,模型優(yōu)化器可以對(duì)主流框架的預(yù)處理模型進(jìn)行優(yōu)化及轉(zhuǎn)化,充分利用已有資源不必從零開始加快了應(yīng)用開發(fā)進(jìn)程;推理引擎提供統(tǒng)一的API可以運(yùn)行在不同的硬件平臺(tái)上,并且可以指定模型運(yùn)行在特定的硬件設(shè)備上,一次編程永久使用,加快了推理進(jìn)程;優(yōu)化工具集以及行業(yè)應(yīng)用演示案例即提供了參考代碼又提供了性能優(yōu)化工具,加快了應(yīng)用開發(fā)流程;核心組件三劍客協(xié)同作用,我們使用OpenVINO??工具包既可以作為學(xué)習(xí)人工智能開發(fā)的技術(shù)指導(dǎo)又可以作為快速開發(fā)應(yīng)用從而加速產(chǎn)品進(jìn)入市場(chǎng)的好工具。
筆者認(rèn)為實(shí)訓(xùn)教程比較好的展現(xiàn)形式就是少說多練,用較為精煉的語言突出重點(diǎn),通過大量的實(shí)踐案例鞏固學(xué)習(xí)成果。這也是我們推薦使用OpenVINO? 筆記作為教程的原因。
從下一節(jié)開始,我們利用OpenVINO? 筆記深入學(xué)習(xí)核心組件使用,詳解核心組件API從而掌握推理引擎及模型優(yōu)化器使用技能。
我們執(zhí)行Jupyter命令開啟學(xué)習(xí)之旅。
source $HOME/openvino_env/bin/activate
jupyter-lab openvino_notebooks/notebooks
圖2-4? OpenVINO? 筆記工作環(huán)境
2.2 推力引擎詳解
2.1.1 Hello World
學(xué)習(xí)目標(biāo):
認(rèn)識(shí)OpenVINO? 推理引擎
掌握使用推理引擎基礎(chǔ)步驟
了解筆記使用的模型及軟件模塊
Hello World,Hello OpenVINO? 。看到Hello World,這代表將會(huì)用最簡(jiǎn)潔的代碼展示將要學(xué)習(xí)的內(nèi)容,我們開始操練。
在OpenVINO??筆記工程中雙擊001-hello-world進(jìn)入子目錄,雙擊001-hello-world.ipynb打開筆記文件。
圖2-5? hello-world筆記
我們使用筆記執(zhí)行全部單元格命令,快速獲得最終結(jié)果。進(jìn)入運(yùn)行菜單-點(diǎn)擊運(yùn)行全部單元格按鈕。
圖2-6 hello-world筆記執(zhí)行全部單元格
不需要等待太久,我們就得到了對(duì)輸入圖片進(jìn)行分類推理結(jié)果,顯示結(jié)果圖片中是短毛尋回犬。
圖2-7 hello-world運(yùn)行結(jié)果
演示筆記僅用19行代碼就實(shí)現(xiàn)了人工智能分類應(yīng)用,恭喜我們正式開啟了人工智能應(yīng)用開發(fā)之路。接下來我們通過解讀代碼來學(xué)習(xí)筆記是如何實(shí)現(xiàn)圖片分類識(shí)別的功能。我們使用筆記單步執(zhí)行功能,查看每一步的執(zhí)行情況。在單步執(zhí)行研讀代碼之前,我們選擇內(nèi)核菜單欄,點(diǎn)擊重啟內(nèi)核并清楚所有結(jié)果為我們接下來單步操作做好準(zhǔn)備。
圖2-8 hello-world單步執(zhí)行
1、導(dǎo)入程序所需要的python模塊
圖2-9 hello-world導(dǎo)入模塊
import?json
import?cv2
import?matplotlib.pyplot?as?plt
import?numpy?as?np
from?openvino.inference_engine?import?IECore
認(rèn)識(shí)新模塊:
json(JavaScript Object Notation) 是一種輕量級(jí)的數(shù)據(jù)交換格式,易于閱讀和編寫。
cv2大名鼎鼎的openCV機(jī)器視覺函數(shù)庫(kù)
matplotlib 是一個(gè)2D繪圖庫(kù),它以各種硬拷貝格式和跨平臺(tái)的交互式環(huán)境生成出版質(zhì)量級(jí)別的圖形。通過 matplotlib開發(fā)者可以僅需要幾行代碼,便可以生成繪圖,直方圖,功率譜,條形圖,錯(cuò)誤圖,散點(diǎn)圖等。
numpy(Numerical Python)是一個(gè)開源的數(shù)值計(jì)算擴(kuò)展。這個(gè)工具可用來存儲(chǔ)和處理大型矩陣,支持大量的維度數(shù)組與矩陣運(yùn)算,此外也針對(duì)數(shù)組運(yùn)算提供大量的數(shù)學(xué)函數(shù)庫(kù)。
OpenVINO? .inference_engine 推理引擎模塊
2、加載網(wǎng)絡(luò)模型
初始化推理引擎、讀入網(wǎng)絡(luò)模型、配置使用的硬件設(shè)備并加載網(wǎng)絡(luò)、配置輸入輸出
圖2-10 hello-world加載網(wǎng)絡(luò)模型
ie?=?IECore()
net?=?ie.read_network(model="model/v3-small_224_1.0_float.xml")
exec_net?=?ie.load_network(net,?"CPU")
input_key?=?next(iter(exec_net.input_info))
output_key?=?next(iter(exec_net.outputs.keys()))
MobileNetV3模型介紹
MobileNet是由Gooogle研究者們?cè)O(shè)計(jì)的一類卷積神經(jīng)網(wǎng)絡(luò),模型具有計(jì)算消耗小、運(yùn)行速度快、運(yùn)行效果準(zhǔn)的特點(diǎn),非常適合在移動(dòng)設(shè)備上運(yùn)行。
3、 加載圖片
圖2-11 hello-world加載顯示圖片
image?=?cv2.cvtColor(cv2.imread("data/coco.jpg"),?cv2.COLOR_BGR2RGB)
input_image?=?cv2.resize(image,?(224,?224))
input_image?=?np.expand_dims(input_image.transpose(2,?0,?1),?0)
plt.imshow(image);
讀取圖片、色彩空間轉(zhuǎn)換openCV庫(kù)默認(rèn)讀取圖片的格式為BGR,mobilenetv3需要輸入的色彩空間為RGB,因此在讀出圖片后需要進(jìn)行色彩空間轉(zhuǎn)換;調(diào)整輸入圖片尺寸為224x224以適配模型需要。代碼執(zhí)行完成,將顯示需要推理的圖片。
4、 執(zhí)行推理
result?=?exec_net.infer(inputs={input_key:?input_image})[output_key]
result_index?=?np.argmax(result)
5、處理并顯示結(jié)果
imagenet_classes=json.loads(open("utils/imagenet_class_index.json").read())
imagenet_classes={int(key)?+?1:?value?for?key,?value?in?imagenet_classes.items()}
imagenet_classes[result_index]
將推理結(jié)果與json文件中的類名進(jìn)行匹配,具有更好的可讀性。
圖2-12 hello-world顯示推理結(jié)果
2.2.2? ?推理引擎API詳解
學(xué)習(xí)目標(biāo):
掌握推理引擎API使用
在上一節(jié)中我們學(xué)習(xí)了利用推理引擎開僅用十幾行代碼便完成分類任務(wù)的案例,在本節(jié)中我們深入學(xué)習(xí)推理引擎的API,掌握完整的開發(fā)流程。
雙擊002-OpenVINO? -api目錄,雙擊打開002-OpenVINO? -api.ipynb筆記。本節(jié)解釋了OpenVINO? 推理引擎API的基礎(chǔ)知識(shí)。它包括:
加載推理引擎及信息顯示
加載不同模型
IR模型
ONNX模型
獲取模型信息
模型輸入
模型輸出
使用模型進(jìn)行推理
重塑和調(diào)整大小
改變圖像大小
改變批量大小
為便于學(xué)習(xí)筆記本被劃分為帶有標(biāo)題的章節(jié)。每一節(jié)都是獨(dú)立的,不依賴于前面的章節(jié)。同時(shí),筆記提供了一個(gè)分割和分類的IR模型和一個(gè)分割的ONNX模型作為例子。我們同樣使用Juypter筆記單步執(zhí)行的功能進(jìn)行學(xué)習(xí)。
1、 導(dǎo)入模塊并初始化引擎
圖2-11 OpenVINO? -api初始化推理引擎
from?openvino.inference_engine?import?IECore
ie?=?IECore()
2、 查詢支持的硬件設(shè)備并顯示
圖2-14 OpenVINO? -api查詢系統(tǒng)支持的推理設(shè)備
devices?=?ie.available_devices
for?device?in?devices:
device_name?=?ie.get_metric(device,?"FULL_DEVICE_NAME")
print(f"{device}:?{device_name}")
推理引擎可以將網(wǎng)絡(luò)模型加載導(dǎo)特定的硬件設(shè)備上。這里的設(shè)備指的是CPU、Intel GPU、Neural Compute Stick 2等。`available_devices`屬性顯示了當(dāng)前系統(tǒng)上可用的設(shè)備。`ie.get_metric()`的 "FULL_DEVICE_NAME "選項(xiàng)顯示設(shè)備的名稱。在本節(jié)筆記本中,使用的是CPU設(shè)備。要使用集成的GPU,請(qǐng)使用`device_name="GPU"`代替。請(qǐng)注意,在GPU上加載網(wǎng)絡(luò)會(huì)比在CPU上加載網(wǎng)絡(luò)慢,但推理可能會(huì)更快。
3、 加載模型
圖2-15 OpenVINO? -api加載模型
from?openvino.inference_engine?import?IECore
ie?=?IECore()
classification_model_xml?=?"model/classification.xml"
net?=?ie.read_network(model=classification_model_xml)
exec_net?=?ie.load_network(network=net,?device_name="CPU")
在初始化推理引擎后,首先用read_network()讀取模型文件,然后用load_network()將其加載到指定設(shè)備上。IR模型IR(Intermediate Representation)模型由一個(gè)包含模型信息的.xml文件和一個(gè)包含權(quán)重的.bin文件組成。read_network()希望權(quán)重文件與xml文件位于同一目錄下,文件名相同,擴(kuò)展名為.bin:model_weights_file == Path(model_xml).with_suffix(".bin")。如果是這種情況,指定權(quán)重文件是可選的。如果權(quán)重文件有不同的文件名,可以通過read_network()的weights參數(shù)來指定。
新版本的推理引擎支持直接讀取ONNX模型,讀取和加載ONNX模型的方法與讀取和加載IR模型的方法相同。model參數(shù)指向ONNX文件名。
圖2-16 OpenVINO? -api加載ONNX模型
from?openvino.inference_engine?import?IECore
ie?=?IECore()
onnx_model?=?"model/segmentation.onnx"
net_onnx?=?ie.read_network(model=onnx_model)
exec_net_onnx?=?ie.load_network(network=net_onnx,?device_name="CPU")
4、 獲取關(guān)于模型的信息
OpenVINO??IENetwork實(shí)例存儲(chǔ)了關(guān)于模型的信息。關(guān)于模型的輸入和輸出的信息在net.input_info和net.output中。這些也是ExecutableNetwork實(shí)例的屬性。在下面的單元格中我們使用net.input_info和net.output,你也可以使用exec_net.input_info和exec_net.output。
圖2-17 OpenVINO? -api模型信息
from?openvino.inference_engine?import?IECore
ie?=?IECore()
classification_model_xml?=?"model/classification.xml"
net?=?ie.read_network(model=classification_model_xml)
net.input_info
模型輸入,上面的單元格顯示,加載的模型期望有一個(gè)輸入,名稱為_input_。如果加載了一個(gè)不同的模型,你可能會(huì)看到一個(gè)不同的輸入層名稱,而且你可能會(huì)看到更多的輸入。有一個(gè)對(duì)第一個(gè)輸入層名稱的引用通常是有用的。對(duì)于一個(gè)只有一個(gè)輸入的模型,next(iter(net.input_info))得到這個(gè)名稱。
圖2-18 OpenVINO? -api模型輸入
input_layer?=?next(iter(net.input_info))
input_layer
這個(gè)輸入層的信息被存儲(chǔ)在input_info中。下一個(gè)單元格會(huì)打印出輸入的布局、精度和形狀。
圖2-19 OpenVINO? -api模型信息
print(f"input?layout:?{net.input_info[input_layer].layout}")
print(f"input?precision:?{net.input_info[input_layer].precision}")
print(f"input?shape:?{net.input_info[input_layer].tensor_desc.dims}")
這里的輸出告訴我們,模型期望輸入的形狀是[1,3,224,224],而且是以N、C、H、W布局。這意味著模型期望的輸入數(shù)據(jù)的批量大小(N)為1,3個(gè)通道(C),圖像的高度(H)和寬度(W)為224。預(yù)計(jì)輸入數(shù)據(jù)的精度為FP32(浮點(diǎn))。
5、 模型輸出
模型輸出信息存儲(chǔ)在net.output中。上面的單元格顯示,該模型返回一個(gè)輸出,名稱為_MobilenetV3/Predictions/Softmax_。如果你加載了一個(gè)不同的模型,你可能會(huì)看到一個(gè)不同的輸出層名稱,你可能會(huì)看到更多的輸出。因?yàn)檫@個(gè)模型有一個(gè)輸出,所以按照輸入層的方法來獲取它的名字。
圖2-20 OpenVINO? -api模型輸出
from?openvino.inference_engine?import?IECore
ie?=?IECore()
classification_model_xml?=?"model/classification.xml"
net?=?ie.read_network(model=classification_model_xml)
net.outputs
devices?=?ie.available_devices
for?device?in?devices:
device_name?=?ie.get_metric(device,?"FULL_DEVICE_NAME")
print(f"{device}:?{device_name}")
獲取輸出布局、精度和形狀與獲取輸入布局、精度和形狀類似
圖2-21 OpenVINO? -api模型輸出信息
print(f"output?layout:?{net.outputs[output_layer].layout}")
print(f"output?precision:?{net.outputs[output_layer].precision}")
print(f"output?shape:?{net.outputs[output_layer].shape}")
這個(gè)單元格的輸出顯示,模型返回的輸出形狀為[1, 1001],其中1是批處理規(guī)模(N),1001是類的數(shù)量(C)。輸出以32位浮點(diǎn)形式返回。
6、 使用模型進(jìn)行推理
要使用模型進(jìn)行推理,請(qǐng)調(diào)用_ExecutableNetwork_的infer()方法,即我們用load_network()加載的exec_net。infer()需要帶有參數(shù),_inputs_是一個(gè)字典,將輸入層名稱映射到輸入數(shù)據(jù)。
1) 準(zhǔn)備工作:加載網(wǎng)絡(luò)
圖2-22 OpenVINO? -api初始化引擎并加載網(wǎng)絡(luò)
from?openvino.inference_engine?import?IECore
ie?=?IECore()
classification_model_xml?=?"model/classification.xml"
net?=?ie.read_network(model=classification_model_xml)
exec_net?=?ie.load_network(network=net,?device_name="CPU")
input_layer?=?next(iter(net.input_info))
output_layer?=?next(iter(net.outputs))
2) 準(zhǔn)備工作:加載圖像并轉(zhuǎn)換為輸入形狀。
為了在網(wǎng)絡(luò)中處理圖像,需要將其加載到一個(gè)數(shù)組中,調(diào)整為網(wǎng)絡(luò)所期望的形狀,并轉(zhuǎn)換為網(wǎng)絡(luò)的輸入布局。
圖2-23 OpenVINO? -api讀入圖片信息
import?cv2
image_filename?=?"data/coco_hollywood.jpg"
image?=?cv2.imread(image_filename)
image.shape
該圖像的形狀為(663,994,3)。它的高度為663像素,寬度為994像素,并有3個(gè)顏色通道。我們得到一個(gè)網(wǎng)絡(luò)期望的高度和寬度的參考,并調(diào)整到這個(gè)尺寸
圖2-16 OpenVINO? -api加載ONNX模型
N,?C,?H,?W?=?net.input_info[input_layer].tensor_desc.dims
resized_image?=?cv2.resize(src=image,?dsize=(W,?H))
resized_image.shape
現(xiàn)在,圖像的寬度和高度是網(wǎng)絡(luò)所期望的。它仍然是H,C,W格式。我們首先調(diào)用np.transpose()將其改為N,C,H,W格式(其中N=1),然后通過調(diào)用np.expand_dims()添加N維。用np.astype()將數(shù)據(jù)轉(zhuǎn)換為FP32。
圖2-25 OpenVINO? -api處理圖片符合模型要求
import?numpy?as?np
input_data?=?np.expand_dims(np.transpose(resized_image,?(2,?0,?1)),?0).astype(np.float32)
input_data.shape
3) 進(jìn)行推理
現(xiàn)在,輸入數(shù)據(jù)的形狀是正確的,僅用一個(gè)簡(jiǎn)單的命令即可進(jìn)行推理。
圖2-26 OpenVINO? -api 推理獲得結(jié)果
result?=?exec_net.infer({input_layer:?input_data})
result
.infer()返回一個(gè)字典,將輸出層映射到數(shù)據(jù)。由于我們知道這個(gè)網(wǎng)絡(luò)返回一個(gè)輸出,并且我們?cè)趏utput_layer變量中存儲(chǔ)了對(duì)輸出層的引用,我們可以用result[output_layer]獲得數(shù)據(jù)。
圖2-27 OpenVINO? -api 推理結(jié)果
output?=?result[output_layer]
output.shape
輸出的形狀是(1,1001),我們看到這是輸出的預(yù)期形狀。這個(gè)輸出形狀表明,該網(wǎng)絡(luò)返回了1001個(gè)類的概率
5) 重塑和調(diào)整大小
調(diào)整圖像大小
我們可以不使用重塑圖像來適應(yīng)模型,而是通過重塑模型來適應(yīng)圖像。注意不是所有的模型都支持重塑,而支持重塑的模型可能不支持所有的輸入形狀。如果你重塑模型的輸入形狀,模型的準(zhǔn)確性也可能受到影響。我們首先檢查模型的輸入形狀,然后重塑為新的輸入形狀。
圖2-28 OpenVINO? -api 調(diào)整圖像尺寸
from?OpenVINO.inference_engine?import?IECore
ie?=?IECore()
segmentation_model_xml?=?"model/segmentation.xml"
segmentation_net?=?ie.read_network(model=segmentation_model_xml)
segmentation_input_layer?=?next(iter(segmentation_net.input_info))
segmentation_output_layer?=?next(iter(segmentation_net.outputs))
print("~~~~?ORIGINAL?MODEL?~~~~")
print(f"input?layout:?{segmentation_net.input_info[segmentation_input_layer].layout}")
print(f"input?shape:?{segmentation_net.input_info[segmentation_input_layer].tensor_desc.dims}")
print(f"output?shape:?{segmentation_net.outputs[segmentation_output_layer].shape}")
new_shape?=?(1,?3,?544,?544)
segmentation_net.reshape({segmentation_input_layer:?new_shape})
segmentation_exec_net?=?ie.load_network(network=segmentation_net,?device_name="CPU")
print("~~~~?RESHAPED?MODEL?~~~~")
print(f"net?input?shape:?{segmentation_net.input_info[segmentation_input_layer].tensor_desc.dims}")
print(
f"exec_net?input?shape:?"
f"{segmentation_exec_net.input_info[segmentation_input_layer].tensor_desc.dims}"
)
print(f"output?shape:?{segmentation_net.outputs[segmentation_output_layer].shape}")
分割網(wǎng)絡(luò)的輸入形狀是[1,3,512,512],采用NHCW布局:網(wǎng)絡(luò)期望3通道圖像的寬度和高度為512,批量大小為1。我們用IENetwork的.reshape()方法重新塑造網(wǎng)絡(luò),使其接受寬度和高度為544的輸入圖像。這個(gè)分割網(wǎng)絡(luò)總是返回寬度和高度與輸入寬度和高度相同的數(shù)組,所以將輸入尺寸設(shè)置為544x544也會(huì)修改輸出尺寸。重塑之后,再次將網(wǎng)絡(luò)加載到設(shè)備上。
改變批處理大小
我們也可以使用.reshape()來設(shè)置批量大小,通過增加_new_shape_的第一個(gè)元素。例如,要設(shè)置2個(gè)批次的大小,在上面的單元格中設(shè)置new_shape = (2,3,544,544)。如果你只想改變批量大小,你也可以直接設(shè)置batch_size屬性。
圖2-29 OpenVINO? -api 調(diào)整批處理大小
from?OpenVINO.inference_engine?import?IECore
ie?=?IECore()
segmentation_model_xml?=?"model/segmentation.xml"
segmentation_net?=?ie.read_network(model=segmentation_model_xml)
segmentation_input_layer?=?next(iter(segmentation_net.input_info))
segmentation_output_layer?=?next(iter(segmentation_net.outputs))
segmentation_net.batch_size?= 2
segmentation_exec_net?=?ie.load_network(network=segmentation_net,?device_name="CPU")
print(f"input?layout:?{segmentation_net.input_info[segmentation_input_layer].layout}")
print(f"input?shape:?{segmentation_net.input_info[segmentation_input_layer].tensor_desc.dims}")
print(f"output?shape:?{segmentation_net.outputs[segmentation_output_layer].shape}")
輸出顯示,通過設(shè)置批量大小為2,輸入和輸出形狀的第一個(gè)元素(N)現(xiàn)在的值為2。讓我們看看如果我們將輸入圖像通過網(wǎng)絡(luò)傳播會(huì)發(fā)生什么。
圖2-30 OpenVINO??-api批量為2的情況
import?numpy?as?np
from?OpenVINO.inference_engine?import?IECore
ie?=?IECore()
segmentation_model_xml?=?"model/segmentation.xml"
segmentation_net?=?ie.read_network(model=segmentation_model_xml)
segmentation_input_layer?=?next(iter(segmentation_net.input_info))
segmentation_output_layer?=?next(iter(segmentation_net.outputs))
input_data?=?np.random.rand(*segmentation_net.input_info[segmentation_input_layer].tensor_desc.dims)
segmentation_net.batch_size?=?2
segmentation_exec_net?=?ie.load_network(network=segmentation_net,?device_name="CPU")
result_batch?=?segmentation_exec_net.infer({segmentation_input_layer:?input_data})
print(f"input?data?shape:?{input_data.shape}")
print(f"result?data?data?shape:?{result_batch[segmentation_output_layer].shape}")
輸出顯示,如果批次大小為2,網(wǎng)絡(luò)輸出將有2的批次大小,即使只有一個(gè)圖像通過網(wǎng)絡(luò)傳播。不管批次大小如何,你總是可以在一個(gè)圖像上做推理。在這種情況下,只有第一個(gè)網(wǎng)絡(luò)輸出包含有意義的信息。通過創(chuàng)建批次大小為2的隨機(jī)數(shù)據(jù)來驗(yàn)證對(duì)兩幅圖像的推理是否有效。
圖2-31 OpenVINO? -api批次為2的輸出結(jié)果
import?numpy?as?np
from?OpenVINO.inference_engine?import?IECore
ie?=?IECore()
segmentation_model_xml?=?"model/segmentation.xml"
segmentation_net?=?ie.read_network(model=segmentation_model_xml)
segmentation_input_layer?=?next(iter(segmentation_net.input_info))
segmentation_output_layer?=?next(iter(segmentation_net.outputs))
segmentation_net.batch_size?=?2
input_data?=?np.random.rand(*segmentation_net.input_info[segmentation_input_layer].tensor_desc.dims)
segmentation_exec_net?=?ie.load_network(network=segmentation_net,?device_name="CPU")
result_batch?=?segmentation_exec_net.infer({segmentation_input_layer:?input_data})
print(f"input?data?shape:?{input_data.shape}")
print(f"result?data?shape:?{result_batch[segmentation_output_layer].shape}")
通過上面的學(xué)習(xí),我們可以總結(jié)出使用推理引擎進(jìn)行推理的流程,我們只要按照流程步驟進(jìn)行編程便可得到結(jié)果。我們?cè)賮砘仡櫹峦暾鞒?,在后續(xù)的章節(jié)中我們會(huì)通過不同的案例不斷練習(xí)這個(gè)流程,直至熟練掌握:
初始化載入硬件插件,所有AI計(jì)算硬件的插件都由IECore對(duì)象自行內(nèi)部管理。讀取IR文件,用類IECore將IR文件使用read_network()方法讀入到IENetwork類對(duì)象中去。
配置輸入輸出,將模型載入內(nèi)存后,用inputs和outputs指定模型輸入輸出張量的精度和布局(layout)。
載入模型,模型載入AI計(jì)算硬件后,會(huì)獲得一個(gè)ExecutableNetwork對(duì)象,該對(duì)象執(zhí)行推理計(jì)算。read_network()方法中的deviceName參數(shù)指定使用哪個(gè)AI計(jì)算硬件。
準(zhǔn)備輸入數(shù)據(jù)通過OpenCV采集圖像數(shù)據(jù)到Mat對(duì)象,然后用frameToBlob()函數(shù)將OpenCV Mat對(duì)象中的圖像數(shù)據(jù)傳給InferenceEngine Blob對(duì)象,AI模型將從InferenceEngine Blob對(duì)象中獲取圖像數(shù)據(jù)。
執(zhí)行推理計(jì)算,用infer()方法執(zhí)行同步推理計(jì)算,或者用StartAsync()和Wait()方法執(zhí)行異步推理計(jì)算。
處理模型輸出輸出為模型輸出的張量outputs,此時(shí)可以對(duì)結(jié)果進(jìn)行讀取、打標(biāo)簽或畫框等操作。
圖2-32 OpenVINO? -api推理引擎使用流程
2.3.3? ?Hello Segmentation
學(xué)習(xí)目標(biāo):
鞏固學(xué)習(xí)推理引擎API
掌握推理引擎使用流程
認(rèn)識(shí)道路分割模型
在上節(jié)中我們?cè)敿?xì)學(xué)習(xí)了推理引擎的API使用,我們按照初始化推理引擎-讀取網(wǎng)絡(luò)模型-配置輸入輸出-載入模型-準(zhǔn)備數(shù)據(jù)-執(zhí)行推理-處理輸出數(shù)據(jù)的流程即可完成人工智能應(yīng)用的開發(fā)。在本節(jié)中,我們使用Open Model Zoo的[road-segmentation-adas-0001]模型進(jìn)行練習(xí),鞏固推理引擎的API學(xué)習(xí)成果。ADAS是高級(jí)駕駛輔助服務(wù)的縮寫。該模型識(shí)別了四個(gè)類別:背景、道路、路邊和標(biāo)志。該模型的原框架為PyTorch,輸入圖像大小896x512。了解背景后我們開始操練。
1、 導(dǎo)入模塊
圖2-33 hello-segmentation
import?cv2
import?matplotlib.pyplot?as?plt
import?numpy?as?np
import?sys
from?OpenVINO.inference_engine?import?IECore
sys.path.append("../utils")
from?notebook_utils?import?segmentation_map_to_image
sys模塊 sys 模塊提供訪問解釋器使用或維護(hù)的變量,和與解釋器進(jìn)行交互的函數(shù)。通俗來講,sys 模塊為程序與 Python 解釋器的交互,提供了一系列的函數(shù)和變量,用于操控 Python 運(yùn)行時(shí)的環(huán)境。sys 模塊是 Python 中內(nèi)置的模塊,所以不需要再單獨(dú)安裝,只需在使用前 import sys 即可。
2、 加載模型
圖2-34 hello-segmentation初始化引擎及加載模型
ie?=?IECore()
net?=?ie.read_network(
model="model/road-segmentation-adas-0001.xml")
exec_net?=?ie.load_network(net,?"CPU")
output_layer_ir?=?next(iter(exec_net.outputs))
input_layer_ir?=?next(iter(exec_net.input_info))
遵循OpenVINO? 推理引擎使用流程,在這一步中,完成了推理引擎初始化、讀取網(wǎng)絡(luò)模型、加載網(wǎng)絡(luò)、配置輸入輸出的操作。
3、 加載圖像
根據(jù)網(wǎng)絡(luò)模型輸入要求,對(duì)圖像進(jìn)行處理并顯示原始圖像
圖2-35 hello-segmentation圖像處理
image?=?cv2.imread("data/empty_road_mapillary.jpg")
rgb_image?=?cv2.cvtColor(image,?cv2.COLOR_BGR2RGB)
image_h,?image_w,?_?=?image.shape
N,?C,?H,?W?=?net.input_info[input_layer_ir].tensor_desc.dims
resized_image?=?cv2.resize(image,?(W,?H))
input_image?=?np.expand_dims(
resized_image.transpose(2,?0,?1),?0
)
plt.imshow(rgb_image)
讀入圖像、將圖像色彩空間由BGR轉(zhuǎn)換為RGB、根據(jù)網(wǎng)絡(luò)模型輸入需要調(diào)整圖像尺寸,顯示圖像。
4、 執(zhí)行推理并顯示結(jié)果
圖2-36 hello-segmentation推理結(jié)果
result?=?exec_net.infer(inputs={input_layer_ir:?input_image})
result_ir?=?result[output_layer_ir]
segmentation_mask?=?np.argmax(result_ir,?axis=1)
plt.imshow(segmentation_mask[0])
5、 準(zhǔn)備數(shù)據(jù)可視化
圖2-37 hello-segmentation可視化準(zhǔn)備
alpha?=?0.3
mask?=?segmentation_map_to_image(segmentation_mask,?colormap)
resized_mask?=?cv2.resize(mask,?(image_w,?image_h))
image_with_mask?=?cv2.addWeighted(resized_mask,?alpha,?rgb_image,?1?-?alpha,?0)
在這一步中,定義顏色圖,每種類別以一種顏色表示,定義了分割圖層的透明度,使用工具函數(shù)進(jìn)行圖像色彩空間轉(zhuǎn)換,創(chuàng)建帶有掩膜的圖像。下一步進(jìn)行數(shù)據(jù)可視化展示。
6、 數(shù)據(jù)可視化展示
圖2-38 hello-segmentation可視化展示
data?=?{"Base?Photo":?rgb_image,?"Segmentation":?mask,?"Masked?Photo":?image_with_mask}
f,?axs?=?plt.subplots(1,?len(data.items()),?figsize=(15,?10))
for?ax,?(name,?image)?in?zip(axs,?data.items()):
ax.axis('off')
ax.set_title(name)
ax.imshow(image)
plt.show(f)
通過數(shù)據(jù)可視化我們得到了原始圖像,分割圖像以及原始圖像與分割圖像進(jìn)行疊加的圖像,可以更直觀的展示推理結(jié)果。
2.2.4? ?Hello Detection
本節(jié)目標(biāo):
強(qiáng)化學(xué)習(xí)推理引擎API
熟練掌握推理引擎使用流程
了解文本檢測(cè)模型
本節(jié)學(xué)習(xí)使用推理引擎完成檢測(cè)模型的應(yīng)用,學(xué)習(xí)如何在一個(gè)給定的IR模型上進(jìn)行文本檢測(cè)。我們使用Open Model Zoo中的[horizontal-text-detection-0001]模型。它檢測(cè)圖像中的文本,并返回形狀為[100, 5]的blob數(shù)據(jù)。對(duì)于每個(gè)檢測(cè)的描述都有[x_min, y_min, x_max, y_max, conf]格式。該模型是基于FCOS架構(gòu)的文本檢測(cè)器,以類似MobileNetV2為骨干,適用于有或多或少水平文字的室內(nèi)/室外場(chǎng)景。源框架為PyTorch,與基礎(chǔ)模型相比,該模型的主要優(yōu)點(diǎn)是尺寸更小,性能更快。
下面我們開始練習(xí)。
1、 導(dǎo)入所需模塊
圖2-39 hello-detection導(dǎo)入模塊
import?cv2
import?matplotlib.pyplot?as?plt
import?numpy?as?np
from?OpenVINO.inference_engine?import?IECore
from?os.path?import?isfile
2、 加載網(wǎng)絡(luò)模型
圖2-40 hello-detection加載網(wǎng)絡(luò)模型
ie?=?IECore()
model_folder?=?"model"
model_name?=?"horizontal-text-detection-0001"
model_extensions?=?("bin",?"xml")
for?extension?in?model_extensions:
if?not?isfile(f'{model_folder}/{model_name}.{extension}'):
raise?FileNotFoundError(f"Missing?model?file!?Please?download?missing?file:?{model_name}.{extension}")
net?=?ie.read_network(
model="model/horizontal-text-detection-0001.xml"
)
exec_net?=?ie.load_network(net,?"CPU")
output_layer_ir?=?next(iter(exec_net.outputs))
input_layer_ir?=?next(iter(exec_net.input_info))
又到了熟悉的流程、在這一步中完成了推理引擎初始化、網(wǎng)絡(luò)模型讀取、網(wǎng)絡(luò)加載、輸入輸出配置工作。與前幾節(jié)代碼相比,代碼中加入了條件判斷來確定是否包含需要的模型文件,如果沒有文件則需要先行下載,代碼加入的目的是讓程序更為健壯。
3、加載并處理圖片
圖2-41 hello-detection圖片預(yù)處理
image?=?cv2.imread("data/intel_rnb.jpg")
N,?C,?H,?W?=?net.input_info[input_layer_ir].tensor_desc.dims
resized_image?=?cv2.resize(image,?(W,?H))
input_image?=?np.expand_dims(
resized_image.transpose(2,?0,?1),?0
)
plt.imshow(image)
獲取模型輸入的要求,并根據(jù)要求對(duì)圖像進(jìn)行處理以滿足網(wǎng)絡(luò)模型輸入要求,最終顯示圖像。
4、進(jìn)行推理
圖2-42 hello-detection加載網(wǎng)絡(luò)模型
result?=?exec_net.infer(inputs={input_layer_ir:?input_image})
boxes?=?result['boxes']
boxes?=?boxes[~np.all(boxes==0,?axis=1)]
完成推理并保存推理結(jié)果。
5、 數(shù)據(jù)可視化
圖2-43 hello-detection結(jié)果展示
def?convert_result_to_image(bgr_image,?resized_image,?boxes,?threshold=0.3,?conf_labels=True):
def?multiply_by_ratio(ratio_x,?ratio_y,?box):
return?[max(shape?*?ratio_y,?10)?if?idx?%?2?else?shape?*?ratio_x?for?idx,?shape?in?enumerate(box[:-1])]
colors?=?{'red':?(255,?0,?0),?'green':?(0,?255,?0)}
(real_y,?real_x),?(resized_y,?resized_x)?=?image.shape[:2],?resized_image.shape[:2]
ratio_x,?ratio_y?=?real_x/resized_x,?real_y/resized_y
rgb_image?=?cv2.cvtColor(bgr_image,?cv2.COLOR_BGR2RGB)
for?box?in?boxes:
conf?=?box[-1]
if?conf?>?threshold:
(x_min,?y_min,?x_max,?y_max)?=?map(int,?multiply_by_ratio(ratio_x,?ratio_y,?box))
rgb_image?=?cv2.rectangle(
rgb_image,
(x_min,?y_min),
(x_max,?y_max),
colors['green'],
3
)
if?conf_labels:
rgb_image?=?cv2.putText(
rgb_image,
f"{conf:.2f}",
(x_min,?y_min?-?10),
cv2.FONT_HERSHEY_SIMPLEX,
0.8,
colors['red'],
1,
cv2.LINE_AA
)
return?rgb_image
plt.figure(figsize=(10,6))
plt.axis('off')
plt.imshow(convert_result_to_image(image,?resized_image,?boxes,?conf_labels=False))
2.1.5? ?小結(jié)
通過本節(jié)學(xué)習(xí)我們掌握了推理引擎API函數(shù)、掌握了使用推理引擎進(jìn)行開發(fā)的完整流程,同時(shí)通過案例我們學(xué)習(xí)了Mobilenetv3分類模型、基于PyTorch框架的道路分割模型以及文本檢測(cè)模型。
2.3 模型優(yōu)化器詳解
我們一直在學(xué)習(xí)探討深度學(xué)習(xí)、神經(jīng)網(wǎng)絡(luò)。其實(shí),神經(jīng)網(wǎng)絡(luò)并不復(fù)雜,就是多個(gè)神經(jīng)元的堆疊。多個(gè)神經(jīng)元之間通過網(wǎng)絡(luò)拓?fù)?/a>結(jié)構(gòu)相連,具備一定的分類能力,謂之“神經(jīng)網(wǎng)絡(luò)”。通常情況,網(wǎng)絡(luò)層數(shù)越多、參數(shù)越多,數(shù)據(jù)越多推理的精度越高。但并不是所有的網(wǎng)絡(luò)層都有助于進(jìn)行推理。OpenVINO? 的模型優(yōu)化器可以自動(dòng)識(shí)別推理過程中是無用的,并且可能會(huì)增加推理時(shí)間的圖層,比如對(duì)于訓(xùn)練很重要的Dropout圖層。通過對(duì)于無用層的裁剪完成模型優(yōu)化功能。
我們先了解下模型優(yōu)化器提供的功能及特點(diǎn):
優(yōu)化網(wǎng)絡(luò)
改變格式
削減部分網(wǎng)絡(luò)
支持自定義層
支持主流框架格式包括TensorFlow、Caffe、MXNet、Kaidi和ONNX格式
生成文件為IR中間層
模型優(yōu)化器后準(zhǔn)確度、精度基本不變,但性能必定會(huì)提升。模型生成IR中間層
在了解完模型優(yōu)化器的工作原理后,我們開始實(shí)訓(xùn)環(huán)節(jié),在后續(xù)章節(jié)中我們將練習(xí)將Tensoflow模型、PyTorch模型、PaddlePaddle模型進(jìn)行優(yōu)化并完成推理。
2.3.1?? Tensorflow模型優(yōu)化
學(xué)習(xí)目標(biāo):
掌握將TensorFlow模型轉(zhuǎn)換為OpenVINO??IR格式
1、 導(dǎo)入模塊
圖2-44 tensorflow-to-OpenVINO??導(dǎo)入模塊
import?json
import?sys
import?time
from?pathlib?import?Path
import?cv2
import?matplotlib.pyplot?as?plt
import?mo_tf
import?numpy?as?np
from?openvino . inference_engine?import?IECore
認(rèn)識(shí)新模塊
pathlib 是python自帶的用于處理文件路徑的模塊,使用pathlib可以創(chuàng)建路徑對(duì)象。使用路徑對(duì)象而不是字符串的一個(gè)重要優(yōu)點(diǎn)是,我們可以在路徑對(duì)象上調(diào)用方法。
mo_tf 模型優(yōu)化器用于處理tensorflow模型的轉(zhuǎn)換的模塊
圖2-45 tensorflow-to-OpenVINO? 定義模型名稱
model_path?=?Path("model/v3-small_224_1.0_float.pb")
ir_path?=?Path(model_path).with_suffix(".xml")
在本節(jié)演示中,我們使用tensorflow MobileNetV3模型。
2、 構(gòu)建轉(zhuǎn)換命令
調(diào)用OpenVINO? 模型優(yōu)化工具,將TensorFlow模型轉(zhuǎn)換為OpenVINO??IR,精度為FP16。模型被保存到當(dāng)前目錄。我們將平均值添加到模型中,并通過--scale_values將輸出與標(biāo)準(zhǔn)偏差進(jìn)行縮放。有了這些選項(xiàng),在通過網(wǎng)絡(luò)傳播之前,沒有必要對(duì)輸入數(shù)據(jù)進(jìn)行標(biāo)準(zhǔn)化處理。原始模型希望輸入的圖像是RGB格式的。轉(zhuǎn)換后的模型也希望是RGB格式的圖像。如果你想讓轉(zhuǎn)換后的模型適用于BGR圖像,你可以使用--反轉(zhuǎn)輸入通道選項(xiàng)。參見模型優(yōu)化器開發(fā)者指南以了解更多關(guān)于模型優(yōu)化器的信息,包括命令行選項(xiàng)的描述。查看模型文檔,了解有關(guān)模型的信息,包括輸入形狀、預(yù)期顏色順序和平均值。
圖2-46 tensorflow-to-OpenVINO??構(gòu)建優(yōu)化命令
mo_path?=?str(Path(mo_tf.__file__))
mo_command?=?f""""{sys.executable}"
"{mo_path}"
--input_model?"{model_path}"
--input_shape?"[1,224,224,3]"
--mean_values="[127.5,127.5,127.5]"
--scale_values="[127.5]"
--data_type?FP16
--output_dir?"{model_path.parent}"
"""
mo_command?=?"?".join(mo_command.split())
print("Model?Optimizer?command?to?convert?TensorFlow?to?OpenVINO? :")
print(mo_command)
3、 執(zhí)行優(yōu)化命令
模型優(yōu)化過程會(huì)花一些時(shí)間,根據(jù)運(yùn)行設(shè)備不同時(shí)間會(huì)有差異。當(dāng)我們看到輸出結(jié)果的最后幾行包括`[ SUCCESS ] Generated IR version 10 model.`則模型優(yōu)化是成功的。同時(shí)我們?cè)趍odel文件夾可以看到新生成的xml及bin文件。
圖2-47 tensorflow-to-OpenVINO? 執(zhí)行模型優(yōu)化及模型輸出
4、 對(duì)轉(zhuǎn)換后的模型進(jìn)行推理測(cè)試
1) 加載模型
圖2-48 tensorflow-to-OpenVINO? 加載模型
ie?=?IECore()
net?=?ie.read_network(str(ir_path))
exec_net?=?ie.load_network(net,?"CPU")
2)? ? 獲取模型信息
圖2-49 tensorflow-to-OpenVINO? 獲取模型信息
input_key?=?list(exec_net.input_info)[0]
output_key?=?list(exec_net.outputs.keys())[0]
network_input_shape?=?exec_net.input_info[input_key].tensor_desc.dims
3) 加載圖像并處理為適合網(wǎng)絡(luò)需要的格式
圖2-50 tensorflow-to-OpenVINO? 獲取模型信息
image?=?cv2.cvtColor(cv2.imread("data/coco.jpg"),?cv2.COLOR_BGR2RGB)
resized_image?=?cv2.resize(image,?(224,?224))
input_image?=?np.reshape(resized_image,?network_input_shape)?/?255
input_image?=?np.expand_dims(np.transpose(resized_image,?(2,?0,?1)),?0)
plt.imshow(image)
4)?執(zhí)行推理
圖2-51 tensorflow-to-OpenVINO?執(zhí)行推理并輸出結(jié)果
esult?=?exec_net.infer(inputs={input_key:?input_image})[output_key]
result_index?=?np.argmax(result)
imagenet_classes?=?json.loads(open("utils/imagenet_class_index.json").read())
imagenet_classes?=?{
int(key)?+?1:?value?for?key,?value?in?imagenet_classes.items()
}
imagenet_classes[result_index]
5) 性能測(cè)試
測(cè)量在一千張圖片上進(jìn)行推理所需的時(shí)間。以便于顯示出模型優(yōu)化后的性能。對(duì)于更精確的基準(zhǔn)測(cè)試,請(qǐng)使用OpenVINO? 基準(zhǔn)測(cè)試工具。我們?cè)诤竺娴恼鹿?jié)會(huì)學(xué)習(xí)如何使用OpenVINO? Benchmark進(jìn)行基準(zhǔn)測(cè)試。
圖2-52 tensorflow-to-OpenVINO? 性能測(cè)試結(jié)果
num_images?=?1000
start?=?time.perf_counter()
for?_?in?range(num_images):
exec_net.infer(inputs={input_key:?input_image})
end?=?time.perf_counter()
time_ir?=?end?-?start
print(
f"IR?model?in?Inference?Engine/CPU:?{time_ir/num_images:.4f}?"
f"seconds?per?image,?FPS:?{num_images/time_ir:.2f}"
)
至此,我們使用模型優(yōu)化器將TensorFlow模型轉(zhuǎn)化為推理引擎可以使用的IR模型,并完成了推理及簡(jiǎn)單的性能測(cè)試。
2.1.2? ?PyTorch模型優(yōu)化
學(xué)習(xí)目標(biāo):
掌握PyTorch模型轉(zhuǎn)化為ONNX格式的方法
掌握將ONNX轉(zhuǎn)化為IR格式的方法
本節(jié)演示了使用OpenVINO??對(duì)PyTorch語義分割模型進(jìn)行優(yōu)化并使用轉(zhuǎn)換后的模型進(jìn)行推理的逐步說明。
PyTorch模型需要先被轉(zhuǎn)換為ONNX格式,然后再使用模型優(yōu)化器將ONNX模型轉(zhuǎn)化為OpenVINO? 中間表示(IR)格式。ONNX和IR模型被加載到OpenVINO? 推理引擎中以顯示模型預(yù)測(cè)。該模型在CityScapes上進(jìn)行了預(yù)訓(xùn)練。模型來源是https://github.com/ekzhang/fastseg? 。
Fastseg是用于實(shí)時(shí)語義分割的MobileNetV3的PyTorch實(shí)現(xiàn),具有預(yù)訓(xùn)練的權(quán)重和最先進(jìn)的性能。
我們開始實(shí)操練習(xí)
1、 導(dǎo)入模塊
圖2-53 pytorch-onnx-to-OpenVINO? 導(dǎo)入模塊
由于安裝命令是依賴網(wǎng)絡(luò)將軟件包下載至本地環(huán)境,網(wǎng)絡(luò)環(huán)境不同所用安裝時(shí)間不盡相同,若網(wǎng)絡(luò)順暢,我們終將順利迎來安裝成功的提示。至此,環(huán)境安裝成功,我們已經(jīng)具備了運(yùn)行OpenVINO? Notebooks工程的全部環(huán)境。
import?sys
import?time
import?os
from?pathlib?import?Path
import?cv2
import?matplotlib.pyplot?as?plt
import?mo_onnx
import?numpy?as?np
import?torch
from?fastseg?import?MobileV3Large
from?openvino.inference_engine?import?IECore
sys.path.append("../utils")
from?notebook_utils?import?CityScapesSegmentation,?segmentation_map_to_image,?viz_result_image
認(rèn)識(shí)新模塊:
mo_onnx 模型優(yōu)化器轉(zhuǎn)換ONNX格式模塊
torch PyTorch框架的功能模塊,包含卷積函數(shù)、池化功能等
fastseg fastseg算法模型模塊
2、 模型轉(zhuǎn)換配置
設(shè)置模型的名稱,以及將用于網(wǎng)絡(luò)的圖像寬度和高度。CityScapes是在2048x1024的圖像上進(jìn)行預(yù)訓(xùn)練的。使用更小的尺寸會(huì)影響模型的準(zhǔn)確性,但會(huì)提高推理速度。
圖2-54 pytorch-onnx-to-OpenVINO? 模型轉(zhuǎn)換配置
IMAGE_WIDTH?=?1024
IMAGE_HEIGHT?=?1024?if?IMAGE_WIDTH?==?2048?else?512
DIRECTORY_NAME?=?'model'
BASE_MODEL_NAME?=?DIRECTORY_NAME?+?f"/fastseg{IMAGE_WIDTH}"
model_path?=?Path(BASE_MODEL_NAME).with_suffix(".pth")
onnx_path?=?model_path.with_suffix(".onnx")
ir_path?=?model_path.with_suffix(".xml")
設(shè)置圖片高度為1024,設(shè)置存儲(chǔ)PyTorch、ONNX以及IR模型的路徑
3、 下載Fastseg模型
圖2-55 pytorch-onnx-to-OpenVINO? 下載模型
print("Downloading?the?Fastseg?model?(if?it?has?not?been?downloaded?before)....")
model?=?MobileV3Large.from_pretrained().cpu().eval()
print("Loaded?PyTorch?Fastseg?model")
path_to_dir?=?f"{os.getcwd()}/{DIRECTORY_NAME}"
os.makedirs(path_to_dir,?exist_ok=True)
print("nSaving?the?model")
torch.save(model.state_dict(),?str(model_path))
print(f"Model?saved?at?{model_path}")
在本節(jié)中,我們直接從github下載Fastseg預(yù)訓(xùn)練模型存儲(chǔ)在model文件夾中。這是我們?cè)陂_發(fā)應(yīng)用中用到的獲取模型方式之一,在后續(xù)章節(jié)中我們還將介紹如何利用OpenVINO? Model Zoo開放模型庫(kù)獲取模型。
4、 將PyTorch模型導(dǎo)出為ONNX格式
我們使用torch模塊onnx.export功能將PyTorch模型轉(zhuǎn)換為ONNX模型,如果在輸出顯示一些警告,我們可以忽略。如果輸出的最后一行顯示 "ONNX模型導(dǎo)出到fastseg1024.onnx.`",則轉(zhuǎn)換成功。
圖2-56 pytorch-onnx-to-OpenVINO? 模型轉(zhuǎn)換
if?not?onnx_path.exists():
dummy_input?=?torch.randn(1,?3,?IMAGE_HEIGHT,?IMAGE_WIDTH)
torch.onnx.export(
model,
dummy_input,
onnx_path,
opset_version=11,
do_constant_folding=False,
)
print(f"ONNX?model?exported?to?{onnx_path}.")
else:
print(f"ONNX?model?{onnx_path}?already?exists.")
5、 將ONNX模型轉(zhuǎn)換為OpenVINO? IR格式
調(diào)用OpenVINO??模型優(yōu)化工具,將ONNX模型轉(zhuǎn)換成OpenVINO? IR,精度為FP16。模型被保存到當(dāng)前目錄。我們?cè)谀P椭屑尤肫骄担⒂?-scale_values對(duì)輸出的標(biāo)準(zhǔn)偏差進(jìn)行縮放。有了這些選項(xiàng),在通過網(wǎng)絡(luò)傳播之前,沒有必要對(duì)輸入數(shù)據(jù)進(jìn)行標(biāo)準(zhǔn)化。執(zhí)行這個(gè)命令可能需要一些時(shí)間。輸出中可能有一些錯(cuò)誤或警告。如果輸出的最后幾行包括[ SUCCESS ] 生成了IR版本10模型,則模型優(yōu)化是成功的。
1)???? 準(zhǔn)備轉(zhuǎn)換命令
圖2-57 pytorch-onnx-to-OpenVINO? 準(zhǔn)備模型優(yōu)化命令
mo_path?=?str(Path(mo_onnx.__file__))
mo_command?=?f""""{sys.executable}"
"{mo_path}"
--input_model?"{onnx_path}"
--input_shape?"[1,3,?{IMAGE_HEIGHT},?{IMAGE_WIDTH}]"
--mean_values="[123.675,?116.28?,?103.53]"
--scale_values="[58.395,?57.12?,?57.375]"
--data_type?FP16
--output_dir?"{model_path.parent}"
"""
mo_command?=?"?".join(mo_command.split())
print("Model?Optimizer?command?to?convert?the?ONNX?model?to?OpenVINO:")
print(mo_command)
2)???? 執(zhí)行模型優(yōu)化
圖2-58 pytorch-onnx-to-OpenVINO? 執(zhí)行模型優(yōu)化
if?not?ir_path.exists():
print("Exporting?ONNX?model?to?IR...?This?may?take?a?few?minutes.")
mo_result?=?%sx?$mo_command
print("n".join(mo_result))
else:
print(f"IR?model?{ir_path}?already?exists.")
6、 模型對(duì)比
通過前面的操作,我們已有了原始模型、ONNX模型以及IR模型,通過比較ONNX、IR和PyTorch模型的預(yù)測(cè)結(jié)果,以確認(rèn)分割結(jié)果與預(yù)期相符。
1)???? 加載和預(yù)處理輸入圖像
對(duì)于OpenVINO??模型,歸一化被移到模型中。對(duì)于ONNX和PyTorch模型,圖像在通過網(wǎng)絡(luò)傳播之前需要進(jìn)行標(biāo)準(zhǔn)化處理。
圖2-59 pytorch-onnx-to-OpenVINO? 圖片預(yù)處理
def?normalize(image:?np.ndarray)?->?np.ndarray:
"""
Normalize?the?image?to?the?given?mean?and?standard?deviation
for?CityScapes?models.
"""
image?=?image.astype(np.float32)
mean?=?(0.485,?0.456,?0.406)
std?=?(0.229,?0.224,?0.225)
image?/=?255.0
image?-=?mean
image?/=?std
return?image
image_filename?=?"data/coco_cross.png"
image?=?cv2.cvtColor(cv2.imread(image_filename),?cv2.COLOR_BGR2RGB)
resized_image?=?cv2.resize(image,?(IMAGE_WIDTH,?IMAGE_HEIGHT))
normalized_image?=?normalize(resized_image)
input_image?=?np.expand_dims(np.transpose(resized_image,?(2,?0,?1)),?0)
normalized_input_image?=?np.expand_dims(np.transpose(normalized_image,?(2,?0,?1)),?0)
2)???? 使用ONNX及IR模型進(jìn)行推理驗(yàn)證
推理引擎可以直接加載ONNX模型。我們首先加載ONNX模型,進(jìn)行推理并顯示結(jié)果。之后,我們加載用模型優(yōu)化器轉(zhuǎn)換為中間表征(IR)的模型,對(duì)該模型進(jìn)行推理并顯示結(jié)果。我們已經(jīng)熟悉推理引擎的使用步驟,此處不多贅述。
推理引擎中的ONNX模型
圖2-60 pytorch-onnx-to-OpenVINO??onnx模型推理結(jié)果
ie?=?IECore()
net_onnx?=?ie.read_network(model=onnx_path)
exec_net_onnx?=?ie.load_network(network=net_onnx,?device_name="CPU")
input_layer_onnx?=?next(iter(exec_net_onnx.input_info))
output_layer_onnx?=?next(iter(exec_net_onnx.outputs))
res_onnx?=?exec_net_onnx.infer(inputs={input_layer_onnx:?normalized_input_image})
res_onnx?=?res_onnx[output_layer_onnx]
result_mask_onnx?=?np.squeeze(np.argmax(res_onnx,?axis=1)).astype(np.uint8)
viz_result_image(
image,?segmentation_map_to_image(result_mask_onnx,?CityScapesSegmentation.get_colormap()),?resize=True
)
使用IR模型進(jìn)行推理
圖2-61 pytorch-onnx-to-OpenVINO??IR模型推理結(jié)果
PyTorch原始模型推理
在PyTorch模型上做推理,以驗(yàn)證輸出在視覺上看起來與ONNX/IR模型的輸出相同。
圖2-62pytorch-onnx-to-OpenVINO?原始模型推理結(jié)果
從結(jié)果看,三種模型都成功輸出了結(jié)果。接下來我們進(jìn)行性能測(cè)試。
1)???? 性能比較
測(cè)量在五幅圖像上進(jìn)行推理所需的時(shí)間,給出簡(jiǎn)版的性能的對(duì)比。
圖2-63 pytorch-onnx-to-OpenVINO? 模型結(jié)果對(duì)比
num_images?=?5
start?=?time.perf_counter()
for?_?in?range(num_images):
exec_net_onnx.infer(inputs={input_layer_onnx:?input_image})
end?=?time.perf_counter()
time_onnx?=?end?-?start
print(
f"ONNX?model?in?Inference?Engine/CPU:?{time_onnx/num_images:.3f}?"
f"seconds?per?image,?FPS:?{num_images/time_onnx:.2f}"
)
start?=?time.perf_counter()
for?_?in?range(num_images):
exec_net_ir.infer(inputs={input_layer_ir:?input_image})
end?=?time.perf_counter()
time_ir?=?end?-?start
print(
f"IR?model?in?Inference?Engine/CPU:?{time_ir/num_images:.3f}?"
f"seconds?per?image,?FPS:?{num_images/time_ir:.2f}"
)
with?torch.no_grad():
start?=?time.perf_counter()
for?_?in?range(num_images):
model(torch.as_tensor(input_image).float())
end?=?time.perf_counter()
time_torch?=?end?-?start
print(
f"PyTorch?model?on?CPU:?{time_torch/num_images:.3f}?seconds?per?image,?"
f"FPS:?{num_images/time_torch:.2f}"
)
從對(duì)比結(jié)果顯示經(jīng)過模型優(yōu)化器處理再經(jīng)推理引擎執(zhí)行的模型,要比在同一設(shè)備上使用原始模型進(jìn)行推理的效率成倍提升。
2.3.3? ?PaddlePaddle模型優(yōu)化
學(xué)習(xí)目標(biāo):
掌握PaddlePaddle模型轉(zhuǎn)化為ONNX模型的方法
掌握ONNX模型轉(zhuǎn)化為IR格式模型的方法
本節(jié)學(xué)習(xí)如何將在ImageNet數(shù)據(jù)集上預(yù)訓(xùn)練的MobileNet V3 PaddleHub模型轉(zhuǎn)換ONNX及OpenVINO? IR模型。同時(shí)我們繼續(xù)強(qiáng)化學(xué)習(xí)如何使用OpenVINO? Inference Engine對(duì)圖像進(jìn)行分類推理,并比較使用PaddlePaddle原始模型與模型優(yōu)化器轉(zhuǎn)化后的IR模型推理結(jié)果差異。
模型來源是:
https://www.paddlepaddle.org.cn/hubdetail?name=mobilenet_v3_large_imagenet_ssld&en_category=ImageClassification
1、 導(dǎo)入模塊
圖2-64 paddle-onnx-to-OpenVINO? 原始模型推理結(jié)果
print(f"output?layout:?{net.outputs[output_layer].layout}")
print(f"output?precision:?{net.outputs[output_layer].precision}")
print(f"output?shape:?{net.outputs[output_layer].shape}")
認(rèn)識(shí)新模塊:
time 用于時(shí)間處理的模塊
paddlehub paddlepaddle框架提供的預(yù)訓(xùn)練模型庫(kù)
Python 是交互式shell庫(kù),支持變量自動(dòng)補(bǔ)全、自動(dòng)縮進(jìn)以及多種功能函數(shù)
paddle PaddlePaddle飛槳模型模塊
PIL python圖像處理庫(kù),用于圖像處理例如創(chuàng)建、打開、顯示、保存圖像、合成、裁剪等等。
scipy 是一個(gè)高級(jí)的科學(xué)計(jì)算庫(kù),包含線性代數(shù)、優(yōu)化、集成和統(tǒng)計(jì)的模塊,該模塊包含致力于科學(xué)計(jì)算中常見問題的各個(gè)工具箱。
2、 PaddlePaddle飛槳模型下載配置
設(shè)置IMAGE_FILENAME為要使用的圖片的文件名。設(shè)置MODEL_NAME為要從PaddleHub下載的PaddlePaddle模型。MODEL_NAME也將是轉(zhuǎn)換后的ONNX和IR模型的基本名稱。本節(jié)使用mobilenet_v3_large_imagenet_ssld模型進(jìn)行測(cè)試。其他模型可能使用不同的預(yù)處理方法,可根據(jù)需要進(jìn)行一些修改,以便在原始模型和轉(zhuǎn)換模型上得到相同的結(jié)果。hub.config.server是PaddleHub服務(wù)器的URL。你應(yīng)該不需要修改這個(gè)設(shè)置。
圖2-65 paddle-onnx-to-OpenVINO? 定義模型及下載服務(wù)器
IMAGE_FILENAME?=?"coco_close.png"
MODEL_NAME?=?"mobilenet_v3_large_imagenet_ssld"
hub.config.server?=?"https://paddlepaddle.org.cn/paddlehub"
3、 PaddlePaddle模型推理
我們從PaddleHub加載并下載模型,讀取并顯示一幅圖像,對(duì)該圖像進(jìn)行推理,并顯示前三個(gè)預(yù)測(cè)結(jié)果。第一次運(yùn)行時(shí),我們會(huì)從PaddleHub下載所需要的模型
圖2-66 paddle-onnx-to-OpenVINO? 原始模型推理結(jié)果
classifier.classification()將一張圖片作為輸入,并返回圖片的類別名稱。默認(rèn)情況下,返回最佳網(wǎng)絡(luò)結(jié)果。使用top_k'參數(shù),將返回最佳的k'結(jié)果,其中k是一個(gè)數(shù)字。對(duì)圖像的預(yù)處理和將網(wǎng)絡(luò)結(jié)果轉(zhuǎn)換為類別名稱是在幕后完成的。分類模型返回一個(gè)數(shù)組,其中包含1000個(gè)ImageNet類別中每個(gè)類別的浮點(diǎn)值。該值越高,網(wǎng)絡(luò)就越有信心認(rèn)為該值對(duì)應(yīng)的類號(hào)(該值在網(wǎng)絡(luò)輸出數(shù)組中的索引)是該圖像的類號(hào)。classification()函數(shù)將這些數(shù)字轉(zhuǎn)換為類別名稱和softmax概率。
我們通過process_image()函數(shù)查看PaddlePaddle的分類函數(shù)以及加載和預(yù)處理數(shù)據(jù)的實(shí)現(xiàn),可以看到裁剪和調(diào)整大小的效果。由于歸一化,顏色看起來會(huì)很奇怪,而且matplotlib會(huì)對(duì)剪裁值發(fā)出警告。
圖2-67 paddle-onnx-to-OpenVINO? process_image結(jié)果
4、 將模型轉(zhuǎn)換為OpenVINO? 的IR格式
為了將PaddlePaddle模型轉(zhuǎn)換為IR格式,我們首先將模型轉(zhuǎn)換為ONNX,然后將ONNX模型轉(zhuǎn)換為IR格式。
1) 準(zhǔn)備工作
PaddlePaddle的MobileNet模型包含了關(guān)于輸入形狀、平均值和比例值的信息,我們可以用它來轉(zhuǎn)換模型。
圖2-68 paddle-onnx-to-OpenVINO??獲取模型信息
input_shape?=?list(classifier.cpu_predictor.get_input_tensor_shape().values())
print("input?shape:",?input_shape)
print("mean:",?classifier.get_pretrained_images_mean())
print("std:",?classifier.get_pretrained_images_std())
2) 將PaddlePaddle模型轉(zhuǎn)換為ONNX模型
我們用paddle2onnx.export_onnx_model()方法將PaddlePaddle模型轉(zhuǎn)換為ONNX,詳細(xì)信息請(qǐng)參考(https://github.com/PaddlePaddle/paddle2onnx)執(zhí)行完成后我們?cè)趍odel文件夾得到了ONNX模型。
圖2-69 paddle-onnx-to-OpenVINO? 獲取模型信息
target_height,?target_width?=?next(iter(input_shape))[2:]
x_spec?=?InputSpec([1,?3,?target_height,?target_width],?"float32",?"x")
print(
"Exporting?PaddlePaddle?model?to?ONNX?with?target_height?"
f"{target_height}?and?target_width?{target_width}"
)
classifier.export_onnx_model(".",?input_spec=[x_spec],?opset_version=11)
3) 將ONNX模型轉(zhuǎn)換為OpenVINO? IR格式
調(diào)用OpenVINO? 模型優(yōu)化工具,將PaddlePaddle模型轉(zhuǎn)換為OpenVINO? IR,精度為FP32。這些模型被保存到當(dāng)前目錄中。我們可以用--mean_values將均值添加到模型中,用--scale_values將輸出與標(biāo)準(zhǔn)差進(jìn)行縮放。有了這些選項(xiàng),在通過網(wǎng)絡(luò)傳播之前,沒有必要對(duì)輸入數(shù)據(jù)進(jìn)行標(biāo)準(zhǔn)化處理。然而,為了得到與PaddlePaddle模型完全相同的輸出,有必要以同樣的方式對(duì)圖像進(jìn)行預(yù)處理。因此,在本教程中,我們不向模型添加平均值和比例值,我們使用process_image函數(shù),如上節(jié)所述,以確保IR和PaddlePaddle模型使用相同的預(yù)處理方法。
圖2-70 paddle-onnx-to-OpenVINO?? 轉(zhuǎn)換為IR模型
model_xml?=?f"{MODEL_NAME}.xml"
if?not?os.path.exists(model_xml):
mo_command?=?f'mo?--input_model?{MODEL_NAME}.onnx?--input_shape?"[1,3,{target_height},{target_width}]"'
display(Markdown(f"Model?Optimizer?command?to?convert?the?ONNX?model?to?IR:?`{mo_command}`"))
display(Markdown("_Converting?model?to?IR.?This?may?take?a?few?minutes..._"))
!?$mo_command
else:
print(f"{model_xml}?already?exists.")
使用模型優(yōu)化器完成轉(zhuǎn)換后,在model文件夾生成.xml以及.bin的IR模型。
4) 使用推理引擎進(jìn)行推理
加載IR模型,獲取模型信息,加載圖像,進(jìn)行推理,將推理結(jié)果轉(zhuǎn)換成有意義的結(jié)果,并顯示輸出
ie?=?IECore()
net?=?ie.read_network(f"{MODEL_NAME}.xml")
exec_net?=?ie.load_network(net,?"CPU")
input_layer?=?next(iter(net.input_info))
output_layer?=?next(iter(net.outputs))
image?=?Image.open(IMAGE_FILENAME)
plt.imshow(image)
input_image?=?process_image(image)
ie_result?=?exec_net.infer({input_layer:?input_image})[output_layer][0]
softmax_result?=?softmax(ie_result)
top_indices?=?np.argsort(softmax_result)[-3:][::-1]
top_softmax?=?softmax_result[top_indices]
for?index,?softmax_probability?in?zip(top_indices,?top_softmax):
print(f"{classifier.label_list[index]},?{softmax_probability:.5f}")
ie?=?IECore()
net?=?ie.read_network(f"{MODEL_NAME}.xml")
exec_net?=?ie.load_network(net,?"CPU")
input_layer?=?next(iter(net.input_info))
output_layer?=?next(iter(net.outputs))
image?=?Image.open(IMAGE_FILENAME)
plt.imshow(image)
input_image?=?process_image(image)
ie_result?=?exec_net.infer({input_layer:?input_image})[output_layer][0]
softmax_result?=?softmax(ie_result)
top_indices?=?np.argsort(softmax_result)[-3:][::-1]
top_softmax?=?softmax_result[top_indices]
for?index,?softmax_probability?in?zip(top_indices,?top_softmax):
print(f"{classifier.label_list[index]},?{softmax_probability:.5f}")
由輸出結(jié)果也可以驗(yàn)證我們的優(yōu)化流程是成功的。
1) 執(zhí)行效率對(duì)比
測(cè)量在50張圖片上進(jìn)行推理所需的時(shí)間,并比較結(jié)果。時(shí)間信息給出了一個(gè)性能的指示。為了進(jìn)行公平的比較,我們把處理圖像的時(shí)間也包括在內(nèi)。
圖2-71 paddle-onnx-to-OpenVINO? 原始模型推理
使用PaddlePaddle原始模型在CPU上進(jìn)行推理,每幅圖像推理時(shí)間為0.0506秒,F(xiàn)PS為19.76推理結(jié)果為拉布拉多尋回犬。
圖2-72 paddle-onnx-to-OpenVINO? IR模型推理
使用優(yōu)化后的IR模型在CPU上進(jìn)行推理,每幅圖像推理時(shí)間為0.0093秒,F(xiàn)PS為107.74推理結(jié)果為拉布拉多尋回犬, 在推理精度沒有降低的同時(shí)推理效率大幅度提升。
2.3.4? ?模型下載器及轉(zhuǎn)換工具
學(xué)習(xí)目標(biāo):
掌握使用模型下載器下載模型
掌握使用模型轉(zhuǎn)換器轉(zhuǎn)換公共模型
從前面章節(jié)的學(xué)習(xí)中,我們認(rèn)識(shí)到獲取模型、選擇模型是人工智能應(yīng)用開發(fā)基礎(chǔ)環(huán)節(jié)同時(shí)也是最重要的環(huán)節(jié),我們從github、PaddleHub下載了預(yù)訓(xùn)練模型,此外Pytorch Hub、Tensorflow都提供了預(yù)訓(xùn)練模型供開發(fā)者使用。OpenVINO? 工具包同樣提供了Open Model Zoo開放模型庫(kù)內(nèi)置了大量的可以商用的預(yù)訓(xùn)練模型以及公開模型供我們使用。與此同時(shí),為了方便管理、下載使用這些模型,OpenVINO?工具包提供了模型加載器以及模型轉(zhuǎn)換器工具。本節(jié)我們學(xué)習(xí)使用下載器及轉(zhuǎn)換器,如何從Open Model Zoo下載一個(gè)模型,將其轉(zhuǎn)換為OpenVINO? 的IR格式,顯示模型的信息,并對(duì)該模型進(jìn)行基準(zhǔn)測(cè)試。讓我們站在巨人肩膀上加速前進(jìn)。
關(guān)于Open Model Zoo開放模型庫(kù)的工具
模型下載配套的工具有模型下載器、模型轉(zhuǎn)換器、信息轉(zhuǎn)儲(chǔ)器和基準(zhǔn)工具。
模型下載器 omz_downloader從Open Model Zoo下載模型
模型轉(zhuǎn)換器 omz_converter將不是OpenVINO? 的IR格式的Open Model Zoo模型轉(zhuǎn)換成IR格式
信息挖掘器 omz_info_dumper ?? 打印關(guān)于Open Model Zoo模型的信息。
基準(zhǔn)測(cè)試工具benchmark_app ??? 通過計(jì)算推理時(shí)間對(duì)模型性能進(jìn)行基準(zhǔn)測(cè)試。
了解以上信息后,我們正式進(jìn)入操練環(huán)節(jié)。
1、 準(zhǔn)備工作
設(shè)置模型名稱,設(shè)置model_name是下載的Open Model Zoo中模型的名稱,演示中我們依舊使MobileNet模型。更多信息可以從官方站點(diǎn)獲得:
https://docs.OpenVINO?toolkit.org/cn/latest/index.html
圖2-73 model-tool 設(shè)置模型名稱
#?model_name?=?"resnet-50-pytorch"
model_name?=?"mobilenet-v2-pytorch"
2、 導(dǎo)入模塊
圖2-74 model-tool 導(dǎo)入模塊
import?json
import?os.path
import?subprocess
import?sys
from?pathlib?import?Path
from?IPython.display?import?Markdown
from?OpenVINO.inference_engine?import?IECore
sys.path.append("../utils")
from?notebook_utils?import?DeviceNotFoundAlert,?NotebookAlert
認(rèn)識(shí)新模塊:
subprocess 模塊允許我們啟動(dòng)一個(gè)新進(jìn)程,并連接到它們的輸入/輸出/錯(cuò)誤管道,從而獲取返回值
3、 環(huán)境配置
設(shè)置文件和目錄的路徑。默認(rèn)情況下,本演示筆記本從Open Model Zoo下載模型到你的$HOME目錄下的open_model_zoo_models目錄。在Windows上,$HOME目錄通常是c:usersusername,在Linux上是/home/username。如果你想改變文件夾,在下面的單元格中改變base_model_dir。
為了便于模型管理我們可以根據(jù)需要修改以下設(shè)置。
base_model_dir。模型將被下載到這個(gè)目錄下的intel和public文件夾。
omz_cache_dir: Open Model Zoo的緩存文件夾。對(duì)于模型下載器和模型轉(zhuǎn)換器來說,指定一個(gè)緩存目錄不是必須的,但它可以加速后續(xù)的下載。
precision: 如果指定,只下載此精度的模型。
圖2-75 model-tool 環(huán)節(jié)配置
base_model_dir?=?Path("~/open_model_zoo_models").expanduser()
omz_cache_dir?=?Path("~/open_model_zoo_cache").expanduser()
precision?=?"FP16"
ie?=?IECore()
gpu_available?=?"GPU"?in?ie.available_devices
print(
f"base_model_dir:?{base_model_dir},?omz_cache_dir:?{omz_cache_dir},?gpu_availble:?{gpu_available}"
)
4、?從Open Model Zoo下載模型
指定、顯示和運(yùn)行模型下載器命令以下載模型
圖2-76 model-tool 下載模型
download_command?=?(
f"omz_downloader?--name?{model_name}?--output_dir?{base_model_dir}?--cache_dir?{omz_cache_dir}"
)
display(Markdown(f"Download?command:?`{download_command}`"))
display(Markdown(f"Downloading?{model_name}..."))
!?$download_command
我們成功下載了模型,存儲(chǔ)在open_model_zoo_models/public/mobilenet-v2-pytorch目錄下,需要注意,在下載模型時(shí)一定要保證網(wǎng)絡(luò)暢通。
5、 將模型轉(zhuǎn)換為OpenVINO? 的IR格式
我們成功下載了PyTorch模型,但推理引擎無法直接加載,因此我們需要進(jìn)行模型轉(zhuǎn)換。模型轉(zhuǎn)換器的作用是將非IR格式的模型轉(zhuǎn)換為IR格式。通過指定、顯示和運(yùn)行Model Converter命令,將模型轉(zhuǎn)換為IR格式。如果輸出的最后幾行包括[ SUCCESS ] Generated IR version 10 model。
圖2-77 model-tool 模型轉(zhuǎn)換命令
convert_command?=?f"omz_converter?--name?{model_name}?--precisions?{precision}?--download_dir?{base_model_dir}?--output_dir?{base_model_dir}"
display(Markdown(f"Convert?command:?`{convert_command}`"))
display(Markdown(f"Converting?{model_name}..."))
!?$convert_command
在前面的小節(jié)中,在處理PyTorch模型時(shí)需要先轉(zhuǎn)為ONNX,然后在運(yùn)行模型優(yōu)化器將ONNX模型轉(zhuǎn)為IR模型,此處我們使用模型轉(zhuǎn)換器這一命令,可以完成全部操作,加快了開發(fā)進(jìn)度。
圖2-78 model-tool 模型轉(zhuǎn)換結(jié)果
通過輸出結(jié)果我們不難發(fā)現(xiàn),模型轉(zhuǎn)換器為我們自動(dòng)執(zhí)行了模型轉(zhuǎn)換以及模型優(yōu)化工作,這也是Open Model Zoo提供的便捷命令。當(dāng)然我們也可以需要自行修改參數(shù)分步執(zhí)行。
接下來,info dumper功能查看下我們得到的模型信息。
6、 獲取模型信息
圖2-78 model-tool 獲取模型信息
model_info_output?=?%sx?omz_info_dumper?--name?$model_name
model_info?=?json.loads(model_info_output.get_nlstr())
if?len(model_info)?>?1:
NotebookAlert(
f"There?are?multiple?IR?files?for?the?{model_name}?model.?The?first?model?in?the?"
"omz_info_dumper?output?will?be?used?for?benchmarking.?Change?"
"`selected_model_info`?in?the?cell?below?to?select?a?different?model?from?the?list.",
"warning",
)
model_info
Info Dumper會(huì)打印出Open Model Zoo模型的下列信息。
模型名稱
描述
用來訓(xùn)練模型的框架
許可證網(wǎng)址
模型所支持的精確性
子目錄:下載模型的位置
任務(wù)類型
這些信息可以通過在終端運(yùn)行omz_info_dumper --name model_name來顯示。這些信息也可以被解析并在腳本中使用。
圖2-78 model-tool info_dumper輸出結(jié)果
現(xiàn)在,我們有了可以執(zhí)行推理的模型,接下來我們使用benchmark工具進(jìn)行基準(zhǔn)性能測(cè)試,來驗(yàn)證我們模型轉(zhuǎn)換的效果。
7、 運(yùn)行基準(zhǔn)測(cè)試工具
默認(rèn)情況下,Benchmark Tool在CPU上以異步模式運(yùn)行推理60秒。它以延遲(每幅圖像毫秒)和吞吐量(每秒幀數(shù))的形式返回推理速度。
圖
圖2-78 model-tool benchmark_app輸出結(jié)果
用Benchmark工具,我們可以準(zhǔn)確跟蹤到每一步執(zhí)行所耗時(shí)間以及最終的統(tǒng)計(jì)時(shí)間,便于我們更好的優(yōu)化模型及優(yōu)化程序。此外我們還可以利用基準(zhǔn)測(cè)試工具提供的擴(kuò)展參數(shù),進(jìn)行不同的測(cè)試配置,例如指定推理設(shè)備、指定運(yùn)行推理時(shí)間、指定同步或一步執(zhí)行方式以及設(shè)置批量大小等等,通過設(shè)置不同參數(shù)組合,對(duì)模型進(jìn)行多維度測(cè)試。下面的單元格顯示了一些benchmark_app與不同參數(shù)的例子。一些有用的參數(shù)是。
-d 用于推理的設(shè)備。例如。cpu, gpu, multi. 默認(rèn)值。CPU
-t 運(yùn)行推理的時(shí)間,以秒數(shù)計(jì)。默認(rèn)值:60
-api 使用異步(async)或同步(sync)推理。默認(rèn)值:async
-b 批量大小。默認(rèn)值:1
圖2-78 model-tool benchmark輸出
def?benchmark_model(model,?device="CPU",?seconds=60,?api="async",?batch=1):
ie?=?IECore()
if?("GPU"?in?device)?and?("GPU"?not?in?ie.available_devices):
DeviceNotFoundAlert("GPU")
else:
benchmark_command?=?f"benchmark_app?-m?{model_path}?-d?{device}?-t?{seconds}?-api?{api}?-b?{batch}"
display(Markdown(f"**Benchmark?{model_name}?with?{device}?for?{seconds}?seconds?with?{api}?inference**"))
display(Markdown(f"Benchmark?command:?`{benchmark_command}`"))
benchmark_output?=?%sx?$benchmark_command
benchmark_result?=?[line?for?line?in?benchmark_output?if?not?(line.startswith(r"[")?or?line.startswith("??")?or?line=="")]
print("n".join(benchmark_result))
ie?=?IECore()
for?device?in?ie.available_devices:
device_name?=?ie.get_metric(device,?"FULL_DEVICE_NAME")
print(f"{device}:?{device_name}")
benchmark_model(model_path,?device="CPU",?seconds=15,?api="async")
benchmark_model(model_path,?device="AUTO",?seconds=15,?api="async")
benchmark_model(model_path,?device="GPU",?seconds=15,?api="async")
在筆記中我們指定了CPU設(shè)備,指定異步處理,推理時(shí)間15秒,批量設(shè)置為1,得到了測(cè)試結(jié)果。由于測(cè)試設(shè)備中并沒有進(jìn)行GPU配置,因此沒有得到GPU推理的參考結(jié)果。
2.3.5? ?小結(jié)
通過本節(jié)學(xué)習(xí)我們掌握了模型優(yōu)化器的使用;掌握了如何將tensorflow、PyTorch、PaddlePaddle模型轉(zhuǎn)化為OpenVINO??IR模型;此外,我們也學(xué)習(xí)了如何利用模型下載器從Open Model Zoo開放模型庫(kù)下載模型,以及使用模型轉(zhuǎn)化器將下載的模型轉(zhuǎn)換為推理引擎支持的IR模型。最后我們也學(xué)習(xí)了利用Benchmark基準(zhǔn)測(cè)試工具對(duì)模型進(jìn)行基準(zhǔn)測(cè)試,為優(yōu)化模型以及優(yōu)化程序提供參考。
2.4 本章小結(jié)
通過本章學(xué)習(xí)相信大家已經(jīng)掌握了OpenVINO??推理引擎以及模型優(yōu)化器的使用,通過多個(gè)筆記實(shí)操,相信大家也熟練掌握了利用OpenVINO? 快速開發(fā)人工智能應(yīng)用的精髓:使用模型優(yōu)化器準(zhǔn)備模型,對(duì)需要推理的圖片進(jìn)行預(yù)處理以滿足模型輸入的需要,使用推理引擎執(zhí)行推理獲得結(jié)果,最后對(duì)推理結(jié)果進(jìn)行可視化操作以便于查看。
通過實(shí)訓(xùn)相信大家也認(rèn)識(shí)了分類模型、文字檢測(cè)模型、語義分割模型的使用。在下一章我們繼續(xù)實(shí)戰(zhàn),用OpenVINO??工具包開發(fā)更復(fù)雜、更有趣的應(yīng)用,同時(shí),我們也會(huì)學(xué)習(xí)從訓(xùn)練到推理的人工智能全流程開發(fā),并借助OpenVINO? 對(duì)訓(xùn)練結(jié)果進(jìn)行性能優(yōu)化。
《下篇》將于下周更新。