ねこと画像処理。
(みかん – 吉祥寺 きゃりこ)
前回の ねこと画像処理 part 2 – 猫検出 では画像内の猫の顔を検出する方法を紹介しましたが、今回はディープラーニングの技術を用いて猫の品種を識別したいと思います。
学習データ
ねこと画像処理 part 1 – 素材集めでは、自分で撮影した写真を学習データとして使うと書いたのですが、都内の猫カフェ等で出会える猫に限ってしまうと品種の偏りが大きくなってしまうので、ここではしぶしぶ研究用のデータセットを使うことにします。。ただ、Shiba Inuがあるのに日本が誇るMike Nekoが含まれていないのでデータセットとしての品質は悪いと思います。
オックスフォード大学が公開している動物画像のデータセットです。その内猫画像は2400枚、クラス数は12で1クラスにつき200枚あります。今回は学習用に1800枚、検証用に600枚使います。つまり学習用画像は1クラスにつき150枚です。少ないようにも思えますが、12クラス程度であればこの枚数でもそこそこの精度が出せます。
学習モデル(分類器)の作成
この領域の問題は Fine-Grained Visual Categorization (FGVC) と呼ばれていて、対象となるドメイン(今回は猫の品種)を絞って分類を行います。視覚的に似ているものを扱うため高い精度を出すのは難しいのですが、Deep Learningの登場などもきっかけとなり最近は活発に研究が進められています。
今回試す分類手法の手順としては2つ、Deep Convolutional Neural Network (DCNN) の中間層(隠れ層)の出力を特徴量として抽出、それを素性として適当な分類器で予測を行う方法と、ImageNetなどの大規模な教師データを基に学習したモデルのパラメータを初期値として、他の教師データを使ってネットワーク全体を微調整するFune-tuningと呼ばれる方法の2つです。
ちなみに、CNNはHubelとWieselの研究がルーツとされているそうで、以下の論文では猫の視覚野に特定の特徴に反応する単純細胞(simple cells)と位置が変わっても同じ反応を示す複雑細胞(complex cells)があることを発見したと報告しています。始まりは猫というわけです。かわいい。
[Hubel68] Hubel, D. and Wiesel, T. (1968). Receptive fields and functional architecture of monkey striate cortex. Journal of Physiology (London), 195, 215–243.
Deep Learning(ディープラーニング:深層学習)という言葉が生まれて何年か経ち、今ではプロダクトもいくつか揃ってきていますが、今回はCaffeという名前のOSSライブラリを利用します。このライブラリはDCNN実装のひとつで、GPUにも対応しています。現在はBLVC(BERKELEY VISION AND LEARNING CENTER)で活発に開発が進められています。
実装
ニューラルネットワークのアーキテクチャはImageNetのデータ(ILSVRC-2012)で学習したモデルを使います。これはConvolution 5層、Pooling 5層、Full-connected 3層の構造になっていて、活性化関数は ReLU(Rectified Linear Unit)、中間層から抽出する特徴量は4096次元です。
(※ ライブラリ自体はオープンソース BSD 2-Clause license ですが、ImageNetのデータは非商用なので注意)
また、Caffeでは特徴量などの多くのオブジェクトが numpy.ndarray 形式で表現されているので、SciPy や scikit-learn など広く利用されている機械学習ライブラリの文脈にそのまま持ち込めるというメリットがあります。ここでは scikit-learn の分類器実装を使います。マルチプロセス対応も簡単なのでおすすめです。
Fine-tuningで学習する場合は、付属のcaffeコマンドを使うだけです。
1 2 |
## ソルバー設定ファイルと学習済みモデルを指定してFune-tuning $ caffe train -solver catnet_solver.prototxt -weights bvlc_reference_caffenet.caffemodel |
ソースコードはGitHubに上げておきます。以下の処理をコマンドラインツール化しています。
- cat classifier – wellflat/cat-fancier
- DCNNで特徴抽出 (出力はlibsvmテキスト形式かNumPyのnpyバイナリ形式)
- SVM/Logistic Regression/Random Forestで分類モデル作成 (マルチプロセスでGrid Search + Cross Validation)
- 精度評価 (precision/recall, f1-score, confusion matrix)
- Fine-tuning(ファインチューニング)用のネットワーク定義/ソルバー設定ファイル等
検証
前述のように12クラス2400枚のデータの内、学習用に1800枚、検証用に600枚割り当てています。検証データに対する分類結果は以下のようになりました。ハイパーパラメータはグリッドサーチ(5-fold cv)で選択しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
## SVM RBF Kernel SVC(C=7.7426368268112693, cache_size=200, class_weight=None, coef0=0.0, degree=3, gamma=7.7426368268112782e-05, kernel='rbf', max_iter=-1, probability=False, random_state=None, shrinking=True, tol=0.001, verbose=False) precision recall f1-score support Abyssinian 0.84 0.91 0.88 47 Bengal 0.84 0.83 0.84 46 Birman 0.72 0.79 0.75 52 Bombay 0.98 0.98 0.98 46 British_Shorthair 0.82 0.75 0.78 53 Egyptian_Mau 0.87 0.87 0.87 61 Maine_Coon 0.87 0.89 0.88 45 Persian 0.85 0.91 0.88 45 Ragdoll 0.76 0.76 0.76 41 Russian_Blue 0.84 0.82 0.83 57 Siamese 0.81 0.69 0.75 55 Sphynx 0.94 0.96 0.95 52 avg / total 0.85 0.84 0.84 600 ## Logistic Regression LogisticRegression(C=0.0005, class_weight=None, dual=False, fit_intercept=True, intercept_scaling=1, penalty='l2', random_state=None, tol=0.0001) precision recall f1-score support Abyssinian 0.88 0.79 0.83 56 Bengal 0.78 0.69 0.73 42 Birman 0.73 0.73 0.73 56 Bombay 0.88 1.00 0.94 46 British_Shorthair 0.86 0.73 0.79 49 Egyptian_Mau 0.85 0.87 0.86 47 Maine_Coon 0.79 0.82 0.81 56 Persian 0.84 0.86 0.85 49 Ragdoll 0.67 0.71 0.69 52 Russian_Blue 0.79 0.89 0.84 46 Siamese 0.81 0.80 0.80 49 Sphynx 0.94 0.94 0.94 52 avg / total 0.82 0.82 0.82 600 ## Random Forest RandomForestClassifier(bootstrap=True, compute_importances=None, criterion=gini, max_depth=None, max_features=auto, min_density=None, min_samples_leaf=1, min_samples_split=2, n_estimators=180, n_jobs=1, oob_score=True, random_state=None, verbose=0) precision recall f1-score support Abyssinian 0.91 0.79 0.85 53 Bengal 0.69 0.83 0.75 35 Birman 0.67 0.57 0.62 49 Bombay 0.85 0.98 0.91 48 British_Shorthair 0.70 0.64 0.67 50 Egyptian_Mau 0.85 0.80 0.82 55 Maine_Coon 0.81 0.75 0.78 59 Persian 0.87 0.73 0.79 55 Ragdoll 0.53 0.83 0.65 41 Russian_Blue 0.76 0.70 0.73 54 Siamese 0.88 0.78 0.82 54 Sphynx 0.84 0.98 0.90 47 avg / total 0.79 0.78 0.78 600 |
Classifier Type | Accuracy |
---|---|
Support Vector Machine (RBF) | 84.5% |
Logistic Regression | 81.8% |
Random Forest | 77.6% |
* Confusion Matrix
* ROC curve
* Fine tuning
Fine-tuningで学習したモデルの分類精度は以下のように accuracy 86% 程度でした。
1 2 3 4 5 6 7 |
## 10000 iteration I0901 13:07:19.200945 19831 solver.cpp:252] Iteration 10000, loss = 0.0176203 I0901 13:07:19.201012 19831 solver.cpp:270] Iteration 10000, Testing net (#0) I0901 13:07:33.071226 19831 solver.cpp:319] Test net output #0: accuracy = 0.8634 I0901 13:07:33.071305 19831 solver.cpp:319] Test net output #1: loss = 0.671083 (* 1 = 0.671083 loss) I0901 13:07:33.071317 19831 solver.cpp:257] Optimization Done. I0901 13:07:33.071323 19831 caffe.cpp:134] Optimization Done. |
いずれの手法も80%以上の分類精度です。普通のカテゴリ分類だと8割の精度は微妙な数字かもしれませんが、FGVCの問題でここまでの精度が出れば最初としては良い方かなと思います。学習データも1800枚しかありませんし。
scikit-learn の SVC は学習/予測速度が遅いので、大規模データを扱う場合は LogisticRegression あるいは LinearSVC を使うのが良いかなと思います。RandomForestClassifier も学習は速いので時間がない時には便利です。
考察など
ボンベイやスフィンクス等のわかりやすい特徴を持つ品種はほぼ間違えずに分類できていますが、視覚的によく似ている品種は分類精度が低く、例えばバーマンとラグドールを間違えるケース(精度70%前後)が目立っています。この2品種は見た目が非常に似ていることから比較されることが多いのですが、機械も人間と同じような間違え方をするのは興味深いです。ちなみに、バーマンのブリーダーは日本にはあまりいないらしく、都内の猫カフェでも見かけない猫です。
実際は足先の毛色などで判別できるらしいのですが、どっちもかわいいので問題ありません。
Fine-tuningは一応手元でいろいろ試してみたのですが、モデル構築に時間がかかる割に優位な精度向上が見られませんでした。さくらVPS(低スペックプラン)上で学習させたい場合は、学習時のバッチサイズはかなり小さくしてイテレーション回数を増やす方法を採らないとスワップすらも喰い尽くして落ちてしまうので注意。また、DCNNのフルトレーニングをしたい場合はGPUサーバ必須な感じです。個人でTesla K20/K40はさすがに買わないと思うので、ゲーム用のGeforceとかを使うことになりますけど、大変なのは室温管理ですね。この時期だと。
教師ラベルの収集
前回のパートでも述べましたが、ハードルとなるのはやはり教師データの収集かと思います。こういった画像分類の技術は、例えばフォトストックサービスでの写真の自動タグ付けなどへの利用がまず考えられますが、実際のWebサービスで使うには非商用(研究用)のデータは使えません。FGVC用のデータだと一般の人では正しくラベル付けできないので、専門家を対象にクラウドソーシングなどをする必要があります。ただ、クラウドソーシングの品質管理というのも結構面倒で、複数の必ずしも信頼できないワーカーによって生成されたデータから真のラベルを推定するという問題が加わることになります。多数決による品質保証ではFGVC用のデータはほとんど集まらないでしょうし、コストパフォーマンスも悪いです。AMTのTurKitみたいなやつは人間が関数の一部になってて正直恐ろしいというか気持ち悪い感じがしてしまうのですが、「ヒューマンコンピューテーション」とか「人間と機械による協調問題解決」とか言うと聞こえはいいんですよね。
最後に
とりあえず、ペットブリーダーや獣医さんなどを除き、一般的な人間の知識を超える程度の識別性能は出すことができました。僕は猫が好きですが、さすがにバーマンとラグドールは判別できません。
また、CNNのモデルを作るにはレイヤー定義やいろんな細かいパラメータを吟味しなければならないのですが、僕には適切なチューニングの方針を立てられるほどの知識や経験がまだないのが正直なところで、CNN関連の論文内で出てくるアーキテクチャをそのままマネして試しているだけです。まぁ僕は製品を作るのが仕事なので、理屈の方に深入りしすぎない距離感は見極めたいと思ってますけれど。
そういえば、ILSVRC2014 の結果が公開されてました。予想してたとはいえCNNだらけですね。RCNNというのは物体検出処理にCNNを適用した手法なのですが、DPMと比較して圧倒的な性能を叩き出してしまうということでちょっと前から話題になっているトピックです。
ニューラルネットはもうしばらく様子見かなぁという感じでぼーっとしてた人にとってはいろいろと悩ましい今日この頃だと思うんですが、こういう定量的なブレークスルーがあると製品作りも現実味を帯びてきますので、いろんなWebサービスやアプリでもDeep Learningが活用される事例がどんどん増えていくんだろうなと思います。
以下、分類結果例を信頼度(確率)順に上位3位まで並べています。
[('Abyssinian', 0.621), ('Bengal', 0.144), ('Sphynx', 0.087)]
[('Bengal', 0.583), ('Egyptian_Mau', 0.107), ('Persian', 0.092)]
[('Birman', 0.479), ('Ragdoll', 0.218), ('Persian', 0.146)]
[('Bombay', 0.532), ('Russian_Blue', 0.228), ('Siamese', 0.139)]
[('Maine_Coon', 0.602), ('Ragdoll', 0.216), ('Bengal', 0.052)]
[('Russian_Blue', 0.581), ('British_Shorthair', 0.226), ('Abyssinian', 0.057)]
[('F-14 Tomcat', 0.703), ('Russian_Blue', 0.054), ('Bombay', 0.051)]
画像の識別と言うかパターン認識はコンピュータは
苦手だと思ったんですがどんどん精度が上がってるんですね
レントゲンなどの医療画像診断もそのうち出来そうですね。
https://github.com/wellflat/cat-fancier/tree/master/classifier
Please tell me how to use your soft.
記事を参考にさせていただいてます.
githubの中にあるpklファイルはどうやって作成するのか教えていただければと思います.
Hello?
I have a question regarding your program listed in GitHub.
In the function train(const string& protoFile, const string& modelFile, const vector& trainData, const vector& trainLabel, const string& type, int kFold),
there is an error cv::OutOfMemoryError at the line “net->forward()” I wonder why this is happening.
Thanks,
一通り、何かセットにして売っているのがあれば欲しいです。
ハードまでセットにして売っているところはあるけれど、
速度は遅くていいから、適当に動いてみられるのがあればとおもいます。