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
ディスカッション
コメント一覧
まだ、コメントがありません