画像認識チュートリアルのTop６%の手法を触ってみた（Digit Recognizer、CNN）

今回はコンペへの実際の参加ではなく、コンペにあるカーネル（他の人のお手本みたいなやつ）を試してみます。
今回は初めてdeep learning を使ったので、最初はKerasの使い方が全然分かりませんでした（）

実際に触ったやつ
https://www.kaggle.com/yassineghouzam/introduction-to-cnn-keras-0-997-top-6

それではいつものように流れを追っていきます

##Digit Recognizerとは
与えられた画像を見て、訓練データの画像はなんと37800個もあって、それぞれの画像が０から９までのどの数字になるかの識別を行うコンペです。データは28×28のピクセルのもので、それぞれのピクセルごとに０から255までの数字が割り与えられます（値は小さければ小さいほど白に近い）。


##前処理
今回の前処理はあまりやることは多くありません。というのも、画像データをピクセルごとに０から１の範囲に標準化して画像データなので訓練データのYをカテゴライズ化して、訓練データを反転させたりして水増しするだけです。それでは見ていきます。


標準化とカテゴライズ化（モジュールのインポートは省略）

```python
train = pd.read_csv("../input/train.csv")
test = pd.read_csv("../input/test.csv")
Y_train = train["label"]
X_train = X_train / 255.0
test = test / 255.0

Y_train = to_categorical(Y_train, num_classes = 10)
```


次に水増しの作業です。これが最初正直何言ってるか全然分かりませんでしたが、Kerasのドキュメントを読みながら必死に理解しました
やってる事は、拡大だったり回転だったりをするのかしないのかなどを設定し、するならその値も設定するって感じですね。このImageDataGeneratorは後ほどmodelにFitさせるときにまとめて使用します。

ImageDataGeneratorの説明↓
https://keras.io/ja/preprocessing/image/

```python

datagen = ImageDataGenerator(
        featurewise_center=False,  # set input mean to 0 over the dataset
        samplewise_center=False,  # set each sample mean to 0
        featurewise_std_normalization=False,  # divide inputs by std of the dataset
        samplewise_std_normalization=False,  # divide each input by its std
        zca_whitening=False,  # apply ZCA whitening
        rotation_range=10,  # randomly rotate images in the range (degrees, 0 to 180)
        zoom_range = 0.1, # Randomly zoom image 
        width_shift_range=0.1,  # randomly shift images horizontally (fraction of total width)
        height_shift_range=0.1,  # randomly shift images vertically (fraction of total height)
        horizontal_flip=False,  # randomly flip images
        vertical_flip=False)  # randomly flip images

datagen.fit(X_train)
```


さて、これで前処理は完了です。次にモデルの設計をしていきます。

##モデルの設計
モデルの構成としては

28×28×1を入力
　　　↓
二回畳み込む
　　　↓
プーリング層
　　　↓
ドロップアウト層
　　　↓
一次配列にする（Flatten()）
　　　↓
中間層（258個のニューロン）
　　　↓
ドロップアウト層
　　　↓
10個のニューロン
　　　↓
　　出力

こんな感じの流れになってます。ちなみにこの値になるまでのパラメータチューニングは今回は省略、というかよく自分でも分かってないし実際になったら重そうだからやりたくない（）


```python
model = Sequential()

model.add(Conv2D(filters = 32, kernel_size = (5,5),padding = 'Same', 
                 activation ='relu', input_shape = (28,28,1)))
model.add(Conv2D(filters = 32, kernel_size = (5,5),padding = 'Same', 
                 activation ='relu'))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Dropout(0.25))


model.add(Conv2D(filters = 64, kernel_size = (3,3),padding = 'Same', 
                 activation ='relu'))
model.add(Conv2D(filters = 64, kernel_size = (3,3),padding = 'Same', 
                 activation ='relu'))
model.add(MaxPool2D(pool_size=(2,2), strides=(2,2)))
model.add(Dropout(0.25))


model.add(Flatten())
model.add(Dense(256, activation = "relu"))
model.add(Dropout(0.5))
model.add(Dense(10, activation = "softmax"))
```

##実行
あとはこれをコンパイルして実行します。
OptimizerにはRMSprop、評価指標にはクロスエントロピーを使用してます。
また、epochは１に設定されていますが、これは一回回すのにも時間がかかるためです。実際は30回回してますが、自分は重かったのでそんなに回してないです笑

```python
optimizer = RMSprop(lr=0.001, rho=0.9, epsilon=1e-08, decay=0.0)
model.compile(optimizer = optimizer , loss = "categorical_crossentropy", metrics=["accuracy"])
learning_rate_reduction = ReduceLROnPlateau(monitor='val_acc', 
                                            patience=3, 
                                            verbose=1, 
                                            factor=0.5, 
                                            min_lr=0.00001)
epochs = 1 # Turn epochs to 30 to get 0.9967 accuracy
batch_size = 86

history = model.fit_generator(datagen.flow(X_train,Y_train, batch_size=batch_size), epochs = epochs, validation_data = (X_val,Y_val),verbose = 2, steps_per_epoch=X_train.shape[0] // batch_size, callbacks=[learning_rate_reduction])
```

最後にこのモデルを使って予測をして完成です！


```python
results = model.predict(test)
```


##最後に

とにかく感想としては、やっぱりディープラーニングは動きが重くて時間かかるなあと感じました。
ちなみに今回は自分はKerasや畳み込みニューラルネットワークについて全く知らなかったので、「直感DeepLearning」という本を使って理解しました。中のロジックについては今まさにcourseraのDeepLeaningコースで学習しているところです。今度はこれについても書こうと思っています。