當YOLOv5遇見OpenVINO

當YOLOv5遇見OpenVINO

1YOLOv5網路

YOLOv5 於2020年6月釋出!一經推出,便得到CV圈的矚目,目前在各大目標檢測競賽、落地實戰專案中得到廣泛應用。

YOLOv5在COCO上的效能表現:

當YOLOv5遇見OpenVINO

YOLOv5程式碼連結:

https://github.com/ultralytics/yolov5

YOLOv5一共有4個版本,分別是Yolov5s、Yolov5m、Yolov5l、Yolov5x,其中效能依次增強。比如YOLOv5s模型引數量最小,速度最快,AP精度最低;YOLOv5x模型引數量最大,速度最慢,AP精度最高。

其中YOLOv5網路結構如下:

當YOLOv5遇見OpenVINO

圖源:https://zhuanlan。zhihu。com/p/172121380

2OpenVINO™工具套件介紹

當YOLOv5遇見OpenVINO

OpenVINO™工具套件是英特爾針對自家硬體平臺開發的一套深度學習工具庫,包含推理庫,模型最佳化等等一系列與深度學習模型部署相關的功能。同時可以相容各種開源框架訓練好的模型,擁有演算法模型上線部署的各種能力,只要掌握了該工具,你可以輕鬆的將預訓練模型在

英特爾的CPU、VPU

等裝置上快速部署起來。

當YOLOv5遇見OpenVINO

3重新訓練YOLOv5

3。1 下載YOLOv5程式碼和權重檔案

大家可以直接clone YOLOv5官方github程式碼:

git clone https://github。com/ultralytics/yolov5

也可以在官方github的releases中下載正式釋出的版本:

https://github。com/ultralytics/yolov5/releases

我們這裡下載YOLOv5 v3。1版本的原始碼和yolov5s。pt權重檔案。值得注意,目前YOLOv5已更新至v5。0,但在實際轉換OpenVINO™工具套件推理應用中遇到不少問題,為了方便使用,這裡推薦較穩定的YOLOv5 v3。1版本。

當YOLOv5遇見OpenVINO

3.2 資料集準備

資料集可以是自己標註的,也可以用網上開源的資料集。如果是標註自己的目標檢測資料集,一般使用labelImg工具(超好用!支援COCO等格式)。

這裡我們下載使用roboflow開源的

口罩檢測資料集(Mask Wearing Dataset)

,該資料集只有149幅影象,方便練手,而且格式直接支援YOLOv5!

https://public。roboflow。com/object-detection/mask-wearing

當YOLOv5遇見OpenVINO

3.3 重新訓練YOLOv5

3.3.1 修改引數

訓練自定義資料集,一般需要修改兩個引數:

nc:需要識別的類別

anchors:YOLOv5預設自適應anchors計算,也可以自定義透過k-means演算法計算

其中,nc是一定要修改的,比較每個資料集的類別會不一樣,而anchors可以不用修改,即預設自適應計算。

比如Mask Wearing資料集只有兩種類別:mask和no-mask,所以nc = 2。可見data。yaml中的資訊:

當YOLOv5遇見OpenVINO

當YOLOv5遇見OpenVINO

這裡使用YOLOv5s進行訓練,所以需要同步修改yolov5/models/yolov5s。yaml 檔案中的nc數值,設定為2:

當YOLOv5遇見OpenVINO

3.3.2 訓練YOLOv5

訓練命令如下:

python train。py ——data 資料集路徑/data。yaml ——cfg models/yolov5s。yaml ——weights ‘’ ——batch-size 64 ——epochs 100

注:訓練命令列的引數含義可參考:https://docs。ultralytics。com,比如batch size、epochs可以根據訓練裝置自行調整

訓練完成後,權重檔案會自動儲存在runs資料夾中,自動生成last。pt和best。pt,如下圖所示:

當YOLOv5遇見OpenVINO

3.3.3 YOLOv5 Demo檢測

對測試集中的影象進行檢測,執行命令如下:

python detect。py ——weight runs/exp6/weights/best。pt ——source 資料集路徑/test/images/1288126-10255706714jpg_jpg。rf。95f7324cbfd48e0386e0660b5e932223。jpg

輸入影象:

當YOLOv5遇見OpenVINO

口罩檢測結果:

當YOLOv5遇見OpenVINO

