【翻譯】手把手教你用AlexeyAB版Darknet

  • 2020 年 1 月 16 日
  • 筆記

前言: 自從Joseph Redmon提出了yolov3後,其darknet倉庫已經獲得了16k的star,足以說明darknet的流行。該作者最新一次更新也是一年前了,沒有繼續維護。不過自來自俄國的大神AlexeyAB在不斷地更新darknet, 不僅添加了darknet在window下的適配,而且實現了多種SOTA目標檢測演算法。AlexeyAB也在庫中提供了一份詳細的建議,從編譯、配置、涉及網路到測量指標等,一應俱全。通過閱讀和理解AlexeyAB的建議,可以為我們帶來很多啟發。本文是來自翻譯AlexeyAB的darknet中的README,並在翻譯的過程中加入我們的一些經驗。

作者: BBuf&PPRP

下圖是CSPNet中統計的目前的State of the Art的目標檢測模型。其中從csresnext50-panet-spp-optimal模型是CSPNet中提出來的,可以結合AlexeyAB版本的Darknet就可以實現。

1. 依賴

1.1 環境要求

  • window系統或者linux系統。
  • CMake版本高於3.8。
  • CUDA 10.0,cuDNN>=7.0。
  • OpenCV版本高於2.4。
  • Linux下需要GCC 或者Clang, Window下需要Visual Studio 15、17或19版。

1.2 數據集獲取

  1. MS COCO數據集: 使用./scripits/get_coco_dataset.sh來獲取數據集。
  2. OpenImages數據集: 使用./scripits/get_openimages_dataset.py獲取數據集,並按照規定的格式重排訓練集。
  3. Pascal VOC數據集: 使用./scripits/voc_label.py對數據集標註進行處理。
  4. ILSVRC2012數據集(ImageNet Classification): 使用./scripits/get_imagenet_train.sh獲取數據集,運行./scripits/imagenet_label.sh用於驗證集。
  5. German/Belgium/Russian/LISA/MASTIF 交通標誌數據集。
  6. 其他數據集,請訪問https://github.com/AlexeyAB/darknet/tree/master/scripts#datasets

結果示意:

1578922944407

其他測試結果可以訪問:https://www.youtube.com/user/pjreddie/videos

2. 相比原作者Darknet的改進

  • 添加了對windows下運行darknet的支援。
  • 添加了SOTA模型: CSPNet, PRN, EfficientNet。
  • 在官方Darknet的基礎上添加了新的層:[conv_lstm], [scale_channels] SE/ASFF/BiFPN, [local_avgpool], [sam], [Gaussian_yolo], [reorg3d] (修復 [reorg]), 修復 [batchnorm]。
  • 可以使用[conv_lstm]層或者[crnn]層來實現針對影片的目標檢測。
  • 添加了多種數據增強策略: [net] mixup=1 cutmix=1 mosaic=1 blur=1
  • 添加了多種激活函數: SWISH, MISH, NORM_CHAN, NORMCHAN_SOFTMAX。
  • 增加了使用CPU-RAM提高GPU處理訓練的能力,以增加mini_batch_size和準確性。
  • 提升了二值網路,讓其在CPU和GPU上的訓練和測試速度變為原來的2-4倍。
  • 通過將Convolutional層和Batch-Norm層合併成一個層,提升了約7%速度。
  • 如果在Makefile中使用CUDNN_HALF參數,可以讓網路在TeslaV100,GeForce RTX等型號的GPU上的檢測速度提升兩倍。
  • 針對影片的檢測進行了優化,對高清影片檢測速度可以提升1.2倍,對4k的影片檢測速度可以提升2倍。
  • 數據增強部分使用Opencv SSE/AVX指令優化了原來樸素實現的數據增強,數據增強速度提升為原來的3.5倍。
  • 在CPU上使用AVX指令來提高了檢測速度,yolov3提高了約85%。
  • 在網路多尺度訓練(random=1)的時候優化了記憶體分配。
  • 優化了檢測時的GPU初始化策略,在bacth=1的時候執行初始化而不是當batch=1的時候重新初始化。
  • 添加了計算mAP,F1,IoU, Precision-Recall等指標的方法,只需要運行darknet detector map命令即可。
  • 支援在訓練的過程中畫loss曲線和準確率曲線,只需要添加-map標誌即可。
  • 提供了-json_port,-mjpeg_port選項,支援作為json和mjpeg 伺服器來在線獲取的結果。可以使用你的編寫的軟體或者web瀏覽器與json和mjpeg伺服器連接。
  • 添加了Anchor的計算功能,可以根據數據集來聚類得到合適的Anchor。
  • 添加了一些目標檢測和目標跟蹤的示例:https://github.com/AlexeyAB/darknet/blob/master/src/yolo_console_dll.cpp
  • 在使用錯誤的cfg文件或者數據集的時候,添加了運行時的建議和警告。
  • 其它一些程式碼修復。

3. 命令行使用

Linux中使用./darknet,window下使用darknet.exe.

Linux中命令格式類似./darknet detector test ./cfg/coco.data ./cfg/yolov3.cfg ./yolov3.weights

