最新の物体検出YOLO v3 (Keras2.2.0+TensorFlow 1.8.0)を独自データで学習できるようにしてみた
物体検出コードといえば、Faster-RCNN、SSD、そしてYOLOが有名ですが、そのYOLOの最新版である”YOLO v3”のKeras+TensorFlow版を使って、独自データにて学習できるところまで持っていきましたので、ここに手順を書きます。
まず、YOLO v3の威力をご覧ください。
YOLO: Real-Time Object Detection
最近出たアルゴリズムなので、SSDよりも高速&正確であるというのが謳い文句です。ごらんのとおり、物体検出数も精度のなかなかです。
制度と速度を他の物体検出コードと比較したグラフです。わざとグラフの横軸からはみ出すように作ってますが・・・実際動かしてみると、確かに以前試したTensorFlow+Keras版SSDよりも速く動作します。
基本的には、READMEを読めば分かるように作られている・・・はずですが、クイックスタートでさえちょっとてこずりました。ましてや深層学習して学習モデル適用は、READMEだけではわかりません。
このAI民主化時代(誰でもAIを使える時代)に、これではいただけません。
ということで、以下、Windows版Anaconda 3(我が家はVer.4.4.0)にTensorFlow 1.8.0+Keras 2.2.0をインストールして、クイックスタートから独自データによる学習、および推論コード実行まで実施いたしましたので、紹介します。
準備 & クイックスタート
最初に、準備がてら動かしてみましょう。
※ Windows版Anaconda 3のインストール方法、TensorFlow 1.8.0+Keras 2.2.0のインストールについては省略します。以下のサイトなどを参考に、あらかじめ導入をお願いします。
Windows10にKeras(+TensorFlow)をインストールしてAnaconda+Jupyterで動かしてみる
まず、”YOLO v3”のコードを、以下から入手します。
https://github.com/qqwweee/keras-yolo3
Windowsの場合は「Clone or Download」を押して「Download ZIP」をクリックしてダウンロード。ファイルを解凍します。
学習済みデータを入手します。YOLO: Real-Time Object Detectionのページの中ほど、「Detection Using A Pre-Trained Model」のところに”here (237 MB)”というのがあるので、これをクリックします。
すると、”yolov3.weights”というファイルが得られます。これを、先ほど解凍したフォルダに入れます。
ここでAnaconda 3のプロンプトを開き、TensorFlow実行環境に変えて(activate tensorenv 等)、上の解凍フォルダに入ります。
まず、入手した学習済みデータをKeras用に変換します。以下のコマンドを入力します。
$ python convert.py yolov3.cfg yolov3.weights model_data/yolo.h5
これで、Keras用の学習済みデータが「model_data」フォルダに入ります(yolo.h5)。
ここで、とりあえず動かしてみます。
静止画を認識させたい場合は、YOLO v3のフォルダに検出させたい画像ファイルを入れておきます。
$ python yolo.py
と入力。
「Input image filename:」と出てくるので、あらかじめYOLO v3の入ったフォルダに入れた画像ファイルのファイル名をコロンの後ろに入力します。
こんな画像が出れば、成功です。
動画を使いたい場合は、同様にYOLO v3のフォルダに動画を入れて、
$ python yolo_video.py (動画ファイル名) [出力ファイル名]
と実行します。動かすだけなら、出力ファイル名のところは何も入れなくても動作します。
独自データでの準備
以降は、VOC2007形式でのデータセットを作って、これを学習させるまでの手順を書きます。
※以下、TensorFlow+KerasでSSDを独自データで使えるようにしてみた: EeePCの軌跡の記事と同じです。
まずは、独自データとなる画像を集めます。これは必須。
続いて、「AnnotationTool.exe」のリンクをクリックして、アノテーションツールをダウンロードします。
私がとりあえず作ったWindows上で動かすアノテーションデータ作成ソフトです。
使い方は以下を参照。
-----------------------------------------------------------------------
① まずアノテーションファイル(*.xmlと”trainval.txt”)を保存するフォルダ(作業フォルダ)を作りドラッグ&ドロップ
② アノテーションを作成したい画像ファイルをドラッグ&ドロップ
③ 画像ファイルが出てくるので、物体をマウスで囲みます
④ ”ラベル名”のテキストボックスに物体の名前を書きます(半角英数)
⑤ ”ラベル作成”をクリックすると登録
同一画像内で認識させたい物体の数だけ③~⑤を繰り返します。
⑥ 一通り終わったら「Annotation追加」をクリック
次の画像ファイルを読み込むため、再び②で別の画像を読み込み、⑥までを繰り返します。
すべての画像ファイルのアノテーション登録が終わったら
⑦ ”終了”をクリック
-----------------------------------------------------------------------
これを実行すると、画像ファイル分の「~.xml」ファイルと、「trainval.txt」ができているはずです。
これを、以下のように「VOCdevkit/VOC2007」に反映。
・ 「Annotations」フォルダには作成されたxmlファイルを全部入れます。
・ 「ImageSets/Main」にある「trainval.txt」に、上で作られた「trainval.txt」の中身を追記します。
・ 「JPEGImages」フォルダに、独自データの画像ファイルをすべて入れます。
これで、データセットの準備は完了です。
独自データによる学習実行
いよいよ学習ですが、いくつか下準備が必要です。
まず、YOLO v3フォルダの直下に、上で作った「VOCdevkit」フォルダをそのまま置きます。
VOCdevkitの中の「VOC2007/ImageSets/Main」の中にある「trainval.txt」をコピーして、「train.txt」、「val.txt」、「test.txt」の3つのファイルを作っておきます。
続いて、「model_data」フォルダにある「yolo.h5」をコピーして「yolo_weights.h5」というファイル名に変えます。
また、「model_data」フォルダにある「voc_classes.txt」のラベル名を書き換えます。
この中にはaeroplane、bicycle、bird、boat・・・という20のラベル名が書かれているはずです。これを、上から順に独自データ用のラベル名に書き換えておきます。
「voc_annotation.py」の6行目も同様に書き換えます。
ここまで出来たら、以下のコマンドを実行。
$ python voc_annotation.py
すると、YOLO v3フォルダに「2007_val.txt」、「2007_train.txt」、「2007_test.txt」が生成されます。このうち「2007_train.txt」のみを「train.txt」とファイル名を変更しておきます(後の2つは使いません。消してもOK)。
これで学習実行準備完了。
あとは、
$ python train.py
と実行するだけ。
こんな感じに、学習が実行されます。
---------------------------------------
さて、デフォルトでは50エポックほど実行されますが、学習途上で終わった(loss値がまだ減少しそう)ならば、「logs/000」フォルダ内にある学習済みデータ(~.h5)を「model_data」フォルダに移します。
最後まで実行していたら「trained_weights_stage_1.h5」というファイルがあるはず。途中でも「ep~-loss~-val_loss~.h5」というファイルができているので、これの一番新しいのを用いてもいいです。
学習済みファイルを移したら、「train.py」の中の33行目の「freeze_body=2, weights_path='model_data/yolo_weights.h5')」のyolo_weights.h5の部分を書き換えます。
エポック数を増やす場合は、「train.py」の63行目にある「epochs=50,」の数字を変えます。
独自データによる学習済みデータを使った推論
いよいよ独自データの学習モデルで推論を実行します。
コマンドはクイックスタートと同じですが、「yolo.py」を以下のように書き換える必要があります。
22行目:「self.model_path = 'model_data/yolo.h5'」 ⇒ 「yolo.h5」のところを、新しい学習モデル(logs/000/~.h5)名に書き換え。
24行目:「self.classes_path = 'model_data/coco_classes.txt'」 ⇒ 「coco_classes.txt」を「voc_classes.txt」に変更。
あとは、クイックスタートと同じです。
静止画は
静止画を認識させたい場合は、YOLO v3のフォルダに検出させたい画像ファイルを入れておきます。
$ python yolo.py
とコマンド入力。動画は
動画を使いたい場合は、同様にYOLO v3のフォルダに動画を入れて、
$ python yolo_video.py (動画ファイル名) [出力ファイル名]
と実行。
所感とまとめ
SSDに対抗意識を燃やして作っているだけあって、SSDよりもちょっと速くて検出数も多いです。
ただ、どっちの精度が高いかはよくわからないので、TensorFlow+KerasでSSDを独自データで使えるようにしてみた: EeePCの軌跡の記事を参考に、SSDと共に検討してみるのがよろしいかと思われますね。
幸い、どちらも同じデータセットが使えます。
それにしても、物体検出コードも随分と身近になりました。
物体検出手法を独自データで試してみたい方は、先のSSDの記事とこのYOLO v3を参考にお試しください。
« 65000円の光造形方式3Dプリンターがすごいらしい | トップページ | いまさらですがMacBook Air買いました »
「科学・技術」カテゴリの記事
- 2024年まとめ記事(2024.12.31)
- 円形計算尺を購入してみた(2024.05.19)
- 東京ビッグサイトへ行ってきました(2024.04.25)
- 月着陸実証機SLIMが再起動!(2024.01.29)
- JAXAより小型月着陸実証機「SLIM」の写真公開(撮影はSORA-Q)(2024.01.26)
「数値解析系」カテゴリの記事
- Windows 11でFORTRANをコンパイルしたい!という方への対処法(2025.01.04)
- どこに視線を向けているかを可視化してくれる物体検出器(2024.12.23)
- 2024年まとめ記事(2024.12.31)
- 生成AI解説書籍「ChatGPT & 生成AI」という本を買った(2024.12.08)
- Googleの生成AI「Gemini Advanced」に入ってみた(2024.12.01)
コメント
« 65000円の光造形方式3Dプリンターがすごいらしい | トップページ | いまさらですがMacBook Air買いました »
このブログの通りに実行したのですが、
入手した学習済みデータをKeras用に変換します。以下のコマンドを入力します。
$ python convert.py yolov3.cfg yolov3.weights model_data/yolo.h5
というところで、コマンドプロンプト上で
unsage: convert.py [-h] [-p][-w] config_path weights_path output_path
convert.py: error: the following arruments are required: output_path
と出てしまい先に進めません。ご存知でしたら何か解決策を教えてください。
投稿: R Type | 2018年11月19日 (月) 16時14分
こんにちは、RTypeさん。
アウトプット先のパスがダメだと言ってるようですね。「〜 model_data/yolo.h5」を「〜 ./model_data/yolo.h5」とするといかがでしょうか?
投稿: arkouji | 2018年11月20日 (火) 04時37分
返信ありがとうございます。成功しました。
次の$ python yolo.py でエラーが出たのでpillowとmatplotlibを入れ動かしてみたのですが、Using TensorFlow backendと出るだけで処理が終わってしまい「Input image filename:」と出てきませんでした。
投稿: R Type | 2018年11月20日 (火) 11時53分
実行はpython yolo.pyではなく、python yolo_video.py --imageでした。
yolo.pyにmain分が入っていません。
投稿: R Type | 2018年11月21日 (水) 15時58分
画像の入ったファイルごと検出をして、ファイルの中の画像をすべた検出するにはどうすればいいでしょうか?
投稿: 初心者 | 2018年11月26日 (月) 14時22分
いきなりすいません。
1つ質問がありまして、trained_weights_stage_1.h5の他に、
51〜100エポック間の学習ファイル「〜final.h5」ファイルも作成されますが、なぜ分けられているのでしょうか?
「〜final.h5」を使って動画検出すると、精度はいいのですが、枠が対象とずれて反応してしまいます。
投稿: r6 | 2018年11月29日 (木) 01時19分
R Typeさん
yolo.pyの末尾に以下を追加してみてください
def detect_img(yolo):
while True:
img = input('Input image filename:')
try:
image = Image.open(img)
except:
print('Open Error! Try again!')
continue
else:
r_image = yolo.detect_image(image)
print(type(r_image))
import cv2
cv2.imwrite("out.jpg", np.asarray(r_image)[..., ::-1])
r_image.show()
yolo.close_session()
if __name__ == '__main__':
detect_img(YOLO())
解決済みならすみません。
投稿: 常に転職したいマン | 2018年12月 6日 (木) 10時07分
独自データでの学習実行で[
python voc_annotation.py を実行すると
Traceback (most recent call last):
File "voc_annotation.py", line 31, in
convert_annotation(year, image_id, list_file)
File "voc_annotation.py", line 11, in convert_annotation
tree=ET.parse(in_file)
File "C:\ProgramData\Anaconda3\envs\tensorflow\lib\xml\etree\ElementTree.py",
line 1197, in parse
tree.parse(source, parser)
File "C:\ProgramData\Anaconda3\envs\tensorflow\lib\xml\etree\ElementTree.py",
line 598, in parse
self._root = parser._parse_whole(source)
xml.etree.ElementTree.ParseError: not well-formed (invalid token): line 1, colum
n 1
と出たのですがどうすれば解決できますか?
投稿: R Type | 2018年12月 6日 (木) 13時50分
R Typeさん
invalid token): line 1, column1 = 一行目一列目
つまりファイルの一番最初の文字が実体参照出来ず、読み込めないというエラーです。
XMLファイルから最初の文字だけ削除してもう一度トライしてみてください。
それでもエラーが出るならアノテーションをやり直す、アノテーションツールを変えるなどして、実体参照出来ない文字の混入を防いでください。
投稿: 常に転職したいマン | 2018年12月 6日 (木) 16時36分
r6さん
1〜50epochまでのファイルと51〜100epochまでのファイルが分かれている理由は、学習の効率化によるものです。
train.pyのコードを見ると、50epochまでは学習率0.001、100epochまでは学習率0.0001となっています。
これは、ある程度学習が進んだ場合、AIが学習しづらい状況にする事で学習の停滞を防ぐことを狙いとしています。
(人間で言えば、簡単な問題が解けたら難しい問題を解けるようにする事で学力を上げるようなもの)
また、精度が高いのに枠がズレている件ですが、
いわゆる過学習(学習データに適応しすぎる現象)となっている可能性があります。
〜final.h5ではなく、51epoch以降のh5をyolo.pyで読み込んでみて下さい。過学習がなく、学習が十分に進んでいるh5ファイルであれば、枠がうまくハマる...ハズです。
長文駄文失礼しました。
こちらも解決済みならすみません。
投稿: 常に転職したいマン | 2018年12月 6日 (木) 21時17分
常に転職したいマンさん
返信ありがとうございます。
作ったxmlファイルの中身を書き換えるということでしょうか?
fg0001.jpg
original
original
XXX
0
0
?
250
250
3
gf
Unspecified
1
0
8
3
242
240
投稿: R Type | 2018年12月 7日 (金) 13時39分
は( )に書き換え
(annotation)
(filename) fg0001.jpg (/filename)
(source)
(database) original (/database)
(annotation) original (/annotation)
(image) XXX (/image)
(flickrid) 0 (/flickrid)
(/source)
(owner)
(flickrid) 0 (/flickrid)
(name) ? (/name)
(/owner)
(size)
(width) 250 (/width)
(height) 250 (/height)
(depth) 3 (/depth)
(/size)
( object)
(name) gf (/name)
(pose) Unspecified (/pose)
(truncated) 1 (/truncated)
(difficult) 0 (/difficult)
(bndbox)
(xmin) 8 (/xmin)
(ymin) 3 (/ymin)
(xmax) 242 (/xmax)
(ymax) 240(/ymax)
(/bndbox)
(/object)
(/annotation)
投稿: R Type | 2018年12月 7日 (金) 13時50分
返信と解説ありがとうございます。
枠ずれの件はデータセットを作り直して解決しました。
投稿: r6 | 2018年12月13日 (木) 14時28分
別のアノテーションツールで.txtを学習させたい画像の数だけ作成したのですがそれを使って独自のweightファイルを作成することは可能でしょうか?
投稿: 大学生 | 2018年12月14日 (金) 13時19分
お世話になっております。
重ね重ねの質問ご容赦願います。
YOLOv3における閾値の設定(変更)について、
静止画判定に対しては下記URLに記載されていますが、
https://pjreddie.com/darknet/yolo/
動画判定に対しても、閾値の設定は可能なのでしょうか。
SSD kerasだとわかりやすいところにパラメータ(conf_thresh)がありましたが・・・。
ご教示いただければ幸いです。
よろしくお願いいたします。
投稿: hoge | 2019年3月11日 (月) 23時34分
こんにちは、hogeさん。
うーん、実はわたしもよく分かってません。一度コードをじっくりと読めば分かるんでしょうが……結局このコードを実用で使っていないため、よく分からないままというのが現状です。すいません。
速度が遅いのですが、私は業務用にはOpenCVによるLBP特徴+通常の画像認識を使って物体検出させてます。意外とチューニングしやすいので、そちらを好んで使っております。私の業務では、結構よく似たものを見分けることが多いため、そういう用途ではYOLOやSSDは見落としが多いんですよね。これも、やり方次第かもしれませんが。
投稿: arkouji | 2019年3月12日 (火) 06時10分
独自データによる学習において、
python train.pyと打ち込んだところ
AssertionError: class id must be less than num_classes
と表示されて学習が実行できませんでした。
どなたか解決策を教えていただけませんか。
投稿: sho | 2019年5月 7日 (火) 05時10分