Google Colab+KerasでCNNを爆速構築

## はじめに
Google ColabとKerasを用いてCNNを爆速で学習させる方法を紹介する。

CNN(畳み込みニューラルネットワーク)は画像認識に強い。機械学習の世界では「うどんといえば香川」、「画像といえばCNN」です。

用いる画像データとしては企業のデータを使うわけにもいかないし、MNISTではつまらないと思うのでここではCIFAR-10を用いてやってみることにする。

### CIFAR-10とは
約8000万枚の画像がある[80 Million Tiny Images](http://people.csail.mit.edu/torralba/tinyimages/)からサブセットとして約6万枚の画像を抽出してラベル付けしたデータセットで以下の特徴がある。

*   全部で60000枚
*   画像サイズは32ピクセルx32ピクセル
*   RGBの3チャンネルカラー画像
*   クラスラベルはairplane, automobile, bird, cat, deer, dog, frog, horse, ship, truckで10クラス
*   50000枚（各クラス5000枚）の訓練画像と10000枚（各クラス1000枚）のテスト画像に分割されている

読み方は ~~サイファーテン~~ **シィーファーテン** (参考動画: https://www.youtube.com/watch?v=XDqziNMCqH8)

## Google Colabとは
Googleが提供する数あるサービスの内、JupyterでGPUやTPUが無料で使えるサービスである。

GPUでやってみた体感としては自分のローカル環境(MacbookPro2017, 13inch, 3.3GHz Intel Core i5, メモリ16GB)と比べて約100倍近い速さで学習できる。

作ったNotebookはGoogle Driveに保存される。(Google Colab URL: https://colab.research.google.com/)

## Kerasとは
TensorFlowをラップして使いやすくした認識でいいと思う。
バックグラウンドではTensorFlowが動いている。

## CIFAR-10を見てみる
まず、CIFAR-10にどんな画像が入っているか見てみよう。
CIFAR-10データセットをインポートする。

```py
from keras.datasets import cifar10
(X_train, y_train), (X_test, y_test) = cifar10.load_data()
```

トレーニングデータの最初の30個を描写してみる。

```py
import matplotlib.pyplot as plt

# ラベルのリストを定義
cifar10_labels = [
    'airplane',
    'automobile',
    'bird',
    'cat',
    'deer',
    'dog',
    'frog',
    'horse',
    'ship',
    'truck'
]

# 描写
for index, img in enumerate(X_train[:30]):
    plt.subplot(3, 10, index + 1)
    plt.imshow(img)
    plt.axis('off')
    plt.title(cifar10_labels[y_train[index][0]])
    plt.tight_layout()

plt.show()
```

![cifar10_sample.png](https://qiita-image-store.s3.amazonaws.com/0/265344/22554293-98ba-7dbd-db3e-d2f4f783db15.png)

様々な画像データで構成されていることがわかった。
次にデータの前処理を行う。

## データ前処理
前処理として、特徴量の正規化とクラスラベルのone-hot-vector化を行う。
### 特徴量の正規化
以下のコードで正規化を行う。(RGBは0〜255の範囲のため)

```py
# 特徴量の正規化
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')
X_train /= 255.
X_test /= 255.
```

### クラスラベルのone-hot-vector化
クラスラベルは順序を持たないので、one-hot-vector化しておく。

```py
from keras.utils import np_utils

# クラスラベルのone-hot-vector化
y_train = np_utils.to_categorical(y_train, 10)
y_test = np_utils.to_categorical(y_test, 10)
```

最後にCNNモデルを構築していく。

## CNNの構築
レイヤー構造を、(畳み込み層×2 + Maxプーリング層 + ドロップアウト)×2 + 全結合層として以下のように構築していく。

```py
# 必要なものをimport
from keras.models import Sequential
from keras.layers import Conv2D
from keras.layers import MaxPool2D
from keras.optimizers import Adam

from keras.layers.core import Dense, Activation, Dropout, Flatten
from tensorflow.python.keras.callbacks import TensorBoard

# モデルを定義
model=Sequential()

# 層を追加していく
model.add(Conv2D(32,(3,3),padding='same',input_shape=(32,32,3)))
model.add(Activation('relu'))
model.add(Conv2D(32,(3,3),padding='same'))
model.add(Activation('relu'))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Dropout(0.25))

model.add(Conv2D(64,(3,3),padding='same'))
model.add(Activation('relu'))
model.add(Conv2D(64,(3,3),padding='same'))
model.add(Activation('relu'))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Dropout(0.25))

model.add(Flatten()) # 平坦化
model.add(Dense(512))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(10,activation='softmax'))

# コンパイル
model.compile(optimizer='adam',loss='categorical_crossentropy',metrics=['accuracy'])

# TensorBoardで結果を見るためのインスタンス化
tsb = TensorBoard(log_dir='./logs')

# 学習
history = model.fit(
    X_train,
    y_train,
    batch_size=32,
    epochs=20,
    validation_split=0.2,
    callbacks=[tsb]
)
```

## TensorBoardで学習結果を確認してみる
ちゃんと学習できているかTensorBoardを用いて確認してみます。

```shell
$ tensorboard --logdir=./logs/
```

で、TensorBoardを起動し`localhost:6006`にアクセス。

<img width="422" alt="スクリーンショット 2018-12-10 23.20.51.png" src="https://qiita-image-store.s3.amazonaws.com/0/265344/79fb7a22-b577-2b99-a827-904d9bfe8d42.png">

ちゃんと学習できているようで安心。

ここからやることとしては、さらに精度を向上させるためパラメータやレイヤー構成を変えてみてチューニングしていく作業に入っていく。

## おわりに
今回はGoogle Colabとkerasを用いてGPUを使いCNNを構築してみました。

最後まで読んでいただきありがとうございます！