Linux中的可執行文件在根目錄下,Window下則在builddarknetx64文件夾中。以是不同情況下應該使用的命令:

  • Yolo v3 COCO – 圖片測試: darknet.exe detector test cfg/coco.data cfg/yolov3.cfg yolov3.weights -thresh 0.25
  • 輸出坐標 of objects: darknet.exe detector test cfg/coco.data yolov3.cfg yolov3.weights -ext_output dog.jpg
  • Yolo v3 COCO – 影片測試: darknet.exe detector demo cfg/coco.data cfg/yolov3.cfg yolov3.weights -ext_output test.mp4
  • 網路攝影機: darknet.exe detector demo cfg/coco.data cfg/yolov3.cfg yolov3.weights -c 0
  • 網路影片攝影機 – Smart WebCam: darknet.exe detector demo cfg/coco.data cfg/yolov3.cfg yolov3.weights http://192.168.0.80:8080/video?dummy=param.mjpg
  • Yolo v3 – 保存影片結果為res.avi: darknet.exe detector demo cfg/coco.data cfg/yolov3.cfg yolov3.weights test.mp4 -out_filename res.avi
  • Yolo v3 Tiny版本 COCO – video: darknet.exe detector demo cfg/coco.data cfg/yolov3-tiny.cfg yolov3-tiny.weights test.mp4
  • JSON and MJPEG 伺服器 :創建JSON和MJPEG伺服器,允許軟體或Web瀏覽器進行與伺服器之間進行多個連接 。假設兩者需要的埠為ip-address:80708090: ./darknet detector demo ./cfg/coco.data ./cfg/yolov3.cfg ./yolov3.weights test50.mp4 -json_port 8070 -mjpeg_port 8090 -ext_output
  • Yolo v3 Tiny on GPU: darknet.exe detector demo cfg/coco.data cfg/yolov3-tiny.cfg yolov3-tiny.weights -i 1 test.mp4
  • 另一個可進行圖片測試的命令 Yolo v3 COCO – 圖片測試: darknet.exe detect cfg/yolov3.cfg yolov3.weights -i 0 -thresh 0.25
  • Amazon EC2上訓練, 如果想要看mAP和Loss曲線,運行以下命令: http://ec2-35-160-228-91.us-west-2.compute.amazonaws.com:8090 (Darknet 必須使用OpenCV進行編譯才能使用該功能): ./darknet detector train cfg/coco.data yolov3.cfg darknet53.conv.74 -dont_show -mjpeg_port 8090 -map
  • 186 MB Yolo9000 – 圖片分類: darknet.exe detector test cfg/combine9k.data cfg/yolo9000.cfg yolo9000.weights
  • 處理一系列圖片,並保存結果為json文件darknet.exe detector test cfg/coco.data cfg/yolov3.cfg yolov3.weights -ext_output -dont_show -out result.json < data/train.txt
  • 處理一系列圖片,並保存結果為txt文件:darknet.exe detector test cfg/coco.data cfg/yolov3.cfg yolov3.weights -dont_show -ext_output < data/train.txt > result.txt
  • 偽標註: 處理一個list的圖片 data/new_train.txt ,可以讓結果保存為Yolo訓練所需的格式,標註文件為 <image_name>.txt 。通過這種方法可以迅速增加訓練數據量。具體命令為:darknet.exe detector test cfg/coco.data cfg/yolov3.cfg yolov3.weights -thresh 0.25 -dont_show -save_labels < data/new_train.txt
  • 如何計算anchor(通過聚類得到): darknet.exe detector calc_anchors data/obj.data -num_of_clusters 9 -width 416 -height 416
  • 計算mAP@IoU=50: darknet.exe detector map data/obj.data yolo-obj.cfg backupyolo-obj_7000.weights
  • 計算mAP@IoU=75: darknet.exe detector map data/obj.data yolo-obj.cfg backupyolo-obj_7000.weights -iou_thresh 0.75

利用Video-Camera和Mjepg-Stream在Android智慧設備中運行YOLOv3

  1. 下載 mjpeg-stream APP: IP Webcam / Smart WebCam:
    • Smart WebCam – 從此處下載: https://play.google.com/store/apps/details?id=com.acontech.android.SmartWebCam2
    • IP Webcam下載地址: https://play.google.com/store/apps/details?id=com.pas.webcam
  2. 將你的手機與電腦通過WIFI或者USB相連。
  3. 開啟手機中的Smart WebCam APP。
  4. 將以下IP地址替換,在Smart WebCam APP中顯示,並運行以下命令:

Yolo v3 COCO-model: darknet.exe detector demo data/coco.data yolov3.cfg yolov3.weights http://192.168.0.80:8080/video?dummy=param.mjpg -i 0

4. Linux下如何編譯Darknet

4.1 使用CMake編譯Darknet

CMakeList.txt是一個嘗試發現所有安裝過的、可選的依賴項(比如CUDA,cuDNN, ZED)的配置文件,然後使用這些依賴項進行編譯。它將創建一個共享庫文件,這樣就可以使用Darknet進行程式碼開發。

在克隆了項目庫以後按照以下命令進行執行:

mkdir build-release  cd build-release  cmake ..  make  make install  

4.2 使用make編譯Darknet

在克隆了項目庫以後,直接運行make命令,需要注意的是Makefile中有一些可選參數:

  • GPU=1代表編譯完成後將可以使用CUDA來進行GPU加速(CUDA應該在/usr/local/cuda中)。
  • CUDNN=1代表通過cuDNN v5-v7進行編譯,這樣將可以加速使用GPU訓練過程(cuDNN應該在/usr/local/cudnn中)。
  • CUDNN_HALF=1代表在編譯的過程中是否添加Tensor Cores, 編譯完成後將可以將目標檢測速度提升為原來的3倍,訓練網路的速度提高為原來的2倍。
  • OPENCV=1代表編譯的過程中加入OpenCV, 目前支援的OpenCV的版本有4.x/3.x/2.4.x, 編譯結束後將允許Darknet對網路攝影機的影片流或者影片文件進行目標檢測。
  • DEBUG=1 代表是否開啟YOLO的debug模式。
  • OPENMP=1代表編譯過程將引入openmp,編譯結束後將代表可以使用多核CPU對yolo進行加速。
  • LIBSO=1 代表編譯庫darknet.so。
  • ZED_CAMERA=1 構建具有ZED-3D相機支援的庫(應安裝ZED SDK),然後運行。

