YOLOのオリジナルデータ学習手順 #3-2 YOLOv3 Darknet版

**Chapters**

📘 **Chapter #0**　[YOLOとは](https://qiita.com/tfukumori/items/65056a4d51b531cdd45c)
📘 **Chapter #1**　[環境設定](https://qiita.com/tfukumori/items/6f33af8f9dc2ac974f43)
📘 **Chapter #2**　[アノテーション](https://qiita.com/tfukumori/items/0911c8fe1f5319530d4b)
📘 **Chapter #3**
　📗 **Chapter #3-1**　[YOLOv3 Keras版実装](https://qiita.com/tfukumori/items/d1f79078803d8a7fe103)
　📗 **Chapter #3-2**　[YOLOv3 Darknet版](https://qiita.com/tfukumori/items/15edd532e0a04c0a4672)
📘 **Chapter #A**
　📗 **Chapter #A-1**　[YOLOの各バージョンについてまとめ](https://qiita.com/tfukumori/items/519d84bf3feb8d246924)
　📗 **Chapter #A-2**　[YOLOv3 Keras版実装に関して関連記事のまとめ](https://qiita.com/tfukumori/items/9e62c4a7acd7ea6ddd3b)
　📗 **Chapter #A-3**　[ONNX変換・確認ライブラリ、アプリケーションまとめ](https://qiita.com/tfukumori/items/3f438294e722bc29fe16)

---

# TL;DR