4 模型轉換(YOLOv5—>OpenVINO™工具套件)

將YOLOv5的。pt訓練權重檔案轉換成OpenVINO™工具套件呼叫的檔案,主要的流程是:。pt 權重檔案 —> ONNX 權重檔案 —> IR 檔案(。bin和xml)。其中利用ONNX(Open Neural Network Exchange,開放神經網路交換)進行檔案格式轉換。

當YOLOv5遇見OpenVINO

使用版本說明:

Ubuntu 18。04

OpenVINO™工具套件 2021。03

4.1 .pt 權重檔案 —> ONNX 權重檔案

先安裝ONNX,然後執行指令碼,實現轉換。

4.1.1 安裝ONNX

ONNX的安裝方法相對簡單,直接pip安裝即可:

pip install onnx

4.1.2 ONNX轉換

YOLOv5官方提供了轉換成ONNX權重的指令碼檔案,位於yolov5/models/export。py,使用說明詳見:https://github。com/ultralytics/yolov5/issues/251

注意,這裡需要將export。py指令碼檔案中的opset_version修改為10:

torch。onnx。export(model, img, f, verbose=False, opset_version=10, input_names=[‘images’],

output_names=[‘classes’, ‘boxes’] if y is None else [‘output’])

然後再執行如下轉換指令:

python models/export。py ——weights runs/exp6/weights/best。pt ——img 640 ——batch 1

轉換成功後,就會在runs/exp6/weights資料夾中生成best。onnx檔案。

當YOLOv5遇見OpenVINO

注:這裡可以使用Netron開啟yolov5s。onnx,進而視覺化YOLOv5模型。

Netron線上視覺化:https://netron。app/

Netron github:https://github。com/lutzroeder/netron

4.2 ONNX 權重檔案 —> IR 檔案(.bin和.xml)

先安裝、配置OpenVINO™工具套件,然後執行指令碼,實現轉換。

4.2.1 安裝OpenVINO™工具套件

安裝OpenVINO™工具套件的方法有很多,詳見官網:

https://docs。openvinotoolkit。org/latest/index。html

這裡我是使用APT的方式,具體參考:https://docs。openvinotoolkit。org/latest/openvino_docs_install_guides_installing_openvino_apt。html

安裝命令如下:

wget https://apt。repos。intel。com/openvino/2021/GPG-PUB-KEY-INTEL-OPENVINO-2021

apt-key add GPG-PUB-KEY-INTEL-OPENVINO-2021

apt-key list

touch /etc/apt/sources。list。d/intel-openvino-2021。list

echo “deb https://apt。repos。intel。com/openvino/2021 all main” >> /etc/apt/sources。list。d/intel-openvino-2021。list

apt update

執行完上述命令後,可出現:

當YOLOv5遇見OpenVINO

然後搜尋可下載的包,要注意系統版本:

sudo apt-cache search intel-openvino-dev-ubuntu18

當YOLOv5遇見OpenVINO

這裡安裝

intel-openvino-dev-ubuntu18-2021.3.394

版本

apt install intel-openvino-dev-ubuntu18-2021。3。394

安裝成功後,輸出內容如下圖所示:

當YOLOv5遇見OpenVINO

4.2.2 OpenVINO™工具套件轉換

安裝好OpenVINO™工具套件後,我們需要使用OpenVINO™工具套件的模型最佳化器(Model Optimizer)將ONNX檔案轉換成IR(Intermediate Representation)檔案。

首先設定 OpenVINO™工具套件的環境和變數:

source /opt/intel/openvino_2021/bin/setupvars。sh

然後執行如下指令碼,實現ONNX模型到IR檔案(。xml和。bin)的轉換:

python /opt/intel/openvino_2021/deployment_tools/model_optimizer/mo。py ——input_model runs/exp6/weights/best。onnx ——model_name yolov5s_best -s 255 ——reverse_input_channels ——output Conv_487,Conv_471,Conv_455

關於命令列的引數用法,更多細節可參考:https://docs。openvinotoolkit。org/cn/latest/openvino_docs_MO_DG_prepare_model_convert_model_Converting_Model_General。html

轉換成功後,即可得到

yolov5s_best.xml

yolov5s_best.bin

檔案。

當YOLOv5遇見OpenVINO

5 使用OpenVINO™工具套件進行推理部署

5.1 安裝Python版的OpenVIN

O™

工具套件

