<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          實用教程詳解:用OpenCV的DNN模塊部署YOLOv5目標檢測

          共 4032字,需瀏覽 9分鐘

           ·

          2021-01-19 18:18

          ↑ 點擊藍字?關(guān)注極市平臺

          作者丨nihate
          審稿|鄧富城
          編輯丨極市平臺

          極市導讀

          ?

          本文中介紹的整套程序只依賴OpenCV庫就能正常運行,徹底擺脫了對深度學習框架的依賴。文章講述了作者在自己編寫用OpenCV的dnn模塊做YOLOv5目標檢測的程序的過程中遇到的bug以及解決的辦法。?>>加入極市CV技術(shù)交流群,走在計算機視覺的最前沿

          最近看到多篇講解YOLOv5在OpenVINO部署做目標檢測文章,但是沒看到過用OpenCV的DNN模塊做YOLOv5目標檢測的。于是,我就想編寫一套用OpenCV的DNN模塊做YOLOv5目標檢測的程序。

          在編寫這套程序時,遇到的bug和解決辦法,在這篇文章里講述一下。

          YOLOv5之前的YOLOv3和YOLOv4的官方代碼都是基于darknet框架的實現(xiàn)的,因此OpenCV的DNN模塊做目標檢測時,讀取的是.cfg和.weight文件,那時候編寫程序很順暢,沒有遇到bug。

          但是YOLOv5的官方代碼(https://github.com/ultralytics/yolov5)是基于Pytorch框架實現(xiàn)的,而OpenCV的DNN模塊不支持讀取Pytorch的訓練模型文件。如果想要把Pytorch的訓練模型.pth文件加載到OpenCV的DNN模塊里,需要先把Pytorch的訓練模型.pth文件轉(zhuǎn)換到.onnx文件,然后才能載入到Opencv的DNN模塊里。

          因此,用OpenCV的DNN模塊做YOLOv5目標檢測的程序,包含兩個步驟:

          1. 把Pytorch的訓練模型.pth文件轉(zhuǎn)換到.onnx文件。

          2. OpenCV的DNN模塊讀取.onnx文件做前向計算。

          1. 把Pytorch的訓練模型.pth文件轉(zhuǎn)換到.onnx文件

          在做這一步時,我得吐槽一下官方代碼:

          https://github.com/ultralytics/yolov5

          這套程序里的代碼混亂,在Pytorch里,通常是在.py文件里定義網(wǎng)絡結(jié)構(gòu)的,但是官方代碼是在.yaml文件定義網(wǎng)絡結(jié)構(gòu),利用Pytorch動態(tài)圖特性,解析.yaml文件自動生成網(wǎng)絡結(jié)構(gòu)。在.yaml文件里有depth_multiple和width_multiple,它是控制網(wǎng)絡的深度和寬度的參數(shù)。

          這么做的好處是能夠靈活的配置網(wǎng)絡結(jié)構(gòu),但是不利于理解網(wǎng)絡結(jié)構(gòu)。假如你想設斷點查看某一層的參數(shù)和輸出數(shù)值,那就沒辦法了。因此,在我編寫的轉(zhuǎn)換到.onnx文件的程序里,網(wǎng)絡結(jié)構(gòu)是在.py文件里定義的。

          其次,在官方代碼里,還有一個奇葩的地方,那就是.pth文件。

          起初,我下載官方代碼到本地運行時,torch.load讀取.pth文件總是出錯,后來把pytorch升級到1.7,就讀取成功了。可以看到版本兼容性不好,這是它的一個不足之處。

          設斷點查看讀取的.pth文件里的內(nèi)容,可以看到.pth里既存儲有模型參數(shù),也存儲有網(wǎng)絡結(jié)構(gòu),還儲存了一些超參數(shù),包括anchors,stride等等的。第一次見到有這種操作的,通常情況下,.pth文件里只存儲了訓練模型參數(shù)的。

          查看models\yolo.py里的Detect類,在構(gòu)造函數(shù)里,有這么兩行代碼:

          我嘗試過把這兩行代碼改成self.anchors = a 和 self.anchor_grid = a.clone().view(self.nl, 1, -1, 1, 1, 2),程序依然能正常運行,但是torch.save保存模型文件后,可以看到.pth文件里沒有存儲anchors和anchor_grid了,在網(wǎng)頁搜索register_buffer,解釋是:pytorch中register_buffer模型保存和加載的時候可以寫入和讀出。

          在這兩行代碼的下一行:

          它的作用是做特征圖的輸出通道對齊,通過1x1卷積把三種尺度特征圖的輸出通道都調(diào)整到 num_anchors*(num_classes+5)。

          閱讀Detect類的forward函數(shù)代碼,可以看出它的作用是根據(jù)偏移公式計算出預測框的中心坐標和高寬,這里需要注意的是,計算高和寬的代碼:

          pwh = (ps[:, 2:4].sigmoid() * 2) ** 2 * anchors[i]

          沒有采用exp操作,而是直接乘上anchors[i],這是YOLOv5與YOLOv3v4的一個最大區(qū)別(還有一個區(qū)別就是在訓練階段的loss函數(shù)里,YOLOv5采用鄰域的正樣本anchor匹配策略,增加了正樣本。其它的是一些小區(qū)別,比如YOLOv5的第一個模塊采用FOCUS把輸入數(shù)據(jù)2倍下采樣切分成4份,在channel維度進行拼接,然后進行卷積操作,YOLOv5的激活函數(shù)沒有使用Mish)。

          現(xiàn)在可以明白Detect類的作用是計算預測框的中心坐標和高寬,簡單來說就是生成proposal,作為后續(xù)NMS的輸入,進而輸出最終的檢測框。我覺得在Detect類里定義的1x1卷積是不恰當?shù)?,應該把它定義在Detect類的外面,緊鄰著Detect類之前定義1x1卷積。

          在官方代碼里,有轉(zhuǎn)換到onnx文件的程序:python models/export.py --weights yolov5s.pt --img 640 --batch 1

          在pytorch1.7版本里,程序是能正常運行生成onnx文件的。觀察export.py里的代碼,在執(zhí)行torch.onnx.export之前,有這么一段代碼:

          注意其中的for循環(huán),我試驗過注釋掉它,重新運行就會出錯,打印出的錯誤如下:

          由此可見,這段for循環(huán)代碼是必需的。

          2. OpenCV的DNN模塊讀取.onnx文件做前向計算

          在生成.onnx文件后,就可以用OpenCV的DNN模塊里的cv2.dnn.readNet讀取它。然而,在讀取時,出現(xiàn)了如下錯誤:

          我在網(wǎng)頁搜索這個問題的解決辦法,看到一篇技術(shù)文章(https://zhuanlan.zhihu.com/p/286298001),文章里講述的第一條:

          于是查看YOLOv5的代碼,在common.py文件的Focus類,torch.cat的輸入里有4次切片操作,代碼如下:

          那么現(xiàn)在需要更換索引式的切片操作,觀察到注釋的Contract類,它就是用view和permute函數(shù)完成切片操作的,于是修改代碼如下:

          其次,在models\yolo.py里的Detect類里,也有切片操作,代碼如下:

          前面說過,Detect類的作用是計算預測框的中心坐標和高寬,生成proposal,這個是屬于后處理的,因此不需要把它寫入到onnx文件里。

          總結(jié)一下,按照上面的截圖代碼,修改Focus類,把Detect類里面的1x1卷積定義在緊鄰著Detect類之前的外面,然后去掉Detect類,組成新的model,作為torch.onnx.export的輸入,

          torch.onnx.export(model, inputs, output_onnx, verbose=False, opset_version=12, input_names=['images'], output_names=['out0', 'out1', 'out2'])

          最后生成的onnx文件,opencv的dnn模塊就能成功讀取了,接下來對照Detect類里的forward函數(shù),用python或者C++編寫計算預測框的中心坐標和高寬的功能。

          周末這兩天,我在win10+cpu機器里編寫了用OpenCV的DNN模塊做Yolov5目標檢測的程序,包含Python和C++兩個版本的。程序都調(diào)試通過了,運行結(jié)果也是正確的。

          我把這套代碼發(fā)布在了Github上,地址是:

          https://github.com/hpc203/yolov5-dnn-cpp-python

          后處理模塊,python版本用numpy array實現(xiàn)的,C++版本的用vector和數(shù)組實現(xiàn)的,整套程序只依賴OpenCV庫(opencv4版本以上的)就能正常運行,徹底擺脫對深度學習框架pytorch,tensorflow,caffe,mxnet等等的依賴。

          用OpenVINO作目標檢測,需要把onnx文件轉(zhuǎn)換到.bin和.xml文件,相比于用DNN模塊加載onnx文件做目標檢測是多了一個步驟的。因此,我就想編寫一套用OpenCV的DNN模塊做YOLOv5目標檢測的程序,用Opencv的DNN模塊做深度學習目標檢測,在win10和ubuntu,在cpu和gpu上都能運行,可見DNN模塊的通用性更好,很接地氣。

          作者檔案

          作者:nihate
          歡迎大家聯(lián)系極市小編(微信ID:fengcall19)加入極市原創(chuàng)作者行列


          推薦閱讀




          添加極市小助手微信(ID : cvmart2),備注:姓名-學校/公司-研究方向-城市(如:小極-北大-目標檢測-深圳),即可申請加入極市目標檢測/圖像分割/工業(yè)檢測/人臉/醫(yī)學影像/3D/SLAM/自動駕駛/超分辨率/姿態(tài)估計/ReID/GAN/圖像增強/OCR/視頻理解等技術(shù)交流群:月大咖直播分享、真實項目需求對接、求職內(nèi)推、算法競賽、干貨資訊匯總、與?10000+來自港科大、北大、清華、中科院、CMU、騰訊、百度等名校名企視覺開發(fā)者互動交流~
          △長按添加極市小助手

          △長按關(guān)注極市平臺,獲取最新CV干貨

          覺得有用麻煩給個在看啦~??
          瀏覽 110
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  免费h片在线观看网址 | av亚洲产国偷v产偷v自拍 | 黄色五月天视频 | 欧美成人免费一区二区三区 | 操逼喷水视频 |