ChainerでIris分類

自分用の備忘録としてchainerの書き方とIris分類を書き起こしておく
これから機械学習を始めたい方も是非参照して欲しい

# 環境
以下は自分の環境である。
- MacBook Pro(15-inch 2018)
- macOS Mojave (ver 10.14.4)
- python3 (ver 3.7.2)
- chainer (ver 5.3.0)
- numpy (ver 1.17.0)
- pandas (ver 0.24.2)
# import
上記を使える状態にするためにインポートをする。
これで機械学習に必要なライブラリを使えるようになる。

```python3:Iris_train.py
import chainer
import chainer.links as L
import chainer.functions as F
```
ここにある```... as ~```というのは...をこれ以降~という呼び方をしても呼び出せるようにしている。
便利なので覚えておくべき。

# モデル構築
これから実際に機械学習を行うコードを作成する。
chainerでモデルを構築する方法はいくつかあるが、今回は最もポピュラーな方法で記述していく。

```python3:Iris_train.py
class MyChain(chainer.Chain):
    def __init__(self,):
        super(MyChain, self).__init__(
                         l1 = L.Linear(4, 64),
                         l2 = L.Linear(64, 32),
                         l3 = L.Linear(32,16),
                         l4 = L.Linear(16, 8),
                         l5 = L.Linear(8, 2),
                         )
    def __call__(self, x):
        h1 = F.relu(self.l1(x))
        h2 = F.relu(self.l2(h1))
        h3 = F.relu(self.l3(h2))
        h4 = F.relu(self.l4(h3))
        h5 = F.sigmoid(self.l5(h4))
        return h3
```
それぞれ```l1~l5```が実際の機械学習の重みを格納する変数であり、```h１〜h５```が学習の際に使用する活性化関数に当たる。

# データセットの用意
データはIris.csvを使用する。[ここ](https://sourceforge.net/projects/datadensityplot/files/Iris.csv/download?use_mirror=astuteinternet&download=&failedmirror=jaist.dl.sourceforge.net)からダウンロード
一度開いて
"setosa" -> 0
"versicolor" -> 1
"virsinica" -> 2
のように書き換える。トレーニングを行う際には数字にしてあげないと学習されない
このCSVをコードと同じディレクトリに配置する。コードには以下を記述

```python3:Iris_train.py
import pandas as pd
df = pd.read_csv("./iris.csv")
x = df[["sepal.length", "sepal.width", "petal.length", "petal.width"]].values
x = np.array(x, "float32")
t = df["variety"].values
```

変数```x```には学習対象となるあやめの額弁の幅、長さといったデータが入っている。この時データを全て```float32```に変換しておくこと、
これをやらないとあとでエラーになるので注意。

#オプティマイザーの準備
何も考えずにAdamを使う

```python:Iris_train.py
my_nn = MyChain()
optimizer = chainer.optimizers.Adam()
optimizer.setup(my_nn)
```
# 学習
早速回していく、バッチサイズだとか細かいことは気にしない
epochはとりあえず１０００に設定する

```python3:Iris_train.py
for _ in range(1000):
    my_nn.zerograds()
    y = my_nn(x)
    loss = F.softmax_cross_entropy(y, t)
    acc = F.accuracy(y, t)
    loss.backward()
    optimizer.update()
    print("epoch:{}  ==> acc:{} loss:{}".format(_, acc.data, loss.data))
```

多分ここまでやれば実行はできるので、いざ実行

``` zsh
> python3 iris_train.py
epoch:0  ==> acc:0.0 loss:3.036327362060547
epoch:1  ==> acc:0.1133333370089531 loss:2.8747689723968506
epoch:2  ==> acc:0.3266666531562805 loss:2.7357027530670166
epoch:3  ==> acc:0.3333333432674408 loss:2.6169583797454834
epoch:4  ==> acc:0.3333333432674408 loss:2.5149309635162354
epoch:5  ==> acc:0.3333333432674408 loss:2.4245212078094482
...
epoch:996  ==> acc:0.9800000190734863 loss:0.04298550263047218
epoch:997  ==> acc:0.9800000190734863 loss:0.04296574369072914
epoch:998  ==> acc:0.9800000190734863 loss:0.04291696473956108
epoch:999  ==> acc:0.9800000190734863 loss:0.04287692531943321
```
ガバガバ精度なのは気にしない
学習に満足したら保存する
コードに以下を追加

```python
chainer.serializers.save_npz("model_Iris.npz", my_nn)
```

保存したファイルを使いたいときは以下のようにしてロードしてデータを入れるだけ

```python:Iris_test.py
import chainer
import numpy as np
from Iris_train import MyChain

test_nn = MyChain()
chainer.serializers.load_npz("model_Iris.npz", test_nn)

import pandas as pd
df = pd.read_csv("./iris.csv")
x = df[["sepal.length", "sepal.width", "petal.length", "petal.width"]].values
x = np.array(x, "float32")
t = df["variety"].values
test = test_nn(x)

label = ["setosa", "versicolor", "verginica"]
i = 0
for _ in test:
    pred_index = np.argmax(_.data)
    real_index = t[i]
    print("予測:%s　実ラベル:%s" % (label[pred_index], label[real_index]))
    i += 1
```