Google Colab上でKaggleのデータをロード、モデル訓練、提出の全てを行う

　なんか最近Google Colaboratoryが流行ってるらしいですね。

　[Google Colabを導入](https://qiita.com/clocker/items/ebeb5ea9ce216e1d6205)

　Jupyter notebookをクラウド上で走らせることができるGoogleのウェブサービスですが、注目すべきは**GPUもTPUも無料**ということでしょう。

「ま、まぁオレもね、本気を出せばKaggleで上位狙えるんだけどね、ちょ、ちょっと手持ちにフツーのラップトップしかなくて、スペック的にアニメ観るくらいしかできないんだよね」

　という言い訳ももう通用しない時代に突入しました。

　Kaggleは、というより機械学習全般は計算機の能力がものをいいます。課題のデータ量が増大している今、Kaggle内のKernelでは学習が捗らないことも多く、私も去年[Kaggleの練習問題（Regression）を解いてKagglerになる](https://qiita.com/katsu1110/items/a1c3185fec39e5629bcb)という入門記事を書いてからKaggleを去りました(ぉぃ

　が、Google colabolatoryの登場により最近「ちょっとまたKaggleやってもいいかな……」と思い始めてきました。そこで、機械学習では定番のMNIST、KaggleではDigit Recognizerと呼ばれる練習問題を用いて、

1. Kaggle上のデータをGoogle colaboratoryにロード
2. Google colaboratory上でCNNのトレーニング
3. Google colaboratory上でKaggleに結果を提出

　という流れをまとめたいと思います。Google、Kaggleのアカウントを持っていることは前提とします。

　Kaggleのkernelでもまとめています。

　[How to submit from Google Colab](https://www.kaggle.com/code1110/how-to-submit-from-google-colab)

~~Qiitaはもういいので~~こちらにupvoteをいただけると嬉しいです。

# Kaggle上のデータをGoogle colaboratoryにロード
　Google Driveを開き、Colab Notebookというフォルダー（名前はなんでも大丈夫）を作ります。そこで**右クリック -> More -> Colaboratory**で、Google colaboratoryを始めることができます。

<img width="388" alt="click_colab.jpeg" src="https://qiita-image-store.s3.amazonaws.com/0/122354/fe84676c-6437-efef-178c-f6d8ed3728f4.jpeg">

　GPUを使いたいので、**編集 -> ノートブックの設定**より、ハードウェアアクセラレータをGPUに変更、保存します。

<img width="413" alt="gpu.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/122354/2857e591-6a2f-cc78-dfc0-4c8e9fc93103.png">


　さて、Google colaboratory上でKaggleのデータを扱うためには、まずKaggle上でAPIを作成する必要があります。KaggleのHPへ行き、**右上の自分のアイコンをクリック -> My Account -> （下の方にある）APIの項目の"Create New API Token"をクリック**します。ダウンロードウィンドウがポップアップで出てくるので、**kaggle.json**をダウンロードします。

<img width="669" alt="createAPI.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/122354/2f307711-d155-d1e5-16b7-e2bfd29caab3.png">

　Google colaboratoryに戻り、一行目に以下を打ち込みます。

```python:

from google.colab import files
files.upload()

```

　このセルを実行すると、先ほどダウンロードしたkaggle.jsonを開くように求められます。kaggle.jsonを開き、以下を打ち込むことでパスを設定します。

```python:

!mkdir -p ~/.kaggle
!mv kaggle.json ~/.kaggle/

```

kaggle.jsonをGoogle Driveの任意なフォルダに保存しておけば、[Kaggle API with Colab](https://colab.research.google.com/drive/1eufc8aNCdjHbrBhuy7M7X6BGyzAyRbrF#scrollTo=y5_288BYp6H1&forceEdit=true&offline=true&sandboxMode=true)で紹介された方法でColabへコピーできます。

```python:
from googleapiclient.discovery import build
import io, os
from googleapiclient.http import MediaIoBaseDownload
from google.colab import auth

auth.authenticate_user()

drive_service = build('drive', 'v3')
results = drive_service.files().list(
        q="name = 'kaggle.json'", fields="files(id)").execute()
kaggle_api_key = results.get('files', [])

filename = "/root/.kaggle/kaggle.json"
os.makedirs(os.path.dirname(filename), exist_ok=True)

request = drive_service.files().get_media(fileId=kaggle_api_key[0]['id'])
fh = io.FileIO(filename, 'wb')
downloader = MediaIoBaseDownload(fh, request)
done = False
while done is False:
    status, done = downloader.next_chunk()
    print("Download %d%%." % int(status.progress() * 100))
os.chmod(filename, 600)
```


　Kaggleをインストールします。

```python:

!pip install kaggle

```

　すると、以下のようにばーっとインストールが進むはずです。

<img width="592" alt="kaggle_install.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/122354/e19b73be-acf4-3d64-0037-a03fa9931737.png">

　アクセスパーミッションのため、以下を打ち込みます。

```python:

!chmod 600 /root/.kaggle/kaggle.json

```

　さて、これでもうKaggle上のデータをダウンロードできます。Kaggle上で各CompetitionのDataのページに行くと、APIのアドレスが見つかります。

<img width="752" alt="APIpass.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/122354/80cc6043-ca39-9436-b536-916297753463.png">

　ダウンロードのコマンドは以下のようになります。

```python:

!kaggle competitions download -c digit-recognizer

```

　これを実行すると無事、ファイルがロードされます。

<img width="860" alt="files.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/122354/2b8b8444-d0d5-ae42-888b-35fd512ac7a9.png">

　画面左側で、ロードされたファイルたちが確認できますね。

# Google colaboratory上でCNNのトレーニング
　データがロードできたら、後は好きにモデルを組んでトレーニングするだけです。MNISTは画像分類課題なので、何も考えずにCNN (Convolutional Neural Network) を使います。より頭を使わなくて済むよう、Kerasで実装します。

　Google colaboratoryでKerasをインストールするには、以下を実行します。

```python:

!pip install -q keras

```

　ありがたいことにNumpyやPandasは既に入っているため、今回はもう追加するものはありません。必要なライブラリをimportします。

```python:

import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)

# keras
import keras
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation, Flatten
from keras.layers.normalization import BatchNormalization
from keras.layers import Conv2D, MaxPooling2D, ZeroPadding2D, GlobalAveragePooling2D
from keras.layers.advanced_activations import LeakyReLU 
from keras.preprocessing.image import ImageDataGenerator
from keras.utils.np_utils import to_categorical
from keras.optimizers import SGD, RMSprop
from keras.callbacks import ReduceLROnPlateau  
from sklearn.model_selection import train_test_split

```

　ダウンロードしたデータは、/content/以下にあるので以下のようにPandasで読み込みます。

```python:

# load training & test datasets
train = pd.read_csv("/content/train.csv")
test = pd.read_csv("/content/test.csv")

```

　今回の記事の目的はGoogle colaboratory上でKaggleのデータを扱うことなので、モデルの詳細については説明しません。ここに書かれているモデルでも上位30％は入れると思いますが（保証はしませんー）、きっとKaggleのPublic Kernel上にもっといいのがあるので、そっちをパクってくることをおススメします。

### Train, Test

```python:

# pandas to numpy
y_train = train["label"]
X_train = train.drop(labels=["label"], axis=1)

del train

# normalize
X_train = X_train/255.0
test = test/255.0

# reshape the data so that the data
# represents (label, img_rows, img_cols, grayscale)
X_train = X_train.values.reshape(-1, 28, 28, 1)
test = test.values.reshape(-1, 28, 28, 1)

# one-hot vector as a label
y_train = to_categorical(y_train, num_classes=10)

```

### CNN

```python:

# convolution -> batch normalization -> ReLU actuvation -> pooling
model = Sequential()

model.add(Conv2D(32, (3, 3), input_shape=(28,28,1)))
model.add(BatchNormalization(axis=-1))
model.add(Activation('relu'))
model.add(Conv2D(32, (3, 3)))
model.add(BatchNormalization(axis=-1))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2,2)))

model.add(Conv2D(64,(3, 3)))
model.add(BatchNormalization(axis=-1))
model.add(Activation('relu'))
model.add(Conv2D(64, (3, 3)))
model.add(BatchNormalization(axis=-1))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2,2)))

model.add(Flatten())

# Fully connected layer
model.add(Dense(512))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Dropout(0.2))
model.add(Dense(10))

model.add(Activation('softmax'))

```

### Compile

```python:

# compile model
optimizer = RMSprop(lr=0.001, rho=0.9, epsilon=1e-08, decay=0.0)
model.compile(loss='categorical_crossentropy', optimizer=optimizer, metrics=['accuracy'])

```

### for cross validation　

```python:

# cross validation
X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size=0.10, random_state=1220)

```

### data argumentation

```python:

# data argumentation
gen = ImageDataGenerator(rotation_range=8, width_shift_range=0.08, shear_range=0.3,
                         height_shift_range=0.08, zoom_range=0.08)
train_generator = gen.flow(X_train, y_train, batch_size=64)

```

### decreasing learning rate

```python:

# learning rate
learning_rate_reduction = ReduceLROnPlateau(monitor='val_acc', patience=3, verbose=1, factor=0.5, min_lr=0.00001)

```

### training model

```python:

# model training
model.fit_generator(train_generator, epochs=30, validation_data = (X_val, y_val), verbose=2, steps_per_epoch=X_train.shape[0]/36,
                                       callbacks=[learning_rate_reduction])

```

　あとはGPUがモデルを訓練し終わるのを待つだけです。

# Google colaboratory上でKaggleに結果を提出
　モデルの訓練が終わったら、Google colaboratory上から結果をKaggleに提出しましょう。

　まず、モデルのテストデータに対する予測は、

```python:

# model prediction on test data
predictions = model.predict_classes(test, verbose=0)

```

　次に、提出用csvを作ります。

```python:

# make a submission file
submissions = pd.DataFrame({"ImageId": list(range(1,len(predictions)+1)),
    "Label": predictions})
submissions.to_csv("my_submission.csv", index=False, header=True)

```

　これを、以下のコマンドでKaggleに提出することができます。

```python:

# submit the file to kaggle
!kaggle competitions submit digit-recognizer -f my_submission.csv -m "Yeah! I submit my file through the Google Colab!"

```

<img width="593" alt="submit.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/122354/a2f1c964-5b74-3c8e-0b1d-ad131af1c793.png">

　上のように表示されたら、結果はKaggleに提出されています。

## 終わりに
　Google colaboratoryに登場によって、計算能力が比較的劣るコンピューターしかない個人でも、PythonをGPUやTPUを使って無料で走らせられるようになりました。こうした、個人の可能性が広がるサービスって素晴らしいですね!

### 参考
- [Kaggle/kaggle-api
](https://github.com/Kaggle/kaggle-api)
- [Using kaggle datasets into Google Colab](https://stackoverflow.com/questions/49310470/using-kaggle-datasets-into-google-colab)
- [Applying Convolutional Neural Network on the MNIST dataset](https://yashk2810.github.io/Applying-Convolutional-Neural-Network-on-the-MNIST-dataset/)