やっとchainerでCNNを動作させるところまで辿り着きました。かたりぃなです。
何がやりたいのか?
ARというかHololensのMRで現実世界のオブジェクトを識別して追加の情報をユーザーに提示できれば楽しいだろうなと思っています。 HololensのAPIを軽く見たところ、深度マップなどの面倒は見てくれるようですが、画像からの物体検出などは見当たりませんでした。 画像処理といえばOpenCVなんかが有名で、最近はdnnモジュールが追加されているのでこいつを使って公開されている学習済みモデルを取り込めば一般物体認識はできそうですが、学習済みモデルを持ってくるだけでは私のやりたいことに届かなさそうです。 手作業で前処理や特徴抽出を記述していくのもアリかもしれませんが、そういう試行錯誤に時間を費やすのは勿体ないと思います。 なら自前でモデルを作ってDeepLearningのフレームワークを使って学習させよう、そしてAR/MRでなんか面白いことやりたいなといったところです。 過去にChainer動かしてみたりもしてますし、ゲーム目的とはいえGPUもよさげなのが手に入りました。 さっそくやってみます。 今回のゴールはcifarデータセットをCNNで処理して一般物体認識を行うことです。
cifarデータセットとは
10種類のラベル付けされた画像のデータセットです。一般物体認識における分類問題と呼ばれるものです。 画像の情報として
- RGBの3チャンネル
- 32x32 pixel です。 これができれば私がやりたいことの実現に向けた足掛かりになりそうです。
データセットの中身を確認する
cifarデータセットのpython-typeでダウンロードしてそこからデータを取り出します。 pythonはあまり慣れていないので調べることが多いです。 ネットの情報ではcPickleを使おうという情報が散見されますが、どうやらインストールしたpythonのバージョンにはcPickleが無いらしく、仕方ないのでpickleを使います。 シリアライズとデシリアライズを面倒見てくれるモジュールらしいです。 手元の環境ではエンコードタイプの問題でややこしいことになってしまいました。
# python3ではcPickleがなくなったらしいので、pickleを使う import pickle; # metadataがラベルデータ # それ以外がデータセット # データは32x32,3ch(RGB)の形式 # ただのバイト列としてエンコーディングされたものとして扱う f = open('data_batch_1', 'rb') train_data = pickle.load(f, encoding="bytes") len(train_data) # result : 4 train_data.keys() # result : dict_keys([b'filenames', b'data', b'labels', b'batch_label']) type(train_data[b'data']) # result : <class 'numpy.ndarray'> train_data[b'data'].shape # result : (10000, 3072) type(train_data[b'labels']) # result : <class 'list'> train_data[b'labels'][:10] # result : [6, 9, 9, 4, 1, 1, 2, 7, 8, 3] sample_image = train_data[b'data'][:100].reshape((10, 10, 3, 32, 32)).transpose((0, 3, 1, 4, 2)).reshape((320, 320, 3)) # 先頭100個をタイル状に並べ替える Image.fromarray(sample_image).save('sample.png') # result : outputfile "sample.png"
これでデータ構造はわかりました。何か目に見えるものがあると達成感ありますね。
CNNとは
畳み込み(2次元カーネル)を使ったニューラルネットワークです。 今回は動かすことが目的なので、細かいパラメータ調整はしていません。
こちらのページを参考にさせていただきました。
Chainerのtrainerを使ってCIFAR-10の分類に挑戦したかった - Qiita
詰まったポイント
ネットで調べてみましたが、少し前のバージョンのchainerのコードが多く見受けられました。 functionsetとforwardで順方向の計算グラフを定義されていたりしましたが、functionsetは非推奨となったようで、NN全体をchainとして定義するのが今の主流のようです。 手作業で書こうとしましたが、ゼロから書くのはまだ無理でした。 上記ページのコードを引用して動作確認しました。 pickleのところとか、学習結果の出力を少し試してみた程度の変更です。
全体のコード。
giste82cb557c1939de2f1bb45089637ea59
cpuのみで動かすと重くて全然進みませんが、GPUなら数十分で終わりました。これなら色々と試行錯誤できそうです。
今後の展望
以前に試したARの原理の延長で、物体ごとに異なるオブジェクトを表示してみたいですね。
ただ、カードゲームなんかで全ての種類のカードを分類するのはちょっときつそうなので、適当な分類ラベルを選択して限定的に実装してみたいと思います。 またDeepLearningを使えば検出精度の向上も期待できるかもしれません。 DeepLearningで何ができるか、色々と試行錯誤してみましょう。 週末のまとまった時間でキリのいいところまでできたのでひと段落です。
では今回はこれくらいで。