”けものフレンズ”動画顔検出器をディープラーニング+OpenCV物体検出で作る(転移学習&メモリ不足対策)
ディープラーニングネタはしばらくぶりですが、最近個人・業務において水面下でいろいろとやってたので、まとめて載せます。
ベースとなるのはこちらの記事。
けものフレンズの動画からフレンズさんの顔を検出するやつを無理やり作ってみた: EeePCの軌跡
このときから教師データも検出器も変わってませんが、コードの方をいろいろ工夫したので、そちらを紹介します。
また、物体検出の方のコードを公開してなかったので、そちらも載せておきます。
さて、私がTensorFlowによるディープラーニングを行うにあたり、2つほど問題がありました。
ひとつは“転移学習”、もう一つは”メモリ不足”。
この2つを解決したコードを作成しました。以下のリンクからダウンロードしてください(右クリックして”名前を付けて保存”)。
・学習用コード
・物体検出用コード
他にも”アニメ顔検出器”が必要です。
入手元:http://anime.udp.jp/data/lbpcascade_animeface.xml
他に用意するものは、”けものフレンズ”の顔データ(1キャラ当たり30枚以上)と動画(360p以上)が必要です。別にアニメであれば、けものフレンズでなくてもいいです。
もし題材を人の顔(アイドル等)にするのであれば、OpenCVに付属する顔検出器(haarcascade_frontalface_default.xml)等をご使用ください。
これらを動かすために、ひとつのフォルダにこの2つのコードを入れて、以下のフォルダを作っておいてください。
「data」「face」「model」の3つです(「movie」は不要です)。
「data」フォルダの中に、以下のように教師データ(フォルダごとに分けたけもフレ各キャラの顔画像)を入れておきます。
私は37種類、計2236枚集めました。
著作権が絡むので、さすがにこの教師データを公開するわけにはいきません。動画から頑張って切り出してください。この辺りの記事が参考になるかと。
TensorFlowで「けものフレンズ」の”フレンズ判別器”作ってみた: EeePCの軌跡
また、私はこのコードをTensorFlow 1.2.0、Windows用64ビット版Anaconda 4.2.0、これにOpenCVをpipまたはcondaコマンドでインストールした環境で使っております。
では、一つ一つ紹介します。
機械学習の実行
まずは”学習”から。
この”cnn_train_56_d.py”というコードは、先の”転移学習”に対応しました。
以前、けもフレ判別器を作ったときは、フレンズさんの画像が増えるたびに1から学習しなおしてました。
が、既に学習器があるのに、一人フレンズを学習させるのもいちいち最初からやり直し。
ものすごい時間がかかるし、ラベルが増えると収束性が悪くなります。最悪、学習が全く進行しなくなることもあります。
そこで、ラベルが追加になっても既存の学習器を初期値にして学習をさせることで、大幅に機械学習の時間を削減する&収束しやすくするというテクニックがあります。
これを”転移学習”といいます。
このコード、普通の新規学習から転移学習まで、以下の3パターンの学習ができるように作りました。
・ 新規学習
dataフォルダにラベルごとのフォルダを作り、画像を入れます。
そのあとに以下のコマンドを実行。
> python cnn_train_56_d.py
これは今までの実行形式ですね。
・追加学習
この言葉の表現が正しいかどうかわかりませんが・・・フレンズの数は同じ(ラベルを増やさず)で、画像データのみを増やした場合は、まず「model」フォルダに学習器(model_end.ckpt.data-00000-of-00001、model_end.ckpt.indexのように「○○.ckpt.data-00000-of-00001」「○○.ckpt.index」の2つのファイル)を入れておきます。
そして、以下のコマンドを実行。
> python cnn_train_56_d.py ○○.ckpt
これで、追加の学習がはじまります。
サイクル数が足りなくて、損失値(loss)がまだ大きいときに更にサイクルを回したくなった時もこれを使います。
・転移学習
けものフレンズ2期がはじまって「わあい!新しいフレンズさん!」が増えてしまって、さらにフレンズを追加したい(ラベルを増やしたい)ときに使います。
まず「data」フォルダに新しいラベルのフォルダと画像データを追加。
そのあとに、以下のコマンドを実行します。
> python cnn_train_56_d.py ○○.ckpt 1
「追加学習」のコマンドの最後に「1」がついてます。
実は、後ろは「1」でなくても、例えば0でも、誕生日でも、彼女の名前でもOK。
要するに、何か書いてあると転移学習が動くようになってます。ダサいコードですね。すいません。
コードを見てもらうとわかりますが、最終段付近の結合層、Softmax以外の「tf.name_scope」の後ろの名前には「A_」というのがついてます。
この「A_」が付いた名前の層の部分のみの重み値を読み込むため、ラベル数が増えてもエラーが出ません。最後の2層だけ真っさらにして学習を行うという仕組みです。
まったく新規でやるよりも早く計算ができるだけでなく、おそらく画像が増えると学習が進まなくなりますが、転移学習だとかなり強引に学習を進行させることができます。
もう一つの問題、「メモリ不足」問題についてです。
我が家のGeForce GTX1050Tiはメモリが4GBしかありません。
ところが、教師データが4000枚近くになるとメモリ不足で落ちるという事態に陥りました。
で、いったいどこでメモリを食っているのかと思って調べてみると、どうやら各Step(= epoch)ごとに「精度(accuracy)」と「損失(loss)」を計算するところでメモリを大量に使用していることが判明。
どうやら、accuracy、lossを計算する際にtrain用の画像データ(全画像の9割)をいっぺんに放り込むため、大量のメモリを消費してしまうようです。
これを解決するために参考にしたのは、以下のサイト。
メモリの少ないグラフィックボードで MNIST を動かす - walkingmask’s development log
このaccuracy、lossを分割(ここでは50分割)して計算し、それぞれ平均、合計を取ります。
具体的には、以下のようなコードがあるはずです。
num_test = len(train_label)
sum_accuracy = 0
sum_loss = 0
for i in range(0,num_test,50):
sum_accuracy = sum_accuracy + sess.run(acc, feed_dict={
images_placeholder: train_image[i:i+50],
labels_placeholder: train_label[i:i+50],
keep_prob: 1.0})
sum_loss = sum_loss + sess.run(loss_value, feed_dict={
images_placeholder: train_image[i:i+50],
labels_placeholder: train_label[i:i+50],
keep_prob: 1.0})
train_accuracy = sum_accuracy /(num_test/50.0)
train_loss = sum_loss
line = "step , %d , training_accuracy , %g , loss , %g"%(step, train_accuracy, train_loss)
print (line)
私のところで実行するとちょっとaccuracyの値が大きめ(1を超えることもある)になりますが、まあ大体わかるので、これでいいかなぁと。
これで劇的にメモリを削減できました。我が家のGTX1050Tiで計算できる画像枚数が飛躍的に増加しました。
会社では112×112の1.2万枚の学習(CPUで実行)をやらせたら、16GBメモリが飛ぶ事態に遭遇。メモリが32GBくらいないと動かないため困り果ててました(しばらく128GBのマシンで実行してました)が、これで16GB機でも余裕で動いてくれるようになりました。
メモリ少なめのグラフィックボードで実行したい方は、是非参考になさってください。
なお、教師データ用の画像のラベル付けツール”AnnotationTool.exe”も少し改良したものを置いております。
以前でも紹介したVOC2007構成のアノテーションファイルを出してくれるツールですが、このコードに合わせて正方形にカットできるようにしました。
ただ、アノテーションファイルを作っても、そのままではこのコードで使えないため、ラベルごとに画像を切り出してくれるツールも作りました。
この辺を使うと、画像ファイル集めが少し楽になります。
物体検出
続いて「物体検出」です。
コマンドは以下。
> python rcnn_app_56_a.py
(動画データはあらかじめどこかから調達してご用意ください。コード中の”kemo07.mp4”にその動画ファイル名を入れます)
これで、次のような動画が生成されるはずです。
ただ、「lbpcascade_animeface.xml」のアニメ顔検出器では、一部のフレンズさん(ハシビロコウなど)が検出できません。
OpenCVの機能を使って自分で作ることもできますが、私はいいものが作れませんでした。
OpenCVでLBP特徴を使った”物体検出器”を作成してみた: EeePCの軌跡
画像データが”けもフレ”だけでは足りませんでしたね。
ただ、かばんちゃんとサーバルちゃんはわりとちゃんと認識します。
さて、これで第2期の準備完了!新しいフレンズにも対応できる画像認識器にするぞ!
なんて思ってましたけど、昨今のあの監督解任騒ぎ。
画像認識以前の問題で、存亡が危ぶまれております。大丈夫でしょうかね?なんとかしてほしいものです。
« Arduinoで世界初のパソコン”ALTAIR 8800”が作れる!? | トップページ | コンパクトな折り畳み式の4K対応のドローン”Moment Drone” »
「数値解析系」カテゴリの記事
- Tanuki-8Bの4ビット量子化ggufモデルでRAGをやってみました(2024.09.14)
- 純日本産なローカルLLM「Tanuki-8B」を試してみた(2024.09.02)
- 東京のセールスフォースに行ってきました(2024.07.24)
- ローカルLLM「Llama-3-ELYZA-JP-8B」にいろいろ聞いてみた(2024.07.01)
- ElyzaのLlama3ベースの言語モデル「Llama-3-ELYZA-JP-8B」のRAGが予想以上に賢かった件(2024.06.27)
« Arduinoで世界初のパソコン”ALTAIR 8800”が作れる!? | トップページ | コンパクトな折り畳み式の4K対応のドローン”Moment Drone” »
コメント