5. 如何在Window下編譯Darknet

5.1 使用CMake-GUI進行編譯

建議使用以下方法來完成Window下Darknet的編譯,需要環境有:Visual Studio 15/17/19, CUDA>10.0, cuDNN>7.0, OpenCV>2.4

使用CMake-GUI編譯流程:

  1. Configure.
  2. Optional platform for generator (Set: x64) .
  3. Finish.
  4. Generate.
  5. Open Project.
  6. Set: x64 & Release.
  7. Build.
  8. Build solution.

5.2 使用vcpkg進行編譯

如果你已經滿足Visual Studio 15/17/19 、CUDA>10.0、 cuDNN>7.0、OpenCV>2.4的條件, 那麼推薦使用通過CMake-GUI的方式進行編譯。

否則按照以下步驟進行編譯:

  • 安裝或更新Visual Studio到17+,確保已經對其進行全面修補。
  • 安裝CUDA和cuDNN。
  • 安裝Git和CMake, 並將它們加入環境變數中。
  • 安裝vcpkg然後嘗試安裝一個測試庫來確認安裝是正確的,比如:vcpkg install opengl
  • 定義一個環境變數VCPKG_ROOT, 指向vcpkg的安裝路徑。
  • 定義另一個環境變數VCPKG_DEFAULT_TRIPLET將其指向x64-windows。
  • 打開Powershell然後運行以下命令:
PS >                  cd $env:VCPKG_ROOT  PS Codevcpkg>         .vcpkg install pthreads opencv[ffmpeg]  #replace with opencv[cuda,ffmpeg] in case you want to use cuda-accelerated openCV  
  • 打開Powershell, 切換到darknet文件夾,然後運行.build.ps1進行編譯。如果要使用Visual Studio,將在Build後找到CMake為您創建的兩個自定義解決方案,一個在build_win_debug中,另一個在build_win_release中,其中包含適用於系統的所有配置標誌。

5.3 使用legacy way進行編譯

  • 如果你有CUDA10.0、cuDNN 7.4 和OpenCV 3.x , 那麼打開builddarknetdarknet.sln, 設置x64和Release 然後運行Build, 進行darknet的編譯,將cuDNN加入環境變數中。
    • C:opencv_3.0opencvbuildx64vc14bin找到opencv_world320.dllopencv_ffmpeg320_64.dll, 然後將其複製到darknet.exe同級目錄中。
    • C:Program FilesNVIDIA GPU Computing ToolkitCUDAv10.0中檢查是否含有bin和include文件夾。如果沒有這兩個文件夾,那就將他們從CUDA安裝的地方複製到這個地方。
    • 安裝cuDNN 7.4.1 來匹配CUDA 10.0, 將cuDNN添加到環境變數CUDNN。將cudnn64_7.dll複製到builddarknetx64中。
  • 如果你是用的是其他版本的CUDA(不是CUDA 10.0), 那麼使用Notepad打開builddarknetdarknet.vxcproj, 將其中的CUDA 10.0替換為你的CUDA的版本。然後打開darknet.sln, 然後右擊工程,點擊屬性properties, 選擇CUDA C/C++, 然後選擇Device , 然後移除compute_75,sm_75。之後從第一步從頭開始執行。
  • 如果你沒有GPU但是有OpenCV3.0, 那麼打開builddarknetdarknet_no_gpu.sln, 設置x64和Release, 然後運行build -> build darknet_no_gpu。
  • 如果你只安裝了OpenCV 2.4.14,那你應該修改darknet.sln中的路徑。
    • (右鍵點擊工程) -> properties -> C/C++ -> General -> Additional Include Directories: C:opencv_2.4.13opencvbuildinclude
    • (右鍵點擊工程)-> properties -> Linker -> General -> Additional Library Directories: C:opencv_2.4.13opencvbuildx64vc14lib
  • 如果你的GPU有Tensor Cores(Nvidia Titan V/ Tesla V100/ DGX-2等型號), 可以提升目標檢測模型測試速度為原來的3倍,訓練速度變為原來的2倍。darknet.sln -> (右鍵點擊工程) -> properties -> C/C++ -> Preprocessor -> Preprocessor Definitions, and add here: CUDNN_HALF; 注意:CUDA 必須在Visual Studio安裝後再安裝。

6. 如何訓練

