スポンサーリンク

Chainer2のMNIST_MLPコードの解読にtryしてみる

本当は、画像ファイルからデータセットの作成も行いたいが、そこまで余裕がないので、まずは、以下の公式GitHubのMNIST_MLPのコードを改変したものの解読にtryしてみる。

https://github.com/mitmul/chainer-handson/blob/master/2-Try-Trainer-class_ja.ipynb

(今回のコード)

https://gist.github.com/adash333/87c4329891613d0b39563a63fe711c8b

(環境)
Panasonic CF-RZ4
Windows 8.1 Pro
Anaconda 4.4.0
Python 3.5
PHP 5.6.23

Chainer2.0は以下のようにインストールし、再開時は、activate chainer2で仮想環境を起動。

http://twosquirrel.mints.ne.jp/?p=19928

(0)Chainerプログラミングの流れ
(Trainerを用いる場合:初心者にはこれがお勧めと思われる)

ChainerにはTrainerというモジュールがあり、基本的にこれを用いて学習を行う。
Trainerの構造は、以下の図の通りだが、Trainerが使用できるように、

1.Updater
2.Iterator
3.Dataset
4.Optimizer
5.Model
6.Extensions

を記載していく必要がある。
上記を記載した後に、trainer.run() で学習を実行する。

出典:https://qiita.com/mitmul/items/eccf4e0a84cb784ba84a

(1)#1 Chainerを使用するためのimport文

(2)#2 データの準備・設定
from chainer import iterators
# trainerを利用するために、Iteratorを定義してdatasetにアクセスできるようにする

(3)#3 モデルの記述
class MyModel(Chain):
    def __init__(self):
        super(MyModel,self).__init__(
            # パラメータを含む関数の宣言
        )
    
    def __call__(self, ...):
    # モデルを記載

(4)#4 モデルと最適化アルゴリズムの設定(ほぼお約束の3行)
model = MyModel()
optimizer = optimizers.Adam()
optimizer.setup(model)

(5)#5 学習
for epoch in range(繰り返し回数)
    データの加工
    model.cleargrads() #勾配初期化
    loss = model(...)  #誤差計算
    loss.backward      #勾配計算
    optimizer.update   #パラメータ更新

(6)#6 結果の出力とパラメータの保存

(7)

 

(1)jupyter notebookを起動し、New > Python3 を行い、以下のサイトのコードを順番に入力していく

https://github.com/mitmul/chainer-handson/blob/master/2-Try-Trainer-class_ja.ipynb

 

#1 datasetの準備

# original code from https://github.com/mitmul/chainer-handson/blob/master/2-Try-Trainer-class_ja.ipynb

#1 datasetの準備

'''
本当は画像からdatasetを準備するべきだが、簡便のため、今回は
chainer.datasetsが提供するNumpy配列のmnistデータをimportする。
chainer.datasetsを使用しないで自分で画像からchainer用のデータセットを
作成する方法については、以下を参照
http://twosquirrel.mints.ne.jp/?p=20366"
'''

from chainer.datasets import mnist
train, test = mnist.get_mnist()

(2)#2 Iteratorの準備

# ChainerにはTrainerというモジュールがあり、基本的にこれを用いて学習を行う。
# Trainerの構造は、以下の図の通りだが、Trainerが使用できるように、順番に、
# Updater, Iterator, Dataset, Optimizer, Model, Extensions
# を記載していく必要がある。
# 上記を記載した後に、trainer.run() で学習を実行する。
# Trainerの構造の図のリンク(絶対に閲覧お勧めの図)

上記の出典はこちら

from chainer import iterators

batchsize = 128

train_iter = iterators.SerialIterator(train, batchsize)
test_iter = iterators.SerialIterator(test, batchsize, False, False)

(3) #3 Modelの準備

# ChainerのTrainerを使用するために、Modelを準備する
# LinkとFunction

Chainerでは、ニューラルネットワークの各層を、LinkとFunctionに区別します。
Linkは、パラメータを持つ関数です。
Functionは、パラメータを持たない関数です。
これらを組み合わせてモデルを記述します。

