Unityで自分で集めた画像からモバイルで物体検出

最終更新 2019/12/02

まずはじめに

いきなりですが、この記事は実装が終わっておらず書きかけの状態です。
結論として出た事柄から記述することによりよりよい情報になることを目指します。

物体検出とは

日本語の記事が見つからない場合は英語で調査する必要があります。

物体検出は英語だと”Object Detaction”といいます。

写真や動画から物を検出する際に必要な情報は以下の通りです。

  • 位置検出(どこにあるか) : Location
  • 分類(どんなものか) : Classification
  • 信頼性(分類の可能性) : Confidence

Unityで物体検出をするために

物体検出、で調べるとOpenCVが出るため、OpenCVforUnityを購入します。

更に、Unity標準のWebCameTextureだとあまり機能が無いため、NatCamを購入します。

OpenCVのサンプル

NatCamとOpenCVforUnityの連携を見ると、Matクラスへの変換までが記述されてあるためそちらをインポートします。

ひとまずUnityで準備できることは以上です。
ここからは自分で集めた画像から物体検出をするための準備を行います。

PCのスペック

Windows10(x64)
メモリ : 32GB
SSD : Sumsugn SSD 970 Evo Plus 1TB
nVidia RTX 2070 super

必要な知識

画像を用意

自分で検知したいものを撮影していくか、Imageクローラを用意し、CreativeCommonsの商用利用可能画像を取得していきましょう。
大体1種類の検知につき、画像を50個は用意します。

このとき、例えばリンゴの場合はカットしたものなどを一種類として入れると精度が悪くなると思われます。
そのため、ハーフカットや更にカットしたリンゴを認識したい場合は、別々の種類として画像を用意し、
それぞれ50枚ほど用意しましょう。

調査履歴(メモ)

さて何から手をつけたらいいかが分からないためobjdetectから参考にしました。

objdetect

FaceDetectionExample
HOGDescriptorExample
QRCodeDetectorExample
とありますが、やりたいことは顔とQRコード認識ではないためHOGDescriptorを読んでみます。
HOG( Histogram of Oriented Gradients )Descriptorは Haar-like特徴や LBP(Local Binary Pattern)特徴 のように、
特徴検知をして物体検出を行う手法のようです。
SVM(Support Vector Machines) という単語も出てきますがひとまず特徴ごとの特性を見てみよう。
学術論文の絵だけ見れば分かるかもでチラ見をします。

Haar-like特徴

白黒にして矩形分割して似たような感じであればそれって感じな仕組みなのかな?

LBP(Local Binary Pattern)特徴

これも白黒か。これは最初から分割して白黒の濃淡で似ている、みたいにしている仕組みかな?

HOG(Histogram of Oriented Gradients)

これは論文どこだろう。色味の差分が大きいところを情報としてもっていてそれが似ていたら、という感じなのかな。

SVM( Support Vector Machines )

検出方法はあるけど、それがなにかを表すための情報がSVMのようだ。

これを自作するの大変じゃない? ということで他サンプルを漁る。

dnn( ディープニューラルネットワーク )

MobileNetSSDWebCamTextureExample
TensorFlowWebCamTextureExample
YoloObjectDetectionWebCamTextureExample
を参考にします。

MobileNetSSD のサンプルではいくつかの定数と以下のデータが必要なようです。
MobileNetSSD_deploy.caffemodel
MobileNetSSD_deploy.prototxt
classesList

TensorFlow の サンプルではいくつかの定数と以下のデータが必要なようです。
tensorflow_inception_graph.pb 
imagenet_comp_graph_label_strings.txt 

Yolo の サンプルではいくつかの定数と以下のデータが必要なようです。
yolov3-tiny.weights
yolov3-tiny.cfg.txt
coco.names

この三種はMobileでも動作するようなので、高速なのだと思われます。

各種データ

classesList , imagenet_comp_graph_label_strings.txt , coco.names は
エディタで中身を見ると、それぞれ分類リストが記述されているようです。
それ以外のデータを用意できれば自作の物体検出が出来ると思われます。

ではMobileNetSSD 、 TensorFlow 、 Yolo など聞いた事もないので調査します。

MobileNetSSD

SSD(Single Shot Multibox Detector) というアルゴリズムがあります。
こちらはとても遅く、モバイルで写真や動画から物体検出するにはコストが高すぎるようです。
そこで計算を早めたものがMobileNetというものを利用して高速化したMobileNetSSDの登場、ということなんですが
ここから先は学術論文を読んでもよく分からんなのでURLだけ貼っときます。

classesList は分類の情報。
caffemodel とprototxtってなんなの? prototxt は計算式が入ってるっぽい。caffemodelが重みの情報かな?

TensorFlow

tensorFlowは 機械学習モデルの開発およびトレーニングに役立つオープンソースのコア ライブラリらしい。

imagenet_comp_graph_label_strings.txt は分類の情報。
pbファイルってなんなの?計算式と重み両方の情報が入ってるのかな?