6.1 Pascal VOC dataset

  1. 下載預訓練模型 (154 MB): http://pjreddie.com/media/files/darknet53.conv.74 將其放在 builddarknetx64文件夾中。
  2. 下載pascal voc數據集並解壓到 builddarknetx64datavoc 放在 builddarknetx64datavocVOCdevkit文件夾中: 2.1 下載 voc_label.pybuilddarknetx64datavoc,地址為: http://pjreddie.com/media/files/voc_label.py。
    • http://pjreddie.com/media/files/VOCtrainval_11-May-2012.tar
    • http://pjreddie.com/media/files/VOCtrainval_06-Nov-2007.tar
    • http://pjreddie.com/media/files/VOCtest_06-Nov-2007.tar
  3. 下載並安裝python: https://www.python.org/ftp/python/3.5.2/python-3.5.2-amd64.exe
  4. 運行命令: python builddarknetx64datavocvoc_label.py (來生成文件: 2007_test.txt, 2007_train.txt, 2007_val.txt, 2012_train.txt, 2012_val.txt)。
  5. 運行命令: type 2007_train.txt 2007_val.txt 2012_*.txt > train.txt
  6. yolov3-voc.cfg文件中設置 batch=64subdivisions=8
  7. 使用 train_voc.cmd 或者使用以下命令開始訓練: darknet.exe detector train cfg/voc.data cfg/yolov3-voc.cfg darknet53.conv.74

(Note: 如果想要停止loss顯示,添加 -dont_show標誌. 如果使用CPU運行, 用darknet_no_gpu.exe 代替 darknet.exe。)

如果想要改數據集路徑的話,請修改 builddarknetcfgvoc.data文件。

Note: 在訓練中如果你看到avg為nan,那證明訓練出錯。但是如果在其他部分出現nan,這屬於正常現象,訓練過程是正常的。

6.2 如何使用多GPU訓練?

  1. 首先在一個GPU中訓練大概1000個輪次: darknet.exe detector train cfg/voc.data cfg/yolov3-voc.cfg darknet53.conv.74
  2. 然後停下來基於這個保存的模型 /backup/yolov3-voc_1000.weights 使用多GPU (最多4個GPU): darknet.exe detector train cfg/voc.data cfg/yolov3-voc.cfg /backup/yolov3-voc_1000.weights -gpus 0,1,2,3

在多GPU訓練的時候,learning rate需要進行修改,比如單gpu使用0.001,那麼多gpu應該使用0.001/GPUS。然後cfg文件中的burn_in參數和max_batches參數要設置為原來的GPUS倍。

6.3 訓練自定義數據集(重點關注)

訓練較早提出的Yolo 系列演算法如yolov2-voc.cfg, yolov2-tiny-voc.cfg, yolo-voc.cfg, yolo-voc.2.0.cfg,請看https://github.com/AlexeyAB/darknet/tree/47c7af1cea5bbdedf1184963355e6418cb8b1b4f#how-to-train-pascal-voc-data

