画像認識の精度向上に圧倒的な効果がある「CNN(Convolutional Neural Network)」のベーシックなところを、今回はとりあげてみます。
2017/12/01追記
>以下の説明に使っている画面例は、Version1.00のものです。
>Version1.10で一部アイコンデザイン等が変わっています。
>しかし、説明への影響がないと判断し、差し替えはしていません。
説明の前提など
CNNは、全結合層だけでなく畳み込み層(Convolution )とプーリング層(Pooling)から構成されるニューラルネットワークのことです。
CNNと一口に言っても構成方法にのバリエーションは沢山ありますし、Poolingと名の付くレイヤーだけみても沢山の種類があります。
それらを全部理解しようとすると、前にすすめないので、ここでは一番多く使われている「Convolution」と「MaxPooling」の2つに絞ります。
絞ったうえで、以下の2つの構成を試します。
右が、Convolution+ReLUの組み合わせ1組に対してMaxPoolingレイヤーが1個というパターン。
左は、Convlution+ReLuの組み合わせを2回繰り返した後に、MaxPooloingがくるパターンです。
この2つのパターンで、深さを同じにしたときに、学習精度に差はでるのだろうか?というのが今回の「素朴な疑問」です。
説明の便宜上、上記の図をベースに左側のパターン(Covlution2つ+MaxPooling1つ)と右側のパターン(Convolution1:MaxPooling1)とよびます。
右側のパターン
ニューラルネットワークコンソールを起動します。
赤枠の、Convolution+ReLUのレイヤーが一段のパターンです。
実は、上記の右側の1層だけのパターンは、すでに別記事でやってます。
なので、その時のプロジェクトを開くか、上記記事を参考にやってみてください。
その時の結果として精度(Accuracy)は、「98,4%」でした。
これが比較の基準値にします。
左側のパターン
今度は左側です。
一から作ってもよいですが、右側パターンにあわせて、以下のサンプルプロジェクトを開いて別名に保存したものを加工してやってみます。
inputとAffineの間をあけて、間の線を消します。
それで、以下の順番にレイヤーをドロップしていきます。
- convolution
- ReLU
- convolution
- ReLU
- MaxPooling
その間をShiftキーを押しながらクリックして、線をつなぎます。
この状態で上書き保存して、学習をします。
inputデータの量は増やしていないですが、Covolutionの層が増えているので、処理時間はそれなりにかかるようになります。
開始ボタンを押してから、シャワーをゆっくり浴びて帰ってくるくらいの時間は待つつもりでどうぞ。
学習結果はこんな感じです。
評価結果は、98,6%。
基準値が、98,4%ですから、微妙な改善です。
まあ、誤差みたいなもので、ほぼ同じだと思ってよさそうです。
次は右のパターンを2層にしてみる
じゃあ、次は右のパターンを2層にしてみます。
同じ「Convolution」+「ReLU」2つでも、Poolingを間にもうひとつ挟む方法に変えてみるわけですから、1つ目のReLUと2つ目のConvolutionの間に「MaxPooling」を挟めばいいですね。
- convolution
- ReLU
- MaxPooling
- convolution
- ReLU
- MaxPooling
こんな感じです。
この学習結果グラフはこうです。
それで正確さは・・99%になりました。
これは改善したといえるかもしれません。
今回はMNIST(手書き文字)画像の4と9の2値分類ですから、この程度の浅いCNNでもちょっとした工夫で改善するみたいです。
ConvolutionとPoolingの役割をイメージできるともっといいな
基本的で、ごく浅いCNNを3パターンほど組んでみました。
ごくシンプルなのに、MNISTデータ位ならかなりの確率で識別できるのが凄いです。
実際のところ。
ConvolutionとMaxPoolingの各レイヤーが何故画像データに対して、このように効果があるのかのイメージができると、もう少しバリエーションを考えられるようになったりもします。
その辺については、以下の4回にまとめてますので、よければ合わせて読んでもらえるといいかな・・と思います。
おまけ:対象データ数を増やすやり方
上記では、inputデータを「4」と「9」の2つに絞って実行しています。
学習時間を短くしたかったので。
ですが、当然のことながら、inputデータを、フルで「0」から「9」までの10パターンを使うようにもできます。
やってみたい方のために変更方法だけ確認しておきます。
10パターンのMNISTデータに変更する
プロジェクトを開いた状態で「DATASET」を選びます。
左側の「training」を選んで、OpenDataset(上図 赤丸部分)を押します。
表示された選択肢から「minist_training.csv」を選びます。
同じようにして、validationを左側で選んで、今度は「minist_test.csv」を選択しておきます。
選択し終わったら、忘れずに上書き保存をしておきます。
これで、テストデータはMNIST(手書き数字画像)のフルセット(10パターン)が使えるようになります。
EDITタブで10パターン対応に変更
もし、inputをフルセットに変更した場合は、EDITタブに戻って、今度は「BinaryCrossEntropy」を選択して、Deleteキーで消し、と「SoftmaxCrossEntropy」をドロップして、Shiftキー+クリックで線でつなぐようにします。
inputが2値(4か9のどちらか)ではなく、10値(0から10のどれか)になったので、BinaryCrossEntropyのままだと、結果が無茶苦茶になるからです。
10パターンにあわせて途中のレイヤーのoutputサイズも変更
Inputをフルにして、「SoftmaxCrossEntropy」に変更した場合、その前をつなぐ全結合層(Affine)のoutputサイズも変更が必要になります。
このへんは、言葉の説明は難しいので、CNN1層だけの場合を元に、変更例を簡単に説明してみます。
MNISTは1,28,28サイズ(Affineで受けるなら、1×28×28=784)です。
Convoolution→MaxPoolingをへて、16,12,12に変換されているわけです。
なので、続くAffineには「16×12×12 = 2304」ではいってきます。
SoftMaxは、0~9の10個の数字の各々にたいして、0である確率はXX%、1である確率は・・みたいな感じで求めて、一番確率の高い数字を回答として出力するとイメージするとわかりやすいです。
つまり、10個に集約する必要があるということですね。
そこに持っていくのにあたり、いきなり2304→10ではなくて、段階的に次元をへらす方が結果的には良さげなのですね。
そのため、上記例では一旦最初のAffineのOutputで、144(1×12×12)にして、SoftMaxの入力にする前に、もうひとつAffineをはさんで、144→10に次元を減らしていってます。
この例は、必ず、こうしなければいけないというものではありません。
とっかかりとして、まあ、ありがち・・程度に見てもらえればと思います。
ちなみに、試しに学習・評価をバッチサイズ64、MAXエポック 30で簡単にやってみたところ、Accuracyが98.7%程度いけたので、そう悪くはないと思います。
時間に余裕のある方は、一度試行錯誤を試してみてもよいかもしれません。
2017/12/01追加
Version1.10でアイコンデザインが変更になった主な部分はここです。
見たら、だいたいわかりますよね。