# Yolov3 訓練
請先make 這個 darknet https://github.com/pjreddie/darknet
make教學可看(https://github.com/AlexeyAB/darknet)
Makefile裡面自行修改參數
```
GPU=1
CUDNN=1
OPENCV=0 (若有安裝opencv [C++, 非opencv-python], 不能使用opencv 3.4.1)
OPENMP=1 (GNU Compiler Collection有支援)
DEBUG=0 (除錯用,一般用不到,別動)
```
arch提供參考參數如下(若為該架構就uncomment)
```
# GeForce RTX 2080 Ti, RTX 2080, RTX 2070, Quadro RTX 8000, Quadro RTX 6000, Quadro RTX 5000, Tesla T4, XNOR Tensor Cores
# ARCH= -gencode arch=compute_75,code=[sm_75,compute_75]
# Jetson XAVIER
# ARCH= -gencode arch=compute_72,code=[sm_72,compute_72]
# Tesla V100, GTX 1180, Titan V, Quadro GV100
# ARCH= -gencode arch=compute_70,code=[sm_70,compute_70]
# For Jetson Tx2 or Drive-PX2 uncomment:
# ARCH= -gencode arch=compute_62,code=[sm_62,compute_62]
# GTX 1080, GTX 1070, GTX 1060, GTX 1050, GTX 1030, Titan Xp, Tesla P40, Tesla P4
# ARCH= -gencode arch=compute_61,code=[sm_61,compute_61]
# For Quadro GP100, Tesla P100
# ARCH= -gencode arch=compute_60,code=[sm_60,compute_60]
# For Jetson TX1, Tegra X1, DRIVE CX, DRIVE PX :
# ARCH= -gencode arch=compute_53,code=[sm_53,compute_53]
# For Quadro M6000 , GeForce 900, GTX-970, GTX-980, GTX Titan X :
# ARCH= -gencode arch=compute_52,code=[sm_52,compute_52]
# For Tesla/Quadro M series :
# ARCH= -gencode arch=compute_50,code=[sm_50,compute_50]
# For Tesla K80 :
# ARCH= -gencode arch=compute_37,code=[sm_37,compute_37]
# For Tesla K40 :
# ARCH= -gencode arch=compute_35,code=[sm_35,compute_35]
# For GeForce 700, GT-730 :
# ARCH= -gencode arch=compute_30,code=[sm_30,compute_30]
# For GeForce 400, 500, 600, GT-630 :
# ARCH= -gencode arch=compute_20,code=[sm_20,compute_30]
```
## 訓練資料為(假設是VOC格式)
DataSet的根目錄我用`path_to_dataset`代替.
首先準備voc dataset, 擺放方式如下:
```
path_to_dataset (dir)
│
└───images (dir)
│ │
│ │ file001.jpg
│ │ file002.jpg
│ └ ...
│
└───labels_voc (dir)
│ │ file001.xml
│ │ file002.xml
│ └ ...
│
└───labels (dir)
│
└─(empty)
*註: (dir) 為資料夾
```
檔名請對齊,file001.jpg 就對應file001.xml
## Step1 VOC to darknet format
下載`label_to_yolo.py`至`path_to_dataset`根目錄:
https://gist.github.com/hsuRush/f6689a62a740f0cf3ffa3ff99a79b7df
`需改path_to_dataset跟class以及valid_split, valid_split`為train set, valid set切的比例. 若為0.1則比例為9:1.
- 跑`python label_to_yolo.py`他會將VOC label資料(在`path_to_dataset/labels_voc`)轉為darknet的格式並放入`path_to_dataset/labels/`,並且會產生train.txt以及test.txt
將產生train.txt以及test.txt放至`path_to_dataset/`
## Step2 Kmeans for anchor box
`kmeans.py`:
https://gist.github.com/hsuRush/4bf21fff72f00cb7e37c2af3f572a86e
預設`CLUSTERS` = 9
將`path_to_dataset`改為`labels_voc`所在的絕對路徑
將`HEIGHT`, `WIDTH`, `classes`改為你現在DataSet的規格
調整`times`, 他會多跑幾次然後選擇最好的kmeans結果.
好了之後跑`python kmeans.py` 他會輸出一個`k_means_anchor`
將`k_means_anchor`檔案以文本方式打開如下
```
Accuracy: 89.91%
anchors = 69,25, 78,33, 71,29, 44,19, 75,37, 47,23, 58,27, 91,42, 55,22
```
將`darknet/cfg/yolov3.cfg` 複製出來, 假設叫yolov3_fruit.cfg
將`69,25, 78,33, 71,29, 44,19, 75,37, 47,23, 58,27, 91,42, 55,22`複製到yolov3_fruit.cfg裡面的`anchors = `. Take yolov3 as exmaple, change [Line 609](https://github.com/pjreddie/darknet/blob/0ff23438c66629deff8df2551baffbbb29987dee/cfg/yolov3.cfg#L609), [Line 695](https://github.com/pjreddie/darknet/blob/0ff23438c66629deff8df2551baffbbb29987dee/cfg/yolov3.cfg#L695), [Line 782](https://github.com/pjreddie/darknet/blob/0ff23438c66629deff8df2551baffbbb29987dee/cfg/yolov3.cfg#L782)
並且yolov3_fruit.cfg有兩處需要修改的地方:
第一處:[yolo]層中classes改成你的類別數(在v3中共三處),假設我使用的是fruit的資料集,有3類,所以`classes=3`。
第二處:[yolo]層前一層的[convolution]層中(在v3中共三處),filters的數量改成(`classes`+4+1 * `CLUSTERS`).
Take yolov3 as exmaple, change [Line 610](https://github.com/pjreddie/darknet/blob/0ff23438c66629deff8df2551baffbbb29987dee/cfg/yolov3.cfg#L603), [Line 696](https://github.com/pjreddie/darknet/blob/0ff23438c66629deff8df2551baffbbb29987dee/cfg/yolov3.cfg#L689), [Line 783](https://github.com/pjreddie/darknet/blob/0ff23438c66629deff8df2551baffbbb29987dee/cfg/yolov3.cfg#L776)
所以假設我kmeans跑得是(CLUSTERS=9)是(3+4+1)*9 = 72, 所以改為`filters=72`
Take yolov3 as exmaple, change [Line 609](https://github.com/pjreddie/darknet/blob/0ff23438c66629deff8df2551baffbbb29987dee/cfg/yolov3.cfg#L603), [Line 695](https://github.com/pjreddie/darknet/blob/0ff23438c66629deff8df2551baffbbb29987dee/cfg/yolov3.cfg#L689), [Line 782](https://github.com/pjreddie/darknet/blob/0ff23438c66629deff8df2551baffbbb29987dee/cfg/yolov3.cfg#L776)
## Step3 DataSet preparation
創.names 跟.data
.names放class的名稱, 例如`darknet/data/fruit.names`的內容為
```
apple
banana
pineapple
```
例如 `darknet/cfg/fruit.data`內容為:
```
classes= 3 (class個數)
train = path_to_dataset/train.txt (train.txt的完整路徑) (產生於Step1)
valid = path_to_dataset/test.txt (test.txt的完整路徑) (產生於Step1)
names = /home/username/darknet/data/fruit.names (fruit.names的完整路徑)
backup = /home/username/backup (訓練過程的暫存點checkpoint會存在這,要先創好資料夾先創好資料夾先創好資料夾)
```
# Step 4 Training Settings

將`yolov3_fruit.cfg`Testing部份如上圖所示`#`字號註解掉, Training無`#`字號。
將`yolov3_fruit.cfg`的max_batches,batch跟steps改成適當的數字 [參考](https://github.com/AlexeyAB/darknet#how-to-train-to-detect-your-custom-objects)
舉例我在cfg裡面設:
```
max_batches = 6000
policy=steps
steps=4000,5000
scales=.1,.1
```
在make成功darknet的情況下,
在darknet/ 打開terminal
* for `linux`:
跑 `./darknet detector train cfg/fruit.data cfg/yolov3_fruit.cfg`
* for `window`:
跑 `darknet.exe detector train cfg/fruit.data cfg/yolov3_fruit.cfg`
``-gpu 0,1,2...`` for multi-gpu
訓練的資訊請看 https://chtseng.wordpress.com/2018/09/01/%E5%BB%BA%E7%AB%8B%E8%87%AA%E5%B7%B1%E7%9A%84yolo%E8%BE%A8%E8%AD%98%E6%A8%A1%E5%9E%8B-%E4%BB%A5%E6%9F%91%E6%A9%98%E8%BE%A8%E8%AD%98%E7%82%BA%E4%BE%8B/ 的第八點
# Step 5
訓練好後把cfg的testing 的`#`拿掉 training的部份加上`#`

若需要使用python inference, 請看
https://github.com/107368002/darknet/blob/48dcb887e8f8a7253e5dcdb4297b19b43b58ea55/python/darknet.py#L48
記得路徑要改 (48行)
```
lib=CDLL("/home/czchen/stevenwork/plate_detection_ML_hw3/darknet/libdarknet.so", RTLD_GLOBAL)
```