sagantaf

メモレベルの技術記事を書くブログ。

CNN(Convolutional Neural Network)を理解する

この記事の目的

CNNの理論を理解し、Kerasで実装できるようにするために、理論部分をまとめた記事。


0. 通常のニューラルネットワークの問題

通常のニューラルネットワークにある全結合層では2次元以上のデータを1次元(1列のデータ)に並べ替えて入力している。

そのため、すべての数値を同じものと捉えて学習していた。 この場合、2次元以上→1次元、とデータの次元数を落としているので、数値同士の位置情報が無視されてしまい、学習の精度が上がらない。

f:id:sagantaf:20190526144525p:plain
次元を落として入力するため位置情報を学習できない

そのため、データの位置情報を無視することなく、画像だったら画像の形のまま学習できるように、畳み込みニューラルネットワーク Convolutional Neural Network(以下、CNN)が開発された。


1. CNNの基本

基本的には、データの特徴を畳み込み層であぶり出し、プーリング層で他のデータでも使えるようにぼやかすことを繰り返す。

CNNではConvolutional層Pooling層の2つが一般的に使われる。

Convolutional層とPooling層を適用した後、Affine層を通し、結果を出力する。 例えば下記のような形になる。

f:id:sagantaf:20190526144801p:plain
CNNのネットワーク例

また、後述するDropout層、BatchNormalization層といったレイヤーも使われる。


2. 畳み込み層(Convolutional層)

Convolutional層では、入力データにフィルタ(=カーネルとも呼ばれる)を利用して畳み込み演算を行う。

f:id:sagantaf:20190526144951p:plain
畳み込み演算の流れ

上図の緑色の部分を重ね合わせ、乗算し、全て合計して計算する。

入力画像とフィルタが似たような配置だった場合、乗算によってより数値が高くなり、画像の特徴として抽出できる仕組み。様々なフィルタを適用することで、各画像の様々な場所の特徴を捉えたフィルタ群が完成していく。

畳み込みの処理をしていくにあたっては、

  • フィルタのサイズをどうするか
  • どうフィルタを適用していくか(ストライド
  • 出力サイズをどうするか(パディング)

を決めることになる。

フィルタのサイズをどうするか

フィルタのサイズに厳密な決まりごとはないが、奇数かつ小さいサイズの方が精度が出るため、3×3や5×5がよく利用される。

詳しい解説は下記に記載されている。

Deciding optimal filter size for CNNs - Towards Data Science

どうフィルタを適用していくか(ストライド

通常は入力画像に対してフィルタを1つずつずらしながら畳み込み演算を実施するが、ずらす数を設定することもできる。このフィルタを適用する位置の間隔のことをストライドと呼ぶ。

ストライドを1から2や3に増やすことで、大雑把に畳み込み演算することになるため、出力サイズが小さくなり、処理が短時間になる一方で、画像の特徴を取りこぼす可能性がある。そのため畳み込み層ではストライドはあまり使われない。 よっぽどサイズが大きい画像に特徴抽出したい対象が大きく写っている場合は、ストライドを適用しても特徴を失うことなく効率的に処理ができる。

逆に、後述するPooling層ではストライドは積極的に利用される。

出力サイズをどうするか(パディング)

入力データの周りに固定データを合わせることで入力のサイズを大きくし、出力サイズを調整することができる。 これをパディングと呼び、画像のはじの特徴も捉えることができる、出力サイズが小さくなって演算ができなくなることを避けられる、といったメリットがある。 周辺を0で埋める「ゼロパディング」がよく利用されるが、この場合、周辺が暗くなってしまう。それを回避するために、周辺の画素数をそのまま外挿するパディング方法なども存在する。

データ形状の変化

入力時のデータ形状は [縦×横×チャネル数(色の数)] になる。

28×28のサイズのRGB画像であれば、 28 × 28 × 3 になる。

この入力画像に適用するConvolitional層として、
 3×3のフィルタを32枚、ストライド1、パディング1
を設定した場合、畳み込み処理後のデータのサイズは 28 × 28 × 32 となる。

つまり、畳み込み層の出力は、 [縦×横×フィルタ数] となる。

ただし、フィルタサイズ、ストライド、パディングの設定値によっては計算ができない場合もあるため、注意する。

たとrば、10*10の入力画像に対してフィルタが3*3でストライドを3にした場合だと割り切れないため、場合によってはエラーになる(ライブラリによっては自動で可能な部分だけ計算してくれるものもある)。

畳み込みまとめ

畳み込み層は画像の特徴を抽出するためのレイヤーになっている。そのため、畳み込み層を2つ連続で続けるなど、レイヤーを増やすと、1つ目に適用した結果に対して2回目の畳み込みをするため、より小さい特徴を捉えられるようになる。

ネットワークを深くして精度が上がった有名なネットワークもある(AlexNet,VGGなど)。

ただし、深くしすぎると勾配消失問題が起きたり、過学習したりするという別の問題が発生するため、別途対処が必要になる。


3. 活性化関数について

畳み込み後の活性化関数は、勾配消失問題に対応するため ReLU が使われることが多い。

ReLUは正の値をそのまま出力し、マイナスの値は0にしてしまう関数。 畳み込み処理後のデータは特徴が正の大きな値となって現れてくる。そもそもマイナスの値である部分は特徴としてフィルタリングされなかった部分であるため、0にしてしまっても問題ない。


4. プーリング層(Pooling層)

畳み込み層で浮き出てきた特徴をぼやけさせ、他の似たような特徴と同じとみなして学習させることを目的としている。

そうすることで同じものが写った別の画像でも特徴を検知できるようになる。(汎化能力アップ)

同様の理屈で、プーリング層の出力には活性化関数を適用しない。活性化関数を使うと特徴を際立たせることになってしまい、ぼやかした意味がなくなってしまう。

プーリングの手法は、最大プーリングや平均プーリングが代表的。ただし、効果の違いなどまだ不明なことも残されている。

また畳み込み層と同じくストライドを設定して計算することもできる。ぼやかす機能として役に立つため、畳み込み層とは違いストライドを2以上に設定することが多い。


5. CNNの特徴

CNNの特徴は下記2つある。

・局所受容野(local receptive field):
  全結合とは違い、特的のユニット同士のみが結合されるため、局所的な特徴を学習できる。また、データの形状も特徴として捉えることができる。

・重み共有:
  1種類の画像(縦-横-チャネル)に対しては同一の重みとバイアスを共有し適用するため、似た特徴を捉えやすい。どこにあってもきちんと特徴を抽出できるようになる。また、パラメタが減り全結合層よりも計算時間が短縮できる。どちらも学習効率が良くなる効果が得られる。


6. そのほか利用される層

Dropout層

学習に必要なエポック数が増えるが、過学習を抑制できる。

BatchNormalization層

平均0分散1に正規化する層。正規化によって、

  • 学習が早くなる
  • 初期値にあまり依存しない=初期値にロバスト
  • 過学習を抑制する(Dropoutなどの必要性を減らす)

といった利点が生まれる。

また、Dropout層と併用するときには注意する。逆効果になる可能性がある。

参考ページ

Understanding the Disharmony between Dropout and Batch Normalization by Variance Shift · Issue #608 · arXivTimes/arXivTimes · GitHub

このBatchNormalizationは、データ数が多くパラメタが少ないような過学習しにくいモデルの場合は不要。(逆にない時よりも精度が悪くなる可能性がある)


7. CNNの設計

捉えたい特徴を確認し、最初は基本的な形からスタートする。

その後、少しずつ変更してみる。

ネットワークを深くしたり、Augmentationをしたり、Dropout層やBatchNormalization層を追加したり。

下記のような記事を参考に過去の精度の高いネットワークで試すのもあり。

畳み込みニューラルネットワーク(CNN)の設計(一) - Qiita

畳み込みニューラルネットワークの高精度化と高速化


8. CNNの精度向上のために考えること

まずはデータを疑う。データがきちんと整っていないと、どんなにアーキテクチャーやハイパラメタを調整しても精度は上がらない。

入力データの問題

  • 画像サイズは一定か
  • 画像サイズに対して対象が小さすぎないか(小さすぎると特徴が捉えられない)
  • 反射したりして特徴が複雑になっている画像ではないか(パターンが捉えられない=もっと画像が必要になる)

アーキテクチャの問題

  • ぼやかすタイミングがあっているか?畳み込みでstrideしていないか?
  • 過学習していないか?しているのであれば画像の枚数を増やす、Dropoutする
  • 逆に過学習を避けようとしてDropoutやBatchNormalizationをつけすぎていないか(DropoutをConv層はやめてDense層だけにしてみるとか)
  • DropoutとBatchNormalizationを併用していないか
  • レイヤーが少ない方が精度が高くないか?(勾配爆発消失)

上記の問題を考えてみた上で、

  • ネットワークを深くする  畳み込み-ReLU-Pooling のセットを増やしてみる。

  • Augumentationする  画像を回転させたり、拡大させたり、反転させたりして同じ画像を複数枚に増やす。

を実施してみることで精度が上がることもある。


参考にした書籍やサイト

直感 Deep Learning ―Python×Kerasでアイデアを形にするレシピ

直感 Deep Learning ―Python×Kerasでアイデアを形にするレシピ

深層学習 (機械学習プロフェッショナルシリーズ)

深層学習 (機械学習プロフェッショナルシリーズ)

TensorFlowではじめるDeepLearning実装入門 (impress top gear)

TensorFlowではじめるDeepLearning実装入門 (impress top gear)

PythonとKerasによるディープラーニング

PythonとKerasによるディープラーニング

定番のConvolutional Neural Networkをゼロから理解する - DeepAge

畳み込みニューラルネットワークの仕組み | POSTD

たたみ込みの理解 - Qiita

畳み込みニューラルネットワークの仕組み | POSTD



なお、時系列データに対する深層学習のアルゴリズムであるRNNおよびLSTMのまとめは下記にあります。

sagantaf.hatenablog.com