【華爲雲技術分享】基於Atlas 200 DK的原版YOLOv3(基於Darknet-53)實現(Python版本)

摘要:本文將爲大家帶來使用Atlas 200 DK的原版YOLOv3(基於Darknet-53)實現的展示。

前言

YOLOv3可以算作是經典網絡了,較好實現了速度和精度的Trade off,成爲和目標檢測的首選網絡,堪稱是史詩鉅作級別(我是這麼認爲的)。YOLOv3是在YOLOv1和YOLOv2的基礎上,改進而來,如果希望深入瞭解,建議看看前兩個版本,這裏附上網絡上比較好的分析博文:

YOLOv1   https://blog.csdn.net/litt1e/article/details/88814417

YOLOv2   https://blog.csdn.net/litt1e/article/details/88852745

對於今天的主角YOLOv3,強烈建議看看作者的原版論文,像是一篇報告,篇幅很短,寫的十分風趣幽默,是論文屆一股清流啊。附上論文鏈接:

論文地址:https://pjreddie.com/media/files/papers/YOLOv3.pdf
論文:YOLOv3: An Incremental Improvement
 

環境要求:

Atlas 200 DK

配置好的虛擬機,可連接Atlas 200 DK
 

這裏提供完整的工程,包括轉化好的模型,只要你有Atlas 200 DK即可運行。
 

介紹

好了,下面該今天的主角登場了——YOLOv3,先看看結構圖,來個直觀的瞭解:

是的,沒錯,這張圖是我在博客上看到的,附博客鏈接:https://blog.csdn.net/leviopku/article/details/82660381,這篇博客解析了YOLOv3,寫的不錯,大家可以看看。在博客中,作者總結了YOLOv3的特點,如下:

yolo_v3作爲yolo系列目前最新的算法,對之前的算法既有保留又有改進。先分析一下yolo_v3上保留的東西:

1. 分而治之”,從yolo_v1開始,yolo算法就是通過劃分單元格來做檢測,只是劃分的數量不一樣。

2. 採用"leaky ReLU"作爲激活函數。

3. 端到端進行訓練。一個loss function搞定訓練,只需關注輸入端和輸出端。

4. 從yolo_v2開始,yolo就用batch normalization作爲正則化、加速收斂和避免過擬合的方法,把BN層和leaky relu層接到每一層卷積層之後。

5. 多尺度訓練。在速度和準確率之間tradeoff。想速度快點,可以犧牲準確率;想準確率高點兒,可以犧牲一點速度。

YOLO系列的提升很大一部分決定於backbone網絡的提升,從v2的darknet-19到v3的darknet-53。yolo_v3還提供替換backbone——tiny darknet。要想性能牛叉,backbone可以用Darknet-53,要想輕量高速,可以用tiny-darknet。

總之,YOLO就是天生“靈活”,所以特別適合作爲工程算法。這裏要說明的是,leaky ReLU在Ascend 310上適配不是很好,可能只有TensorFlow1.12版本可以用,大家注意,如果使用TensorFlow版本模型去轉化爲.om模型,建議使用TensorFlow 1.12版本,據說適配比較好哦。

 

整體流程

整體例程和PC端類似,分爲數據輸入,預處理,送入模型推理,推理結果解析四部分。這裏是基於我以前發的另一個工程修改的,你可以在本工程看到原來工程的痕跡哦,附上原工程鏈接:https://bbs.huaweicloud.com/blogs/170452,在原工程上修改,這樣可以提高效率,比如創建Graph等操作都直接就行了,建議大家也可以參考,在實現自己工程時,最好在官方例程或現有能運行代碼上修改,這樣比較快,也更容易成功。

  1. 模型獲取和轉換。

先來看看模型轉化,模型使用的是基於COCO數據集訓練的TensorFlow版本的YOLOv3模型。

模型來自https://github.com/wizyoung/YOLOv3_TensorFlow/releases/ 裏面的yolo_tf_weights.zip可自行下載,不過不下載也沒事,這裏提供了完成的代碼,只要你有Atlas 200 DK即可運行。下載後按照帖子轉換完成,得到.pb模型。帖子鏈接:https://bbs.huaweicloud.com/forum/thread-45383-1-1.html

下面是模型轉化,通過Netron可以看到模型輸入節點爲Placeholder 輸入爲1, 416,416,3。這表示模型輸入爲一張圖片,圖片爲416*416大小,3通道,也就是我們常用的RGB格式。