Training Yolo v3:

  1. 創建與 yolov3.cfg內容相同的 yolo-obj.cfg 或者直接複製然後重命名為yolo-obj.cfg 然後
  • 設置cfg文件中 batch=64
  • 設置cfg文件中 subdivisions=16
  • 設置cfg文件中max_batches參數 (一般可以設置為classes*2000 但是不要低於 4000), 比如 如果你有三個類,那麼設置max_batches=6000
  • 設置steps參數,一般為80%和90%的max_batches。比如 steps=4800,5400
  • 設置網路輸入長寬必須能夠整除32,比如 width=416 height=416 `
  • 修改yolo層中的 classes=80 改為你的類別的個數,比如classes=3:
  • 修改yolo層前一個卷積層convolutional輸出通道數。修改的filter個數有一定要求,按照公式filters=(classes+5)×3來設置。這裡的5代表x, y, w, h, conf, 這裡的3代表分配3個anchor。
  • 如果使用 [Gaussian_yolo] (Gaussian_yolov3_BDD.cfg),filters計算方式不太一樣,按照 filters=(classes + 9)x3進行計算。
  • 通常來講,filters的個數計算依賴於類別個數,坐標以及mask的個數(cfg中的mask參數也就是anchors的個數)。 舉個例子,對於兩個目標,你的 yolo-obj.cfgyolov3.cfg 不同的地方應該在每個[yolo]/[region]層的下面幾行:
  [convolutional]    filters=21      [region]    classes=2  
  1. builddarknetx64data創建文件 obj.names , 每行一個類別的名稱。
  2. builddarknetx64data 創建obj.data, 具體內容如下:
  classes= 2 # 你的類別的個數    train  = data/train.txt # 存儲用於訓練的圖片位置    valid  = data/test.txt # 存儲用於測試的圖片的位置    names = data/obj.names # 每行一個類別的名稱    backup = backup/  
  1. 將你的圖片放在 builddarknetx64dataobj文件夾下。
  2. 你應該標註你的數據集中的每一張圖片,使用Yolo_mark這個可視化GUI軟體來標註出目標框並且產生標註文件。地址: https://github.com/AlexeyAB/Yolo_mark

軟體將會為每一個影像創建一個txt文件,並將其放在同一個文件夾中,命名與原圖片的名稱相同,唯一不同的就是後綴是txt。txt標註文件中每一個目標獨佔一行,按照<object-class> <x_center> <y_center> <width> <height>的格式排布。

具體參數解釋:

  • <object-class> -是從 0(classes-1)的整數,代表具體的類別。
  • <x_center> <y_center> <width> <height> – 是歸一化到(0.0 to 1.0]之間的浮點數,都是相對於圖片整體的寬和高的一個相對值。
  • 比如: <x> = <absolute_x> / <image_width> 或者 <height> = <absolute_height> / <image_height>
  • 需要注意的是: <x_center> <y_center> – 是標註框的中心點,而不是左上角。請注意格式。 舉個例子,img1.txt中內容如下,代表有兩個類別的三個目標:
  1 0.716797 0.395833 0.216406 0.147222    0 0.687109 0.379167 0.255469 0.158333    1 0.420312 0.395833 0.140625 0.166667  
  1. builddarknetx64data文件夾中創建train.txt文件,每行包含的是訓練集圖片的內容。其路徑是相對於 darknet.exe的路徑或者絕對路徑:
  data/obj/img1.jpg    data/obj/img2.jpg    data/obj/img3.jpg  
  1. 下載預訓練權重,並將其放在 builddarknetx64文件夾中。
    • 對於csresnext50-panet-spp.cfg (133 MB):請查看原工程。
    • 對於yolov3.cfg, yolov3-spp.cfg (154 MB):請查看原工程。
    • 對於yolov3-tiny-prn.cfg , yolov3-tiny.cfg (6 MB):請查看原工程。
    • 對於enet-coco.cfg (EfficientNetB0-Yolov3):請查看原工程。
  2. 使用以下命令行開始訓練: darknet.exe detector train data/obj.data yolo-obj.cfg darknet53.conv.74。 對於linux用戶使用以下命令開始訓練: ./darknet detector train data/obj.data yolo-obj.cfg darknet53.conv.74 (使用./darknet 而不是 darknet.exe)。 如果想訓練的過程中同步顯示mAP(每四個epoch進行一次更新),運行命令: darknet.exe detector train data/obj.data yolo-obj.cfg darknet53.conv.74 -map
    • 權重文件 yolo-obj_last.weights 將會保存在 builddarknetx64backup 文件夾中,每100個迭代保存一次。
    • 權重文件yolo-obj_xxxx.weights 將會保存在 builddarknetx64backup 文件夾中,每1000個迭代保存一次。
    • 如果不想在訓練的過程中同步展示loss曲線,請執行以下命令 darknet.exe detector train data/obj.data yolo-obj.cfg darknet53.conv.74 -dont_show
    • 如果想在訓練過程中查看mAP和Loss曲線,可以使用以下命令:darknet.exe detector train data/obj.data yolo-obj.cfg darknet53.conv.74 -dont_show -mjpeg_port 8090 -map ,然後在瀏覽器中打開 URL http://ip-address:8090
  3. 訓練結束以後,將會在文件夾builddarknetx64backup中得到權重文件 yolo-obj_final.weights
  • 在100次迭代以後,你可以停下來,然後從這個點載入模型繼續訓練。比如說, 你在2000次迭代以後停止訓練,如果你之後想要恢復訓練,只需要運行命令: darknet.exe detector train data/obj.data yolo-obj.cfg backupyolo-obj_2000.weights,而不需要重頭開始訓練。

注意

  1. 如果在訓練的過程中,發現avg指標變為nan,那證明訓練過程有誤,可能是數據標註越界導致的問題。但是其他指標有nan是正常的。
  2. 修改width,height的時候必須要保證兩者都能夠被32整除。
  3. 訓練結束後,可以使用以下命令來進行測試:darknet.exe detector test data/obj.data yolo-obj.cfg yolo-obj_8000.weights
  4. 如果出現Ouf of memery問題,那說明顯示卡的顯示記憶體不夠,你可以通過設置subdivisions參數,將其從原來的16提高為32或者64,這樣就能降低使用的顯示記憶體,保證程式正常運行。

6.4 訓練tiny-yolo

訓練tiny yolo與以上的訓練過程並無明顯區別,除了以下幾點:

  • 下載tiny yolo的預訓練權重:https://pjreddie.com/media/files/yolov3-tiny.weights
  • 使用以下命令行來獲取預訓練權重: darknet.exe partial cfg/yolov3-tiny.cfg yolov3-tiny.weights yolov3-tiny.conv.15 15, 這裡的15代表前15個層,也就是backbone所在的層。
  • 使用的配置文件應該是 cfg/yolov3-tiny_obj.cfg 而不是 yolov3.cfg
  • 使用以下命令開始訓練: darknet.exe detector train data/obj.data yolov3-tiny-obj.cfg yolov3-tiny.conv.15

如果想使用其他backbone進行訓練比如 DenseNet201-Yolo或者ResNet50-Yolo, 你可以在以下鏈接中找到:https://github.com/AlexeyAB/darknet/blob/master/build/darknet/x64/partial.cmd

如果你採用的是自己設計的backbone,那就無法進行遷移學習,backbone可以直接進行參數隨機初始化。

6.5 什麼時候停止訓練

建議為每個類分配至少2000次迭代,但是整體迭代次數不應少於4000次。如果想要更加精準地定義什麼時候該停止訓練,需要使用以下方法:

  1. 訓練過程中,你將會看到日誌中有很多錯誤的度量指標,你需要在avg指標不再下降的時候停止訓練,如下圖所示:

Region Avg IOU: 0.798363, Class: 0.893232, Obj: 0.700808, No Obj: 0.004567, Avg Recall: 1.000000, count: 8 Region Avg IOU: 0.800677, Class: 0.892181, Obj: 0.701590, No Obj: 0.004574, Avg Recall: 1.000000, count: 8 9002: 0.211667, 0.60730 avg, 0.001000 rate, 3.868000 seconds, 576128 images Loaded: 0.000000 seconds

  • 9002 – 代表當前的迭代次數。
  • 0.60730 avg – average loss (error) – 這個指標是平均loss, 其越低越好。 在這個指標不再下降的時候就可以停止訓練了。最終的值大概分布在0.05-3.0之間,小而簡單的模型通常最終loss比較小,大而複雜的loss可能會比較大。

訓練完成後,你就可以從 darknetbuilddarknetx64backup 文件夾中取出比較靠後的幾個weights文件,並對他們進行測試,選擇最好的權重文件。

舉個例子,你在9000次迭代後停止訓練,但最好的權重可能是7000,8000,9000次的值。這種情況的出現是由於過擬合導致的。過擬合是由於過度學習訓練集的分布,而降低了模型在測試集的泛化能力。

Early Stopping Point示意圖:

Overfitting

為了得到在early stopping point處的權重:

2.1 首先,你的obj.data文件中應該含有valid=valid.txt一項,用於測試在驗證集的準確率。如果你沒有驗證集圖片,那就直接複製train.txt重命名為valid.txt。

2.2 假如你選擇在9000次迭代後停止,那可以通過以下命令測試7000,8000,9000三個模型的相關指標。選擇最高mAP或者最高IoU的模型最為最終模型。

  • darknet.exe detector map data/obj.data yolo-obj.cfg backupyolo-obj_7000.weights
  • darknet.exe detector map data/obj.data yolo-obj.cfg backupyolo-obj_8000.weights
  • darknet.exe detector map data/obj.data yolo-obj.cfg backupyolo-obj_9000.weights

或者你可以選擇使用-map標誌符來直接實時測試mAP值:

darknet.exe detector train data/obj.data yolo-obj.cfg darknet53.conv.74 -map

然後你就能得到loss曲線和mAP曲線,mAP每4個epoch對驗證集進行一次測試,並將結果顯示在圖中。

loss_chart_map_chart

指標解釋

mAP 是Pascal VOC競賽的默認指標,與MS COCO競賽中的AP50指標是一致的。

Precision和Recall參數在Pascal VOC競賽中略微不同,但 IoU 的意義都是相同的.

precision_recall_iou

6.6 如何在pascal voc2007數據集上計算mAP指標

  1. 在VOC2007中計算mAP:
  • 下載VOC數據集,安裝python並且下載“2007_test.txt文件,具體可以參考鏈接:https://github.com/AlexeyAB/darknet#how-to-train-pascal-voc-data`
  • 下載文件 https://raw.githubusercontent.com/AlexeyAB/darknet/master/scripts/voc_label_difficult.pybuilddarknetx64data 文件夾,然後運行 voc_label_difficult.py 從而得到 difficult_2007_test.txt
  • 將下面voc.data文件中的第四行#刪除 classes= 20 train = data/train_voc.txt valid = data/2007_test.txt #difficult = data/difficult_2007_test.txt names = data/voc.names backup = backup/
  • 然後就有兩個方法來計算得到mAP:
    1. 使用Darknet + Python: 運行 build/darknet/x64/calc_mAP_voc_py.cmd ,你將得到 yolo-voc.cfg 模型的mAP值, mAP = 75.9%
    2. 直接使用命令: 運行文件 build/darknet/x64/calc_mAP.cmd -你將得到 yolo-voc.cfg 模型, 得到mAP = 75.8%
  • YOLOv3的論文:https://arxiv.org/pdf/1612.08242v1.pdf指出對於416×416的YOLOv2,Pascal Voc上的mAP值是76.8%。我們得到的值較低,可能是由於模型在進行檢測時的程式碼略有不同。
  • 如果你想為tiny-yolo-voc計算mAP值,將腳本中tiny-yolo-voc.cfg取消注釋,將yolo-voc.cfg注釋掉。
  • 如果你是用的是python 2.x 而不是python 3.x, 而且你選擇使用Darknet+Python的方式來計算mAP, 那你應該使用 reval_voc.pyvoc_eval.py 而不是使用 reval_voc_py3.pyvoc_eval_py3.py 。以上腳本來自以下目錄:https://github.com/AlexeyAB/darknet/tree/master/scripts
  • 目標檢測的例子:darknet.exe detector test data/obj.data yolo-obj.cfg yolo-obj_8000.weights

