アラカン"BOKU"のITな日常

文系システムエンジニアの”BOKU”が勉強したこと、経験したこと、日々思うことを書いてます。

NNabla(Neural Network Libraries)のシンプルチュートリアルをPython3.5でやってみる。

NNablaをせっかくインストールしたので、チュートリアルをやってみます。 

前提として、こちらの記事の手順でインストールされていることとします。

arakan-pgm-ai.hatenablog.com

 

異なる環境を使っている場合は、読み替えてくださいね。

 

必要なライブラリの準備をしておく 

まず、追加で必要なライブラリをインストールしておきます。

  • pyWin32
  • scikit_learn
  • matplotlib

まず、コマンドプロンプトを起動して、nnabla環境切り替えておきます。

activate nnabla

 

◆pyWin32

 

pyWin32は、pythonWindowsAPIを利用するモジュールです。 

NNablaが使っているので、インストールされていないと、import nnabla でエラーになります。 

インストールの時に、iPython上で「import nnabla」して確認するために、pypiwin32をインストールして対応してOKだったのですが、ソースコードに書いて実行しようとすると、nnablaがimportエラーになりました。 

なので、とりあえず、まだの場合は以下のコマンドで入れといた方がいいです。

conda install -c anaconda pywin32

 

sikikit-learn

 

これは機械学習ライブラリです。 

NNablaがあるのに、なぜこれをインストールしておくかというと、テスト用のデータを取得するのに利用できるからです。 

MINISTとか、その縮小版のdigitsとか,結構豊富に学習用データを提供してくれてます。

5. Dataset loading utilities — scikit-learn 0.19.0 documentation

これは、以下のコマンドでインストールしておきます。

pip install scikit-learn

 

◆matplotlib

 

グラフ描画ツールです。 

anacondaベースなので、「matplotlib」は、おそらくすでにインストールされてます。 

確認は以下のコマンドでやります。

pip list | find " matplotlib "

これでインストールされてなかったら、今のコマンドでインストールします。

pip install  matplotlib 

これで準備はOKです。

 

開発環境の説明

ここからはIDLEというpythonの開発環境を使う前提で説明を書きます。 

エディタでソースコードを書いて保存して、F5キーを押すことで、スクリプトを実行することができます。 

IDLEの立ち上げは、コマンドプロンプトのnnabla環境上で以下のコマンドを打ちます。

idle

しばらくすると、このようなコンソール画面が立ち上がります。

f:id:arakan_no_boku:20170925220335j:plain

 

なお、最初に立ち上がってきたIDLEコンソールが、上記みたいな色じゃない・・方もあると思いますが、これは、Options->ConfigureIDLEのHilightingタブで変更できるテーマの違いだけです。 

"BOKU"の設定は、「IDLE DARK」になってます。

f:id:arakan_no_boku:20170925220723j:plain

 

あとは、IDLEのメニューからFile>New Fileを選んで、エディタを立ち上げます。

f:id:arakan_no_boku:20170925220954j:plain

 

そして、エディタにソースコードを書いて、ファイルを保存後、そのファイルをエディタ上で開いた状態で「F5」キーを押すと、スクリプトが実行されて、IDLEコンソールに結果が表示されます。 

もちろん、一度、保存したファイルをメニューの「Open」で開いた時も同じです。 

IDLEコンソールの表示例は、こんな感じです。

f:id:arakan_no_boku:20170926005041j:plain

 

さてチュートリアル

NNabla(Neural Network Libraries)のチュートリアルはこちらにあります。

f:id:arakan_no_boku:20170926005950j:plain

 

ただ、今のところ、英語版しかありません。

 

チュートリアルその1

まず、こちらのチュートリアルを参考にしてやってみます。

NNabla by Examples — Neural Network Libraries 0.9.4 documentation

 ただ、ここに掲載されているコードをそのままコピペしてもうまく行きません。 

主な理由は3つです。

  • iPython用の構文があって、IDLEで実行するとエラーになる。
  • python2用なので、python3では修正しないと動かない。
  • tiny_digits.py(以下のリンク)がソースと同じフォルダにある前提になっている

github.com

そのため、tiny_digits.pyの一部のソースを移植するなど、部分的に書き換えて、python3のIDLEで動くようにしています。 

あと、チュートリアルは、丁寧に逐次内容を確認するステップを踏んでいるため、printやmatplotlib関連のコードがたくさん書かれています。 

それを一本のソースにまとめてしまうと、ごちゃごちゃしてしまうので、最低限だけ残して削除しています。 

最初にソースの全文を載せます。

#① NNabla関連モジュールのインポート
import nnabla as nn
import nnabla.functions as F
import nnabla.parametric_functions as PF
import nnabla.solvers as S
from nnabla.utils.data_iterator import data_iterator_simple