這裏我們輸入的是視頻,使用OpenCV讀取的視頻,得到視頻幀,對每一視頻幀進行逐幀處理,注意OpenCV得到的幀是BGR格式,需要轉爲RGB格式,而且視頻幀大小不一定符合模型輸入要求的416*416, 所以還要做resize。我在模型轉化時,開啓AIPP,完成BGR到RGB的色域轉換,而resize使用OpenCV來完成。之後送入模型,得到推理結果,對推理結果解析,最終將結果寫圖片保存。

 

主要代碼

主代碼 main.py

# -*- coding: utf-8 -*-

# !/usr/bin/python3

# Author: Tianyi_Li

# Last Date: 2020/5/29

# YOLOv3_COCO,基於COCO數據集訓練的TensorFlow版本,檢測80種類別的物體。

# 主函數部分



import sys

import re

import cv2

import yolo3_resnet18_inference

import time

import datetime





# Get Video

lenofUrl = len(sys.argv)



# The number of parameters is incorrect.

if lenofUrl <= 1:

    print("[ERROR] Please input mp4/Rtsp URL")

    sys.exit()

elif lenofUrl >= 3:

    print("[ERROR] param input Error")

    sys.exit()



URL = sys.argv[1]



# match Input parameter format

URL1 = re.match('rtsp://', URL)

URL2 = re.search('.mp4', URL)





# Determine if it is a mp4 video based on matching rules

if URL1 is None:

    if URL2 is None:

        print("[ERROR] should input correct URL")

        sys.exit()

    else:

        mp4_url = True

else:

    mp4_url = False



# Init Graph and Engine

yolo3_resnet18_app = yolo3_resnet18_inference.Yolo3_Resnet18Inference()

if yolo3_resnet18_app.graph is None:

        sys.exit(1)



# Get Start time

run_starttime = datetime.datetime.now()



# Get Frame

cap = cv2.VideoCapture(URL)

ret, frame = cap.read()

print("視頻是否打開成功:", ret)



# Get Video Information

frames_num = cap.get(7)

frame_width = cap.get(3)

frame_height = cap.get(4)



# According to the flag,Perform different processing methods

if mp4_url:

    try:

        while ret:

            # Processing the detection results of a frame of pictures

            strattime = time.time()

            ret = yolo3_resnet18_inference.dowork(frame, yolo3_resnet18_app)

            endtime = time.time()

            print('Process this image cost time: ' + str((endtime - strattime) * 1000) + 'ms')

            if ret is None:

                sys.exit(1)



            # Loop through local video files

            ret, frame = cap.read()



        # Run done, print input video information

        run_endtime = datetime.datetime.now()

        run_time = (run_endtime - run_starttime).seconds

        print("輸入視頻的寬度:", frame_width)

        print("輸入視頻的高度:", frame_height)

        print("輸入視頻的總幀數:", frames_num)

        print("程序運行總時間:" + str(run_time) + "s")

        print('-------------------------end')

    except Exception as e:

        print("ERROR", e)

    finally:

        # Turn off the camera

        cap.release()

else:

    print("[ERROR] Run Failed, please check input video.")

推理代碼

# -*- coding: utf-8 -*-

# !/usr/bin/python3

# YOLOv3_COCO,檢測80種類別的物體



from ConstManager import *

import ModelManager

import hiai

from hiai.nn_tensor_lib import DataType

import numpy as np

import cv2

import utils

import datetime





'''

Yolo3_COCO模型, 輸入H = 416, W = 416,模型的圖像輸入爲RGB格式,這裏使用OpenCV讀取的圖片,得到BGR格式的圖像,在AIPP中完成BGR到RGB的色域轉換和

image/255.0的歸一化操作

bj_threshold 置信度閾值,取值範圍爲0~1。推理的時候,如果預測框的置信度小於該值,那麼就會過濾掉, 默認爲0.3

nms_threshold NMS閾值,取值範圍爲0~1。默認爲0.4

'''