7. 如何提升目標檢測性能?

  1. 訓練之前:
    • train_network_width * train_obj_width / train_image_width ~= detection_network_width * detection_obj_width / detection_image_width
    • train_network_height * train_obj_height / train_image_height ~= detection_network_height * detection_obj_height / detection_image_height
    • 完整模型(5個yolo層):https://raw.githubusercontent.com/AlexeyAB/darknet/master/cfg/yolov3_5l.cfg
    • Tiny模型(3個yolo層):https://raw.githubusercontent.com/AlexeyAB/darknet/master/cfg/yolov3-tiny_3l.cfg
    • 帶空間金字塔池化的完整模型(3個yolo層):https://raw.githubusercontent.com/AlexeyAB/darknet/master/cfg/yolov3-spp.cfg
    • cfg文件中將random設為1:這將在Yolo中使用多尺度訓練,會提升檢測模型準確率。
    • cfg文件中把輸入解析度增大(height=608, width=608或者其他任意32的倍數):這將提升檢測模型準確率。
    • 檢查你要檢測的每個目標在數據集中是否被標記,數據集中任何目標都不應該沒有標籤。在大多數訓練出問題的情況中基本都是有錯誤的標籤(通過使用某些轉換腳本,使用第三方工具標註來獲得標籤),可以通過https://github.com/AlexeyAB/Yolo_mark來檢查你的數據集是否全部標註正確。
    • 我的損失函數很高並且mAP很低,訓練出錯了嗎?在訓練命令末端使用-show_imgs 標誌來運行訓練,你是否能看到有正確的邊界預測框的目標(在窗口或者aug_...jpg)?如果沒有,訓練是發生錯誤了。
    • 對於你要檢測的每個目標,訓練數據集中必須至少有一個相似的目標,它們具有大致相同的形狀,物體側面姿態,相對大小,旋轉角度,傾斜度,照明度等。理想的是,你的訓練數據集包括具有不同比例,旋轉角度,照明度,物體側面姿態和處於不同背景的目標影像,你最好擁有2000張不同的影像,並且至少訓練2000×classes輪次。
    • 希望你的訓練數據集圖片包含你不想檢測的未標註的目標,也即是無邊界框的負樣本圖片(空的.txt文件),並且負樣本圖片的數量和帶有目標的正樣本圖片數量最好一樣多。
    • 標註目標的最佳方法是:僅僅標記目標的可見部分或者標記目標的可見和重疊部分,或標記比整個目標多一點(有一點間隙)?根據你希望如何檢測目標來進行標記。
    • 為了對圖片中包含大量目標的數據進行訓練,添加max=200或者更高的值在你cfg文件中yolo層或者region層的最後一行(YOLOv3可以檢測到的目標全局最大數量為0,0615234375*(width*height)其中widthheight是在cfg文件中的[net]部分指定的)。
    • 對於小目標的訓練(把影像resize到416×416大小後小於16×16的目標):設置layers = -1, 11而不是layers=-1, 36;設置stride=4而不是stride=2
    • 對於既有大目標又有小目標的訓練使用下面的模型:
    • 如果你要訓練模型將左右目標分為單獨的類別(左/右手,左/右交通標誌),那就禁用翻轉的數據擴充方式,即在數據輸入部分添加flip=0
    • 一般規則:你的訓練數據集應包括一組您想要檢測的相對大小的目標,如下: 即,對於測試集中的每個目標,訓練集中必須至少有一個同類目標和它具有大約相同的尺寸: object width in percent from Training dataset ~= object width in percent from Test dataset 也就是說,如果訓練集中僅存在占影像比例80%-90%的目標,則訓練後的目標檢測網路將無法檢測到占影像比例為1-10%的目標。
    • 為了加快訓練速度(同時會降低檢測精度)使用微調而不是遷移學習,在[net]下面設置stopbackward=1。然後執行下面的命令:./darknet partial cfg/yolov3.cfg yolov3.weights yolov3.conv.81 81這將會創建yolov3.conv.81文件,然後使用yolov3.conv.81文件進行訓練而不是darknet53.conv.74
    • 在觀察目標的時候,從不同的方向、不同的照明情況、不同尺度、不同的轉角和傾斜角度來看,對神經網路來說,它們都是不同的目標。因此,要檢測的目標越多,應使用越複雜的網路模型。
    • 為了讓檢測框更准,你可以在每個yolo層添加下面三個參數ignore_thresh = .9 iou_normalizer=0.5 iou_loss=giou,這回提高[email protected],但會降低[email protected]
    • 當你是神經網路方面的專家時,可以重新計算相對於widthheightanchorsdarknet.exe detector calc_anchors data/obj.data -num_of_clusters 9 -width 416 -height 416然後在3個[yolo]層放置這9個anchors。但是你需要修改每個[yolo]層的masks參數,讓第一個[yolo]層的anchors尺寸大於60×60,第二個[yolo]層的anchors尺寸大於30×30,剩下就是第三個[yolo]層的mask。寧外,你需要修改每一個[yolo]層前面的filters=(classes + 5)x<number of mask>。如果很多計算的anchors都找不到合適的層,那還是使用Yolo的默認anchors吧。
  2. 訓練之後:
    • 沒有必要重新訓練模型,直接使用用416x416解析度訓練出來的.weights模型文件。
    • 但是要獲得更高的準確率,你應該使用608x608或者832x832來訓練,注意如果Out of memory發生了,你應該在.cfg文件中增加subdivisions=16,32,64
    • 通過在.cfg文件中設置(height=608 and width=608)或者(height=832 and width=832)或者任何32的倍數,這會提升準確率並使得對小目標的檢測更加容易。

