train_iris.py コードの補足説明

はじめに

train_iris.py をそのまま動かす際には scikitlearn が必要となるので、

pip install scikit-learn
conda install scikit-learn

のどちらかを実行してほしい。


In [1]:
from chainer import cuda
import numpy as np
from sklearn import datasets
from sklearn.model_selection import train_test_split

import pandas as pd

cupy フラグのたて方

CUDA が使えるならば、データセットを numpy 配列ではなく cupy 配列 とすることで、
データセットをGPUメモリに載せられるため高速化につながる。
だが iris はデータそのものがあまりにが小さいので恩恵がないが…

下記のようなコードにすると、簡単に numpy 配列と cupy 配列を切り替えることができる。


In [2]:
# gpu -> args.gpu と読み替えてほしい
gpu = -1
if gpu >= 0:
    # chainer.cuda.get_device(args.gpu).use()  # make a specified gpu current
    # model.to_gpu()  # copy the model to the gpu
    xp = cuda.cupy
else:
    xp = np

データセットの読み込み

iris データセットは scikit-learn に用意されているので、それを利用した。


In [3]:
iris = datasets.load_iris()

In [4]:
pd.DataFrame({
    'sepal length': np.array([iris.data[x][0] for x in range(150)]), #len(iris.data) -> 150
    'sepal width':  np.array([iris.data[x][1] for x in range(150)]),
    'petal length': np.array([iris.data[x][2] for x in range(150)]),
    'petal width':  np.array([iris.data[x][3] for x in range(150)]),
    'target label': np.array(iris.target)
})


Out[4]:
petal length petal width sepal length sepal width target label
0 1.4 0.2 5.1 3.5 0
1 1.4 0.2 4.9 3.0 0
2 1.3 0.2 4.7 3.2 0
3 1.5 0.2 4.6 3.1 0
4 1.4 0.2 5.0 3.6 0
5 1.7 0.4 5.4 3.9 0
6 1.4 0.3 4.6 3.4 0
7 1.5 0.2 5.0 3.4 0
8 1.4 0.2 4.4 2.9 0
9 1.5 0.1 4.9 3.1 0
10 1.5 0.2 5.4 3.7 0
11 1.6 0.2 4.8 3.4 0
12 1.4 0.1 4.8 3.0 0
13 1.1 0.1 4.3 3.0 0
14 1.2 0.2 5.8 4.0 0
15 1.5 0.4 5.7 4.4 0
16 1.3 0.4 5.4 3.9 0
17 1.4 0.3 5.1 3.5 0
18 1.7 0.3 5.7 3.8 0
19 1.5 0.3 5.1 3.8 0
20 1.7 0.2 5.4 3.4 0
21 1.5 0.4 5.1 3.7 0
22 1.0 0.2 4.6 3.6 0
23 1.7 0.5 5.1 3.3 0
24 1.9 0.2 4.8 3.4 0
25 1.6 0.2 5.0 3.0 0
26 1.6 0.4 5.0 3.4 0
27 1.5 0.2 5.2 3.5 0
28 1.4 0.2 5.2 3.4 0
29 1.6 0.2 4.7 3.2 0
... ... ... ... ... ...
120 5.7 2.3 6.9 3.2 2
121 4.9 2.0 5.6 2.8 2
122 6.7 2.0 7.7 2.8 2
123 4.9 1.8 6.3 2.7 2
124 5.7 2.1 6.7 3.3 2
125 6.0 1.8 7.2 3.2 2
126 4.8 1.8 6.2 2.8 2
127 4.9 1.8 6.1 3.0 2
128 5.6 2.1 6.4 2.8 2
129 5.8 1.6 7.2 3.0 2
130 6.1 1.9 7.4 2.8 2
131 6.4 2.0 7.9 3.8 2
132 5.6 2.2 6.4 2.8 2
133 5.1 1.5 6.3 2.8 2
134 5.6 1.4 6.1 2.6 2
135 6.1 2.3 7.7 3.0 2
136 5.6 2.4 6.3 3.4 2
137 5.5 1.8 6.4 3.1 2
138 4.8 1.8 6.0 3.0 2
139 5.4 2.1 6.9 3.1 2
140 5.6 2.4 6.7 3.1 2
141 5.1 2.3 6.9 3.1 2
142 5.1 1.9 5.8 2.7 2
143 5.9 2.3 6.8 3.2 2
144 5.7 2.5 6.7 3.3 2
145 5.2 2.3 6.7 3.0 2
146 5.0 1.9 6.3 2.5 2
147 5.2 2.0 6.5 3.0 2
148 5.4 2.3 6.2 3.4 2
149 5.1 1.8 5.9 3.0 2

150 rows × 5 columns

データセットの分割

scikit-learn にある train_test_sprit を使えば、簡単にデータセットを分割できる

test_size だが Docstring に "Split arrays or matrices into random train and test subsets" とあるように、
ランダムに分割するため分割後のラベルの数が統一されていない

test_size (or train_size) に 0.0 - 1.0 の値を与えると、その割合を test (or train) にしてくれる。


In [5]:
data_train, data_test, tgt_train, tgt_test = train_test_split(iris.data, iris.target, test_size=0.5)

In [6]:
from collections import Counter
Counter(tgt_train)


Out[6]:
Counter({0: 21, 1: 28, 2: 26})

またオプションとして、train_test_sprit を使わず、
偶数番目のデータを train 、奇数番目のデータを test にするオプションも用意した
実行時の引数に --spritintwo y or -s y とすれば実行される


In [7]:
index = np.arange(len(iris.data))
data_train, data_test = iris.data[index[index%2!=0],:], iris.data[index[index%2==0],:]
tgt_train, tgt_test   = iris.target[index[index%2!=0]], iris.target[index[index%2==0]]

In [8]:
Counter(tgt_train)


Out[8]:
Counter({0: 25, 1: 25, 2: 25})

隠れ0層の NN と 線形回帰 (logistic regression)

隠れ層 0 のニューラルネットワークは、 多項ロジスティック回帰と同等 になる。

識別先のクラスを $C = \{c_1, c_2, ... , c_K\}$ 、入力のベクトルを $\mathbf{x} = (x_1, x_2, ... , x_n)^t$ とすると、多項ロジスティック回帰のモデルは、

$$ p(c_k | \mathbf{x}) = \pi (a_k) \\ a_k = (W \mathbf{x} + \mathbf{b})_k $$

$\pi$ を softmax 関数とすると、 上式は隠れ0層の NN と等価だとわかる。

コードにおいては、

class MLP_H0(chainer.Chain):
    # NO HIDDEN LAYER (= LOGISTIC REGRESSION)
    def __init__(self, n_units):
        super(MLP_H0, self).__init__(
            l1=L.Linear(None, 3),  # n_in -> n_out
        )
    def __call__(self, x):
        return self.l1(x)

また L.Classifier の loss function はデフォルトが softmax_cross_entropy である

if  args.mode == 'MLP_H0':
        model = L.Classifier(MLP_H0(args.unit))