(この記事は原文"Train Object Detection System with 1 Class"の和訳です。)
YOLOとDarknetについて
YOLOとは、最新の物体検出システムで、AIを多くの問題解決に応用できる可能性を秘めていると考えています。また、DarknetはC言語で実装されているニューラルネットワークのフレームワークで、YOLOはその上に構築されています。
YOLOの公式リポジトリはここ[1]です。基本的な使い方を知る上でも、READMEは一読しておくことをおすすめします。また、論文[2]については、どういうコンセプトでYOLOが作られているかを深く理解するのに役に立つと思います。
この記事は自分のデータでYOLOを学習させるための実際的なステップやコードに焦点を当てています。詳細なアルゴリズムはさておき、どのようにYOLOが物体を検出するかと理解する上でも、実際に手で動かしてみるに勝るものはありません。ご自分の物体検出システムを実装する大きな手助けになると思います。
EC2を利用しましょう
このチュートリアルでは、基本的にAWSを用いています。また、OSイメージはAWSの深層学習AMI(以下DLAMI)を利用しており、環境構築をスキップしてすぐに核心部分の作業に取り掛かることができます。したがって、ローカルマシンはWindowsでもMacでも同じようにチュートリアルを読み進められると思います。
YOLOの学習は、Linux(UbuntuあるいはAmazon Linux)で行うことを強くおすすめします。Windowsの場合、フレームワークのコンパイル作業がやや煩雑になります。
ところで、DLAMIは定期的にアップデートされますが、最新のものを選択しておけば問題ないでしょう。
YOLOを学習させる際、GPUの計算パワーは必ず必要になります。CPUで学習させた場合、かなり首を長くして計算を待つはめになるでしょう。インスタンスの種類はP2インスタンスを選択しておけばよいでしょう。もちろん、P3インスタンスなどもよいと思います。
EC2にローカルマシンからログインします(お使いの仮想マシンのリージョンにより以下のコマンドは多少変えてください)。
$ ssh -i “<your ssh key>.pem” root@ec2-<your vm’s ip>.ap-northeast-1.compute.amazonaws.com
CUDAのバージョンを10に変更します。
$ sudo rm /usr/local/cuda
$ sudo ln -s /usr/local/cuda-10.0 /usr/local/cuda
YOLOのコードベースを公式リポジトリからクローンします。
$ cd
$ git clone https://github.com/pjreddie/darknet
$ cd darknet
$ vim Makefile
ここで、GPU版をコンパイルするためMakefileを編集します。1行と2行の値を以下のように1に設定します。
GPU=1
CUDNN=1
Darknetをコンパイルしましょう。
make
ネットワークの初期値をダウンロードします。
$ wget https://pjreddie.com/media/files/darknet19_448.conv.23
サンプルのデータセットをダウンロードします。
$ cd
$ git clone https://github.com/sudamasahiko/dataset100jpy
$ cp -r dataset100jpy/* darknet
学習を開始します。
$ cd darknet
$ ./darknet detector train cfg/obj.data cfg/yolo-obj.cfg darknet19_448.conv.23
学習中は以下のように出力されます。
yolo-obj
layer filters size input output
0 conv 32 3 x 3 / 1 416 x 416 x 3 -> 416 x 416 x 32 0.299 BFLOPs
1 max 2 x 2 / 2 416 x 416 x 32 -> 208 x 208 x 32
2 conv 64 3 x 3 / 1 208 x 208 x 32 -> 208 x 208 x 64 1.595 BFLOPs
3 max 2 x 2 / 2 208 x 208 x 64 -> 104 x 104 x 64
4 conv 128 3 x 3 / 1 104 x 104 x 64 -> 104 x 104 x 128 1.595 BFLOPs
5 conv 64 1 x 1 / 1 104 x 104 x 128 -> 104 x 104 x 64 0.177 BFLOPs
6 conv 128 3 x 3 / 1 104 x 104 x 64 -> 104 x 104 x 128 1.595 BFLOPs
7 max 2 x 2 / 2 104 x 104 x 128 -> 52 x 52 x 128
8 conv 256 3 x 3 / 1 52 x 52 x 128 -> 52 x 52 x 256 1.595 BFLOPs
9 conv 128 1 x 1 / 1 52 x 52 x 256 -> 52 x 52 x 128 0.177 BFLOPs
10 conv 256 3 x 3 / 1 52 x 52 x 128 -> 52 x 52 x 256 1.595 BFLOPs
11 max 2 x 2 / 2 52 x 52 x 256 -> 26 x 26 x 256
12 conv 512 3 x 3 / 1 26 x 26 x 256 -> 26 x 26 x 512 1.595 BFLOPs
13 conv 256 1 x 1 / 1 26 x 26 x 512 -> 26 x 26 x 256 0.177 BFLOPs
14 conv 512 3 x 3 / 1 26 x 26 x 256 -> 26 x 26 x 512 1.595 BFLOPs
15 conv 256 1 x 1 / 1 26 x 26 x 512 -> 26 x 26 x 256 0.177 BFLOPs
16 conv 512 3 x 3 / 1 26 x 26 x 256 -> 26 x 26 x 512 1.595 BFLOPs
17 max 2 x 2 / 2 26 x 26 x 512 -> 13 x 13 x 512
18 conv 1024 3 x 3 / 1 13 x 13 x 512 -> 13 x 13 x1024 1.595 BFLOPs
19 conv 512 1 x 1 / 1 13 x 13 x1024 -> 13 x 13 x 512 0.177 BFLOPs
20 conv 1024 3 x 3 / 1 13 x 13 x 512 -> 13 x 13 x1024 1.595 BFLOPs
21 conv 512 1 x 1 / 1 13 x 13 x1024 -> 13 x 13 x 512 0.177 BFLOPs
22 conv 1024 3 x 3 / 1 13 x 13 x 512 -> 13 x 13 x1024 1.595 BFLOPs
23 conv 1024 3 x 3 / 1 13 x 13 x1024 -> 13 x 13 x1024 3.190 BFLOPs
24 conv 1024 3 x 3 / 1 13 x 13 x1024 -> 13 x 13 x1024 3.190 BFLOPs
25 route 16
26 conv 64 1 x 1 / 1 26 x 26 x 512 -> 26 x 26 x 64 0.044 BFLOPs
27 reorg / 2 26 x 26 x 64 -> 13 x 13 x 256
28 route 27 24
29 conv 1024 3 x 3 / 1 13 x 13 x1280 -> 13 x 13 x1024 3.987 BFLOPs
30 conv 30 1 x 1 / 1 13 x 13 x1024 -> 13 x 13 x 30 0.010 BFLOPs
31 detection
mask_scale: Using default ‘1.000000’
Loading weights from darknet19_448.conv.23…Done!
Learning Rate: 0.001, Momentum: 0.9, Decay: 0.0005
Resizing
544
Loaded: 0.000044 seconds
Region Avg IOU: 0.201640, Class: 1.000000, Obj: 0.187609, No Obj: 0.530925, Avg Recall: 0.090909, count: 11
Region Avg IOU: 0.117323, Class: 1.000000, Obj: 0.381525, No Obj: 0.531642, Avg Recall: 0.000000, count: 10
Region Avg IOU: 0.156779, Class: 1.000000, Obj: 0.301009, No Obj: 0.530801, Avg Recall: 0.000000, count: 12
Region Avg IOU: 0.083861, Class: 1.000000, Obj: 0.239799, No Obj: 0.530281, Avg Recall: 0.000000, count: 10
Region Avg IOU: 0.126977, Class: 1.000000, Obj: 0.426366, No Obj: 0.531593, Avg Recall: 0.000000, count: 8
Region Avg IOU: 0.156623, Class: 1.000000, Obj: 0.337786, No Obj: 0.529291, Avg Recall: 0.000000, count: 13
Region Avg IOU: 0.134743, Class: 1.000000, Obj: 0.368207, No Obj: 0.529858, Avg Recall: 0.000000, count: 9
Region Avg IOU: 0.105239, Class: 1.000000, Obj: 0.337773, No Obj: 0.529503, Avg Recall: 0.000000, count: 11
1: 510.735443, 510.735443 avg, 0.000000 rate, 7.901008 seconds, 64 images
数百イテレーションが完了するまで少しばかり待ちましょう。Ctrl+cを押すことで学習を停止させることができます。ここまでくれば、学習済みのYOLOをテストすることができます。
$ ./darknet detector test cfg/obj.data cfg/yolo-obj.cfg backup/yolo-obj_last.weights test_image.jpg
全てが正しく行われれば、以下のようなバウンディングボックス付きの画像が出力されます。
まとめ
想定したように学習はされたでしょうか。この技術は頻繁にアップデートされるため、もしかしたらフレームワークやCUDAのバージョンによるミスマッチが起こり、正しく動かない可能性もあります。その場合にはぜひご自身で周辺情報を収集していただき、コメント欄にてご指摘いただければ幸いです。また、YOLOは最高で約9000クラスの物体検出を行えるよう設計されているため、ぜひ多クラスでの実装にもトライしてみてください。この技術の応用は多くの可能性があると思います。
参考
[1] YOLO: Real-Time Object Detection
https://pjreddie.com/darknet/yolo/
[2] You Only Look Once: Unified, Real-Time Object Detection
https://pjreddie.com/media/files/papers/YOLOv3.pdf