【翻譯】手把手教你用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 數據集獲取
- MS COCO數據集: 使用
./scripits/get_coco_dataset.sh
來獲取數據集。 - OpenImages數據集: 使用
./scripits/get_openimages_dataset.py
獲取數據集,並按照規定的格式重排訓練集。 - Pascal VOC數據集: 使用
./scripits/voc_label.py
對數據集標註進行處理。 - ILSVRC2012數據集(ImageNet Classification): 使用
./scripits/get_imagenet_train.sh
獲取數據集,運行./scripits/imagenet_label.sh
用於驗證集。 - German/Belgium/Russian/LISA/MASTIF 交通標誌數據集。
- 其他數據集,請訪問
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:8070
和8090
:./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
- 下載 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
- Smart WebCam – 從此處下載:
- 將你的手機與電腦通過WIFI或者USB相連。
- 開啟手機中的Smart WebCam APP。
- 將以下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編譯流程:
- Configure.
- Optional platform for generator (Set: x64) .
- Finish.
- Generate.
- Open Project.
- Set: x64 & Release.
- Build.
- 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.dll
和opencv_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
- (右鍵點擊工程) -> properties -> C/C++ -> General -> Additional Include Directories:
- 如果你的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
- 下載預訓練模型 (154 MB):
http://pjreddie.com/media/files/darknet53.conv.74
將其放在builddarknetx64
文件夾中。 - 下載pascal voc數據集並解壓到
builddarknetx64datavoc
放在builddarknetx64datavocVOCdevkit
文件夾中: 2.1 下載voc_label.py
到builddarknetx64datavoc
,地址為: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
。
- 下載並安裝python:
https://www.python.org/ftp/python/3.5.2/python-3.5.2-amd64.exe
- 運行命令:
python builddarknetx64datavocvoc_label.py
(來生成文件: 2007_test.txt, 2007_train.txt, 2007_val.txt, 2012_train.txt, 2012_val.txt)。 - 運行命令:
type 2007_train.txt 2007_val.txt 2012_*.txt > train.txt
。 - 在
yolov3-voc.cfg
文件中設置batch=64
和subdivisions=8
。 - 使用
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訓練?
- 首先在一個GPU中訓練大概1000個輪次:
darknet.exe detector train cfg/voc.data cfg/yolov3-voc.cfg darknet53.conv.74
。 - 然後停下來基於這個保存的模型
/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:
- 創建與
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.cfg
和yolov3.cfg
不同的地方應該在每個[yolo]/[region]
層的下面幾行:
[convolutional] filters=21 [region] classes=2
- 在
builddarknetx64data
創建文件obj.names
, 每行一個類別的名稱。 - 在
builddarknetx64data
創建obj.data
, 具體內容如下:
classes= 2 # 你的類別的個數 train = data/train.txt # 存儲用於訓練的圖片位置 valid = data/test.txt # 存儲用於測試的圖片的位置 names = data/obj.names # 每行一個類別的名稱 backup = backup/
- 將你的圖片放在
builddarknetx64dataobj
文件夾下。 - 你應該標註你的數據集中的每一張圖片,使用
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
- 在
builddarknetx64data
文件夾中創建train.txt文件,每行包含的是訓練集圖片的內容。其路徑是相對於darknet.exe
的路徑或者絕對路徑:
data/obj/img1.jpg data/obj/img2.jpg data/obj/img3.jpg
- 下載預訓練權重,並將其放在
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)
:請查看原工程。
- 對於
- 使用以下命令行開始訓練:
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
,然後在瀏覽器中打開 URLhttp://ip-address:8090
。
- 權重文件
- 訓練結束以後,將會在文件夾
builddarknetx64backup
中得到權重文件yolo-obj_final.weights
。
- 在100次迭代以後,你可以停下來,然後從這個點載入模型繼續訓練。比如說, 你在2000次迭代以後停止訓練,如果你之後想要恢復訓練,只需要運行命令:
darknet.exe detector train data/obj.data yolo-obj.cfg backupyolo-obj_2000.weights
,而不需要重頭開始訓練。
注意:
- 如果在訓練的過程中,發現
avg
指標變為nan
,那證明訓練過程有誤,可能是數據標註越界導致的問題。但是其他指標有nan
是正常的。 - 修改
width
,height
的時候必須要保證兩者都能夠被32整除。 - 訓練結束後,可以使用以下命令來進行測試:
darknet.exe detector test data/obj.data yolo-obj.cfg yolo-obj_8000.weights
- 如果出現
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次。如果想要更加精準地定義什麼時候該停止訓練,需要使用以下方法:
- 訓練過程中,你將會看到日誌中有很多錯誤的度量指標,你需要在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
指標解釋
- IoU (intersect over union) – 平均交並比
- mAP (mean average precision) – 每個類的平均精度。具體解釋請參考之前的文章:目標檢測演算法之常見評價指標(mAP)的詳細計算方法及程式碼解析
mAP 是Pascal VOC競賽的默認指標,與MS COCO競賽中的AP50指標是一致的。
Precision和Recall參數在Pascal VOC競賽中略微不同,但 IoU 的意義都是相同的.

precision_recall_iou
6.6 如何在pascal voc2007數據集上計算mAP指標
- 在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.py
到builddarknetx64data
文件夾,然後運行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:
- 使用Darknet + Python: 運行
build/darknet/x64/calc_mAP_voc_py.cmd
,你將得到yolo-voc.cfg
模型的mAP值, mAP = 75.9% - 直接使用命令: 運行文件
build/darknet/x64/calc_mAP.cmd
-你將得到yolo-voc.cfg
模型, 得到mAP = 75.8%
- 使用Darknet + Python: 運行
- 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.py
和voc_eval.py
而不是使用reval_voc_py3.py
和voc_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. 如何提升目標檢測性能?
- 訓練之前:
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)
其中width
和height
是在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]。 - 當你是神經網路方面的專家時,可以重新計算相對於
width
和height
的anchors
:darknet.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
吧。
- 訓練之後:
- 沒有必要重新訓練模型,直接使用用
416x416
解析度訓練出來的.weights
模型文件。 - 但是要獲得更高的準確率,你應該使用
608x608
或者832x832
來訓練,注意如果Out of memory
發生了,你應該在.cfg
文件中增加subdivisions=16,32,64
。 - 通過在
.cfg
文件中設置(height=608
andwidth=608
)或者(height=832
andwidth=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.tree
和coco9k.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.labels
。9k.names
,inet9k.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.sln
或builddarknetyolo_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
- 使用C++ API的C++例子:
11. 附錄
- 為了將Yolo編譯成C++的DLL文件
yolo_cpp_dll.dll
:打開builddarknetyolo_cpp_dll.sln
解決方案,編譯選項選X64和Release,然後執行Build->Build yolo_cpp_dll就,編譯的一些前置條件為:
- 安裝CUDA 10.0。
- 為了使用cuDNN執行以下步驟:點擊工程屬性->properties->C++->Preprocessor->Preprocessor Definitions,然後在開頭添加一行
CUDNN
。
- 在自己的C++工程中將Yolo當成DLL文件使用:打開
builddarknetyolo_console_dll.sln
解決方案,編譯選項選X64和Release,然後執行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行。
- 你可以利用Windows資源管理器運行
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的微信,我們將你帶入一個熱心分享、共同解決困難的集體!