畳み込みニューラルネットワークでやっていることの理解（VGG 16を例に）


#1.CNN（Convolutional Neural Network:畳み込みニューラルネットワーク）とは

画像の判別では、畳み込みニューラルネットワーク（CNN:Convolutional Neural Network）が高い精度を出すことが知られています。さまざまな解説書やウェブで解説をされていますが、ここでは、CNNの代表的なアルゴリズムVGG16を例に、CNNの仕組みを解説したいと思います。なお、内容の正誤や本稿の利用については、自己責任でお願いします。

まず、人の目で画像を見て、それは○○である、と判断ができるのは、まさに人間の脳の学習の成果ですが、CNNを使うとは、それをコンピュータ、もっと具体的には、ニューラルネットワークで規定されたアルゴリズムによって、計算をすることで判断する、ということです。

ここで、下の図のような入力画像から答えを導き出すアルゴリズムを、たくさんの入力画像と答えのデータセットを使って決めていく作業がまさに「学習」になります。そのフレームワークの１つとしてよく使われているのがCNNであるとも言えます。今回は、CNNの中でもVGG16というモデルを例に、解説を進めていきたいと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280313/0a20221e-eb47-152a-ea40-bc2538ac24af.png)


#2.VGG16 アルゴリズムの解説

ここでは、VGG16の構造について解説しておきたいと思います。VGG16は、２２４×２２４×３（RGB）のサイズの画像を入力し、その後に、①畳み込み層（Convolution層）、②プーリング層、全結合層から構成されるネットワークを経た後、最後にソフトマックス関数をかけて答えを導くものとなっています。

①畳み込み層では、入力画像とフィルタ（検出器）の畳み込み演算が行われます。また、全結合層でも、重み演算が行われることになります（そこでも、重みがパラメータとして掛けられることになります）。学習では、こうしたフィルタのパラメータや、重みのパラメータについて、たくさんのデータを基に決めていく計算が行われることになります。その計算によって得られたパラメータを適用すれば、入力画像の内容を判別するためのアルゴリズムが出来上がる、というわけです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280313/da1a7e39-84fc-97ea-2bab-4d320baae29e.png)

さて、全結合層の計算はさまざまなテキストやウェブの解説で紹介されています。一方、特にVGG16の畳み込みやプーリングの具体的な演算方法について丁寧な解説がされているコンテンツが少ないように思います。最近では便利なモジュールがありますので、このあたりのことをきちんと理解しなくても、ニューラルネットワークを使うことができます。ただ、応用のことを考えると、アルゴリズムの中身を理解することは重要だと思いますので、そこを中心に解説したいと思います。

#3.Convolution+ReLU層でやっていること（①を例に）

畳み込み演算では、「元画像の行列データ」と「フィルタ（検出器）の行列データ」について、
A:フィルタのサイズと同じサイズで区切った元画像の一部の行列
B:フィルタ（検出器）の行列
のそれぞれ同じ位置にある数字を掛け算して全部足し上げた数字を計算していきます。

これを１つずつずらしながら計算していくわけです。このずらし幅は「ストライド」と呼ばれます。
ただし、入力画像をそのままでこの計算をやってしまうと、サイズが小さくなってしまうので、この計算をスタートする前に「パディング」という作業（入力画像の周囲に「０」のデータを置く作業）を行います。
VGG16の構造の①に相当する部分で具体的にどのような計算が行われているか、説明をした図が以下になりますので参考にしてみてください。

【①の計算内容（全体）】
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280313/4c97f295-6c95-9b6c-700c-482650867486.png)

【①の計算内容（Aと２０番目のフィルタの計算例）】
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280313/30aed948-f719-de48-52cd-cdefbf04c32b.png)

#4.プーリング層でやっていること（②を例に）

プーリング層は、単に次元を減らすだけの計算であり、畳み込み層と違って学習するパラメータがあるわけではありません。また、チャネルごとに独立して計算が行われるため、入力データと出力データのチャネル数は変化しません。以下の例だと、６４のチャネルがありますが、これがプーリング演算のみによって変化することはありません。ただし、VGG１６では、例えば、プーリング後の１１２×１１２×６４を割り増して１１２×１１２×１２８（６４×２）としています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280313/5f90fbc5-31a4-ad12-5c1d-e5aa67cfbece.png)

#5. 学習について

VGG16のパラメータを決めていく作業（学習）について触れておきたいと思います。ニューラルネットワークの学習の目的は、入力画像と答えの間のずれ（専門用語では、損失関数）をできるだけ小さくするパラメータを見つけることにあります。この最適なパラメータを見つける問題を解くことを最適化といい、人間では到底計算をすることができないため、コンピュータに頼ることになります。

さて、この最適化にはいくつかの手法があります。モジュールを使う場合には、最適化手法（SGD、AdaGrad、Adam）と学習率を指定するだけで良いので、実用を優先される方は、あまり関心を持っていないかもしれません。もし関心がある方は、既にネット上にもさまざまな解説があるので、ぜひ参照をしてみてください。

また、学習の際には、過学習の問題が発生しがちです。パラメータが大量にあることでハマってしまって柔軟性がないアルゴリズムになってしまうのです。訓練データが少ない場合にもこの問題は起こります。過学習が発生してしまった場合には、Weight Decay　や　Dropoutといった手法を試されることをオススメします。

#6. 転移学習とは

ここまで、VGG16を事例にCNNの仕組みについて解説をしましたが、膨大な学習データを用意して、ゼロからCNNの学習をするのは大変コストがかかります。特にCNNの最初の方の畳み込み層については、画像の特徴を抽出するプロセスですから、わざわざゼロから学習してフィルタを決定しなくとも、既に膨大な画像を使って学習したものを転用することで十分であることが多いのです。このため、実践的な学習では、こうした転用を行う「転移学習」という手法を使うことが一般的です。

転移学習では、CNNの最初の方のレイヤは学習済みモデルとそこで既に決められたパラメータを採用し、後半のところはレイヤを追加して（追加したレイヤは当然パラメータは決められていない）、追加したレイヤのパラメータを学習して決めることになります。
ただ、このやり方だと十分な精度が出ないこともあります。そうした場合には、「ファインチューニング」といって、学習済みモデルのパラメータの「更新」を含めた形で学習するやり方が使われることもあります。当然、単なる転移学習よりも、ファインチューニングつきの転移学習の方が学習に要する時間（計算量）は大きくなります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280313/e2bfd3b5-fa14-b4df-1aa9-143095e57208.png)


#7. 今後の展開

今回はCNNについて、VGG16を使った解説に重点を置きました。今後、Python-Kerasによる実装についてご紹介したいと思います。

#8. 参考

以下、参考になる文献などについてご紹介します。

①VGG16の公式論文

https://arxiv.org/abs/1409.1556

②CNNの解説。初心者向けで相当わかりやすい。（英語）

https://www.youtube.com/watch?v=AjtX1N_VT9E&t=2306s

③VGG16の構造解説動画（英語）

https://www.youtube.com/watch?v=mRVTKrbRYi0

（書籍）

https://www.oreilly.co.jp/books/9784873117584/