本文記錄了如何在Ubuntu/Docker中使用Alexey實現的C版YOLOv4在自己的數據集上進行訓練與測試。
論文 :
YOLOv4: Optimal Speed and Accuracy of Object Detection
代碼 :
https://github.com/AlexeyAB/darknet
環境配置
建議使用docker容器配置環境,docker的安裝不在此贅述,docker安裝好后拉取一個nvidia/cuda鏡像,docker的一些用法可以看這里。如果你不使用docker的話可以跳過docker相關部分。
首先把我們的docker跑起來
$docker run -itdp 0.0.0.0:32774:22 --gpus '"device=1,2"' --name yolo -v /home/usr/:/home -v /data0:/data0 nvidia/cuda-10.0-cudnn7-devel-ubuntu16.04:v1 /bin/bash
"-itdp 0.0.0.0:32774:22"
表示在后台運行一個交互式容器並將主機的32774
端口映射到docker容器的22/tcp
端口,如果不需要指定端口可以將其改為"-itdP"
,這表示我們不指定tcp端口映射而是隨機映射。
"--gpus '"device=1,2"
表示我們使用主機的1、2號GPU。docker的gpu命令用法可以看這里。
"--name yolo"
表示容器名稱,可自定義。
"-v /home/usr/:/home -v /data0:/data0"
表示將物理機的/home/usr/
目錄掛載在docker容器的/home
路徑下,后面同理,需要掛載幾個目錄就寫幾個-v
參數。
"nvidia/cuda-10.0-cudnn7-devel-ubuntu16.04:v1"
表示要運行的容器名稱:容器標簽
。
"/bin/bash"
表示容器內使用的命令程序。
docker的一些常用命令用法可以看這里。
接着我們安裝依賴
CUDA : 需要CUDA 10.0,安裝看這里。
cuDNN : 需要和CUDA 10.0對應的cuDNN,cuDNN在這里獲取,選擇最新的cuDNN for CUDA 10.0並下載cuDNN Library for Linux
,安裝看這里。
CMake : 需要CMake>=3.8,CMake在這里獲取,選擇"Unix/Linux Source (has \n line feeds)"
后對應的文件下載,使用如下命令編譯安裝
$tar xvzf cmake-3.17.1.tar.gz # 注意替換你下載的版本號,下同
$cd cmake-3.17.1
$./configure
$make -j
$make install
OpenCV : 需要OpenCV>=2.4,OpenCV在這里獲取,選擇Sources
下載,使用如下命令編譯安裝
$unzip opencv-4.2.0.zip # 注意替換成你下載的文件名,下同
$cd opencv-4.2.0.zip
$mkdir build
$cd build
$cmake ..
$make -j
$make install
上述各項依賴安裝期間有權限問題則使用sudo
;各項安裝完成后應查看版本號;必要時通過修改~/.bashrc
添加相關的環境變量並使用source ~/.bashrc
激活,此處不再贅述。
然后我們編譯YOLOv4的darknet
將項目克隆至本地
$git clone https://github.com/AlexeyAB/darknet
$cd darknet
使用下列方式之一進行編譯
- 使用CMake
$mkdir build-release
$cd build-release
$cmake ..
$make -j
$make install
如果期間報錯,可能是之前的依賴安裝有問題,按錯誤提示Google
解決,然后再次編譯,注意再次編譯前使用make clean
清除之前編譯失敗后遺留的中間文件。
- 使用make
在make
前可修改darknet/Makefile
文件前幾行的相關參數,參數含義在這里,一般至少將GPU
和CUDNN
設置為1,以使用GPU加速。
$make -j
如果有報錯,解決后報錯后同樣記得make clean
。
編譯完成后執行
$./darknet
usage: ./darknet <function>
有如上結果說明編譯成功。
最后我們簡單測試一下編譯好的darknet
將yolov4.weights下載到darknet
目錄中,可能需要機智上網。
Google Drive 地址 :
https://drive.google.com/open?id=1cewMfusmPjYWbrnuJRuKhPMwRe_b9PaT
GitHub 地址 :
https://github.com/AlexeyAB/darknet/releases/download/darknet_yolo_v3_optimal/yolov4.weights
然后執行
$./darknet detect cfg/yolov4.cfg yolov4.weights data/dog.jpg
CUDA-version: 10000 (10010), cuDNN: 7.6.5, GPU count: 2
OpenCV version: 4.2.0
compute_capability = 750, cudnn_half = 0
net.optimized_memory = 0
mini_batch = 1, batch = 8, time_steps = 1, train = 0
...
...
[yolo] params: iou loss: ciou (4), iou_norm: 0.07, cls_norm: 1.00, scale_x_y: 1.05
nms_kind: greedynms (1), beta = 0.600000
Total BFLOPS 128.459
avg_outputs = 1068395
Allocate additional workspace_size = 52.43 MB
Loading weights from yolov4.weights...
seen 64, trained: 32032 K-images (500 Kilo-batches_64)
Done! Loaded 162 layers from weights-file
data/dog.jpg: Predicted in 103.595000 milli-seconds.
bicycle: 92%
dog: 98%
truck: 92%
pottedplant: 33%
...
可以看到最后輸出的檢測結果等,目錄下會生成預測結果。
訓練
按下面的格式組織我們的數據
最后用於訓練的命令是
./darknet detector train xxx.data xxx.cfg xxx.weights
因此在訓練前我們需要先組織好三個文件: 用於描述數據集信息的.data文件、用於描述網絡信息的.cfg文件和一個.weights預訓練權重文件。另外我們需要為數據集准備labels文件。
- 下載預訓練權重
在下面的地址之一下載預訓練權重,將其放入darknet目錄。
-
Google Drive地址
https://drive.google.com/open?id=1JKF-bdIklxOOVy-2Cr5qdvjgGpmGfcbp -
GitHub地址
https://github.com/AlexeyAB/darknet/releases/download/darknet_yolo_v3_optimal/yolov4.conv.137
- 調整.data文件,文件內容示例如下
classes= 2
train = data/train.txt
valid = data/test.txt
names = data/obj.names
backup = backup/
- 將
classes
設置為你數據集的目標類別數。 - 將
train
設置為訓練集文件train.txt
的路徑,train.txt
中包含所有的訓練集數據路徑,每行一條,注意相對路徑或絕對路徑均可,相對路徑是相對於可執行文件darknet
的,如下所示:
data/obj/img1.jpg
data/obj/img2.jpg
data/obj/img3.jpg
- 將
valid
設置為測試集文件test.txt
的路徑,方法同train
。 - 將
names
設置為一個.names
文件的路徑,.names
文件中包含了你數據集目標的所有類別,每行一個,如下所示:
dog
cat
person
...
- 將
backup
設置為你將要存放中間權重的目錄路徑,訓練過程中每100個iteration會更新一次latest權重,每10000個iteration會保存一次中間權重,這些權重文件將存儲在你設置的backup
目錄中。
- 調整.cfg文件。
我們首先將cfg/yolov4-custom.cfg
復制一份並重命名為yolov4-obj.cfg
(或其他名字),然后基於yolov4-obj.cfg
進行修改。
yolov4-obj.cfg
文件中,開頭部分描述了用於訓練網絡的一些超參數,然后描述了完整的網絡結構。我們將修改一部分超參數和網絡結構使其適應我們的數據集和訓練環境。
- 設置
batch=64
。 - 設置
subdivisions=16
,如果稍后訓練時顯存溢出的話,可將此處調整為32、64。 - 設置
max_batches=classes*2000
,但是不要小於訓練集的數據量,也不要小於6000,比如你有5類目標,則設置max_batches=10000
。 - 設置
steps
為max_batches
的80%, 90%。 - 設置
width=416
,height=416
或任何32的整數倍,根據數據特點和顯存容量決定。 - 將每個
[yolo]
層的classes
設置為你的數據集目標類別數。注意一共有3個[yolo]
層。 - 將每個
[yolo]
層的上一層中的filters
設置為(classes + 5)x3
,其中classes
就是剛才設置的類別數。
- 准備label文件。
我們需要為每個數據圖像准備一份label文件,里面每一行描述該圖像中標注的一個object的類別和bbox信息,如下所示:
<object-class> <x_center> <y_center> <width> <height>
其中object-class
# TODO: Detail
- 最后,我們的數據集應該組織為如下形式:
Annotations
JPEGImages
labels
trainval.txt
test.txt
其中Annotations
中放置所有圖片的.xml標注文件,JPEGImages
中放置所有的圖片,labels
中放置上文所述的label文件,trainval.txt
和test.txt
為上文所述訓練集和測試集文件。
開始訓練
# TODO: Start Train
測試
# TODO: Test