スマホで撮った写真をディープラーニングで判定してみる　(学習編)



#**■写真を撮って判定してみる**
事前学習済みのネットワークと独自の学習をしたネットワークで結果を比較してみます。
（※画像クリックで動画が再生します。）

[![IMAGE ALT TEXT HERE](https://qiita-image-store.s3.amazonaws.com/0/114533/bf22d3f5-7821-1ff6-73bd-b566693f76a0.png)](https://www.youtube.com/watch?v=6h6X8cr6tHo)


**[こちら](https://deeplearning.mwlab.io/)**　からデモページにアクセスし、上記3ステップで実際に撮った写真を判定させてみることができます。
ネットワークの選択はラジオボタンから行えます。
画像を送ってしばらく待つと黄色い枠に囲まれた分類結果が表示されます。
右側に表示される「prob.」は事後確率を表しています。

#**■二つのネットワークと判定結果について**
利用しているネットワークはいずれもAlexNetですが、
【1】 ILSVRCで優勝した際のパラメータが事前学習された1000種類を分類するネットワーク
【2】 1を使って独自の10種類(画像数：各数１０枚程度)で転移学習(Fine Tuning)させたネットワーク
の違いがあります。

転移学習はカテゴリが元のネットワークのセットに含まれている必要があると誤解されることもありますが、
試してみると【1】には含まれていないコインなども【2】のネットワークでは問題なく分類できることがわかります。

また両方に含まれる項目、例えばノートPC(Laptop)でも、種類を限定して再学習させたほうが
判定結果や事後確率(Prob.)のスコアが概ね良い結果となり、
わずか数１０枚の画像でも、ある程度高い精度で独自の分類ができるので、画像分類判定にはうまく条件を絞りながら転移学習を用いることが有効だとわかります。



#**■システム構築について**
今回スマートフォンで撮った写真を独自のカテゴリで分類するものですが、判定自体はクラウド上で行っています。
ここからは
　**1.システム概要**
　**2.独自の分類をするための転移学習**
　**3.推論用のモデルをサーバーへ展開**
の順でシステムとして運用するための手順を紹介していきますが、このページでは **1.**と**2.** について述べていきます。

##　□システム概要
ディープラーニングの学習：MATLAB
分類器はAWS上でRestfulなサーバーとして立て、node.jsで立てたWebサーバーから画像を受け取り結果を返します。
<img width="448" alt="overall.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/114533/de23f437-308f-5e24-8361-90d94292c22d.png">


##　□独自の分類をするネットワークの学習
###　　◆画像の準備
分類する画像はフォルダ分けして入れておくだけでOKです。フォルダ名が自動的にラベル名として利用できます。
![Folder.png](https://qiita-image-store.s3.amazonaws.com/0/114533/126058a5-d627-b7df-0aff-ac0488830392.png)

###　　◆MATLABによる学習と性能評価
```MATLAB
%% 学習済みのディープニューラルネットワークを呼び出し
alex = alexnet;
layers = alex.Layers

%% 独自の分類をするためにネットワークを変更
layers(23) = fullyConnectedLayer(10); % 分類の個数のUnit数になるように指定する。(今回は10個の分類)
layers(25) = classificationLayer

%% トレーニングデータのセット(画像セットが入っているフォルダmyImagesを指定)
allImages = imageDatastore('myImages', 'IncludeSubfolders', true, 'LabelSource', 'foldernames');
[trainingImages, testImages] = splitEachLabel(allImages, 0.7, 'randomize');% 画像を学習用と評価用に分ける(7:3)
trainingImages.ReadFcn = @(filename) readFunctionTrain(filename);

%% ネットワークを再学習
opts = trainingOptions('sgdm', 'InitialLearnRate', 0.001, 'MaxEpochs', 2, 'MiniBatchSize', 64);
myNet = trainNetwork(trainingImages, layers, opts); % 学習して独自推論のネットワークを得る

%% 評価用にとっておいた画像セットで精度の評価
testImages.ReadFcn = @(filename) readFunctionTrain(filename);
predictedLabels = classify(myNet, testImages);
accuracy = mean(predictedLabels == testImages.Labels) %精度の検証
```

**[参考動画](https://www.youtube.com/watch?v=XMcHiMIT8iE)**
**[サンプルダウンロード](https://jp.mathworks.com/matlabcentral/fileexchange/64008-10?s_eid=PSM_15913)**
再学習された *myNet* が推論のモデルです。
このコードではGPUが接続されていれば自動的にGPUを利用し、なければCPUで学習が進みます。
ここで学習済みネットワークはAdd-onとしてインストールしておけば、関数一行で呼び出すことができ、現在(2018年8月)は下記が利用できます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/114533/6ac5f548-4ac5-ca88-0b22-8ddcd4db51db.png)

また、その他のフレームワークとの連携も対応してます。
**●Caffe・Tensorflow-Kerasのモデルのインポート**
**●ONNXモデルのインポート/エクスポート**

###　　◆ネットワークの選択
今回はAlexNetとGoogleNetを試しました。

| ネットワーク     　 |推論速度(CPU)　　|推論速度(GPU)   |ファイルサイズ　　|精度　　　    |
|:-------------------|:---------------|:----------------|:-----------------|:----------------|
| AlexNet        　  |1.1 s           |     0.5 s     |   約200MB        | 93.0%    |
| GoogleNet       　 |2.4 s           |     0.5 s  　 |  約20MB         　 | 97.0%      |


ここでGPUでの速度確認にはNVIDIA社製のエントリーモデル(GeForce系)を使っています。
今回は画像一枚ずつの判定でGPUの高速化が限定的なので、CPUを利用することにします。
ファイルサイズや精度ではGoogleNetが優れていますが、CPUでの推論速度の点から **AlexNet** を利用することにしました。


##　□推論用のモデルをサーバーへ展開
サーバーへの展開は @Alberobellojiro さんがこちらで解説しています。
  **[スマホで撮った写真をディープラーニングで判定してみる　(デプロイ編)](https://qiita.com/Alberobellojiro/items/036eb9bdb156af8176bc)**




# **■まとめと今後**
　スマホで撮った写真をディープラーニングで判定し、事前学習済みネットワークと再学習後の結果を比較できるものを作ってみました。
　この記事ではNNモデル学習/推論の部分を取り上げましたが、
　転移学習は元の分類に含まれていない種類の分類タスクにも有用です。
　CPUでの推論では速度面でAlexNetが良さそうです。　(MATLABからcuDNNを呼ぶ場合)

学習のモデルに関しての今後ですが、
・画像枚数増加による精度向上について解析
・音判定への適用
に取り組みたいと思っています。

#**■ディープラーニング学習/予測で利用したソフトウェア**
・MATLAB
・Image Processing Toolbox
・Computer Vision System Toolbox
・Parallel computing Toolbox
・Neural Network Toolbox
・Statistics and Machine Learning Toolbox