Google ColaboratoryでKaggleをサクッと試したいときのメモ。Colaboratoryは無料でGPU/TPUが使えるのがうれしい点。
本記事の要点は以下。
- ColaboratoryでKaggle APIを使えるように設定
- 簡単な問題「Titanic」に挑戦
- 予測モデルとしてNeural Networkを学習(機械学習フレームワークはTensorFlow)
必要なもの
- Googleアカウント
- Kaggleアカウント
ノートブックの準備
Colaboratoryにアクセスし、
ファイル > 新しいPython3ノートブック
で新しいノートブックを開く。
編集 > ノートブックの設定 > ハードウェアアクセラレータ > GPU > 保存
とすればGPUが使える。
Kaggle APIの導入
Kaggle APIはコマンドラインからKaggleのデータをダウンロードしたり予測結果をアップロードできるツール。
Kaggle APIをインストール
新しいセルを開いて下記コマンドを実行。
!pip install kaggle
これだけでは使えない。Kaggleアカウントと紐づける必要がある。
Kaggleアカウントと紐づけ
Kaggleにアクセス。
My Profile > Edit Profile > Create New API Token
としてkaggle.jsonをダウンロード。
Google driveを開いて適当な場所にkaggle.jsonをアップロード。
Colaboratoryから以下を実行。
# download API key from google drive
## Original: https://colab.research.google.com/drive/1eufc8aNCdjHbrBhuy7M7X6BGyzAyRbrF#scrollTo=y5_288BYp6H1
## When you run for the first time, you will see a link to authenticate.
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)
初回実行時に認証が必要になるので、表示されるURLから認証コードを入手しコピペする。
オリジナルはfilename = "/content/.kaggle/kaggle.json"
となっているが、/root/.kaggle/に置けというエラーメッセージが出たのでfilename = "/root/.kaggle/kaggle.json"
に変更
Download 100%.
と表示されれば成功。
動作確認
現在オープンなCompetitionの一覧を表示。
!kaggle competitions list
簡単なコンペティションに参加
今回はTitanicというコンペティションに参加。
Titanicは乗船者の年齢や性別といった属性情報から生存Yes/Noの二値を予測するタスク。データサイズも小さく、練習用として扱いやすいKaggleのHello world!的存在。
データのダウンロード
!kaggle competitions download -c titanic
colaboratoryの左カラムの「ファイル」や!ls
などで train.csv, test.csv, gender_submission.csv がダウンロードされていることを確認。
gender_submission.csvは提出する結果ファイルのサンプル。
データの前処理
与えられたCSVファイルには数値以外の文字列や欠損が含まれているので、一定の基準で画一的なベクトル表現に変換する必要がある。データをどう加工するかは予測精度に大きく影響するが、今回は動作確認が目的なので以下のような大雑把なルールで変換する。
- 'Pclass', 'Sex', 'Fare','SibSp', 'Parch', 'Age', 'Embarked'の情報のみ使用
- 3種類の'Embarked'(出港地)は0,1,2に置き換え
- データの欠損は -1 に置き換え
また、学習状況のモニタリングのために学習データの一部を検証用(下記は10%)として使用。検証用データの精度は学習率、ネットワーク構造などのチューニングや過学習の判定に有用。
import numpy as np
import pandas as pd
import tensorflow as tf
import time
def parse(df):
# Nan を -1 に置換
df["Age"] = df["Age"].fillna(-1)
df["Embarked"] = df["Embarked"].fillna(-1)
# 文字列を数値に変換
df["Sex"][df["Sex"] == "male"] = 0
df["Sex"][df["Sex"] == "female"] = 1
df["Embarked"][df["Embarked"] == "S" ] = 0
df["Embarked"][df["Embarked"] == "C" ] = 1
df["Embarked"][df["Embarked"] == "Q"] = 2
return df
def split_val(x,y,rate,seed=None):
# x,y の rate[%] をランダム分割
N = x.shape[0]
val_num = int(N*rate)
if seed is not None:
np.random.seed(seed)
perm = np.random.permutation(N)
ti = perm[:-val_num]
vi = perm[-val_num:]
return x[ti],y[ti],x[vi],y[vi]
def load_data():
train_csv = pd.read_csv('train.csv')
train_csv = parse(train_csv)
train_x = train_csv[['Pclass', 'Sex', 'Fare','SibSp', 'Parch', 'Age', 'Embarked']].values
train_y = train_csv['Survived'].values
return split_val(train_x,train_y,0.1)
学習
予測のアルゴリズムは決定木やSVMなど数多く存在するが、折角なのでTensorFlowを使ってNeural Networkを学習させる。
ネットワーク構造はu_dim次元の中間層をlayer_numだけ繰り返すシンプルな多層パーセプトロン。中間層の出力にReLUとBatchNormalizationを適用。
モデル定義
def create_model(input_placeholder,u_dim,layer_num,y_dim,training):
h = input_placeholder
for i in range(layer_num):
h = tf.layers.dense(inputs=h, units=u_dim,activation=tf.nn.relu)
h = tf.layers.batch_normalization(h,training=training)
h = tf.layers.dense(inputs=h, units=y_dim)
return h
学習。hyperparametersを調整していい感じのモデルを学習する。
np.random.seed(0)
tf.reset_default_graph()
y_dim = 2
# hyperparameters
u_dim = 100
layer_num = 2
epoch = 1000
log_freq = 100
batchsize = 200
lr = 0.001
# data load
train_x,train_y,val_x,val_y = load_data()
N = train_y.shape[0]
Nv = val_y.shape[0]
print('train num: {}, val num: {}'.format(N,Nv))
# calculation graph
x = tf.placeholder(tf.float32, [None, train_x.shape[1]],"input")
y = tf.placeholder(tf.int32, [None])
with tf.variable_scope("model"):
train_z = create_model(x,u_dim,layer_num,y_dim,training=True)
with tf.variable_scope("model", reuse=True):
z = create_model(x,u_dim,layer_num,y_dim,training=False)
cross_entropy = tf.losses.sparse_softmax_cross_entropy(labels=y, logits=train_z)
extra_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
with tf.control_dependencies(extra_ops):
train_step = tf.train.AdamOptimizer(lr).minimize(cross_entropy)
pred_y = tf.cast(tf.argmax(z, 1), tf.int32)
accuracy = tf.reduce_mean(tf.cast(tf.equal(pred_y, y), tf.float32))
# main loop
sess = tf.InteractiveSession()
tf.global_variables_initializer().run()
T = time.time()
for ep in range(1,epoch+1) :
perm=np.random.permutation(N)
for i in range(0,N,batchsize):
batch_xs=train_x[perm[i:i+batchsize]]
batch_ys=train_y[perm[i:i+batchsize]]
sess.run(train_step, feed_dict={x: batch_xs, y: batch_ys})
# monitor
if ep%log_freq ==0 :
train_loss, train_acc = sess.run([cross_entropy, accuracy], feed_dict={x: train_x, y: train_y})
val_loss, val_acc = sess.run([cross_entropy, accuracy], feed_dict={x: val_x, y: val_y})
epochT = time.time()-T
print('Epoch: %d, Time :%.4f (s), train_loss: %f, train_acc: %f, val_loss: %f, val_acc: %f' % (ep, epochT, train_loss, train_acc, val_loss, val_acc))
T = time.time()
以下は学習結果例。
Epoch: 100, Time :1.7708 (s), train_loss: 0.391779, train_acc: 0.822943, val_loss: 0.405918, val_acc: 0.797753
Epoch: 200, Time :1.7101 (s), train_loss: 0.426542, train_acc: 0.704489, val_loss: 0.488159, val_acc: 0.629214
Epoch: 300, Time :1.6960 (s), train_loss: 0.370545, train_acc: 0.839152, val_loss: 0.441939, val_acc: 0.775281
Epoch: 400, Time :1.7387 (s), train_loss: 0.403303, train_acc: 0.816708, val_loss: 0.467801, val_acc: 0.786517
Epoch: 500, Time :1.7077 (s), train_loss: 0.399253, train_acc: 0.846633, val_loss: 0.431753, val_acc: 0.808989
Epoch: 600, Time :1.6997 (s), train_loss: 0.393861, train_acc: 0.825436, val_loss: 0.436137, val_acc: 0.808989
Epoch: 700, Time :1.7178 (s), train_loss: 0.364453, train_acc: 0.834165, val_loss: 0.432697, val_acc: 0.820225
Epoch: 800, Time :1.7211 (s), train_loss: 0.355730, train_acc: 0.840399, val_loss: 0.461115, val_acc: 0.797753
Epoch: 900, Time :1.6965 (s), train_loss: 0.387813, train_acc: 0.815461, val_loss: 0.436706, val_acc: 0.820225
Epoch: 1000, Time :1.7431 (s), train_loss: 0.413756, train_acc: 0.749377, val_loss: 0.415829, val_acc: 0.752809
ちなみに、上記はGPU実行時の処理時間。この程度の計算ではGPUによる高速化の恩恵は小さい。
予測
テストデータも学習データと同様に前処理して、学習した予測モデルに入力。
# data
test_csv = pd.read_csv('test.csv')
test_csv = parse(test_csv)
test_x = test_csv[['Pclass', 'Sex', 'Fare','SibSp', 'Parch', 'Age', 'Embarked']].values
# predict
prediction = sess.run(pred_y, feed_dict={x: test_x})
# parse
PassengerId = np.array(test_csv["PassengerId"]).astype(int)
my_solution = pd.DataFrame(prediction, PassengerId, columns = ["Survived"])
# save
my_solution.to_csv("result.csv", index_label = ["PassengerId"])
result.csvが出力される。!cat result.csv
などで内容を確認できる。
予測結果の提出
!kaggle competitions submit -c titanic -f result.csv -m 'first submit'
1日の提出回数に上限があるので注意。
結果の確認
Kaggleにアクセス。
My Profile > Competitions > Titanic ... > My submissions
から結果を確認。
76.5% など妥当な値が得られていればOK。
参考
以下の記事を参考にさせていただいた。
Google Colaboratory で始める Kaggler 生活(データ入手と提出編)
【Kaggle初心者入門編】タイタニック号で生き残るのは誰?