【深層学習】畳み込みニューラルネットの各関数の使い方を調査 [DW 3日目]


Convolutional Neural Network (CNN) とは

画像に特化したニューラルネット。通常の多層パーセプトロンが入力層、中間層、出力層から成るのに対して、CNNはそれに加えて畳み込み層、プーリング層、局所正規化層(LRN層)をもつ。

Chainer ExampleにあったAlexNet (ILSVRC2012のトップ) を見てみると、以下のようになっている。

AlexBM.pyの抜粋
# …(略)
class AlexBN(chainer.Chain):

    """Single-GPU AlexNet with LRN layers replaced by BatchNormalization."""

    insize = 227

    def __init__(self):
        super(AlexBN, self).__init__(
            conv1=L.Convolution2D(3,  96, 11, stride=4),
            bn1=L.BatchNormalization(96),
            conv2=L.Convolution2D(96, 256,  5, pad=2),
            bn2=L.BatchNormalization(256),
            conv3=L.Convolution2D(256, 384,  3, pad=1),
            conv4=L.Convolution2D(384, 384,  3, pad=1),
            conv5=L.Convolution2D(384, 256,  3, pad=1),
            fc6=L.Linear(9216, 4096),
            fc7=L.Linear(4096, 4096),
            fc8=L.Linear(4096, 1000),
        )
        self.train = True

# …(略)

5つの畳み込み層と3つの全結合層から成っている。また、論文では活性化関数ReLu、マルチGPU、LRN、プーリングが大事だと言っている。上のChainer ExampleではLRNの代わりにバッチ正規化を使っている。バッチ正規化については以下が詳しい。

畳み込み層

L.Convolution2D(3,  96, 11, stride=4)

畳み込みの計算式はいろんな参考書に書いてあるので割愛。ここでは、この関数を使えるようになることを目指す。
 まず、畳込みとは画像にフィルタをかけ変換すること。フィルタも画像と同じように画素数とチャネルという変数をもつ。画像の画素数を $N\times N$ 、チャネル数を $K$ としたとき、画像のサイズを $N\times N\times K$と書くように、フィルタのサイズも $H\times H\times K$のように書く。画像とフィルタのチャネル数は同じになる。
 画像にかけるフィルタは複数種類あっても良い。$M$ 種類のフィルタをかけると、出力画像のチャネル数は $M$ 変換される。 また、フィルタをかける際はフィルタを動かしながら画像に対して部分的にかけていくのだが、その動かしていく幅をストライド幅という。ストライド幅を大きくすると画像特徴を取りこぼしやすくなるので、小さいほうが望ましい。また、画像の縁の外側に仮想的な画素を設けることをパディングと呼ぶ。パディングを与えることで、畳み込んだ時の画像の縮小を抑えることができる。入力と同じサイズにしたい場合はパディングサイズを $H/2$ の少数切り捨てにする。
今までをまとめるとpythonL.Convolution2D()の引数は

  • 第1引数 = 入力チャネル数。 $K$のこと。
  • 第2引数 = 出力チャネル数。 $M$のこと。
  • 第3引数 = フィルタサイズ。 $H$のこと
  • 引数名stride = ストライド幅。(小さいほうが良い。入力画像サイズとの兼ね合いか?)
  • 引数名pad = パディング幅。( $H/2$ の少数切り捨てにすることが多い)

となる。入出力画像の画素数に関する指定は無い。

バッチ正規化

L.BatchNormalization(96)

引数には正規化の対象となる画像のチャネル数を与える。直前の畳込みの出力チャネル数( $M$のこと)と同じになる。

プーリング層

AlexNet.pyから抜粋
  h = self.bn1(self.conv1(x), test=not self.train)
  h = F.max_pooling_2d(F.relu(h), 3, stride=2)

畳み込み層の結果をReLuに入力した後にプーリングを行う。プーリングは、フィルタのように一定の領域に注目し、あるルールに従ってその領域の代表値を1つ出力する。これによって位置不変性を獲得できる。プーリングには色々なバリエーションがある。

  • 平均値プーリング: 領域内の値の平均をとる
  • 最大値プーリング: 領域内の最大をとる

AlexNetでは最大値プーリングを採用している。

F.max_pooling_2d()の引数をまとめると、

  • 第1引数: 入力画像
  • 第2引数: プーリング領域サイズ。領域を大きくし過ぎると精度がさがる。
  • 第3引数: ストライド幅。通常2以上にする。

こちらも、入出力の画素数については指定しない。

AlexNetを使ってみた

次の記事(執筆中)でAlexNetを使ってみた結果を書く。