【Chainerで画像識別3】MNISTは前処理ないから楽?いやいやNN層はしっかり深いんで解説。

【Chainerで画像識別3】MNISTは前処理ないから楽?いやいやNN層はしっかり深いんで解説。

次郎系は食ったことがありませんが
コールはヤサイなし、ニンニクアブラカラメで間違いないでしょう。

 

ども、アイーンです。

 

今日はMNIST(エムニスト)を使った画像認識の続きをやってきましょう。

画像の前処理は終わりましたね。

といっても、もともとtrainとtestでデータが分かれてたため、なんにもしておりません。

らく~♪

 

それではここからニューラルネットワークの作成と、Trainer(トレーナー)を使った訓練のコードを書いていきます。

 

それではいってみよ~。

 

画像識別ニューラルネットワークの作成

今回も、コードが短いので全文を載せておきます。

はいドン!

import chainer
import chainer.links as L
import chainer.functions as F
from chainer import Variable,Chain,optimizers,serializers,datasets

import numpy as np
import matplotlib.pyplot as plt

from chainer.datasets import tuple_dataset
from chainer import training, iterators
from chainer.training import extensions


#データの読み込み
mnist_data = datasets.get_mnist(ndim=3)
train_data = mnist_data[0]
test_data = mnist_data[1]

class Gazou(Chain):
    def __init__(self):
        super(Gazou,self).__init__(
            cnn1 = L.Convolution2D(1,15,5),
            cnn2 = L.Convolution2D(15,40,5),
            l1 = L.Linear(640,400),
            l2 = L.Linear(400,10),
        )

    def __call__(self, x, t):
        return F.softmax_cross_entropy(self.predict(x), t)

    def predict(self,x):
        h1 = F.max_pooling_2d(F.relu(self.cnn1(x)), 2)
        h2 = F.max_pooling_2d(F.relu(self.cnn2(h1)), 2)
        h3 = F.dropout(F.relu(self.l1(h2)))
        return self.l2(h3)

model = Gazou()
opt = optimizers.Adam()
opt.setup(model)

iterator = iterators.SerialIterator(train_data,500)
updater = training.StandardUpdater(iterator, opt)
trainer = training.Trainer(updater,(20, "epoch"))
trainer.extend(extensions.ProgressBar())
trainer.run()

serializers.save_npz("tegaki.npz", model)

 

今回は、畳み込み層とプーリング層を2回通し、最終的に学習済みのデータを作成するところまで行います。

 

畳み込み層の詳細

画像識別の基礎は、「畳み込み層」と「プーリング層」の知識が必要でしたね。
忘れた方は、ぜひ前回の記事を確認してみてください。

cnn1 = L.Convolution2D(1,15,5)というコードは、2次元の画像を畳み込む層です。

(1、15、5)は左から(チャネル数、フィルタの枚数、フィルタのサイズ)になります。

チャネル数は1(グレースケール)です。

フィルタの枚数は15枚
これにより1枚の画像データに特徴マップが15枚重なった状態になります。

cnn2でチャネル数が15になっているのは

cnn1により1つの画像データに「15枚の画像が層になって1つの画像データ」状態だからです。ここポイントね。

フィルタのサイズは5
これで各フィルタのサイズ(ピクセル数)を5×5に設定します。

 

ここで畳み込まれた入力が、次のプーリング層へ入力されます。

 

プーリング層の詳細

h1 = F.max_pooling_2d(F.relu(self.cnn1(x)), 2)とは、畳み込み層からきた特徴マップをプーリングする層です。

 

ReLU関数は、0以下は0、0より大きければ入力値のままという活性化関数でした。

(F.relu(self.cnn1(x)), 2)と書いてcnn1から来た特徴マップを入力します。

後ろの2という設定は、プーリングするサイズです。
これにより、2×2の範囲で最大値を探します。

 

画像のサイズ変化について

こっから。問題はこっからなんです。

前回の記事で、「畳み込みやプーリングを行うと、画像のサイズが変化する」と書きました。

画像のサイズが変わる。つまり、入力値が変わる。

これまで、L.Linear(入力値、出力値)とニューラルネットワークの設定を行ってきました。

入力のサイズが分からないと、入力値の設定が出来ません。

 

ガチやべぇじゃん。

ゴリラに哀れまれる覚えはありません。

しかし、ちまちま紙に「え~入力が28×28だから、フィルタサイズが4×4の場合・・・」

やってられるか。

 

そんなあなたに朗報です。

実は、L.Linear(None、出力値)と書けば、入力値を柔軟に受け止めてくれるんです。

まるで母の愛のようです。

 

しかし、今回は分かりやすく解説するため

数値で記載してみました。

 

今回のコードでは、入力データは以下の順で層に入っていきます。
この右側に、今回のコードによる画像のサイズ変化を書いてみますので
概要をつかむための参考にしてください。

畳み込みのフィルタサイズは5×5で
プーリングのサイズは2×2です。

入力(1枚、28×28)

畳み込み層1(15枚、24×24)

プーリング層1(15枚、12×12)

畳み込み層2(40枚、8×8)

プーリング層2(40枚、4×4)

ニューラルネットワーク
(40×4×4で入力は640)

出力

このように変化します。

 

ドロップアウトについては、また後日しっかり解説しますが

簡単にご説明しますと

ドロップアウトの層を通すと、ある一回の更新時に

ニューラルネットワークのノードをいくつか無効にして更新を行います。

次の更新では、別のノードを無効化するという手順を繰り返し

過学習(訓練データを学習したが、未知のデータに対応できない状態)を防ぎます。

 

今度じっくり解説します。

 

まとめ

いかがでしたか?

便利ですね~Chainer

畳み込みとプーリングを実際にコードで見ると

ずいぶん複雑な内容なのに、スッキリと書かれているように見えます。

…でも実行したら、終了まで22分って出たぞ。

 

次回は、学習済みのデータを使って訓練が成功しているのかを確認してみましょう。

 

これで貴方の肩書は「サイズに理解のある人」です。

・・・最近太ってきたなぁ。

 

それでは。