這裡使用Python進行推理測試。因為我上面採用apt的方式安裝OpenVINO™工具套件,這樣安裝後Python環境中並沒有OpenVINO™工具套件,所以我這裡需要用pip安裝一下OpenVINO™工具套件。

注:如果你是編譯原始碼等方式進行安裝的,那麼可以跳過這步:

pip install openvino

另外,安裝時要保持版本的一致性:

當YOLOv5遇見OpenVINO

5.2 OpenVINO™工具套件實測

OpenVINO™工具套件官方提供了YOLOv3版本的Python推理demo,可以參考:

https://github。com/openvinotoolkit/open_model_zoo/blob/master/demos/object_detection_demo/python/object_detection_demo。py

我們這裡參考這個已經適配好的YOLOv5版本:https://github。com/violet17/yolov5_demo/blob/main/yolov5_demo。py,該原始碼的輸入資料是camera或者video,所以我們可以將test資料集中的影象轉換成影片(test。mp4)作為輸入,或者可以自行修改成影象處理的程式碼。

其中YOLOv5版本相對於官方YOLOv3版本的主要修改點:

1. 自定義letterbox函式,預處理輸入影象:

def letterbox(img, size=(640, 640), color=(114, 114, 114), auto=True, scaleFill=False, scaleup=True):# Resize image to a 32-pixel-multiple rectangle https://github。com/ultralytics/yolov3/issues/232 shape = img。shape[:2] # current shape [height, width] w, h = size# Scale ratio (new / old) r = min(h / shape[0], w / shape[1])if not scaleup: # only scale down, do not scale up (for better test mAP) r = min(r, 1。0)# Compute padding ratio = r, r # width, height ratios new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r)) dw, dh = w - new_unpad[0], h - new_unpad[1] # wh paddingif auto: # minimum rectangle dw, dh = np。mod(dw, 64), np。mod(dh, 64) # wh paddingelif scaleFill: # stretch dw, dh = 0。0, 0。0 new_unpad = (w, h) ratio = w / shape[1], h / shape[0] # width, height ratios dw /= 2 # divide padding into 2 sides dh /= 2if shape[::-1] != new_unpad: # resize img = cv2。resize(img, new_unpad, interpolation=cv2。INTER_LINEAR) top, bottom = int(round(dh - 0。1)), int(round(dh + 0。1)) left, right = int(round(dw - 0。1)), int(round(dw + 0。1)) img = cv2。copyMakeBorder(img, top, bottom, left, right, cv2。BORDER_CONSTANT, value=color) # add border top2, bottom2, left2, right2 = 0, 0, 0, 0if img。shape[0] != h: top2 = (h - img。shape[0])//2 bottom2 = top2 img = cv2。copyMakeBorder(img, top2, bottom2, left2, right2, cv2。BORDER_CONSTANT, value=color) # add borderelif img。shape[1] != w: left2 = (w - img。shape[1])//2 right2 = left2 img = cv2。copyMakeBorder(img, top2, bottom2, left2, right2, cv2。BORDER_CONSTANT, value=color) # add borderreturn img

2. 自定義parse_yolo_region函式, 使用Sigmoid函式的YOLO Region層 :

def parse_yolo_region(blob, resized_image_shape, original_im_shape, params, threshold):

# —————————————————————— Validating output parameters ——————————————————————

out_blob_n, out_blob_c, out_blob_h, out_blob_w = blob。shape

predictions = 1。0/(1。0+np。exp(-blob))

assert out_blob_w == out_blob_h, “Invalid size of output blob。 It sould be in NCHW layout and height should ” \

“be equal to width。 Current height = {}, current width = {}” \

“”。format(out_blob_h, out_blob_w)

# —————————————————————— Extracting layer parameters ——————————————————————-

orig_im_h, orig_im_w = original_im_shape

resized_image_h, resized_image_w = resized_image_shape

objects = list

side_square = params。side * params。side

# ——————————————————————- Parsing YOLO Region output ——————————————————————-

bbox_size = int(out_blob_c/params。num) #4+1+num_classes

for row, col, n in np。ndindex(params。side, params。side, params。num):

bbox = predictions[0, n*bbox_size:(n+1)*bbox_size, row, col]

x, y, width, height, object_probability = bbox[:5]

class_probabilities = bbox[5:]

if object_probability < threshold:

continue