今回は、手書き数字MNIST画像を、multiple layer perceptron(多層パーセプトロン)という
ニューラルネットワークモデルを用いて機械学習で分類します。
層構造のイメージは、以下のリンクが参考になります。
https://qiita.com/kenmatsu4/items/7b8d24d4c5144a686412
ネットワークは3層で、入力層、隠れ層、出力層の3層とします。
28×28のグレースケール画像を、0から255までの値をとる各ピクセルの値を、
784個、横に並んだ数字の配列に変換して(、さらに255で割って)、
入力層に入れます。入力層のunit数は784個となります。
中間層のunit数(n_mid_units)は、今回は、100個に設定しています。
手書き数字の0から9まで10種類の画像を分類するため、
出力層のunit数(n_out)は、10個となります。

#3 Modelの準備

 

import chainer import chainer.links as L import chainer.functions as F class MLP(chainer.Chain): def __init__(self, n_mid_units=100, n_out=10): super(MLP, self).__init__() with self.init_scope(): self.l1=L.Linear(None, n_mid_units) self.l2=L.Linear(None, n_mid_units) self.l3=L.Linear(None, n_out) def __call__(self, x): h1 = F.relu(self.l1(x)) h2 = F.relu(self.l2(h1)) return self.l3(h2)

(4) #4 Updaterの準備

以下のコードをコピペ

#4 モデルと最適化アルゴリズムの設定(Updaterの準備)

'''
trainer.run()で学習をしているとき、Updaterが内部で、以下を行っている。
1.データセットからデータを取り出し(Iterator)
2.モデルに渡してロスを計算し(Model = Optimizer.target)
3.Optimizerを使ってモデルのパラメータを更新する(Optimizer)
'''

from chainer import optimizers
from chainer import training

gpu_id = -1  # Set to -1 if you don't have a GPU

model = MLP()
if gpu_id >= 0:
    model.to_gpu(gpu_id)

max_epoch = 3

# モデルをClassifierで包んで、ロスの計算などをモデルに含める
model = L.Classifier(model)

if gpu_id >= 0:
    model.to_gpu(gpu_id)

# 最適化手法の選択
optimizer = optimizers.SGD()
optimizer.setup(model)

# UpdaterにIteratorとOptimizerを渡す
updater = training.StandardUpdater(train_iter, optimizer, device=gpu_id)

 