#② NNabla関連以外のモジュールのインポート
import numpy as np
from sklearn.datasets import load_digits

#③ tiny_digits.pyから転載したデータ整形function
def data_iterator_tiny_digits(digits, batch_size=64, shuffle=False, rng=None):
    def load_func(index):
    """Loading an image and its label"""
        img = digits.images[index]
        label = digits.target[index]
         return img[None], np.array([label]).astype(np.int32)
    return data_iterator_simple(load_func, digits.target.shape[0], batch_size, shuffle, rng, with_file_cache=False)

#④ scikit_learnに用意されているdigits(8✕8サイズ)を取得し、NNablaで処理可能に整形する
np.random.seed(0)
digits = load_digits(n_class=10)
data = data_iterator_tiny_digits(digits, batch_size=64, shuffle=True)

#⑤Affine層1層分生成する。アウトプットサイズは10(0から9の数字)にする
img, label = data.next()
x = nn.Variable(img.shape)
t = nn.Variable(label.shape)
with nn.parameter_scope("affine1"):
    y = PF.affine(x, 10)

#⑥ 損失グラフを生成する
loss = F.mean(F.softmax_cross_entropy(y, t))

#⑦ 学習時にパラメータを更新するSolverをSGDで生成する
learning_rate = 1e-3
solver = S.Sgd(learning_rate)
solver.set_parameters(nn.get_parameters())

#⑧ 1000回学習を繰り返す
for i in range(1000):
    x.d, t.d = data.next()
    loss.forward()
    solver.zero_grad()
    loss.backward()
    solver.update()
    if i % 100 == 0:
        print(str(i)+":loss:"+str(loss.d))

#⑨ 学習結果を使って推論し、最後に正確さを求めて表示する
x.d, t.d = data.next()
y.forward()
mch = 0
for p in range(len(t.d)):
    if t.d[p] == y.d.argmax(axis=1)[p] :
        mch += 1

print("Accuracy:{}".format(mch / len(t.d)))

 

これをエディターで保存して、F5キーを押して実行すると、このような結果が表示されるはずです。

f:id:arakan_no_boku:20170926233246j:plain

 

簡単にポイントだけ、チュートリアルを参考に書いておきます。 

①と②のimportは特に説明不要だと思います。

 

#③ tiny_digits.pyから転載したデータ整形function

 

説明には「画像とラベルをミニバッチとして提供するジェネレータであるデータセットローダを作成します。」と書いてあります。 

普通に画像データを使う場合は、ミニバッチでシャッフルしながら取り出す処理を自前で書かないといけないのですが、このNNablaのユーティリティである「data_iterator_simple」を通すことで、ミニバッチサイズでシャッフルして取り出す処理を自動で行ってくれるジェネレータを作成できるみたいです。

 

#④ scikit_learnに用意されているdigits(8✕8サイズ)を取得し、NNablaで処理可能に整形する

 

なので、ここで画像データを取得して、上記のファンクションを通すことで、data.next()のような形で、シャッフルされたデータを取得できるようにしているみたいです。

 

#⑤Affine層1層分生成する。アウトプットサイズは10(0から9の数字)にする

 

Afineレイヤーを1層定義してます。 

データ・セットのshape(inputサイズ)と、outputサイズ(0から9の手書き数字画像なので10)を引数に与えてます。

 

#⑥ 損失グラフを生成する

 

さっき定義したレイヤーに損失関数としてsoftmax_cross_entropyを使う宣言を加えて、推論と学習を行うグラフを生成しています。

 

#⑦ 学習時にパラメータを更新するSolverをSGDで生成する

solverって書いてますが、ニューラルネットワークコンソールでは、Optimizerとなっていたものと同じです。 

ここでは一番基本的なSGDを使うよ・・ということですね。

 

#⑧ 1000回学習を繰り返す

単純に1000回の繰り返しです。 

ここで重要なのは、チュートリアルに「バックプロパゲーションを実行する前に、すべてのパラメータのグラディエントバッファをゼロに初期化する必要があります。」と書いてあることですね。 

これは、「loss.backward()」を実行する前には、必ず「solver.zero_grad()」を実行しておけよ・・ということみたいです。

 

#⑨ 学習結果を使って推論し、最後に正確さを求めて表示する

ここは見ての通りで、学習済パラメータを使って推論して、結果のうちで最も確率値が高いものをargmaxで取り出したものと、元の正解ラベルを比較して正解をカウントしているだけです。 

こうやってみると、まあまあ、見通しよく書ける感じはします。 

チュートリアルには、他にも書いてあるので、次回も、順次確認して書いていこうかんと思います。 

関連記事

NNablaカテゴリの記事一覧はこちらです。

arakan-pgm-ai.hatenablog.com

ニューラルネットワークコンソールカテゴリの記事一覧はこちらです。

arakan-pgm-ai.hatenablog.com