Chainer/minimal

提供: fukudat
移動: 案内検索

MNIST をベースに,できるだけ本質的でない部分を省いたClassificationのサンプル.

目次

入手方法

github からクローン.

$ git clone https://github.com/fukudat007/wudm.git
$ cd wudm/neural-network/minimal

使い方

まず,人工的なデータを生成するプログラム gendata.py (generate data) で学習用のデータを作成する.

$ ./gendata.py
generating data in minimal-train-data.csv...done.
generating data in minimal-test-data.csv...done.

カレントディレクトリに minimal-train-data.csv と minimal-test-data.csv ができる.

次に,Neural Networkの学習プログラム minimal.py を実行してみる.

$ ./minimal.py
n_in=2, n_unit=2, n_out=2
epoch=20, batchsize=100
outdir=result
epoch       main/loss   validation/main/loss  main/accuracy  validation/main/accuracy  elapsed_time
1           0.745281    0.718819              0.1685         0.354                     0.229203      
2           0.692       0.668101              0.5301         0.725                     1.14496       
3           0.645798    0.625216              0.8603         0.912                     1.94262       
4           0.607484    0.589953              0.9057         0.912                     2.78225
...

すると,./result というディレクトリが作成され,その下に学習結果が出力される.

$ cd result
$ ls -l
total 776
-rw-r--r--  1 fukudat  staff   25555 12  5 23:13 accuracy.png      # epoch vs accuracy graph
-rw-r--r--  1 fukudat  staff  158419 12  5 23:13 actual.png        # 正解データのプロット
-rw-------  1 fukudat  staff    5932 12  5 23:13 log               # 学習経過のログ
-rw-r--r--  1 fukudat  staff   35379 12  5 23:13 loss.png          # epoch vs loss graph
-rw-r--r--  1 fukudat  staff  160090 12  5 23:13 predicted.png     # 予測結果のプロット

プログラムの説明

gendata.py

classify(x1, x2)
2次元の input features (x1, x2) が属すべき「正解」のクラスを整数で返す.
このサンプルでは,中心 (0.5, 0.5) 半径 \sqrt{0.16}=0.4 の内側にあればクラス1 (正例), そうでなければクラス0 (負例) としている.
gendata(filename, nrow)
filename で与えられた名前のCSVファイルを新規作成して,その中に random なデータをnrow行だけ書き込む.
1行1サンプルで,x1, x2, y という形式.x1, x2 を[0, 1) の間の乱数として発生させ,classify()関数で y を求めている.

このファイルを実行すると,上記の関数を使って訓練データminimal-train-data.csv 10,000行,検証データminimal-test-data.csv 1,000行を作成する.

minimal.py

MyChain クラス
このクラスが network の構造を表現している.
__init__(n_in, n_unit, n_out)
入力層 n_in ユニット,隠れ層 n_unit ユニット,出力層 n_out ユニットの3層ネットワークを作成するためのパラメータ (l1, l2)を準備している.
__call__()
network の forward propagation の過程をプログラムする.ここでは,
  • 入力x にマトリックスl1を掛け,その結果に sigmoid 関数を適用
  • その結果にマトリックスl2を掛け,その結果に sigmoid 関数を適用
  • その結果を出力
している.

今回は MyChain を Chainer の Classifier クラスで wrap したものが model となり,optimizerに渡される (63〜65行目付近).

model = L.Classifier(MyChain(n_in, n_unit, n_out))
optimizer = optimizers.Adam()
optimizer.setup(model)

Classifier クラスは default ではsoftmax_cross_entropy をコスト関数として使用している.

カスタマイズのポイント

  • minimal.py の12〜16行目にパラメータがあるので,変更してみる.
    • batchsize = 1つの mini-batch が使う訓練データ数
    • epoch = 訓練データを何回繰り返し読んで学習するか
    • n_unit = 隠れ層のユニット数
    • result = 結果を出力するディレクトリ名
  • gendata.py の classify() 関数をイジって,いろんな分類問題を作成してみる.
    • classify の return value は 0, 1 でなくても良い.2 以上を含めれば,多クラス問題になる(ただしクラス番号は0から始まる).
    • x1, x2 の値は[0, 1)でなくても良い.なんなら x3, x4... と次元を増やしても構わない.
  • minimal.py の MyChain を変更して,network構造,activation関数を変えてみる.
    • 層数を増やしてみる.__init__()l3 を足して,4層のnetworkにする.(__call__()で接続関係も更新する必要がある)
    • activation関数として使われているsigmoidreluに変えてみる.
    • この変更を加えたコード片は以下の通り.
# simple model
class MyChain(Chain):
    # n_in = # of input features
    # u_unit = # of units in the hidden layer
    # n_out = # of output units
    def __init__(self, n_in, n_unit, n_out):
        initializer = initializers.HeNormal()
        super(MyChain, self).__init__(
            l1=L.Linear(n_in, n_unit, initialW=initializer),
            l2=L.Linear(n_unit, n_unit, initialW=initializer),
            l3=L.Linear(n_unit, n_out, initialW=initializer))

    # forward computation
    def __call__(self, x):
        h1 = F.relu(self.l1(x))
        h2 = F.relu(self.l2(h1))
        o = F.relu(self.l3(h2))
        return o
個人用ツール
名前空間

変種
操作
案内
ツールボックス