Yolo

SxSのグリッドにしてBoundingBoxと信頼性、同時にグリッド単位での確率マップを生成してガッチャンコして判別している?

coco.names は分類の情報。
weightsとcfg.txtはなんなの? cfg.txt は計算式が入ってるっぽい。weights が重みの情報かな?

ライセンス

DNN周りでフワっとしているのがライセンス。
まとめると以下の確認をしないといけないようだ。

  • アーキテクチャ的なもの? 例:元となったGitHub Repositoryや論文(設計思想)
  • モデルの重み
  • ソースコード(kerasなどで実装されたソースコードなど)
  • テストアセット(テストに使用した画像など)
  • データベース(画像の切り分け)

参考はIBM。

弁護士柿沼太一様のブログより引用。
法律は「と思われます。」との記述からまだ法律が間に合っていないのかな。

アーキテクチャ

うーん、進化凄い。

その他参考URL

よっしゃこの人のやり方でとりあえず作ってみよう
と作っていったのですが、tensorflow-gpuでの実行では
ビデオカードのメモリが足らずバカスカ失敗する。
(その前に環境構築で苦労する。pipでインストールしたけど
 ローカルで環境構築する場合は参考URLの多いanacondaのほうがいいかも。)

一応PC環境は前に貼ったので各種ライブラリのバージョンを記述。
※後述のGoogleColaboratoryに移行してしまえば環境構築の必要無いと思うのでそちらのほうがいいのではと思ったり。

  • CUDA 10.0
  • cuDNN 7.6
  • Python 3.6.8
  • tensorflow-gpu 1.13.1
  • numpy 1.16.4
  • Keras 2.3.1
  • scikit-learn 0.21.3

64×64のサイズまで縮小後に実行したら
1時間後に出来上がった!

batch_size = 8
num_classes = 103
epochs = 50
steps_per_epoch = 7507 / batch_size
image_input_shape = (64, 64, 3,)
max_queue_size = 2

Accuracy: 0.49885233358837033
f1 score: 0.4725477940429901

うーん、50%の正解率は正直低い。
でも画素数を上げるとCPUでの実行になり
更に学習時間がかかるので却下…。
そしてH5ファイルは520MB。H5って一体なんなん。
とりあえずこれ以上は無理そうなので別の手段に変更。

ONNX

MSとFacebookが 提唱しているニューラルネットワークのモデル表現の標準フォーマット らしい。

さらにNetronというGUIでモデルが見れる拡張子対応してるし
MSがCustomVisionというGUIで学習モデル作れる
クラウドサービス出してるし楽に作れそう!ということでCloud Visionを試してみます。

とりあえずよく分からない用語が出たら見ていくスタイルで、
CustomVisionでモデル作成。こちらはサクサクGUIで作り終え、
onnx形式とtensorflowのpb+label形式で出力。

そこまでは良かったものの、OpenCVforUnityで 読み込もうにもエラーが出る…
ONNXはサンプルにあるため対応しているみたいだけど、何がいけないのか分からないエラーのため断念します。

というわけで素敵なツールなんだけどひとまず諦めます。

NN(Neural Network )について

DNN( Deep Neural Network、ディープニューラルネットワーク )は 脳神経回路(ニューロン)をモデルとしたアルゴリズムを多層構造化したもの
CNN( Convolutional Neural Network、畳み込みニューラルネットワーク ) は DNNだと一次元的な情報になるけど複数次元で意味合いを持ったもの(画像など)
RNN( Recurrent Neural Network 、再帰型ニューラルネットワーク ) は 以前の観測への依存を考慮することが不可欠なもの(株価予想など)

つまりDNNでもRNNでも重みの情報を更新しない限り、強化学習のように学習値が更新されていくわけではないようです。
また、クラウド上ではなくモバイルで動作するようなAIをエッジAIというみたいです。
現在はこのエッジAIの開発が盛んなようで、新たなアーキテクチャが出続けているようです。

Google Colaboratory

Google ColaboratoryというGoogleが提供しているクラウドサービスがあろ、あし。
なんと、数十万円するグラボを無料で使用させてくれます。

注意点がいくつかあるため以下にはご注意ください。
特に90分セッションは学習開始してから放置し始めて食らうことが多いです。

  • 暗号通貨の発掘などは使用禁止
  • 90分間セッションが切れると環境が元の状態に初期化されます
  • 連続使用は12時間まで

JupyterNotebookでの記述がなんともWordpressのブロックエディタのようだけど、分割して実行するのはちょっと便利ですね。
しかしエディタで見るとpythonコードが読みづらくなるので、ipynb形式に対応したエディタで操作しないといけないのが辛いです。

まずは Colab の初期登録。
JupyterNotebookでチュートリアルが出るので見たい人は見て、見なくていい人は
ファイル -> Python3の新しいノートブックを選択(Python2は2020年1月に無くなるので3にしたほうがいい)

