YOLO V3を試すだけであれば学習済みモデルを使えばよいのですが、「やっぱり独自の物体検出をやってみたい!」ということで、独自のデータセットを学習させてみました。その内容を紹介します。
今回はグーの手を検出するだけのモデルを作成することとし、自分のグーの手を撮影し、その動画にVoTTでアノテーションを付けて学習データにしました。
私が実行した環境
- Windows 10 Home
- NVIDIA GTX1080Ti
- CUDA 9.1.85.3
- CuDNN 7.1.3
- Python 3.6.5
- Tensorflow-gpu 1.12.0
- Keras 2.2.4
- opencv-python 4.0.0.21
- matplotlib 3.0.2
- Pillow 5.4.1
- VoTT 1.7.2
まずはYOLO V3を動かす
以下のPythonライブラリをインストール
tensorflow、keras、opencv-python、matplotlib、pillow
Yolo V3のソース一式をダウンロードし、任意のパスに配置
https://github.com/qqwweee/keras-yolo3
学習済みモデルをダウンロードし、"keras-yolo3"フォルダに配置
https://pjreddie.com/media/files/yolov3.weights
weightsをkeras用に変換
python convert.py yolov3.cfg yolov3.weights model_data/yolo.h5
YOLOの実行(静止画)
python yolo_video.py --image
"Input image filename:"と聞かれたらファイル名を入力します。
YOLOの実行(動画)
python yolo_video.py --input hoge.mp4
上記でYOLOが動くことを確認できたら、安心して独自データセットの収集に取り組みます。
データの収集
今回は自分のグーの手をあらゆる角度からただひたすら動画撮影します。
後で1秒毎にアノテーションを付けるので、500枚ほどの学習データを集める想定で10分ほどiPhoneの前でグーの手をグリグリ動かします。
データにアノテーションを付ける
十分な動画が撮れたらアノテーションを付けていきます。
マイクロソフトが公開しているVoTTというアノテーションツールだと、動画へのアノテーションが楽ちんです。
VoTTをダウンロードしてインストールします。
https://github.com/Microsoft/VoTT/releases
VoTTはmp4、oggの動画ファイルに対応しています。
今回はiPhoneで撮影した動画を使ったのでffmpegでmov形式からmp4形式に変換しました。
また、私の環境ではFullHDだと学習中にメモリ不足でエラーが発生したので解像度を下げました。
ffmpeg -i hoge.mov -s 416x234 hoge.mp4
あとはVoTTでこの動画ファイルを読み込んで黙々とアノテーションをつけていきます。
途中で「こんな同じ様な画像ばっかりで意味があるのか…」という考えがよぎりましたが、それほど大変でもないので最後までやりきりました。
一通りアノテーションを付け終えたらExport Tagsを選択し、"Tensorflow Pascal VOC"形式でExportします。
アノテーションをYOLO V3形式にする
YOLO V3のソースに付属している"voc_annotation.py"を使い、VOC形式のアノテーションをYOLO V3で学習する形式に変換します。
voc_annotation.pyの処理に合わせたファイル構成にする
"keras-yolo3"フォルダに"VOCDevkit"というフォルダを作成します。
VoTTからExportした"hoge_output"フォルダの名称を"VOC2007"に変更し、先の"VOCDevkit"フォルダ内に移動します。
"keras-yolo3/VOCDevkit/VOC2007/ImageSets/Main"フォルダに"train.txt"を作成します。
テキストファイルには"keras-yolo3/VOCDevkit/VOC2007/JPEGImages"フォルダ内の全jpgファイルを拡張子なしで列挙します。
hoge_frame_1
hoge_frame_2
...
"train.txt"をコピーして"test.txt"、"val.txt"を作成します。
学習用と評価用などでデータを振り分ける場合は振り分けておいても構いません。
voc_annotation.pyの処理を修正する
VoTTで出力したファイルには、アノテーション位置がfloatで書かれています。そのままでは"voc_annotation.py"で読み込めないので、下記のようにfloatからintに変換するようにソースを修正します。
b = (int(float(xmlbox.find('xmin').text)),
int(float(xmlbox.find('ymin').text)),
int(float(xmlbox.find('xmax').text)),
int(float(xmlbox.find('ymax').text)))
また、6行目あたりのclassesのリストも自分で学習させる内容に合わせて修正します。今回は1クラスなのでclasses = ["gu"]
としておきました。
voc_annotation.pyで変換する
あとは"voc_annotation.py"を実行して変換します。
python voc_annotation.py
出力された"2007_train.txt"がYOLO V3用のアノテーションの形式です。
~\keras-yolo3/VOCdevkit/VOC2007/JPEGImages/hoge_frame_1.jpg 100,200,250,300,0
~\keras-yolo3/VOCdevkit/VOC2007/JPEGImages/hoge_frame_2.jpg 200,100,300,400,0
...
学習
独自のクラスの列挙
"keras-yolo3\model_data"フォルダに"my_classes.txt"を作成し、自分で学習させるクラスを列挙します。
今回はgu
とだけ記載しました。
train.pyの修正
"train.py"が"2007_train.txt"、"my_classes.txt"を読み込むように修正します。
17行目の"annotation_path"に"2007_train.txt"を指定します。
19行目の"classes_path"に"model_data/my_classes.txt"を指定します。
また、私の環境ではデフォルトのbatch_sizeだと学習中にメモリ不足でエラーが発生したので減らしました。
57行目と76行目の"batch_size"を32から8にしています。
学習用にweightsをコンバート
学習用にweightsをコンバートします。
python convert.py -w yolov3.cfg yolov3.weights model_data/yolo_weights.h5
学習の実行
python train.py
学習済みモデルは"\keras-yolo3\logs\000\trained_weights_final.h5"として生成されます。
学習済みモデルで物体検出
学習済みモデル、クラスを指定して起動します。
YOLOの実行(静止画)
python yolo_video.py --model logs/000/trained_weights_final.h5 --classes model_data/my_classes.txt --image
YOLOの実行(動画)
python yolo_video.py --model logs/000/trained_weights_final.h5 --classes model_data/my_classes.txt --input hoge.mp4
学習に用いたのは自分のグーだけでしたが、うちの子のグーも検出できました。
顔でもグーと検出される時もありましたが…