CNNの有名なモデルをTensorFlowで実装する

今日はCNNについて勉強したので、自分用も兼ねて、tensorflowで実装したものを記事にします。

# CNN
## CNNとは
　CNNとは、主に画像認識や画像分類などのタスクで用いられるニューラルネットワークのこと。畳み込み層とプーリング層、全結合層という層を持つのが特徴。
　Convolutional Neural Networkの略で、日本語だと畳み込みニューラルネットワークと言う。
## CNNの実装
シンプルなCNNを実装します。
tensorflowにConv2Dがあるので使います。
```py
import tensorflow as tf

model = tf.keras.models.Sequential([
  tf.keras.layers.Conv2D(32, (3,3), activation='relu', input_shape=(28,28,1)),
  tf.keras.layers.MaxPooling2D((2,2)),
  tf.keras.layers.Flatten(),
  tf.keras.layers.Dense(10, activation='softmax')
])
```

# AlexNet
## AlexNetとは
　AlexNetとは、CNNの一つで、2012年にAIの画像認識の大会で2位に大差をつけて優勝したモデル。
　現在のAIブーム/ディープラーニングブームのきっかけになった。
## 構造
![AlexNet](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116479/305d7af1-1877-c683-115c-f90e2f4028b8.png)
出典：https://www.researchgate.net/figure/An-illustration-of-the-architecture-of-AlexNet-CNN-14_fig4_312188377

## 実装
```py
def alexet(input_shape=(227, 227, 3), num_classes=1000):
    model = models.Sequential()

    model.add(layers.Conv2D(96, (11, 11), strides=(4, 4), activation='relu', input_shape=input_shape, padding="valid"))
    model.add(layers.BatchNormalization())
    model.add(layers.MaxPooling2D(pool_size=(3, 3), strides=(2, 2), padding="valid"))

    model.add(layers.Conv2D(256, (5, 5), strides=(1, 1), activation='relu', padding="same"))
    model.add(layers.BatchNormalization())
    model.add(layers.MaxPooling2D(pool_size=(3, 3), strides=(2, 2), padding="valid"))

    model.add(layers.Conv2D(384, (3, 3), strides=(1, 1), activation='relu', padding="same"))

    model.add(layers.Conv2D(384, (3, 3), strides=(1, 1), activation='relu', padding="same"))

    model.add(layers.Conv2D(256, (3, 3), strides=(1, 1), activation='relu', padding="same"))
    model.add(layers.MaxPooling2D(pool_size=(3, 3), strides=(2, 2), padding="valid"))

    model.add(layers.Flatten())

    model.add(layers.Dense(4096, activation='relu'))
    model.add(layers.Dropout(0.5))

    model.add(layers.Dense(4096, activation='relu'))
    model.add(layers.Dropout(0.5))

    model.add(layers.Dense(num_classes, activation='softmax'))

    return model
```

# VGG16
VGG16は、16層からなるモデル。ILSVRC2014で準優勝。
## 構造
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116479/b81db5d4-5de7-50f9-1e9e-6f018d0c1224.png)
出典：http://www.sanko-shoko.net/note.php?id=pyk1

```py
def vgg16(input_shape=(224, 224, 3), num_classes=1000):
    model = models.Sequential()

    model.add(layers.Conv2D(64, (3, 3), activation='relu', padding='same', input_shape=input_shape))
    model.add(layers.Conv2D(64, (3, 3), activation='relu', padding='same'))
    model.add(layers.MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))


    model.add(layers.Conv2D(128, (3, 3), activation='relu', padding='same'))
    model.add(layers.Conv2D(128, (3, 3), activation='relu', padding='same'))
    model.add(layers.MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))


    model.add(layers.Conv2D(256, (3, 3), activation='relu', padding='same'))
    model.add(layers.Conv2D(256, (3, 3), activation='relu', padding='same'))
    model.add(layers.Conv2D(256, (3, 3), activation='relu', padding='same'))
    model.add(layers.MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))


    model.add(layers.Conv2D(512, (3, 3), activation='relu', padding='same'))
    model.add(layers.Conv2D(512, (3, 3), activation='relu', padding='same'))
    model.add(layers.Conv2D(512, (3, 3), activation='relu', padding='same'))
    model.add(layers.MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))


    model.add(layers.Conv2D(512, (3, 3), activation='relu', padding='same'))
    model.add(layers.Conv2D(512, (3, 3), activation='relu', padding='same'))
    model.add(layers.Conv2D(512, (3, 3), activation='relu', padding='same'))
    model.add(layers.MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))


    model.add(layers.Flatten())
    model.add(layers.Dense(4096, activation='relu'))
    model.add(layers.Dropout(0.5))
    model.add(layers.Dense(4096, activation='relu'))
    model.add(layers.Dropout(0.5))

    model.add(layers.Dense(num_classes, activation='softmax'))

    return model

```

# ResNet
ILSVRC2015優勝
通常の畳み込みネットワークにショートカット接続を加えた構造
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116479/f597a6d0-03c3-a938-c3fb-2e22e3a6f9c7.png)
出典：https://arxiv.org/abs/1512.03385


## 実装
学習済みのモデルが公開されているのでそれを使います。楽なので嬉しい
```py
import tensorflow as tf
from tensorflow.keras.applications.resnet50 import ResNet50

# 学習済みの重みを持つ ResNet50 モデルを作成
model = ResNet50(weights='imagenet')

model.summary()
```

ショートカット接続も実装します。
最初全然分からなくいて、はじめて意味が分かった時はうれしかったです。
```py
def identity_block(input_tensor, kernel_size, filters):
    filters1, filters2, filters3 = filters

    x = layers.Conv2D(filters1, (1, 1))(input_tensor)
    x = layers.BatchNormalization()(x)
    x = layers.Activation('relu')(x)

    x = layers.Conv2D(filters2, kernel_size, padding='same')(x)
    x = layers.BatchNormalization()(x)
    x = layers.Activation('relu')(x)

    x = layers.Conv2D(filters3, (1, 1))(x)
    x = layers.BatchNormalization()(x)

    # ショートカット接続 
    x = layers.add([x, input_tensor])
    x = layers.Activation('relu')(x)

    return x
```
肝は
```
    # ショートカット接続 
    x = layers.add([x, input_tensor])
```
の部分です。
ここで現在の残差ブロックの特徴マップxにショートカット接続の入力input_tenosrが加算されます。

# EfficientNet
Googleが開発したCNN。
モデル最適化を行うことで、計算効率と高い精度を同時に実現している。
## 実装
これも学習済みのモデルが公開されているので使います。うれし。
正直このあたりは、構造を見ても自分には理解できないです。
```py
import tensorflow as tf
from tensorflow.keras.applications import EfficientNetB0

model = EfficientNetB0(weights='imagenet')

model.summary()
```