8. 如何標註以及創建標註文件

下面的工程提供了用於標記目標邊界框並為YOLO v2&v3 生成標註文件的帶影像介面軟體,地址為:https://github.com/AlexeyAB/Yolo_mark

例如對於只有兩類目標的數據集標註後有以下文件train.txt,obj.names,obj.data,yolo-obj.cfg,air 1-6.txt,bird 1-4.txt,接著配合train_obj.cmd就可以使用YOLO v2和YOLO v3來訓練這個數據集了。

下面提供了5重常見的目標標註工具:

  • C++實現的:https://github.com/AlexeyAB/Yolo_mark
  • Python實現的:https://github.com/tzutalin/labelImg
  • Python實現的:https://github.com/Cartucho/OpenLabeling
  • C++實現的:https://www.ccoderun.ca/darkmark/
  • JavaScript實現的:https://github.com/opencv/cvat

9. 使用YOLO9000

同時檢測和分類9000個目標:darknet.exe detector test cfg/combine9k.data cfg/yolo9000.cfg yolo9000.weights data/dog.jpg

  • yolo9000.weights:186Mb的YOLO9000模型需要4G GPU顯示記憶體,訓練好的模型下載地址:http://pjreddie.com/media/files/yolo9000.weights
  • yolo9000.cfg:YOLO9000的c網路結構文件,同時這裡也有9k.treecoco9k.map文件的路徑。 tree=data/9k.tree map = data/coco9k.map
    • 9k.tree:9418個類別的單詞數,每一行的形式為<label> <parent_it>,如果parent_id==-1那麼這個標籤沒有父類別,地址為:https://raw.githubusercontent.com/AlexeyAB/darknet/master/build/darknet/x64/data/9k.tree
    • coco9k.map:將MSCOCO的80個目標類別映射到9k.tree的文件,地址為:https://raw.githubusercontent.com/AlexeyAB/darknet/master/build/darknet/x64/data/coco9k.map
  • combine9k.data:數據文件,分別是9k.labels9k.namesinet9k.map的路徑(修改combine9k.train.list文件的路徑為你自己的)。地址為:https://raw.githubusercontent.com/AlexeyAB/darknet/master/build/darknet/x64/data/combine9k.data
  • 9k.labels:9418類目標的標籤。地址為:https://raw.githubusercontent.com/AlexeyAB/darknet/master/build/darknet/x64/data/9k.labels
  • 9k.names:9418類目標的名字。地址為:https://raw.githubusercontent.com/AlexeyAB/darknet/master/build/darknet/x64/data/9k.names
  • inet9k.map:將ImageNet的200個目標類別映射到9k.tree的文件,地址為:https://raw.githubusercontent.com/AlexeyAB/darknet/master/build/darknet/x64/data/inet9k.map

