2層ニューラルネットワークでKaggle Titanicを解く


ゼロつく」を半分くらい読んでKaggle Titanicできそうだなと思ったのでNotebookを作ってみた。
機械学習で有名な手法であるディープラーニングを学ぼうとする人の足がかりになるといい。ディープラーニングとは層の多い(深い)ニューラルネットワークであるので、最も層の少ないニューラルネットワークはその基礎になる。

コード解説

ノード数を入力層(第0層)で4、中間層(第1層)で30、出力層(第2層)で2としたニューラルネットワークhttps://www.kaggle.com/yusukemigitera/2layernet を解説する。

ライブラリのインポートとデータ取得

import numpy as np

2層ニューラルネットワークを作るのにはNumpyのみを使う。

train = pd.read_csv("../input/titanic/train.csv")
test = pd.read_csv("../input/titanic/test.csv")

Kaggleの提供データはこのような階層に収められている。

欠損データの補完

以下のページを参考にして、ほぼ同じコードでデータの欠損値を補完した。
【Kaggle初心者入門編】タイタニック号で生き残るのは誰?
学習、推論で利用するデータの項目もこのページと同じPclass(チケットクラス)、Sex(性別)、Age(年齢)、Fare(料金)の4項目にした。

使う関数の定義

中間層の活性化関数として使うsigmoid(x)
出力層の活性化関数として使うsoftmax(x)
損失関数として使うcross_entropy_error(y, t)
数値微分のためのnumerical_gradient(f, x)
を定義している。
「ゼロつく」で紹介されたコードが公開されているhttps://github.com/oreilly-japan/deep-learning-from-scratch からコピーした。

2層ニューラルネットワークのクラス

__init__(self, input_size, hidden_size, output_size, weight_init_std=0.01)
重み(とバイアス)の初期値を正規分布の乱数(と0)で設定する。

predict(self, x)
入力データx(行列)に対してa = Wx +bを計算し、活性化関数を通してから次の層へ渡す。
2層なのでこれを2回繰り返す。

loss(self, x, t)
predict(self, x)で推論した値と目標値との交差エントロピー誤差を返す。

numerical_gradient(self, x, t)
クラスの外で定義したnumerical_gradient(f, x)W1, b1, W2, b2で適用する。

学習

iters_num = 100  # 繰り返しの回数を適宜設定する
train_size = x_train.shape[0]
batch_size = 100
learning_rate = 0.5 # 学習率

ハイパーパラメーターの設定。

network = TwoLayerNet(input_size=4, hidden_size=30, output_size=2)
train_loss_list = [] # これは損失関数の値が順調に減っていっているか確かめるため

インスタンスを作るときにノード数を設定する。

    batch_mask = np.random.choice(train_size, batch_size)
    x_batch = x_train[batch_mask]
    t_batch = t_train[batch_mask]

ミニバッチ学習のためランダムに(batch_size)個のデータを取り出す。

    # 勾配の計算
    grad = network.numerical_gradient(x_batch, t_batch)
    #grad = network.gradient(x_batch, t_batch)

    # パラメータの更新
    for key in ('W1', 'b1', 'W2', 'b2'):
        network.params[key] -= learning_rate * grad[key]

    loss = network.loss(x_batch, t_batch)

行列の偏微分で勾配を求め、その値に学習率を掛けたもので重みとバイアスの値を更新する。
勾配を用いて更新することにより、極小値から離れた傾きの大きな座標では大きく値を更新し、極小値に近い傾きの小さな座標では小さく値を更新することができる。

推論

y = network.predict(x_test)

テスト用データをnetwork.predict()に入れるだけ。残りの処理は提出用にデータを整えている。
この辺はもう少しきれいな書き方があるかもしれない。

CSVとして出力

右上のSave VersionボタンからSave & Run All (Commit)を選び保存する。
そのNotebookのページに移り、OutputからSubmit to competitionを押すと提出が完了しスコアが出る。

評価

簡単な作りとはいえスコアは低かった(正解率 64%)。重みの初期値を乱数で設定しているため同じコードでも出るスコアにはばらつきがある。
使う関数やハイパーパラメーター、重みの初期値などを変えれば改善できるかもしれない。