今回は
Joseph Chet Redmonさんの本家Darknet https://pjreddie.com/darknet/yolo/ ではなく、AlexeyAB さんのDarknetを使って追加学習させてみました。前回の記事ではHow to train YOLOv2 to detect custom objectsの解説が全てと書いていますが AlexeyAB さんのDarknetの場合はhttps://github.com/AlexeyAB/darknetが全てです。私が確認した範囲では、認識率は両者ほぼ互角。単精度浮動小数点数指定ができるため、認識スピードがかなり向上できる他に、最近分かったことですが、学習の最適ポイントが掴みやすいなど、かなりの優れものでした(解説を良く読んでみればわかるのですが.....)。
前回の学習では
ジャンケンの3クラスのみの学習をさせたのですが、どうしてもグーが人間の顔と勘違いしやすい傾向がありました。元画像が赤外線カメラなので、そのような傾向があるかとは思いますが、新たに顔を追加学習させたら、さらに良い結果になりそうな気配です。じゃー「どうしたら追加学習できるのか?」ということが、今回のテーマです。
顔がGooになってしまうことがある....のですが、顔データを追加学習させると、こうなります⇩
この画像はLEPTON3.0はPI3に接続。同一LAN内につないだJetson Xavierで画像表示とジャンケン認識をさせてます。
くどくど説明を書いてもかえって分かりにくくなるので、今回は要点のみとします。
ラベリング作業
- 顔の動画を撮影して、2000枚程度の画像を作成した。
- labelimg/data の中にあるpredefined_class.txtに4番目のクラス(今回はFace)を追加する。
- とりあえず別のフォルダで顔のみをラベリングして作ったデータを、前回のデータフォルダにコピーする。
- 前回のアノテーション済みの画像の中に顔が写っている場合は、追加指定を行う。
- 入力ミスで思い当たりのないクラスが増えていることがある。自分で設定したクラスがひとりでにできていたら、前に遡って必ずその部分を消すことが必要。これをしないと、学習中意味不明のエラーまたはメモリオーバーが表示されて、悩まされることになる。
- 今回は精度の高い最新のyolov3で学習。単精度浮動小数点演算機能を外してビルドし直した。(つまり倍精度演算)
Yolov3_voc.fgの変更点
- 認識精度を上げる方法はいくつかあって、https://github.com/AlexeyAB/darknetkこの中のHow to improve object detection: を参照。
- 一番有効なのは、WEIGHTとHEIGHTの数値を大きくしてトレーニングすること。
- 一般的には416x416。精度を上げるには608x608または832x832とする。ただしyolov3の場合608x608で学習させると、私の環境ではメモリーオーバーで止まる。今回618x618の場合は subdivisions=16 とした。
- classesの数値を3箇所変更(今回のクラス追加で4に変更した)
- filtersの数値は YOLOv3の場合(classes + 5)x3)となる。これも3箇所変更。今回は27。本家Yolo(こちらはYOLOv2で(classes+5)x5)とは、この部分の計算方法が違う。
- cfgファイルは、yolov3.cfgでもyolov3_voc.cfgでもあまり変わらないようだ(ただしパラメーターが微妙に違う)。解説の通りyolov3_voc.cfgを使う方が無難。
obj.namesの変更点
- obj.namesにクラス名を1つ追加。今回はFaceとした。
obj.dataの変更点
- obj.data のclassesの数値を変更。今回は4。これが忘れがちで、学習時原因不明エラーの要因となる。
学習
- AlexeyAB さんのdarknetは状況を確認するためにlossの数値と学習回数を関連付けたグラフが表示される。
- 最適学習状況の判別機能が備わっている。学習コマンド実行時最後に-map オプションの指定によりmApの現状の数値がグラフに書き込まれる。
- 学習は8000回目ぐらいが上限で良い様だ。5000前後でmap コマンドを実行して確認しiouとmapの一番高いものを選ぶ
- Lossは小さい方が良いが、データによりそれ以上下がらない場合あり。0.3以下が望ましい
- mApが同じでも認識が良好である場合とそうでない場合がある。なるべく7000回ぐらい試してサンプル画像をTESTしてみるのがベターの様だ。
- Lossが1以下に下がらない場合、クラス数設定が各部で違っている場合が多い=使えない。
- mapが90%を越すころから使い物になってくる。開始から2.5時間から3時間の間。
- 最初の1000回の所要時間で学習終了時刻が、ほぼ予想できる(当たり前か...)。
同一データで、416x416と608x608とした場合の学習内容比較
母艦の性能 CPU:i7 6700K(16GB)GPU: GTX1080Ti ハードディスク主体
cfgファイルのWEIGHTとHEIGHTについて416x416指定の場合
- 以下の結果で1000回あたりほぼ50分必要だった。
時刻 回数 iou mAp
8:48 1000 測定しない 測定しない
10:26 3000 75.66 90.5
11:14 4000 75.97 90.64
12:07 5000 79.16 90.76
12:57 6000 78.83 90.76
13:43 7000 78.88 90.77
14:04 7400 79.26 90.77 この時点でloss=0.273
- なぜかmapが正しく表示されていない。416x416は7000回目のデータを採用した。
cfgファイルのWEIGHTとHEIGHTについて608x608指定の場合
- メモリーオーバー対策にsubdivisions=16とした。1000回あたり約130分必要。
時刻 回数 iou mAp
17.09 1000 測定しない 測定しない
22:37 3000 76.77 90.4
0:29 4000 79.45 90.5
2:24 5000 79.57 90.71
4:16 6000 78.55 90.70
5:59 7000 79.52 90.71
7:47 7400 78.60 90.72 この時点でloss=0.2766
- グラフでもわかる様に収束が遅くばらつきがある。
- 608x608は6000回目のデータを採用した。
考察
- 画像でテストしてみると、今回はなぜか608x608は、416x416より認識率が落ちる様だ。もともとLEPTON画像は160x120の画像なので、少し無理があるのかもしれない。最終的に採用したデータは416x416で学習させた7000回目のものとした。(最初に貼り付けた動画はこのデータを使ってます)
- 認識時はcfgファイル内容を608x608に変更すると認識率は上がる。ただしスピードは犠牲となる。
- テストデータの比率を10%としたが、これを10%以上に上げると多少認識率が上がる可能性はある。
- 倍精度指定での学習データでも、単精度画像認識が可能だった。
- 倍精度浮動小数点指定と、単精度浮動小数点指定で学習結果と時間に差が出るのかどうかのテストはまだだが、Jetson Xavierで単精度浮動小数点指定でビルドしたDarknetの学習をさせてみた場合、 YoloV2のジャンケン3クラス(416x416)の場合で1000回あたり約60分だった。これはJetson Xavier単独でも学習作業が可能であることを示す。
世の中クラウド学習が方々で話題になってますが、色々制約があるのも事実だと思われます。身近な機材で目の前で刻々と変化する学習状態を確認するのも、また、オツなものですよ。(2日も3日も動かすわけじゃないので)
ってことで。今回はおしまい。