10. 如何將YOLO作為DLL和SO庫進行使用?

  • 在Linux上。
    • 使用build.sh 或者
    • 使用cmake編譯darknet 或者
    • Makefile重的LIBSO=0改為LIBSO=1,然後執行make編譯darknet
  • 在Windows上。
    • 使用build.ps1 或者
    • 使用cmake編譯darknet 或者
    • 使用builddarknetyolo_cpp_dll.slnbuilddarknetyolo_cpp_dll_no_gpu.sln解決方法編譯darknet
  • 這裡有兩個API:
    • 使用C++ API的C++例子:https://github.com/AlexeyAB/darknet/blob/master/src/yolo_console_dll.cpp
    • 使用C API的Python例子:
    • https://github.com/AlexeyAB/darknet/blob/master/darknet.py
    • https://github.com/AlexeyAB/darknet/blob/master/darknet_video.py
    • C API:https://github.com/AlexeyAB/darknet/blob/master/include/darknet.h
    • C++ API:https://github.com/AlexeyAB/darknet/blob/master/include/yolo_v2_class.hpp

11. 附錄

  1. 為了將Yolo編譯成C++的DLL文件yolo_cpp_dll.dll:打開builddarknetyolo_cpp_dll.sln解決方案,編譯選項選X64Release,然後執行Build->Build yolo_cpp_dll就,編譯的一些前置條件為:
  • 安裝CUDA 10.0
  • 為了使用cuDNN執行以下步驟:點擊工程屬性->properties->C++->Preprocessor->Preprocessor Definitions,然後在開頭添加一行CUDNN
  1. 在自己的C++工程中將Yolo當成DLL文件使用:打開builddarknetyolo_console_dll.sln解決方案,編譯選項選X64Release,然後執行Build->Build yolo_console_dll: yolo_cpp_dll.dll-API:https://github.com/AlexeyAB/darknet/blob/master/include/yolo_v2_class.hpp
    • 你可以利用Windows資源管理器運行builddarknetx64yolo_console_dll.exe可執行程式並使用下面的命令: yolo_console_dll.exe data/coco.names yolov3.cfg yolov3.weights test.mp4
    • 啟動控制台應用程式並輸入影像文件名後,你將看到每個目標的資訊:<obj_id> <left_x> <top_y> <width> <height> <probability>
    • 如果要使用OpenCV-GUI你應該將yolo_console_dll.cpp中的//#define OPENCV取消注釋。
    • 你可以看到影片檢測例子的源程式碼,地址為yolo_console_dll.cpp的第75行。
struct bbox_t {      unsigned int x, y, w, h;    // (x,y) - top-left corner, (w, h) - width & height of bounded box      float prob;                    // confidence - probability that the object was found correctly      unsigned int obj_id;        // class of object - from range [0, classes-1]      unsigned int track_id;        // tracking id for video (0 - untracked, 1 - inf - tracked object)      unsigned int frames_counter;// counter of frames on which the object was detected  };    class Detector {  public:          Detector(std::string cfg_filename, std::string weight_filename, int gpu_id = 0);          ~Detector();            std::vector<bbox_t> detect(std::string image_filename, float thresh = 0.2, bool use_mean = false);          std::vector<bbox_t> detect(image_t img, float thresh = 0.2, bool use_mean = false);          static image_t load_image(std::string image_filename);          static void free_image(image_t m);    #ifdef OPENCV          std::vector<bbox_t> detect(cv::Mat mat, float thresh = 0.2, bool use_mean = false);  	std::shared_ptr<image_t> mat_to_image_resize(cv::Mat mat) const;  #endif  };  

翻譯來源:

AlexeyAB版本Darknet鏈接 https://github.com/AlexeyAB/darknet


「GiantPandaCV」是由兩位對電腦視覺心懷熱情的95後創建的,專註於深度學習基礎路線,不盲目追求熱點,按照科學的電腦視覺學習路線踏實而堅定地走下去。

目前公眾號有兩位作者,分別是BBuf和pprp,分別負責不同方向的論文閱讀和寫作,同時會分享在我們入門、深入電腦視覺的過程,想法,以及走過的彎路。

歡迎對電腦視覺感興趣或者遇到一些麻煩的朋友們添加BBuf或者pprp的微信,我們將你帶入一個熱心分享、共同解決困難的集體!