- [YOLOv3 Darknet版](https://github.com/AlexeyAB/darknet)でのオリジナルデータ（独自データ）学習手順について、記載します。
    - 重みファイル、cfgファイルはYOLOv3-tinyについての記述となっていますので、必要に応じて[公式ドキュメント](https://github.com/AlexeyAB/darknet)を参考に読み替える必要があります。
- 学習データのアノテーション作業は終わっている前提。アノテーションについての記事はこちら：[YOLOのオリジナルデータ学習手順 #2 アノテーション](https://qiita.com/tfukumori/items/0911c8fe1f5319530d4b)

# 最終調査日

2020年10月6日


# 環境

- Windows 10 Pro 1909 x64
- GeForce GTX 1080 Ti

# 1. ソースをクローン

```bat
cd C:\Users\username\repos
mkdir github
cd .\github
mkdir AlexeyAB
cd .\AlexeyAB
git clone https://github.com/AlexeyAB/darknet
```

# 2. Darknet.exeのビルド

## 2.1. 手順

以下の手順を参考にビルドまで行いました。

[Windows10環境でdarknet使って学習、ビルド編](https://qiita.com/seisantaro/items/ee2ce5712b5a1db8f423)

## 2.2. 使用した資材

|ソフト|インストーラーファイル名|
|---|---|
|Visual Studio 2017 Professional[^1]|vs_professional__1216243409.1564557702.exe|
|NVidiaドライバ|456.38-desktop-win10-64bit-international-dch-whql.exe|
|CUDA Toolkit 10.0|cuda_10.0.130_411.31_win10.exe|
|cuDNN (for CUDA 10.0)|cudnn-10.0-windows10-x64-v7.6.5.32.zip|
|OpenCV|opencv-4.4.0-vc14_vc15.exe|
|CMake|cmake-3.18.3-win64-x64.msi|

[^1]: [参考にした手順](https://qiita.com/seisantaro/items/ee2ce5712b5a1db8f423)ではVisual Studio 2017 Community Editionをインストールしています。

## 2.3. 動作検証

```bat
cd C:\Users\username\repos\github\AlexeyAB\darknet\build\darknet\x64
darknet.exe detector test cfg/coco.data cfg/yolov3-tiny.cfg yolov3-tiny.weights -thresh 0.25
```

エラーなく実行できること、画像ファイルパスを指定して推論できることを確認します。

# 3. トレーニング用資材の用意

[YOLOのオリジナルデータ学習手順 （アノテーション編）](https://qiita.com/tfukumori/items/0911c8fe1f5319530d4b)の手順でVottでエクスポートしたPascal VOC形式から、YOLO形式に変換する必要があります。

## 3.1. Vott 2にてPascal VOC形式でエクスポートしたフォルダの構成

```
PascalVOC-export
├─Annotations
├─ImageSets
│  └─Main
└─JPEGImages
```

## 3.2. Pascal VOC形式→YOLO形式への変換

Vott 2は出力形式としてYOLO形式が選択できないため別途変換が必要です。

1. 変換には[Martin Hwang](https://github.com/ssaru)さんのソースを利用しますので、ソースをクローンします。

    ```bat
    cd C:\Users\username\repos\github
    mkdir ssaru
    cd .\ssaru
    git clone https://github.com/ssaru/convert2Yolo
    ```

2. クローンしたフォルダに移動します。

    ``` bat
    cd convert2Yolo
    ```

3. 上記のフォルダに、Vottでエクスポートした「PascalVOC-export」フォルダをコピーします

4. YOLO形式の出力先フォルダを作成します。

    ``` bat
    mkdir YOLO
    ```

5. 変換を実施します。

    ``` bat
    python example.py --datasets VOC --img_path ./PascalVOC-export/JPEGImages/ --label ./PascalVOC-export/Annotations/ --convert_output_path ./YOLO/ --img_type ".jpg" --manifest_path ./ --cls_list_file ./PascalVOC-export/voc.names
    ```

6. 出力結果は以下の構成となります。

   ```
   └─YOLO/～.txt
   manifest.txt
   ```


## 3.3. フォルダ構成、ファイルの作成

[公式のドキュメント](https://github.com/AlexeyAB/darknet#how-to-train-to-detect-your-custom-objects)、[harmegiddoさんの記事](https://qiita.com/harmegiddo/items/c3db5fd567fa4c6cc9fb#3-training--customize-using-my-dataset)を参考に、フォルダ構成、必要なファイルを作成します。

以下は手作業で作成する手順を記載しています（自動化を行ったら更新予定です）。

### 3.3.1. 最終的な構成

先に最終的な構成を示します。

💡 対象画像がPNG形式の場合の例

```
github\AlexeyAB\darknet\build\darknet\x64\cfg
└─task
    ├─backup
    └─datasets
        <対象画像ファイル名>.txt
        <対象画像ファイル名>.png
        ～
    class.txt
    datasets.data
    train.txt
    test.txt
    yolov3-tiny_obj_custom.cfg
```

### 3.3.2 backupフォルダの作成

`backup`フォルダを作成します。

### 3.3.3 datasetsフォルダの作成

`datasets`フォルダを作成します。

### 3.3.4 画像ファイルのコピー

`datasets`フォルダに3.1.の`PascalVOC-export\JPEGImages`フォルダ内の画像ファイルをコピーします。

### 3.3.5 YOLO形式のアノテーションデータのコピー

`datasets`フォルダに3.2.の`YOLO/～.txt`をコピーします。

### 3.3.6. クラス名ファイル（class.txt）

クラス名を記載します。

### 3.3.7. トレーニングファイル一覧（train.txt）、検証ファイル一覧（test.txt）

トレーニングに使用するファイルの一覧（`train.txt`）、トレーニングに使用するファイルの一覧（`test.txt`）を用意します。
ファイル名（フルパス）を改行区切りで記載します。
（パスが同じであれば、前項で出力した`manifest.txt`の内容を使用できます。）

💡 トレーニングファイルと検証ファイルの切り分け

- トレーニングと検証の比率は特に記載がないため9:1としましたが、8:2が良いとの記事が多いようです。
- データの偏りを防ぐため、本来はランダムに検証ファイルを抜粋したほうが望ましい結果となります。


### 3.3.8. データセット設定ファイル（datasets.data）

各ファイルのパスを記載します。

```
classes= 1
train  = <train.txt のフルパス>
valid  = <test.txt のフルパス>
names = <class.txt のフルパス>
backup = <backup フォルダのフルパス>
```

### 3.3.9. cfgのカスタマイズ

[公式ドキュメント](https://github.com/AlexeyAB/darknet#how-to-train-to-detect-your-custom-objects)を参考に作成します。

参考までに、以下のデータの場合に必要となった変更を記載します。
（2020年10月6日時点のドキュメントを参照）

|項目|値|
|---|--:|
|クラス数|1|
|トレーニング画像数|720|

💡 学習に使用するデータ数

- サンプルを見ると80クラスで500200枚で**1クラス当たり6252.5枚**となっています。学習データは水増しした上で1クラスあたり**6200枚程度**は用意したほうが良いのかもしれません。
- [学習に使用するデータ数についての目安はこちら](https://qiita.com/tfukumori/items/0911c8fe1f5319530d4b#yolo%E3%81%AE%E5%AD%A6%E7%BF%92%E3%81%AB%E5%BF%85%E8%A6%81%E3%81%AA%E7%94%BB%E5%83%8F%E6%95%B0%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)

**手順**

1. `yolov3-tiny_obj.cfg`を`github\AlexeyAB\darknet\build\darknet\x64\cfg\yolov3-tiny_obj_custom.cfg`にコピーします。

2. 機器のスペックに応じた`batch`の変更、およびデータ量に応じた`max_batch`と`steps`の変更を行います。
    - batchを`64`→`8`に変更（メモリエラー対策）
    - max_batchを変更（クラス数、画像数に合わせて適切な数値を設定）
        - classes*2000 , but not less than number of training images and not less than 6000（日本語訳：クラス*2000 、ただし、学習画像の数を下回らず、かつ 6000 を下回らない。）
        - クラス数 1*2000 、ただし、学習画像の数(720)を下回らず、かつ 6000 を下回らない。よって、`6000`。
    - stepsを変更（max_batch数の80% and 90% の数値を設定）。max_batch数`6000`から`4800,5400`。

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204150/e2c7953e-1845-75f9-da95-ac27f8d5c0b4.png)

3. クラス数に応じて、classesとfilterを変更します。
    - classesを変更（判定クラス数が1）
    - activation=linear前のフィルターをクラス数に合わせて変更
    
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204150/7d52e6e3-f6f5-376f-af48-6d8ca0110d1f.png)
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204150/b61fc2bb-becb-1437-b9bd-be3bbedd668f.png)

# 4. 重みファイルの準備

## 4.1. トレーニング方式に応じたファイルをダウンロード

YOLOv3-tinyであれば以下をダウンロードします。

https://github.com/AlexeyAB/darknet#how-to-train-to-detect-your-custom-objects
> for (6 MB): yolov3-tiny.conv.11yolov3-tiny-prn.cfg , yolov3-tiny.cfg
https://drive.google.com/file/d/18v36esoXCh-PsOKwyP2GWrpYDptDY8Zf/view?usp=sharing

## 4.2. 以下に配置

```
github\AlexeyAB\darknet\build\darknet\x64\yolov3-tiny.conv.11
```

# 5. トレーニング

1. ビルドしたDarknet.exeのフォルダに移動（`github\AlexeyAB\darknet\build\darknet\x64`）

2. トレーニング

    ```bat
    darknet.exe detector train ./cfg/task/datasets.data cfg/task/yolov3-tiny_obj_custom.cfg yolov3-tiny.conv.11
    ```

# 6. 結果

## 6.1. チャート例

今回使用した例では、15分程度で終了しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204150/6c4ffa1b-0eef-1560-5262-5d42468c009e.png)

## 6.2. 推論に使用するYOLO Darknet形式の重みファイル

```
github\AlexeyAB\darknet\build\darknet\x64\cfg
└─task
    └─backup
      └─yolov3-tiny_obj_custom_final.weights
```

# 7. 推論

```
darknet.exe detector test cfg/task/datasets.data cfg/task/yolov3-tiny_obj_custom.cfg cfg/task/backup/yolov3-tiny_obj_custom_final.weights <推論対象画像ファイルパス> -thresh 0.25
```

💡 枠表示を行う信頼度の閾値は`-thresh 0.25`の部分で指定します。

# 8. （おまけ）JetsonNanoで使用する場合

細かい記載は省略しますが、以下のリポジトリを参考にJetson NanoのTensorRTで動作するファイルへの変換（コンパイル）を実施し動作確認しています。

https://github.com/jkjung-avt/tensorrt_demos

TensorRTは動作環境（GPU）に特化したファイルを作成するため、**実際に使用する機器上（Jetson Nano）で変換（コンパイル）を行う**必要があります。

1. YOLO Darknet形式の重みファイル → ONNX形式
    https://github.com/jkjung-avt/tensorrt_demos/blob/master/yolo/yolo_to_onnx.py 

2. ONNX形式 → TensorRT形式
    https://github.com/jkjung-avt/tensorrt_demos/blob/master/yolo/onnx_to_tensorrt.py

# 参考文献

- [AlexeyAB/darknet: YOLOv4 - Neural Networks for Object Detection (Windows and Linux version of Darknet )](https://github.com/AlexeyAB/darknet)
- [ssaru/convert2Yolo: This project purpose is convert voc annotation xml file to yolo-darknet training file format](https://github.com/ssaru/convert2Yolo)
- [Windows10環境でdarknet使って学習、ビルド編 - Qiita](https://qiita.com/seisantaro/items/ee2ce5712b5a1db8f423)
- [jkjung-avt/tensorrt_demos: TensorRT YOLOv4, YOLOv3, SSD, MTCNN, and GoogLeNet](https://github.com/jkjung-avt/tensorrt_demos)