class Yolo3_Resnet18Inference(object):

    def __init__(self):

        # 由用戶指定推理引擎的所在Graph的id號

        self.graph_id = 1000

        self.model_engine_id = 100

        # 基於輸入圖片框座標

        self.boxList = []

        # 置信度

        self.confList = []

        # 概率

        self.scoresList = []

        # 輸入圖片中行人部分

        self.personList = []

        # 實例化模型管理類

        self.model = ModelManager.ModelManager()

        self.width = 416

        self.height = 416

        # 描述推理模型以及初始化Graph

        self.graph = None

        self._getgraph()



    def __del__(self):

        self.graph.destroy()



    def _getgraph(self):

        # 描述推理模型

        inferenceModel = hiai.AIModelDescription('Yolo3_Resnet18', yolo3_resnet18_model_path)

        # 初始化Graph

        self.graph = self.model.CreateGraph(inferenceModel, self.graph_id, self.model_engine_id)

        if self.graph is None:

            print("Init Graph failed")



    '''

    1.定義輸入Tensor的格式

    2.調用推理接口

    3.對一幀推理的正確結果保存到self.resultList中

    4.根據返回值True和False判斷是否推理成功

    '''



    def Inference(self, input_image):

        if isinstance(input_image, np.ndarray) is None:

            return False



        # Image PreProcess

        resized_image = cv2.resize(input_image, (self.width, self.height))



        inputImageTensor = hiai.NNTensor(resized_image)

        nntensorList = hiai.NNTensorList(inputImageTensor)



        # 調用推理接口

        resultList = self.model.Inference(self.graph, nntensorList)



        if resultList is not None:

            bboxes = utils.get_result(resultList, self.width, self.height)  # 獲取檢測結果

            # print("bboxes:", bboxes)



            # Yolov_resnet18 Inference

            output_image = utils.draw_boxes(resized_image, bboxes)       # 在圖像上畫框

            output_image = cv2.resize(output_image, (input_image.shape[1], input_image.shape[0]))

            img_name = datetime.datetime.now().strftime("%Y-%m-%d%H-%M-%S-%f")

            cv2.imwrite('output_image/' + str(img_name) + '.jpg', output_image)



        else:

            print('no person in this frame.')

            return False



        return True





def dowork(src_img, yolo3_resnet18_app):



    res = yolo3_resnet18_app.Inference(src_img)

    if res is None:

        print("[ERROR] Please Check yolo3_resnet18_app.Inference!")

        return False

    else:

        # print("[ERROR] Run Failed, dowork function failed.")

        pass

    return True

代碼中加了一些註釋,應該比較好理解,有機會再加更詳細的註釋吧。

執行過程

首先要下載完整代碼,並提供了三段測試視頻,供選擇。代碼下載鏈接

鏈接:https://pan.baidu.com/s/1E86SFEYjmhaGoQVc6Y7gfg 

提取碼:ok0l

 

下載後,解壓縮,可以得到:

之後將包含上述文件的文件夾拷貝到Atlas 200 DK上,在存放目錄下執行命令

scp -r YOLOv3_COCO [email protected]:/home/HwHiAiUser

注意,我是在YOLOv3_COCO文件下目錄下使用的命令,所以直接用文件夾名字就行,否則需要指定路徑,使用的是USB連接開發板,如果用網線連接,IP可能不同,更多拷貝文件的方法,請參考博文每天進步一點點——使用scp命令在Atlas 200 DK和虛擬機之間傳輸文件(文件夾)

鏈接爲 https://bbs.huaweicloud.com/blogs/168928

 

這裏模型有點大,傳輸可能需要點時間,傳輸完成結果爲

之後登陸開發板,執行命令即可。因爲前面,我拷貝到了開發板的/home/HwHiAiUser目錄下,所以直接登陸就能看到了,直接執行命令進入文件夾即可

cd YOLOv3_COCO

下面執行程序

python3 main.py input_video/person.mp4

在input_video文件夾下放了三個用於測試的視頻,分辨率分別是1920*1080 、1280*720和640*480,這裏使用的是person.mp4,分辨率1920*1080

等待程序執行,最後得到

表示程序運行完成,處理一幀大概需要300ms,比較慢,分析可知,主要是讀取視頻和後處理較慢,推理速度挺快的,後期可能要對後處理做優化,比如使用算子完成後處理,或者硬件解碼視頻,使用OpenCV讀取視頻應該不較慢,而且圖像質量感覺一般。

最後,將輸出的結果圖片拷貝到虛擬機就可以查看了,我的命令爲

scp -r [email protected]:/home/HwHiAiUser/YOLOv3_COCO/output_image /home/ascend/tmp

我拷貝到了虛擬機的tmp文件夾下,具體拷貝文件到虛擬機細節可參考博文https://bbs.huaweicloud.com/blogs/168928

總的來說,Atlas 200 DK挺強的,運行118M的YOLOv3模型畢竟很耗資源。在1920*1080 、1280*720和640*480分辨率的視頻下,速度還可以,如圖

最終效果展示

這裏是做了人(紅色),自行車(綠色)和car(藍色)類別的繪製矩形框。可自行修改代碼,繪製COCO數據集80類矩形框,不過速度會慢哈。

 

點擊這裏,瞭解更多精彩內容

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章