在上一篇「OpenVINO 2022大改版讓Edge AI玩出新花樣」[1]中,在最後一小節「5. Preprocessing API」已幫大家簡單提到一些重點。本篇文章將更進一步介紹其應用程式介面(Application Programming Interface, API)基本原理和使用方式,並簡單比較和傳統使用OpenCV進行影像處理方式的差異及如何提升運作效率,讓大家後續使用OpenVINO運行影像類邊緣智能應用時能更有效率。接下來分別從如何「安裝工作環境」、「影像前處理」、「推論後處理」及「新舊版本比較」等幾大面向為大家作更完整說明。
1. 安裝工作環境
在上一篇文章[1]中主要是以C++作為主要程式範例說明,本文改採Python工作環境來說明,方便範例更容易轉移到更多以Python為主的開發平台(如Anaconda, Google Colab, JypterNotebook, Intel DevCloud等)進行測試。
目前OpenVINO支援很多方式安裝,其中以從PyPi安裝最為方便,不管是Windows, Linux (Ubuntu)還是macOS,只須在Python環境下執行「pip install openvino」就可完成安裝。不過這樣的方式只適合部署用(只有Runtime),不適合開發用,因為少了很多常用開者發工具程式,如下所示:
- OpenCV (cv2)
- Model Optimizer (mo)
- Benchmark Tool (benchmark_app)
- Accuracy Checker (accuracy_check)
- Annotation Converter (convert_annotation)
- Post-Training Optimization Tool (pot)
- Model Downloader (omz_downloader, omz_converter)
- other Open Model Zoo Tools (omz_quantizer, omz_info_dumper)
為了讓大家一次到位,建議先建立Python 3.7版虛擬環境,避免污染到自己電腦上原有Python開發環境,接著再安裝OpenVINO開發者版本[3]。以下簡單以Windows 10環境下的Python和Anaconda兩種方式說明建立程序,大家可依自己的習慣擇一安裝即可。
以Python方式安裝步驟:
# 建立Python 3.7虛擬環境,名為openvino_env python -m venv openvino_env --python=3.7 #啟動名為openvino_env的虛擬環境 openvino_env\Scripts\activate # 將pip升級到最新版 python -m pip install --upgrade pip # 安裝OpenVINO最新開發者版本,同時安裝OpenCV, # TensorFlow 2.x, ONNX, PyTorch, Caffe等AI開發框架相關套件包 pip install openvino-dev[tensorflow2,onnx,pytorch,caffe] # 測試OpenVINO 2022.1 Runtime是否安裝完成 python -c "from openvino.runtime import Core" # 測試模型優化器(Model Optimizer)是否安裝完成 mo -h
以Anaconda方式安裝步驟:
# 建立Python 3.7虛擬環境,名為openvino_env conda create -n openvino_env python=3.7 # 啟動名為openvino_env的虛擬環境 activate openvino_env # 將pip升級到最新版 python -m pip install --upgrade pip # 安裝OpenVINO最新開發者版本,同時安裝OpenCV, # TensorFlow 2.x, ONNX, PyTorch, Caffe等AI開發框架相關套件包 pip install openvino-dev[tensorflow2,onnx,pytorch,caffe] # 測試OpenVINO 2022.1 Runtime是否安裝完成 python -c "from openvino.runtime import Core" # 測試模型優化器(Model Optimizer)是否安裝完成 mo -h
補充說明一下,雖然OpenVINO有特別為Anaconda提供一個專屬的開發套件包安裝,但因為同樣地僅為部署用,所以這裡就不特別介紹。而至於為何使用Python 3.7不使用更新版本及更多安裝相關注意事項可參考另一篇文章「使用PyPi (pip install)安裝Intel OpenVINO 2022.1填坑心得」[2]。尤其如果你想要使用Intel 神經運算棒(Neural Compute Stick 2, NCS2 又稱Intel Movidius Myriad X)則一定要仔細了解,不然將無法啟用NCS2。
2. 影像前處理
在利用深度學習來完成的影像智能應用中,以影像分類(Classification)、物件偵測(Object Detection)、影像分割(Semantic Segmentation, Instance Segmentation)最為常見。為了方便模型進行訓練和推論,資料輸入時多半會先正規化到[0, 1]或[-1, 1],而訓練而得的網路權重則會採32位元浮點數(FP32),輸出則依不同類型可能為[0, 1] FP32格式精確度、座標值或[0, 255] INT8格式分類值。
一般當作輸入的原始影像格式(bmp, jpg, png …)、色彩數(1, 8, 24, 32 bit)、通道數(1, 3, 4)、尺寸(長、寬)可能都不一致,更不要說影響影像品質的模糊、亮度、對比、色彩偏移等問題,所以通常輸入模型前需要進行調整。傳統上我們可以使用像OpenCV或Python PIL, Numpy等工具協助,但這些工具多半還是使用CPU進行運算,只有少部份可以使用GPU加速處理。所以OpenVINO 2022.1後開始改用PrePostProcessor APIs(以下簡稱PPP APIs)來改善,可將這部份工作轉到Intel GPU(如UHD630, Iris Xe等)上處理,分散CPU工作量,以增進處理效率。這部份的好處在處理大量影像或串流影像(影片)時就更能看出來。其架構概念如Fig. 1所示。
Fig. 1 OpenVINO新舊版本有無使用預處理函式PrePostProcessor APIs之推論架構比較圖。(OmniXRI整理製作, 2022/8/24) (點擊圖放大) |
如Fig. 1左側所示,舊版OpenVINO除推論部份可選擇CPU / iGPU / VPU(NCS2, Myriad X) / FPGA外,其餘前後處理都要依賴CPU來執行像OpenCV, Numpy之類的函數。而新版OpenVINO引入新的作法,可將預處理及後處理部份直接轉成模型一部份,產生新的「預處理模型」,如Fig. 1中間所示。當需要執行推論時,則像Fig. 1 右側所示,讀入影像及預處理模型後就可直接進行推論,不需再使用CPU進行傳統預處理,此時可自由選擇使用CPU / iGPU / VPU進行推論,當選用iGPU時,其運行效率更是明顯提升不少。不過目前推論後處理部份由於不同應用輸出結果型式不一,所以除了提供輸出數值轉換、矩陣外形變更等大量計算功能外,其餘關於繪圖、文字串、檔案處理部份仍需靠像OpenCV, Python套件來協助處理。接下來就逐一展開為大家介紹。
2.1. 輸入數值轉換
一般輸入影像多半是彩色格式,即每個像素分別由紅綠藍三色彩(三通道)組成,每個通道顏色再由8bit無正負號整數(Unsigned Integer 8 bit, UINT8)來表示色彩強度,其數值表現即為2^8 = 0 ~ 255,故常稱這種影像格式為RGB888或BGR888。為了方便後續推論模型(網路)能統一計算,所以一般會將所有輸入像素數值轉成32bit浮點數(Floating Point 32bit, FP32)。依不同模型要求,會把[0, 255]轉成[0.0, 1.0]或[-1.0, +1.0],以前者為例,即 f(x) = x / 255.0,如Fig.2所示。
# 以OpenCV / Numpy為例: img = cv2.imread(“image.jpg”) # 讀入名為image.jpg的影像檔案到img img = cv2.divide(img, numpy.array([255.0]) # 將img所有像素都除以255.0再存回img
Fig. 2 輸入數值轉換示意圖。(OmniXRI整理製作, 2022/8/24) (點擊圖放大) |
2.2. 矩陣外形變更
如Fig. 3左圖所示,一張彩色影像分別具有高(Height, H)、寬(Width, W)及通道數(Channel, C)。為了滿足輸入格式(即資料排列順序),所以通常會將HWC三維資料擴增為四維資料「NHWC」,這裡的N即為批次數量(Batch Size),亦可看成一次取多少張影像計算,在推論時N通常設為1。另外因為不同的AI開發框架習慣不同,所以有時還須依需求將「NHWC」格式轉換成「NCHW」表示方式,否則會造成輸入資料排列順序不同而造成推論錯誤。
# 以OpenCV / Numpy為例: img1 = cv2.imread(“image.jpg”) # 讀入名為image.jpg的影像檔案到img1 img2 = img1.transpose(1, 2, 0) # 對img1矩陣轉置,將[C,H,W]轉為[H,W,C]存到img2 img3 = np.expand_dims(img2, 0) # 將img2的維度擴增一個維度(N)到img3得到[N,C,H,W]
Fig. 3 (左)矩陣外形變更,(右)影像尺寸調整。(OmniXRI整理製作, 2022/8/24) (點擊圖放大) |
2.3. 影像尺寸調整
一般常見的影像分類或物件偵測模型都有強制要求輸入影像的尺寸(寬、高)及通道數(色彩數)。以知名影像分類模型Alexnet為例,其輸入就為224 x 224 x 3,即寬度、高度皆為224像素,RGB 3通道彩色影像。
通常輸入的影像來源可能來自網路、網路攝影機或自備的影像集,所以影像尺寸有很大差異,有些影像很大、有些很小、而大部份也都不是正方形而是長方形(長寬比不等於1),所以在資料輸入模型前須做尺寸調整,將其縮放至指定尺寸,如Fig. 3右圖所示。
# 以OpenCV / Numpy為例: img = cv2.imread(“image.jpg”) # 讀入名為image.jpg的影像檔案到img img = cv2.resize(img, (W,H), cv2.INTER_LINEAR) # 將img以雙線性內插法縮放到WxH尺寸存回img
2.4. 色彩通道變換
一般從儲存裝置讀取影像檔案到記憶體中會隨著工具不同而會有色彩排列順序不同的問題,如以OpenCV imread函數讀取預設是採BGR格式,而Python PIL Image.open讀取則會以RGB格式。所以將影像要導入模型推論前一定要確認好到底是RGB還是BGR格式,不然會造成推論精確度產生下降。
# 以OpenCV / Numpy為例: img = cv2.imread(“image.jpg”) # 讀入名為image.jpg的影像檔案到img img = cv2.cvtColor(img1, cv2.COLOR_BRG2RGB) # 將img BGR轉成RGB格式存回img
2.5. 額外像素處理
一般影像可不經額外像素處理直接送入模型進行推論,但若經實驗發覺有經過一些額外處理會使得推論結果變好,或者一開始訓練模型前資料集已經指定特定額外的處理,那影像輸入前就一定要經過指定的處理動作。
如Fig. 4所示,假設影像在輸入前要先經過亮度和對比增強(Brightness / Contrast Enhancement)或減弱,則可使用線性增強或非線性增強公式來調整。在這兩個公式中,主要用到乘法、加法及除法,又因為要對整張影像每個像素都作一次運算,所以使用像OpenCV或Python Numpy矩陣演算函式庫來運算就會方便許多。不過這裡如果只使用CPU計算則會非常沒效率,所以後面會說明如何改善。
# 以OpenCV / Numpy進行線性亮度/對比增強為例: array_alpha = np.array([2.0]) # 對比值 2.0 array_beta = np.array([0.0]) # 亮度值 0.0 img = cv2.imread(“image.jpg”) # 讀入名為image.jpg的影像檔案到img img = cv2.multiply(img, array_alpha) # img每個像素乘上對比值再存回img img = cv2.add(img, array_beta) # img每個像素加上亮度值再存回img img = np.clip(img, 0, 255) # 將img數值限制在[0, 255] 再存回img
# 以OpenCV / Numpy進行非線性亮度/對比增強為例: brightness = 0 # 亮度值 0.0 contrast = -100 # 對比值 2.0 img = cv2.imread(“image.jpg”) # 讀入名為image.jpg的影像檔案到img B = brightness / 255.0 # 將亮度值正規化到[0.0, 1.0] C = contrast / 255.0 # 將對比值正規化到[0.0, 1.0] K = math.tan((45 + 44 * C) / 180 * math.pi) # 執行tan正切函式 contrast = np.float32((img-127.5*(1 - B))*K + 127.5*(1 + B)) # 計算非線性亮度/對比增強值
Fig. 4 影像線性及非線性增強(減弱)示意圖及公式。(OmniXRI整理製作, 2022/8/24) (點擊圖放大) |
2.6. PrePostProcessor優化處理方式
在OpenVINO 2022.1開始提供更強大的優化預處理(Optimize Preprocessing)[4],而其中最主要用到PPP APIs,包含C++和Python函式。PPP APIs主要由以下部分組成:
- Tensor(張量):宣告使用者資料格式,如資料的形狀(Shape)、佈局(Layout)、精度(Precision)、顏色格式(Color Formate)等。
- Steps(步驟):描述應用於使用者資料的預處理(Preprocess)步驟的順序,如數值轉換、色彩轉換、影像縮放等。
- Model(模型):指定模型的資料格式,即透過上兩項內容建置預處理模型。
若想了解更完整Python PPP APIs (API 2.0)用法可參考[5]和[6]。接著就簡單列出如何以PPP APIs來達成2.1 ~ 2.5小節的相同功能。
# 以OpenVINO PPP APIs為例: # 導入PPP APIs相關套件包 from openvino.preprocess import PrePostProcessor from openvino.runtime import Core from openvino.preprocess import ColorFormat from openvino.runtime import Layout, Type from openvino.preprocess import ResizeAlgorithm img = cv2.imread(“image.jpg”) # 讀入名為image.jpg的影像檔案到img core = Core() # 宣告OpenVINO Runtime核心 model = core.read_model(model=xml_path) # 讀入指定模型 ppp = PrePostProcessor(model) # 建立PrePostProcessor物件 ppp.input(input_name).tensor() \ # 宣告使用者輸入資料格式(張量) .set_element_type(Type.u8) \ # 設定元素型態為UINT8 .set_shape([N, H, W, C]) \ # 設定原始資料外形為 [N, H, W, C] .set_layout(Layout('NHWC')) \ # 設定資料佈局為 [N, H, W, C] .set_color_format(ColorFormat.BGR) # 設定彩色格式為BGR ppp.input().preprocess().resize(ResizeAlgorithm.RESIZE_LINEAR) # 指定預處理步驟,資料以雙線性內插方式縮放尺寸 ppp.input(input_name).model().set_layout(Layout('NCHW')) # 指定模型資料佈局格式 model = ppp.build() # 建置PPP APIs預處理模型
3. 推論後處理
由於模型功能不一,所以推論後之輸出內容格式也不一致。如影像分類,其輸出為機率值最大的前n個(如Top 10)和分類辨識碼(ID),以文字串輸出即可,原則上不必對原始影像作處理,但有必要時亦可使用OpenCV的文字繪圖功能將機率最高值的ID和機率值繪製在圖上。而物件偵測,其輸出為多物件的辨識碼、機率、中心座標及物件框尺寸(寬高),同樣地,有必要時亦可使用OpenCV的繪圖指令將文字及物件框繪回原始圖像。因此PPP APIs中對於後處理(Post Process)就少了些,僅提供輸出元素型態(Element_type)、佈局(Layout)轉換等基本功能。這部份亦可視實際需求略過不用,直接使用OpenCV或Python Numpy等函式庫處理。更完整的內容可參考PPP APIs PostProcessSteps[7]說明。
4. 新舊版本比較
為了讓大家更清楚了解新舊版本工作上的差異及有無使用PPP APIs在不同硬體裝置上運行推論的效果,接下來會依序給出一些參考範例碼及實驗數據的說明。
4.1. OpenVINO新舊版本程式架構及實驗結果比較
首先列出2021.4使用IE Core + OpenCV和2022.1使用Runtime Core + PPP APIs在讀入影像、影像前處理、載入模型、推論及後處理在程式上的差異。如Fig. 5所示,這裡分別使用官方Github提供的香蕉影像[8]及兩個版本(2021.4[9], 2022.1[10])的hello_classification.py來進行測試及說明。而這兩個範例主要是使用Alexnet,所以推論前要先執行下列指令取得原始模型(Caffe格式),轉換成IR格式(bin + xml)後才能進行推論。
# 下載Alexnet模型 omz_downloader --name alexnet # 轉換模型成為IR格式(bin + xml) omz_converter – name alexnet # 完成後會在目前目錄下產生FP16和FP32 IR格式模型檔案 # 分別在 .\public\alexnet\FP16 和 .\public\alexnet\FP32 # 可看到 alexnet.bin 和 alexnet.xml # 以指定裝置(CPU, GPU, MYRIAD)執行推論 # 由於NSC2(MYRIAD)只能運行FP16數值,為求統一所以全部採用FP16測試。 # OpenVINO 2021.1範例執行 python hello_classification.py -m .\public\alexnet\FP16\alexnet.xml -i banana.jpg -d GPU # OpenVINO 2022.1範例執行 python hello_classification.py .\public\alexnet\FP16\alexnet.xml banana.jpg GPU
Fig.5 新舊版本OpenVINO預處理及推論比較。(OmniXRI整理製作, 2022/8/24) (點擊圖放大) |
我們使用上述兩個範例程式運行在三種裝置(CPU, iGPU, NSC2)來進行分析,並把每一段的運行時間列出比較,如Fig.6所示。猛一看,似乎舊版勝過新版一點點,但單看總時間的比較方式並無法看出效能提升所在,因為這兩個程式採用的是同步模式(synchronous mode)工作,即一個步驟完成再做下一個,所以沒有使用平行加速處理。另外主要最花時間的是將模型載入裝置(IE S4, Runtime S5),尤其是iGPU更是明顯,但如上一篇文章[1]提到的,這部份已透過CPU + iGPU混搭作業來改善了,這裡就不多作說明了。所以這裡我們更應該關心的是預處理部份(IE S3+S6, Runtime S4)和推論部份(IE S7, Runtime S6)。由於Runtime的預處理已融入模型中,會使模型變大一些,如Fig. 7所示,所以理論上推論會慢一些,但這個部份若使用iGPU時,預處理和推論都使用iGPU加速,此時就會得到更有效率的推論結果。
Fig. 6 IE Core及Runtime Core在不同裝置推論效能比較。(OmniXRI整理製作, 2022/8/24) (點擊圖放大) |
註:Fig. 6圖表中0.000或0.00並非完全為零,只是小到四捨五入後仍不在顯示範圍。另外受限於電腦運作時的負載狀況會有所變動,所以每次量到的時間值都會有一定程度變動,這裡僅列出其中一次量測數值比較。
Fig.7 Alexnet原始模型和經PPP預處理後模型比較。(OmniXRI整理製作, 2022/8/24) (點擊圖放大) |
4.2. PPP預處理模型效率提升比較
為了讓大家更清楚看出經過預處理的模型推論效率提升程度,所以在原先Runtime hello_classification.py加入一小段程式,讓PPP預處理的模型可以先儲存起來,等下就能直接取用推論,加快推論速度,其概念可參考Fig. 1中間及右側所示。而儲存PPP預處理模型可參考下面程式範例。
# 儲存PPP預處理模型 from openvino.runtime.passes import Manager pass_manager = Manager() pass_manager.register_pass(pass_name="Serialize", xml_path='ppp_model_saved.xml', bin_path='ppp_model_saved.bin') pass_manager.run_passes(model)
在Fig. 8圖表中,一樣使用三種硬體裝置進行推論,而分別使用二種程式來比較,其內容如下所示。
- 讀入原始模型和待推論影像檔案,經PPP預處理後,再將模型存檔,接著載入指定裝置進行推論,最後將輸出結果顯示出來。
- 讀入待推論影像,直接將PPP預處理好的模型載入到指定裝置進行推論,最後將輸出結果顯示出來。
由於上述第二項工作模式(單獨PPP模型)已將待推論影像預處理工作融入模型中,所以可略過讀入模型時間和預處理時間(即時間為零),如Fig. 8中粉紅色區塊顯示,直接將模型載入指定推論裝置中。從表中可看出,雖然單獨PPP預處理方式的載入模型到裝置和推論時間都會較略大一些,但省下讀取模型和執行PPP預處理的時間較前項增加出來的時間多上許多,所以整體運行時間仍減少許多,執行效率明顯提升許多。
另外從Fig. 8圖表中,亦可看出CPU內建的iGPU推論時間已明顯少於CPU和NCS2 (Myriad X),因此建議未來可多多使用iGPU來完成推論,提升推論效率。
Fig. 8 原始模型加PPP預處理和單獨已PPP預處理模型運行時間比較。(OmniXRI整理製作, 2022/8/24) (點擊圖放大) |
4.3. 影像亮度/對比調整比較
如2.5節所述之非線性亮度/對比增強公式,這裡分別使用OpenCV + Numpy (ov_opencv_nonlinear.py)和PPP (ov_ops.py)方式來進行運行速度之比較。相關程式碼及說明可參考文件[11],而使用的範例圖則參考[12]。經實驗後可得如Fig. 9之數據。
Fig. 9 不同模式及硬體推論速度比較。(OmniXRI整理製作, 2022/8/24) (點擊圖放大) |
首先測試OpenCV + Numpy運行非線性亮度/對比增強程式,由於只支援CPU所以得結果如Fig. 9第二列所示。接著使用PPP方式將非線性亮度/對比增強計算式轉成PPP格式,產生預處理模型再進行推論。Fig.9第三列結果僅為推論部份,不包含模型參數設定、載入動作。最後以benchmark_app來測試PPP產出的預處理模型效能,即只算推論部份,其參數設定為 -api sync -t 10,即以同步運行10秒,最後取平均值,如Fig. 9最後一列所示。
從這個實驗中可看出,當使用額外像素處理時,PPP的優勢就更為明顯,不僅可選擇處理的硬體裝置,更可大幅縮減運算時間,尤其當GPU全速運行時,會有更多的效能增加。
如果你想自己動手測試一下,本文所有相關測試程式、參考圖檔及說明可從下列網址[13]取得。
https://github.com/OmniXRI/OpenVINO_PrePostProcessor
小結
經過上面一連串說明,大家是否能感受到OpenVINO此次2022.1版透過PrePostProcessor (PPP) APIs使得推論效能有明顯的改善。當使用iGPU來推論時,其效能更大幅超越CPU和神經運算棒(NCS2, Myriad X)。對於額外像素處理亦可使用PPP + iGPU來加速計算,讓CPU能空出更多計算能量處理更多計算。如果還無法感受這份快感的朋友,自己動手玩一下,相信一定會有不同的感受。
*本文同步發表於MakerPRO
參考文獻
[1] 許哲豪,OpenVINO 2022大改版讓Edge AI玩出新花樣
https://omnixri.blogspot.com/2022/08/openvino-2022edge-ai.html
[2] 許哲豪,使用PyPi (pip install) 安裝Intel OpenVINO 2022.1填坑心得
http://omnixri.blogspot.com/2022/08/pypi-pip-install-intel-openvino-20221.html
[3] Intel, PyPi – OpenVINO Development Tool
https://pypi.org/project/openvino-dev/
[4] Intel, OpenVINO Document – Deploying Inference – Performing Interface with OpenVINO Runtime – Optimize Preprocessing
https://docs.openvino.ai/2022.1/openvino_docs_OV_UG_Preprocessing_Overview.html
[5] Intel, OpenVINO Document – Deploying Inference – Performing Interface with OpenVINO Runtime – Optimize Preprocessing – preprocessing API - details
https://docs.openvino.ai/2022.1/openvino_docs_OV_UG_Preprocessing_Details.html
[6] Intel, OpenVINO Document – API Reference - OpenVINO Python API – openvino.preprocess
https://docs.openvino.ai/2022.1/api/ie_python_api/_autosummary/openvino.preprocess.html
[7] Intel, OpenVINO Document – API Reference – OpenVINO Python API – openvino.preprocess – openvino.preprocess.PostProcessSteps
https://docs.openvino.ai/2022.1/api/ie_python_api/_autosummary/openvino.preprocess.PostProcessSteps.html
[8] Intel, OpenVINO toolkit test data
https://storage.openvinotoolkit.org/data/test_data/
[9] Intel, Github – openvinotoolkit – openvino – releases/2021/4
https://github.com/openvinotoolkit/openvino/blob/releases/2021/4/inference-engine/ie_bridges/python/sample/hello_classification/hello_classification.py
[10] Intel, Github – openvinotoolkit – openvino – master (2022.1)
https://github.com/openvinotoolkit/openvino/blob/master/samples/python/hello_classification/hello_classification.py
[11] Intel, Image Preprocessing with intel Distribution of OpenVINO Toolkit Pre-/Post-Processor APIs White paper (undefined)
https://cdrdv2.intel.com/v1/dl/getContent/730425?explicitVersion=true
[12] Github, howarder3 / ironman2020_OpenCV_photoshop, Scenery Image File
https://github.com/howarder3/ironman2020_OpenCV_photoshop/blob/master/testdata/scenery.jpg
[13] Github, OmniXRI / OpenVINO_PrePostProcessor
https://github.com/OmniXRI/OpenVINO_PrePostProcessor
沒有留言:
張貼留言