x = (2*x - 0。5 + col)*(resized_image_w/out_blob_w)

y = (2*y - 0。5 + row)*(resized_image_h/out_blob_h)

if int(resized_image_w/out_blob_w) == 8 & int(resized_image_h/out_blob_h) == 8: #80x80,

idx = 0

elif int(resized_image_w/out_blob_w) == 16 & int(resized_image_h/out_blob_h) == 16: #40x40

idx = 1

elif int(resized_image_w/out_blob_w) == 32 & int(resized_image_h/out_blob_h) == 32: # 20x20

idx = 2

width = (2*width)**2* params。anchors[idx * 6 + 2 * n]

height = (2*height)**2 * params。anchors[idx * 6 + 2 * n + 1]

class_id = np。argmax(class_probabilities)

confidence = object_probability

objects。append(scale_bbox(x=x, y=y, height=height, width=width, class_id=class_id, confidence=confidence,

im_h=orig_im_h, im_w=orig_im_w, resized_im_h=resized_image_h, resized_im_w=resized_image_w))

return objects

3. 自定義scale_bbox函式,進行邊界框後處理 :

def scale_bbox(x, y, height, width, class_id, confidence, im_h, im_w, resized_im_h=640, resized_im_w=640):

gain = min(resized_im_w / im_w, resized_im_h / im_h) # gain = old / new

pad = (resized_im_w - im_w * gain) / 2, (resized_im_h - im_h * gain) / 2 # wh padding

x = int((x - pad[0])/gain)

y = int((y - pad[1])/gain)

w = int(width/gain)

h = int(height/gain)

xmin = max(0, int(x - w / 2))

ymin = max(0, int(y - h / 2))

xmax = min(im_w, int(xmin + w))

ymax = min(im_h, int(ymin + h))

# Method item used here to convert NumPy types to native types for compatibility with functions, which don‘t

# support Numpy types (e。g。, cv2。rectangle doesn’t support int64 in color parameter)

return dict(xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax, class_id=class_id。item, confidence=confidence。item)

但在實際測試中,會出現這個問題 :‘openvino。inference_engine。ie_api。IENetwork’ object has no attribute ‘layers’ :

[ INFO ] Creating Inference Engine。。。 [ INFO ] Loading network files: yolov5/yolov5s_best。xml yolov5/yolov5s_best。bin yolov5_demo。py:233: DeprecationWarning: Reading network using constructor is deprecated。 Please, use IECore。read_network method instead net = IENetwork(model=model_xml, weights=model_bin) Traceback (most recent call last): File “yolov5_demo。py”, line 414, in sys。exit(main or 0) File “yolov5_demo。py”, line 238, in main not_supported_layers = [l for l in net。layers。keys() if l not in supported_layers] AttributeError: ‘openvino。inference_engine。ie_api。IENetwork’ object has no attribute ‘layers’

經過我調研後才得知,在OpenVINO™工具套件2021。02及以後版本, ‘ie_api。IENetwork。layers’ 就被官方刪除了:

當YOLOv5遇見OpenVINO

所以需要將第327、328行的內容:

out_blob = out_blob。reshape(net。layers[layer_name]。out_data[0]。shape) layer_params = YoloParams(net。layers[layer_name]。params, out_blob。shape[2])

修改為:

out_blob = out_blob。reshape(net。outputs[layer_name]。shape)

params = [x。_get_attributes() for x in function。get_ordered_ops() if x。get_friendly_name() == layer_name][0]

layer_params = YoloParams(params, out_blob。shape[2])

並在第322行下面新新增一行程式碼:

function = ng。function_from_cnn(net)

最終在終端,輸入下面命令:

python yolov5_demo。py -m yolov5/yolov5s_best。xml test。mp4

加上後處理,使用OpenVINO™工具套件的推理時間平均在220ms左右,測試平臺為英特爾® 酷睿™ i5-7300HQ,而使用PyTorch CPU版本的推理時間平均在1。25s,可見OpenVINO™工具套件加速明顯!

最終檢測結果如下:

當YOLOv5遇見OpenVINO

如果你想在CPU上實現模型的快速推理,可以試試

OpenVINO™工具套件

哦~

由於微信公眾號試行亂序推送,您可能不再能準時收到AI科技評論的推送。為了第一時間收到AI科技評論的報道, 請將“AI科技評論”設為星標賬號在看”。