赤飯にかかったアレ

雑多なメモ帳

chainerで論理演算XORの学習 [chainer練習中、結果は多分間違ってる]

ChainerCVという画像処理に特化したものがあるらしい

github.com

やりたいなぁ、なんかサンプルもいっぱいあるし

ChainerCV Tutorial — ChainerCV 0.10.0 documentation

ただ、その前にchainerで遊びます。

練習を兼ねて交差エントロピー誤差を使いXORの学習をしてみました。

学習とテスト用のデータを一緒にして露骨に過学習させてみます。(やってみたかっただけ)

以下ソース+コメントによる補足

'''
論理演算XORの学習

使ったバージョン
python 3.6.6

numpy 1.15.0
Pillow 5.2.0
chainer 4.2.0
tqdm 4.24.0
'''
import numpy as np
import chainer
import chainer.functions as F
import chainer.links as L
import chainer.initializers as I
from chainer import training
from chainer.training import extensions

'''
# バージョンの確認
from pkg_resources import get_distribution
import platform
print('python', platform.python_version())
print("")
libs = ['numpy', 'Pillow', 'chainer', 'tqdm']
for lib in libs:
version = get_distribution(lib).version
print(lib, version)
'''

# ニューラルネットの構造を設定する
# 入力2(l1)に対して中間層は3つ。ここでRelu関数で処理を行ってh1とする
# 出力2をyとしてreturn
class MyChain(chainer.Chain):
 
def __init__(self):
super(MyChain, self).__init__()
with self.init_scope():
self.l1 = L.Linear(2, 3) # 入力2、中間層3
self.l2 = L.Linear(3, 2) # 中間層3、出力2
def __call__(self, x):
h1 = F.relu(self.l1(x)) # Relu関数
y = self.l2(h1)
return y

epoch = 1000 # 学習回数
batchsize = 4 # ミニバッチサイズ
# ミニバッチ学習用の学習データをいくつかのサイズに分割しておき、その分割された少量のサンプルを使用してニューラネットワークのパラメータを更新する
# ミニバッチサイズが1の場合をオンライン学習、ミニバッチサイズが学習データのサイズと一致する場合をバッチ学習という
# バッチサイズは大きいほど学習が高速化するが収束しなくなるので注意

# データの作成
# 入力データ、出力データはリスト形式で設定、学習データは2次元行列、テストデータは1次元の行列とする
trainx = np.array(([0,0], [0,1], [1,0], [1,1]), dtype=np.float32)
trainy = np.array([0,1,1,0], dtype=np.int32)
# 学習データとテストデータに同じものを使用
train = chainer.datasets.TupleDataset(trainx, trainy)
test = chainer.datasets.TupleDataset(trainx, trainy)

# ネットワークの登録
'''
ネットーワークの登録方法
2. 最適化関数の設定
3. モデルの設定
'''
model = L.Classifier(MyChain(), lossfun=F.softmax_cross_entropy)
# chainer.serializers.load_npz('result/out.model', model)
# 2. 最適化関数の設定 教師データと計算した結果の誤差をどのように学習していくのかを決める関数
optimizer = chainer.optimizers.Adam() # 最適化関数の設定
# 3.作成したオプティマイザにモデルを設定する
optimizer.setup(model)

# イテレータの定義
# 学習データとテストデータの作成
train_iter = chainer.iterators.SerialIterator(train, batchsize) # 学習データ
test_iter = chainer.iterators.SerialIterator(test, batchsize, repeat=False, shuffle=False) # 評価データ
# アップデータの登録
# 学習データとオプティマイザを結びつける
updater = training.StandardUpdater(train_iter, optimizer)

# 学習環境の設定と学習回数の設定
trainer = training.Trainer(updater, (epoch, 'epoch'))

# 学習状況の表示
trainer.extend(extensions.LogReport()) # ログ
trainer.extend(extensions.Evaluator(test_iter, model)) # エポック数の表示
trainer.extend(extensions.PrintReport(['epoch', 'main/loss', 'validation/main/loss','main/accuracy', 'validation/main/accuracy', 'elapsed_time'] )) # 計算状態の表示

# ニューラルネットワークの構造の可視化
# できた.dotファイルをgraphvizをインストールしてpng形式に変換する。コマンドは以下
# dot -K dot -T png cg.dot -o cg.png
trainer.extend(extensions.dump_graph('main/loss')) # ニューラルネットワークの構造

# 精度のグラフ表示
# 縦軸:精度
# 横軸:エポック数
trainer.extend(extensions.PlotReport(['main/accuracy', 'validation/main/accuracy'],'epoch', file_name='accuracy.png')) # 精度のグラフ

# 誤差のグラフ表示
# 縦軸:交差エントロピー誤差
# 横軸:エポック数
trainer.extend(extensions.PlotReport(['main/loss', 'validation/main/loss'], 'epoch',file_name='loss.png')) # 誤差のグラフ

# 学習状況の保存
trainer.extend(extensions.snapshot(), trigger=(100, 'epoch')) # 学習再開のためのスナップショット出力

# chainer.serializers.load_npz("result/snapshot_iter_100", trainer) # 再開用
# chainer.serializers.save_npz("result/out.model", model)

# 学習の開始
trainer.run()

 

実行結果、

epoch       main/loss   validation/main/loss  main/accuracy  validation/main/accuracy  elapsed_time

1           0.746678    0.745468              0.5            0.25                      0.00873882    

2           0.745468    0.744273              0.25           0.25                      0.0130902     

3           0.744273    0.743095              0.25           0.25                      0.0170885 

.

.

637         0.638736    0.638492              0.75           0.75                      9.54412       

638         0.638492    0.638247              0.75           0.75                      9.56882       

639         0.638247    0.637993              0.75           0.75                      9.60504       

640         0.637993    0.637751              0.75           1                         9.63925       

641         0.637751    0.637499              1              1                         9.67876       

642         0.637499    0.637259              1              1                         9.70237       

643         0.637259    0.637006              1              1                         9.7315    

.

. 

998         0.506556    0.506092              1              1                         19.85         

999         0.506092    0.505668              1              1                         19.8964       

1000        0.505668    0.505221              1              1                         19.9257     

 

精度(accuracy)が途中で100%になったのでなんかできてる感じがします。

それではグラフで表示してみます。

 

精度のグラフ表示
縦軸:精度
横軸:エポック数

accuracy.png

f:id:sekihan_0290:20180817213258p:plain

僕、精度って上がっていくようなきがするんだ(なんか変)

 

誤差のグラフ表示
縦軸:交差エントロピー誤差
横軸:エポック数

loss.png

f:id:sekihan_0290:20180817213356p:plain

学習を進めるにつれて値が小さくなっているから学習はできてると考えていいはず

ただ精度が・・・むむむ