MachineLearning
DeepLearning
AzureMachineLearning
Chainer
DeepLearnigLab

Connpassの「Chainer x Azure ML Hackathon CV編」に参加してきた


概要

Connpass「Deep Learning Lab」の「Chainer x Azure ML Hackathon CV編」に参加してきたのでその記録です。

Hackathon となっていましたが、もくもく会的な感じでした!

https://dllab.connpass.com/event/83012/

500円で Azure のGPUインスタンスを利用できてかつ、

500円で AzureMachineLearningWorkbench について教えて頂けてかつ、

500円で Chainer v4 について教えて頂けてかつ、

500円で ビザが食べれた!!ので、

めっちゃ満足でした!


AzureMachineLearningWorkbench

結論から言うと、「ドキュメントめっちゃ良く出来ているから見てね♡」ってことでした。

確かに!!

https://docs.microsoft.com/ja-jp/azure/machine-learning/service/


Chainer v4 の AzureMachineLearning での環境構築

AzureMachineLearning の「Data Science Virtual Machine」で仮想マシンを作ると、

なんと!すでに、Chainer v4が入っているとのことだったので、

JupyterNotebookで、ちょっと動かしたろーって思って、

やってみると、、、

あれ!?

from chainer import Sequential

が通らない。。。

なんでだろうってことで、講師の方に聞きまくりました。

というか、環境構築してもらった!

どうも AzureMachineLearning で作った、

「Data Science Virtual Machine」の仮想環境では、

JupyterNotebookでは、Chainer v4が入ってないとのことでした。

Anacondaの環境ではなく、ローカルの環境が参照されるから的なことみたいです。。。

Jupyter上で、

%%bash

pip3 uninstall chainer
pip3 install chainer

とすると、行けるみたいです。

アンインストールして、インストールすることで、

最新のChainerをインストールということです!

GPUを使いたいので、以下も教えて頂きました。

まず、GPUのVersionを確認します。

Jupyter上で、

%%bash

nvcc --version

とすると、

nvcc: NVIDIA (R) Cuda compiler driver

Copyright (c) 2005-2017 NVIDIA Corporation
Built on Fri_Sep__1_21:08:03_CDT_2017
Cuda compilation tools, release 9.0, V9.0.176

と出てくるので、9.0の「cupy-cuda90」をインポートする必要があるとのことで、

Jupyter上で、

%%bash

pip3 uninstall cupy-cuda90
pip3 install cupy-cuda90

とすると、インポートできました!

よしこれで、「Chainer v4」のチュートリアルができる!


Chainer v4 チュートリアルを実施

このチュートリアルを書いた方に「Chainer v4」の概要を教えて頂きました。

https://qiita.com/mitmul/items/1e35fba085eb07a92560

そして、チュートリアルをみながら、

「cifar10」データセットの画像分類を実施しました。

※調子にのって、チュートリルとは違うモデルの構成にしました。 

 そのせいか精度上がりませんでした。。。

わからないことがあったら、すぐに聞けたので、激熱でした!!


学んだこと


・Sequential で、モデルの定義ができる

こんな感じで、定義ができました。

あんまり詳しくないので、こんな印象を持ちました。

・modelのクラスを定義しなくてもいいよ的なかんじ

・見やすい!!!!

import chainer

import chainer.functions as F
import chainer.links as L
from chainer import training,serializers,Chain,datasets,Sequential,optimizers,iterators
from chainer.training import extensions,Trainer
from functools import partial

model = Sequential(
L.Convolution2D(None, out_channels=32, ksize=3, stride=1),
F.relu,
partial(F.max_pooling_2d, ksize=2, stride=2),
L.Convolution2D(in_channels=32, out_channels=64, ksize=3, stride=1),
F.relu,
partial(F.max_pooling_2d, ksize=2, stride=2),
L.Convolution2D(in_channels=64, out_channels=128, ksize=3, stride=1),
F.relu,
L.Linear(None, 1000),
F.relu,
partial(F.dropout, ratio=0.75),
L.Linear(1000, 10),
)
model = L.Classifier(model)
model.to_gpu(0)


・Trainerを使うと便利

こんな感じで、書くと、学習を実施してくれます。

すっきり書けて、見やすい!

batchsize = 128

max_epoch = 60
gpu_id = 0

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

optimaizer = optimizers.Adam().setup(model)
updater = training.StandardUpdater(train_iter, optimaizer, device=gpu_id)
trainer = Trainer(updater, stop_trigger=(max_epoch, 'epoch'))

trainer.extend(extensions.LogReport())
trainer.extend(extensions.Evaluator(test_iter, model, device=gpu_id), name='val')
trainer.extend(extensions.PrintReport(['epoch', 'main/loss', 'main/accuracy', 'val/main/loss', 'val/main/accuracy', 'elapsed_time', 'lr']))
trainer.extend(extensions.snapshot(filename='snapshot_epoch-{.updater.epoch}'))
trainer.extend(extensions.dump_graph('main/loss'))

#学習を実行する
trainer.run()

学習の過程が、以下の感じで出てくれる。

おおー!!!

epoch       main/loss   main/accuracy  val/main/loss  val/main/accuracy  elapsed_time  lr        

1 1.60217 0.412284 1.29771 0.535305 6.54357
2 1.24028 0.557485 1.15035 0.580696 14.7192
3 1.05871 0.626262 0.938314 0.668908 23.4175
4 0.934494 0.672315 0.890924 0.686017 33.1585
5 0.848975 0.701826 0.836307 0.706685 41.587
6 0.773064 0.728486 0.785557 0.72498 50.0916
7 0.702637 0.755195 0.77106 0.731112 58.5505
8 0.653189 0.770673 0.736721 0.741792 66.8603
9 0.603416 0.787584 0.761884 0.739023 74.8583
10 0.556914 0.803928 0.749218 0.74644 83.118

エポックごとの学習済みモデルを保存してくれる!

これは、なんか面白いって思いました。

trainer.extend(extensions.snapshot(filename='snapshot_epoch-{.updater.epoch}'))

結果として、テストデータに対しては、「0.746835」でした。

うーん、何が悪いんだろう。。。

というか、GPUってすごい!

60エポックで、495.39秒!

ドロップアウトの「ration=0.75」というのも関係あるのかな...???

epoch       main/loss   main/accuracy  val/main/loss  val/main/accuracy  elapsed_time  lr   

59 0.104044 0.965505 1.57049 0.745154 487.431
60 0.102409 0.965313 1.75489 0.746835 495.39

せっかく、エポックごとにモデルを保存しているし、

学習済みモデルを使って、見てみようと思います。


・学習済みモデルを読み出す

こんな感じで、学習済みモデルから、予測結果を返すメソッドを作りました。

from chainer.cuda import to_cpu

import matplotlib.pyplot as plt
import numpy as np

def predict(data, index, epoch, gpu_id):

infer_net = model.copy()
model_path = 'result/snapshot_epoch-' + str(epoch)
serializers.load_npz(model_path , infer_net, path='updater/model:main/')

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

x, y = data[index]

plt.imshow(np.dstack((x[0],x[1],x[2])))
plt.show()

x = infer_net.xp.asarray(x[None, ...])
with chainer.using_config('train', False), chainer.using_config('enable_backprop', False):
y = infer_net.predictor(x)
y = to_cpu(y.array)
dic = {0:'飛行機',1:'自動車',2:'鳥',3:'猫',4:'鹿',5:'犬',6:'蛙',7:'馬',8:'船',9:'トラック'}
print('予測ラベル:', y.argmax(axis=1)[0], dic[y.argmax(axis=1)[0]])

はまったのは、以下の部分。

infer_net = model.copy()

model_path = 'result/snapshot_epoch-' + str(epoch)
serializers.load_npz(model_path , infer_net, path='updater/model:main/')

「infer_net 」に、何入れればいいんだろうって思って、

ググったりして、適当に「L.Classifier(model)」でいいでは?って思って、

ぶち込んでいたら、

KeyError: 'updater/model:main/predictor/predictor/0/W is not a file in the archive'

ってなりました。

そんなもん、学習済みモデルにありませんよ的なことらしい。

講師の方に、「こうすると中身みれるよ」って教えてもらいました。

import numpy as np

s = np.load('result/snapshot_epoch-10')
s.keys()

おっ!たしかに、「updater/model:main/predictor/predictor/0/W」がない!

「updater/model:main/」で読み込んで、「infer_net.predictor(x)」で予測したろーってことで、さっきのメソッドになりました。

['updater/model:main/predictor/3/W',

'updater/optimizer:main/predictor/1/W/m',
'updater/optimizer:main/predictor/2/b/t',
'updater/model:main/predictor/0/W',
'updater/model:main/predictor/3/b',
'updater/optimizer:main/predictor/1/b/v',
'updater/model:main/predictor/1/W',
'extensions/LogReport/_trigger/previous_epoch_detail',
'updater/optimizer:main/predictor/0/W/v',
'updater/model:main/predictor/2/W',
'extension_triggers/PrintReport/previous_epoch_detail',
'updater/optimizer:main/predictor/0/b/t',
'updater/optimizer:main/epoch',
'updater/model:main/predictor/4/b',
'updater/optimizer:main/predictor/4/b/m',
'extension_triggers/val/previous_epoch_detail',
'updater/optimizer:main/t',
'updater/optimizer:main/predictor/4/W/t',
'updater/optimizer:main/predictor/4/b/v',
'updater/optimizer:main/predictor/3/W/v',
'updater/iterator:main/previous_epoch_detail',
'updater/model:main/predictor/1/b',
'updater/optimizer:main/predictor/0/b/v',
'extension_triggers/LogReport/previous_epoch_detail',
'updater/optimizer:main/predictor/3/b/v',
'updater/optimizer:main/predictor/4/b/t',
'extensions/LogReport/_log',
'updater/iterator:main/epoch',
'updater/optimizer:main/predictor/4/W/m',
'updater/iterator:main/order',
'_snapshot_elapsed_time',
'updater/optimizer:main/predictor/0/W/t',
'extension_triggers/snapshot/previous_iteration',
'updater/model:main/predictor/4/W',
'updater/optimizer:main/predictor/0/W/m',
'updater/optimizer:main/predictor/3/b/t',
'updater/optimizer:main/predictor/3/b/m',
'updater/optimizer:main/predictor/0/b/m',
'extensions/LogReport/_trigger/previous_iteration',
'updater/optimizer:main/predictor/2/W/m',
'updater/optimizer:main/predictor/1/b/t',
'updater/optimizer:main/predictor/3/W/m',
'updater/iterator:main/is_new_epoch',
'updater/optimizer:main/predictor/2/W/v',
'extension_triggers/val/previous_iteration',
'updater/model:main/predictor/0/b',
'updater/optimizer:main/predictor/2/W/t',
'extension_triggers/PrintReport/previous_iteration',
'updater/optimizer:main/predictor/3/W/t',
'updater/optimizer:main/predictor/2/b/m',
'updater/optimizer:main/predictor/4/W/v',
'updater/iterator:main/current_position',
'updater/iteration',
'stop_trigger/previous_iteration',
'updater/optimizer:main/predictor/1/W/t',
'updater/optimizer:main/predictor/2/b/v',
'extension_triggers/LogReport/previous_iteration',
'extension_triggers/snapshot/previous_epoch_detail',
'updater/optimizer:main/predictor/1/W/v',
'updater/model:main/predictor/2/b',
'stop_trigger/previous_epoch_detail',
'extensions/LogReport/_summary/_names',
'updater/optimizer:main/predictor/1/b/m']


・学習済みモデルでの予測

まず、1エポック目でどうだ!

飛行機のはずが、、、船!

まあ、1エポック目だし、50%くらいの精度だし仕方ないか!

10_1.png

次は、30エポック目!

おおー、あたったー!

10_30.png

そして、60エポック目!

「鹿」!!!

確かに、鹿の角に見えなくはない。。。

「main/accuracy:0.965313」、「val/main/accuracy:0.746835」なので、

過学習なのかな???

精度が上がるように、チューニングしたいが、時間切れでした。

10_60.png


まとめ

AzureMachineLearning、Chainerを使った勉強ができて楽しかったです!

詳しい方が周りにいて、聞ける状況ってありがたいって思いました。

わからなかったときに、理解できるように教えてくれて本当に助かりました。

教えてくれた方々、ありがとうございました。

次は、精度が上がるように、チューニングできるようになりたい!