(5)#5 学習と結果の出力
# TrainerにUpdaterを渡す
trainer = training.Trainer(updater, (max_epoch, 'epoch’), out=’mnist_result’)
# TrainerにExtensionを追加
from chainer.training import extensions
    # trainer.extend()で、学習の進行状況を表すプログレスバーや、lossのグラフ化と画像の保存などを行う

trainer.run()

以下のコードをコピペ。

#5 学習と結果の出力
# TrainerにUpdaterを渡す
trainer = training.Trainer(updater, (max_epoch, 'epoch'), out='mnist_result')

# TrainerにExtensionを追加
from chainer.training import extensions
# trainer.extend()で、学習の進行状況を表すプログレスバーや、lossのグラフ化と画像の保存などを行う
# 以下は、意味不明なコードが並んでいるが、分からなくてもとりあえずコピペしておく。
trainer.extend(extensions.LogReport())
trainer.extend(extensions.PrintReport(['epoch', 'main/loss', 'main/accuracy', 'validation/main/loss', 'validation/main/accuracy', 'elapsed_time']))
trainer.extend(extensions.PlotReport(['main/loss', 'validation/main/loss'], x_key='epoch', file_name='loss.png'))
trainer.extend(extensions.PlotReport(['main/accuracy', 'validation/main/accuracy'], x_key='epoch', file_name='accuracy.png'))
trainer.extend(extensions.snapshot(filename='snapshot_epoch-{.updater.epoch}'))
trainer.extend(extensions.snapshot_object(model.predictor, filename='model_epoch-{.updater.epoch}'))
trainer.extend(extensions.Evaluator(test_iter, model, device=gpu_id))
trainer.extend(extensions.dump_graph('main/loss'))

# 学習の実行(Extensionsによって、結果も出力される)
trainer.run()

すると、MNIST tutorial.ipynb と同じフォルダに mnist_result フォルダが作成され、中身がいろいろ保存される。詳細は私にはわかりません。

(6)学習結果のパラメータの保存

以下のコードをコピペ。

#6 学習結果のパラメータの保存
# Save paramaters
chainer.serializers.save_npz('my_mnist.model', model)

すると、MNIST tutorial(train).ipynb と同じフォルダに、my_mnist.model ファイルが保存される。

(7)推測

MNIST tutorial(train).ipynb と同じ階層で、New > Python3 で新規ipynbファイルを作成し、MNIST tutorial(predict).ipynb  という名前に変更

以下のコードをコピペ

# predict.py

#7 推測

import numpy as np
from PIL import Image
import chainer
import chainer.functions as F
import chainer.links as L
from chainer import datasets, serializers

# Network definition 
class MLP(chainer.Chain):
    def __init__(self, n_units, n_out):
        super(MLP, self).__init__()
        with self.init_scope():
            # the size of the inputs to each layer will be inferred
            self.l1 = L.Linear(None, n_units)  # n_in -> n_units
            self.l2 = L.Linear(None, n_units)  # n_units -> n_units
            self.l3 = L.Linear(None, n_out)  # n_units -> n_out
    def __call__(self, x):
        h1 = F.relu(self.l1(x))
        h2 = F.relu(self.l2(h1))
        return self.l3(h2)

# filepath は適当に変更。今回は、chainer_MNIST_MLP_predict.pyと同じ階層に、0.jpgを保存しておき、推測する。
filepath = "0.jpg"
# モデルを使って判定する
model = L.Classifier(MLP(100, 10))
# 前回の学習結果のパラメータをインポート
serializers.load_npz('my_mnist.model', model)
# PIL(pillow)を用いてjpg画像を開き、グレースケール画像として読み込む
image = Image.open(filepath).convert('L').resize((28,28))
# グレースケール画像をfloat32型のNumpy配列に変換し、255で割って正規化
image = np.asarray(image).astype(np.float32) / 255
# 上記Numpy配列を1次元ベクトル化(28x28を1x784にreshape)
image = image.reshape((1, -1))
# ニューラルネットワークにおけるノードに対応するオブジェクトに変換する
x = chainer.Variable(image)
# chainer.links.Classifierのpredictorで推測
y = model.predictor(x)
# y.dataという配列の中で一番大きい値をとる要素のインデックスを返す
# 今回は、インデックスの値がそのまま、数字の分類項目となっている
predict = np.argmax(y.data)

print("filepath:" , filepath , " , " , "predict:" , predict)

(8)自分で作った画像を推測してみる

Windowsのペイントで、黒の背景に、白で、以下のように記載して、test.pngとして保存。

predict.py の、

# filepath は適当に変更。今回は、chainer_MNIST_MLP_predict.pyと同じ階層に、0.jpgを保存しておき、推測する。
filepath = “0.jpg"

を、

filepath = “test.png"

に変更して保存して、実行。

残念、8のつもりが、3と判定されてしまった。

まあまあ大丈夫そう。

(9)上記コードの全文。なお、Jupyter Notebookではなく、Anaconda Prompt上からも実行可能。

train_jupyter.py

predict_jupyter.py

(10)本当は、

train, test = chainer.datasets.get_mnist()

ではなく、自分でjpg画像の集まりから、Chainer用のデータセットを作って機械学習したい。。。

統計でもなんでも、手持ちのデータセットを、コンピュータが理解できる形に整形するのが一番難しい。

今のところは、以下の参考リンクのみにとどめるが、いつかちゃんと記載したい。

http://twosquirrel.mints.ne.jp/?p=20366

(参考)

Chainer: ビギナー向けチュートリアル Volmitmul
2017年05月18日に更新
https://qiita.com/mitmul/items/eccf4e0a84cb784ba84a

Chainerチュートリアル の和訳【Chainerの紹介と多層パーセプトロン】20160120
http://www.iandprogram.net/entry/chainer_japanese

【機械学習】ディープラーニング フレームワークChainerを試しながら解説してみる。
kenmatsu4
2015年09月27日に更新
https://qiita.com/kenmatsu4/items/7b8d24d4c5144a686412

Chainer 2.0 のMNISTサンプルで推論を動かす
abechi_17
2017年07月01日に投稿
https://qiita.com/abechi_17/items/b271b7042fae126616d7

chainer 1.11.0以降のmnistを解説
tommyfms2
2016年10月19日に更新
https://qiita.com/tommyfms2/items/a2f23acbf515fba3495b

2016年11月20日
【Chainer】mnistサンプルコードからエッセンスだけ抽出してみた
http://akasuku.blog.jp/archives/67271420.html