Colabの初期設定だとCPU使用になるためTPUへ設定変更
ランタイム -> ランタイムのタイプを変更 -> ハードウェアアクセラレータ を 早いらしい TPU に指定します。

自分の用意した画像(9000枚ほど)を学習させたいのでGoogleDriveと連携します。

from google.colab import drive
drive.mount('/content/gdrive')

連携する場合、新しいタブを開くリンクが出るので選択し、GoogleDrive権限の許可を行うと AuthorizationCode が出力されます。
AuthorizationCode を、 JupyterNotebook 側の指定箇所に貼り付けしEnterすることでマウントされます。

GoogleDriveは以下ディレクトリが出来上がっています。

マイドライブ\Colab Notebooks

アップロードするファイル構成は以下の通りです。

data/train
	hogehoge/1.jpg ~ 45.jpg
	fugafuga/1.jpg ~ 45.jpg
	nikoniko/1.jpg ~ 45.jpg
	tajitaji/1.jpg ~ 45.jpg
        ....
data/val
	hogehoge/45.jpg ~ 50.jpg
	fugafuga/45.jpg ~ 50.jpg
	nikoniko/45.jpg ~ 50.jpg
	tajitaji/45.jpg ~ 50.jpg
        ....

学習用データがtrain、評価用データがvalです。
ひとまず一種類50枚以上集めたあと、
1割をランダムで選定して評価用データに入れ込みます。
学習結果が悪かったらそのとき追加すればいいかと。

なぜだかDriveのデータが反映されなかったので再度実行します。

from google.colab import drive
drive.mount('/content/gdrive')

content/MyDrive/内に全てのデータが反映されています。
うーん。その下に勝手に作られたColab Notebooksはあるんだけどそこだけマウントしてくれないのかな。
そしてGoogleDriveがよく固まります。仕方ないのでWindowsアプリケーションのGoogleDriveをインストールします。

colabのtensorflowは1.15.0なのでちょっと古いバージョンへ戻します。

pip install tensorflow==1.13.1

ipynbはGoogleDriveに入れておけば読み込めるかな?と試したところ、
colab側でファイルとして認識するまでがとても遅く、 ipynb はアップロードする形にしました。

画像検知用語

画像検知において、結果は確率で表します。
結果として、特に一番確率が高いものを提案しますが、
最後は人間がそれは何なのかを判断することになります。

例えば白を黒と認識する人がいたとしましょう。
誰がどう見ても画像に映るのもは白であり機械も白と答えているけれども
検知システムを使用した人が黒だと言えばそれは間違いになってしまうことになってしまいます。

そのため、検知システムでは正解と不正解は学習段階では正しく認識させる必要があります。
正しいラベルでの分別をした場合の認識では結果は以下の4つに分かれます。

  • True Positive : 画像に目的のものが写っており、検知システムは目的のものを検知できた
  • True Negative : 画像に目的のものが写っておらず、 検知システムは 目的のものを検知できなかった
  • False Positive : 誤検知した。画像に 目的のものが写っていないが、検知システムは認識した
  • False Negative : 誤検知した。画像に目的のものが写っており、 検知システムは 目的のものを検知できなかった

True Positive と True Negative は把握しやすいですが、
検知したいものがリンゴの場合、 False Positive は赤いボールだったりするかもしれません。
False Negative はリンゴの断面かもしれません。

ということはリンゴの精度を上げたいは2つのアプローチが出来ます。

1. False Positive を True Negative へ出来るだけ変えていく
リンゴとはこういうものだ、という特徴あるものを認識させていく。
しかし、その学習によってリンゴだけど形がいびつなものがFalse Negativeとして増えていくことになるかもしれない。

2.False Negative を True Positive へ出来るだけ変えていく
リンゴの断面の学習を行ってみる。
しかし、その学習によってリンゴの断面ではないものがFalse Positiveとして増えていくことになるかもしれない。

というわけで、トレードオフになってしまうのでどう舵取りをするか、という点は目的に応じて変える必要があります。

OpenCVサンプルの比較

mobilenetSSD,TensorFlow,Yolo3tinyがOpenCVforUnityには揃っているので
CC0ライセンスの画像を利用してどんな結果になるかを調査します。
それぞれ、「車」、「人」、「モニタ複数」、「モニタ単品」を写します。

MobileNet SSD

全体的に高い確率で認知できました。
学習の重みが良いのでしょうか。アルゴリズムが良いのでしょうか。
難点としては、デフォルトのデータだと21種の画像しか判別がつかない点です。

TensorFlow

TensorFlowのサンプルは他とは違い、1000種類近く見分けられるようです。
物体検出というよりは分類と信頼性のみの表示になっていました。
ラベルの中に人が入っていないため、カツラやメガネと認識しました。
また、モニタのところを机と認識したりしています。

Yolo3tiny

大きい画像の認識が甘い結果になりました。
また、顔の認識に関して、男の人は認識できませんでした。

error

コメントする

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください