【GIF】初心者のためのCNNからバッチノーマライゼーションとその仲間たちまでの解説

# CNNからバッチノーマライゼーションとその仲間たちまでを図で解説！
ディープラーニングが流行するきっかけとなった分野は画像認識と言っても過言ではないでしょう。
実際にディープラーニング流行の火付け役となった2012年の[AlexNet](https://papers.nips.cc/paper/4824-imagenet-classification-with-deep-convolutional-neural-networks.pdf)は画像分類タスクにディープラーニングを適用させて驚異的な結果を出しました。AlexNetの論文は現時点(2019年12月現在)で **被引用数 52,655を誇るバケモノ論文** になっています。このAlexNet以降で **画像認識分野で使われている技術こそがCNN(Convolutional Neural Network)** なのです。(もちろん最強の画像認識モデル[EfficientNet](https://qiita.com/omiita/items/83643f78baabfa210ab1)(拙著の解説記事)もCNNベースです。)

![filtering.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412028/f72b4270-cd8e-b364-eedb-e6da53e18f82.gif)

このCNNの層を深くしていくことで精度を向上させていくのですが、
層を深くすればするほどCNNが逆にうまく学習してくれなくなってしまうのです。
**それを解決した技術が[バッチノーマライゼーション(Batch Normalization)](https://arxiv.org/abs/1502.03167)** (以下、バッチノーム)です。(ちなみにこの論文の被引用数は2019年12月現在で14,761でこちらもバケモノ論文。)このバッチノームは今では当たり前のように使われています。バッチノームの仲間である **レイヤーノーマライゼーションというのは[Transformer](https://qiita.com/omiita/items/07e69aef6c156d23c538)(拙著の解説記事)でも使われており、バッチノーム系はディープラーニングにとって必要不可欠な技術** になっています。

本稿では **CNNの解説から入り、バッチノームおよびその仲間たちを徹底解説** します。本記事は以下の構成です。

1. **CNNってそもそもどう動いているの？**
2. **バッチノーマライゼーションとは？**
3. **バッチノーマライゼーションの仲間たち**
4. **(オプション)なんでバッチノーマライゼーションって強いの？**
5. **まとめ**
6. **参考**

**読んで少しでも何か学べたと思えたら 「いいね」 や 「コメント」 をもらえるとこれからの励みになります！よろしくお願いします！**
(間違いなどもございましたら、ご指摘よろしくお願いします。)

## 1. CNNってそもそもどう動いているの？
まずCNNがどう動いているかについて解説します。
わかりやすさのため、以下では全て入力が白黒(グレースケール)の画像だとします。
カラー(RGB)の場合は入力画像がカラーに変わるだけで他は何も変わらないので、
グレースケールさえ理解できれば大丈夫です。

### 1.1 入力画像1枚、フィルター1枚のCNN
まずは入力画像が1枚、フィルター1枚の時を考えましょう。
左から右へと流れていく感じです。

<img width="1041" alt="1image1filter.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412028/363a18d0-2b79-2aa4-ebe8-be8ae921c4a1.png">

入力画像にフィルター(カーネルとも言われる。)がかかり、フィルター後の画像に対して活性化関数を適用することで出力の画像が得られます。これで畳み込み層(Convolution層)が出来上がります。
フィルターをかけるプロセスを見てみます。

![filtering.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412028/f72b4270-cd8e-b364-eedb-e6da53e18f82.gif)

入力画像の3x3の部分がフィルターによって1マスになります。この **フィルターをかける処理こそが「畳み込み」と言われる処理** です。
そうして **出来上がった画像は一回り小さくなっているので、パディング(padding)と言われる処理を施す** ことで元の画像サイズと同じにします。パディングは出力された画像の周りに任意の数字を埋めていく処理で、**0で埋めることが多いです。(zero padding)**

このフィルターによって得られた画像は、例えば、「元の画像よりカドの明暗がはっきりしている画像」だったり、「元の画像より境界線がはっきりしている画像」のように、画像の基本的な特徴が浮き出ている画像となっています。このフィルターをどう決めているのか、という疑問も浮かぶと思います。その **フィルターは人間でいちいち決めるのは難しいから、ニューラルネットワークに訓練データに基づいて決めてもらう** のです。

ちなみにRGBを持つカラーの場合(=チャネル数3)は、フィルターがR,G,Bチャネルそれぞれに適用され、その合計値が出力されるため結果は以下図のようにグレースケールと変わらず1つのチャネルになっています。つまり、**入力チャネル数がいくらであってもフィルター１つによって出力される画像は１つ**ということです。このようにグレーでもカラーでも出力は変わらないので、ここからはまた入力をグレースケールに戻して考えます。

<img width="822" alt="1filter1rgbimg.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412028/c4503b0d-d192-f98b-d7dc-eef48448730b.png">


### 1.2 入力画像1枚、フィルター複数枚のCNN
通常、フィルターは1つだけではなく複数個使います。(人間の画像認識を超えた[ResNet](https://qiita.com/ikeyasu/items/ea9ced2b8e0fcb3da2be)では64個や128個、512個のフィルターを1個の畳み込み層で使います。)ということで、ここではフィルターを4つ使った時にどうなるか見ましょう。

<img width="1052" alt="1imagemulti-filter.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412028/a5232e8f-4925-0b81-1b17-86b2b54a23cb.png">

1枚の画像に4つのフィルターをそれぞれかけるのでその結果が得られます。
つまり、この **4つのフィルターによって1枚の画像が4つのチャネル(channel)を持つ** ことになります。フィルター1つに対応して画像のチャネル(深さ、チャンネルとも言われる)が1つ出来上がります。

### 1.3 入力画像複数枚、フィルター1枚のCNN
また、入力画像についてですがこれも通常1枚だけでなく、複数枚を一気に処理します。この **複数枚のカタマリのことをミニバッチ** と呼び、通常バッチサイズ(1カタマリの枚数)は16枚や32枚、64枚などです。マシンの性能が上がれば上がるほどこのミニバッチの大きさは大きくすることができます。ミニバッチにフィルターを1つだけかけてみます。

<img width="966" alt="multi-image1filter.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412028/871cd0ea-930c-ecbd-fd6f-61f26cdf423d.png">


各画像にフィルターをかけて、各画像に対応した出力を得ます。
なんら難しいことはありませんね。

### 1.4 入力画像複数枚、フィルター複数枚のCNN
ということで、複数フィルターをかけた場合も考えましょう。
こちらも今まで通りで難しくはありません。

![multi-imagemulti-filter.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412028/1a02c523-a37a-f889-b8b7-57b1f05be8db.gif)


わかりやすさのために各フィルターとそれに対応した出力を赤線で引っ張ってみました。
それぞれの出力画像がフィルターの枚数に応じた4チャネルになっているだけです。
この出力が次の層の入力となります。


## 2. バッチノーマライゼーションとは？

<img width="974" alt="CNNwBN.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412028/ec8d2da1-b7e9-3687-802a-05c3b5a18e68.png">

冒頭でも畳み込み層を何段も重ねて深くすることで精度を上げていくことを述べました。実際、8層しかなかったAlexNet(2012)に対して2014年には19層のVGG-19が発表され、2015年に発表されたResNetはなんと152層。このように層が深くなるとうまく学習ができなくなります。そこで導入されたのがバッチノーマライゼーション。処理内容は、**1ミニバッチ内の全データの同一チャネルが平均0,分散1に正規化する** こと。**ミニバッチというのは1回に処理する複数画像のカタマリ** でしたね。
正規化というのは **データから全体の平均値を引いて、全体の標準偏差で割り算すること** です。

![cnnwbn_anim.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412028/e0e91981-78ff-c9e6-ea3b-eaf71c2a45c1.gif)


バッチノームを適用させる前(紫色)から各チャネルごとにバッチノームを適用させていく経過を表しています。赤色になっているところでそれぞれ平均分散を出して正規化します(緑色が適用後)。

***[注意]***
***「正規化する」≠「正規分布にする」ですので、お気をつけください。
正規化というのは単純にデータの線形変換なので、元のデータが従う分布を変えるわけではないのでご注意ください。***

それでは、実際に原論文で提唱されたバッチノームの手順を見てみましょう。
<img width="835" alt="formula.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412028/b5b9f33f-d365-2a40-bf5a-67dc7f8a7959.png">

> Ioffe, S. et al. "Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift" (2015)

3行目までは単純に正規化しているだけです。
1行目は平均、2行目は分散を取り、3行目で平均0分散1に正規化しています。ここの $\epsilon$ は分散が0の時にゼロ除算しないように設けられている非常に小さな値(=1e-3とか)です。
ただし、4行目で正規化した値に $\gamma$ をかけて $\beta$ を足しています。
これはどういう意味なのでしょうか。
平均0分散1のデータたちに対して $\gamma$ をかけて $\beta$ を足しているので、 **ミニバッチのデータ(の各チャネル)は平均 $\beta$ 、分散 $\gamma$ を新しく持つことになります**。この $\beta$ と $\gamma$ はデータで学習されるパラメータです。**これらのパラメータを設けることでバッチノームで必ず平均0分散1にするのではなく、学習にあった平均と分散に従うように自由度をもたせている** のです。

この手順を図に表したものも用意したのでご参照ください。
ミニバッチ内の一番手前のチャネルにバッチノームを適用させています。
スペースの都合上、特に一番上の画像におけるバッチノーム適用にフォーカスしています。

![bn_formula.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412028/0510477e-b304-85f0-77a2-1b9fc025e55b.gif)

## 3. バッチノーマライゼーションの仲間たち

### 3.1 バッチノームの弱点

バッチノームというのはいまや当たり前のように使われており、優れた結果を出しまくっています。ただし、**[どんな術にも弱点となる穴は必ずある](https://narutonti.com/%E3%82%A4%E3%82%BF%E3%83%81-%E5%90%8D%E8%A8%80/)、と漫画NARUTOでうちはイタチが教えてくれたようにバッチノームにも弱点があります**。それは以下の2つです。

* **バッチサイズが小さいと使えない**
  * 例えば極端な話バッチサイズが1だったら、もちろん正規化なんて無理。
  * エッジコンピュータなどリソースが限られているときはバッチサイズ大きくできないから問題になる。
* **RNNなどの時系列データに使えない**
  * RNNが時系列データに対して広く使われているのを考えると致命的！

### 3.2 バッチノームの仲間たち
上述した問題(特に1つ目)を解決するために出てきた代表的な手法が3つあります。
そちらを下図に表したので簡単に説明します。

<img width="1025" alt="BN_family.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412028/39642ee5-8d99-95b2-5fe2-ee622db7534f.png">


一番左にミニバッチ、左から2番目に本稿の主人公バッチノーマライゼーションがいます。そしてそこから、**[レイヤーノーマライゼーション](https://arxiv.org/abs/1607.06450)**、**[インスタンスノーマライゼーション](https://arxiv.org/abs/1607.08022)**、**[グループノーマライゼーション](https://arxiv.org/abs/1803.08494)** と続きます。**いずれもバッチノームと処理方法は同じで、1度に正規化する範囲が異なるだけです**。(バッチノームは、ミニバッチ内の同一チャネルごとに正規化。)
ここでミニバッチ内のそれぞれのブロックは今まで通り画像データを表しているとします。
この例ではバッチサイズ3でデータのチャネル数が4です。赤色になっている部分がノーマライゼーションを適用する際の平均と分散を計算する箇所を表しています。


いずれもバッチノームが持つ、バッチサイズに下限(通常16以上)を設けてしまうという欠点に対して提案されており、**派生手法はいずれもバッチ方向ではなく、チャネル方向に対して正規化されていることがわかります**。バッチノームのバッチサイズへの下限を克服するためにまず提案されたものが **レイヤーノーム** と **インスタンスノーム** です。**レイヤーノームは1つのデータの全チャネルに対して正規化** を行い、**インスタンスノームは1つのデータの1つのチャネルに対して正規化** を行います。そしてこれらの中間のようなものとして発表されたものが **グループノーム** で、これは **1つのデータの任意のチャネル数に対して正規化** したものです。ここまで読んでもう一度上図を見るとわかりやすいと思います。

上図においてグループノームで1グループのサイズを4に設定すれば、レイヤーノームと同じで逆に1に設定すればインスタンスノームと同じことになります。

### 3.3 一体どれを使えばいいんだ。
答えは簡単です。
<b>バッチノーム一択</b>

実はいずれの方法もバッチノームの性能を越えることができていないのですね。
**あくまでもバッチサイズが小さい時にしかバッチノームよりも良い効果を発揮しない**、ということです。ただ、それぞれ実用で使われている例がありますのでそちらを紹介してこの節を締めたいと思います。

* レイヤーノーム: RNN系や[Transformer](https://qiita.com/omiita/items/07e69aef6c156d23c538)
* インスタンスノーム: GAN系([StyleGAN](https://qiita.com/d-ogawa/items/d645509e3ccedc989680))
* グループノーム: 画像認識系(に良いらしい。([GNの原論文](https://arxiv.org/pdf/1803.08494.pdf)))

## 4.(オプション)なんでバッチノーマライゼーションって強いの？
ニューラルネットにおける勾配降下法やバックプロパゲーションなどをある程度理解していることを前提に書きましたので、よくわからなければ読み飛ばしてもらって構いません。
ここで言っていることは簡単にまとめると、以下の2点だけです。

* **バッチノームがうまくいく理由はまだわかっていない。**
* **でもどうやらバッチノームのおかげでニューラルネットにとってタスクが簡単になっているのだろう。**

ここからは上記2点についてもう少しだけ補足します。

<img width="399" alt="wedontknowyet.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412028/8ee5274d-10d6-c936-8ab1-5b4921bc54d2.png">


**バッチノームが良い理由として内部共変量シフト(= ICS, Internal Covariance Shift)の解消が原論文では言われています**。ICSとは単純に **ニューラルネットの層を過ぎる毎にその層のアウトプットの分布が変わるよ**、ということ。ニューラルネットの中を通るデータの分布が頻繁に変わってしまっては学習しづらいよね、という問題。(だと理解している。間違っていればコメントお願いします。)バッチノームはこのICSを解決しているため精度向上に寄与している、という主張が原論文によってされているわけです。ただし実際はこの主張は間違っているということがわかっています。つまり、**バッチノームによってICSは解決されない** のです。

**ではなぜバッチノームが強いのか。その理由は実はまだわかっていません。**
ただ、１つの可能性として、**バッチノームはチェックポイントとして働いている** という説明がIan Goodfellow氏([GAN](https://qiita.com/triwave33/items/1890ccc71fab6cbca87e)作った人！)によってされています。

まず、活性化関数を持たない単純なニューラルネットを考えます。
各丸が全結合層で、i 回目のイテレーションと(i+1) 回目のイテレーションを表しています。
イテレーションの定義はフィードフォワードとバックプロパゲーションの1セットです。

<img width="1092" alt="wobn.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412028/3b26a4eb-45dd-4a95-81a1-c3097233ce20.png">


**ここでm層に注目すると(i+1) 回目のイテレーションの重み $w^{i+1}_m$ は** 前(i 回目)のイテレーションのLossを使って更新されているため、**i 回目におけるm層よりも前層の重みたち(つまり、 $w_l^{i}, w_k^{i}, ...$ )に対して最適化されています** 。**ただし、** (i+1) 回目の時のフィードフォワードは $w_l^{i}, w_k^{i}, ...$ ではなく、**更新された $w_l^{i+1}, w_k^{i+1}, ...$  を使って予測値を出します**。つまり、ある重みを更新する時には、本来その前の層の重みたちがどう更新されるのかということも考慮しなければ最適な値は求められないのですが、一階微分だけを用いている勾配降下法ではこのような複雑な関係性まで考慮できません。**この複雑な関係性の救世主がバッチノームです**。

バッチノームをいれてみましょう。

<img width="1086" alt="checkpoint.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412028/f9b36d81-d4c0-e48d-24e5-7dfb1543f6ec.png">

再びm層に注目します。バッチノームにより、m層への入力値は正規化されています。m層以前の層による値がどうであろうと一旦バッチノームで調整されてm層へと入力されるのです。これはつまり、**m層の重みはもはやm層以前の全ての重みたちを考えるのではなく、直前のバッチノームのパラメータ $\gamma, \beta$ だけを考えれば良い** のです。**このことにより大量の重みたちによる複雑な関係性を考慮しなくていいため、ニューラルネットが学習しやすくなり精度や速度があがる**、ということです。これがIan Goodfellow氏によるバッチノームがうまくいく理由です。

## 5.まとめと所感
今までなんとなくバッチノームを使っていたのですが、今回調べたおかげで効果や仲間たちがわかりました。バッチノームのことを理解するために、重みの初期化や活性化関数、最適化関数の意義なども今までより深く理解することができたのでそちらも需要があればアウトプットしていきたいと思っていますのでよろしくお願いします。

**読んで少しでも何か学べたと思えたら 「いいね」 や 「コメント」 をもらえるとこれからの励みになります！よろしくお願いします！**
(間違いなどもございましたら、ご指摘よろしくお願いします。)

## 6.参考
* [Batch Normalizationとその派生の整理](https://gangango.com/2019/06/16/post-573/)
Batch Normalizationの概要とその派生たちを簡単に理解できた。だいぶ参考にしています。

* [Normalizing Activations in a Network (C2W3L04)](https://www.youtube.com/watch?v=tNIpEZLv_eg&t=8s)
(英語) Andrew Ng氏によるわかりやすいBN解説動画。数式とともに解説してくれている。

* [Intro to Optimization in Deep Learning: Busting the Myth About Batch Normalization](https://blog.paperspace.com/busting-the-myths-about-batch-normalization/)
(英語) BNがなぜ必要でなぜ有効なのかというのをわかりやすく教えてくれている。

* [An Overview of Normalization Methods in Deep Learning](https://mlexplained.com/2018/11/30/an-overview-of-normalization-methods-in-deep-learning/)
(英語) BNの派生たちを教えてくれている。

* [Understanding Batch Normalization](https://arxiv.org/abs/1806.02375)
(論文) バッチノームが内部共変量シフトを解決しているわけではないという旨が書かれている。

* [An Intuitive Explanation of Why Batch Normalization Really Works (Normalization in Deep Learning Part 1)](https://mlexplained.com/2018/01/10/an-intuitive-explanation-of-why-batch-normalization-really-works-normalization-in-deep-learning-part-1/)
(英語) バッチノームがニューラルネットのHigher-order interactionを緩和させていることが書かれている。