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

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

NNablaでニューラルネットワークコンソールで学習済のパラメータを利用して推論のみを行う。/使い方番外編

2018/07/25追記

>今更ですが、この回に番号をふり忘れていたのに気づきました。

>実際は使い方14だったのですが・・、今更訂正もできないので番外編にしました。

 

NNabla(Neural Network Libraries)で、ニューラルネットワークコンソールからエクスポートしたモデルのPythonソースと、学習済のパラメータを使って、推論だけやってみます。 

前にこの記事でも、頑張ってやってみますね・・って書いたことだし。

arakan-pgm-ai.hatenablog.com

  

Cli.pyという手もあるみたいだけど 

 

ニューラルネットワークコンソールのEVALUATIONウインドウに表示されるcli.pyコマンドをコピペしてデータ・セットパラメータとかを変えて実行すれば、たぶん、できるだろうなとは思います。 

cli.py forward のオプションはこんな感じらしいので。

  • -c 学習結果フォルダのネットワーク定義ファイル(net.nntxt)
  • -p 学習結果フォルダのパラメータファイル(parameters.h5)
  • -d 評価データセットCSVファイル
  • -o 評価結果ファイルの出力フォルダ

でも、それだとニューラルネットワークコンソールを実行してるのと同じだから、いまいち楽しくないです。 

 

2018/10/03追記

cli.pyを直接実行するのは、意外に難しいです。

>どうも仮想環境を使っているっぽくて、普通にやってもうまく動きません。

>nnabla_cli.exeの方を使ってください。

arakan-pgm-ai.hatenablog.com

 

さて、記事に戻ります。

今回は、純粋にNNablaで書いてみたいわけです。 

絶対、できるはずですからね。 

だって、ニューラルネットワークコンソール(Neural Network Console)は、NNablaの「統合開発環境」だと、SONYさんが言ってますから。

www.sonynetwork.co.jp

 

なお、これ以後の説明は、以下の記事の手順でインストールをしている前提で書いてますので、環境の異なる方は適宜読み替えてくださいね。

arakan-pgm-ai.hatenablog.com

 

NNabla環境でIDLEを立ち上げる

 

自分の環境は、nnablaを仮想環境にインストールしてますから、コマンドプロンプトを立ち上げて、「activate nnabla」します。 

nnabla環境で、IDLEを起動します。

f:id:arakan_no_boku:20170928225530j:plain

IDLEコンソールで、File>New File で新規にエディタを開いておいてください。

f:id:arakan_no_boku:20170928225739j:plain

 

ニューラルネットワークコンソールからエクスポート

 

2017/12/02追記

>以降の説明の画面はVersion1.00のものです。

>Version1.10でアイコンのデザインが一部変更になってます。

>しかし、見てわかる程度と判断して、そのままにしています。

 

ニューラルネットワークコンソールを立ち上げます。

f:id:arakan_no_boku:20170928224515j:plain

 

LeNet.sdcprj を選択して開き、ACTION>Export>Python Code(NNabla) を選びます。

f:id:arakan_no_boku:20170928224917j:plain

 そうすると、pythonコードがクリップボードにコピーされます。

f:id:arakan_no_boku:20170928234054j:plain

これを、先程立ち上げておいたIDLEエディタに貼り付けて、名前をつけて保存します。

f:id:arakan_no_boku:20170928235013j:plain

 ここからは、ニューラルネットワークコンソールのバージョンで、ちょっと内容が変わります。

 

Version1.00でエクスポートした場合

 

コピーできたのは、こんな感じのネットワーク定義です。

def network(x, y, test=False):

     # Input -> 1,28,28
     # Convolution -> 16,22,22
     with nn.parameter_scope('Convolution'):
          h = PF.convolution(x, 16, (7,7), (0,0))
     # ReLU
     h = F.relu(h, True)
     # MaxPooling -> 16,11,11
     h = F.max_pooling(h, (2,2), (2,2), True)
     # Convolution_2 -> 30,9,9
     with nn.parameter_scope('Convolution_2'):
            h = PF.convolution(h, 30, (3,3), (0,0))
     # MaxPooling_2 -> 30,4,4

     h = F.max_pooling(h, (2,2), (2,2), True)
     # Tanh_2
     h = F.tanh(h)
     # Affine -> 150
    with nn.parameter_scope('Affine'):
         h = PF.affine(h, (150,))
    # ReLU_2
    h = F.relu(h, True)
    # Affine_2 -> 10
    with nn.parameter_scope('Affine_2'):
         h= PF.affine(h, (10,))

    # Softmax
    h = F.softmax(h)
    # CategoricalCrossEntropy -> 1
    #h = F.categorical_cross_entropy(h, y)
    return  h

 

上記は、エクスポートした結果に3つほどの作業を施してます。 

ひとつは、h = F.categorical_cross_entropy(h, y) のコメントアウトです。 

ニューラルネットワークコンソールからエクスポートすると、これもついてきてしまうのですが、これを残しておくと推論が正しくできません。 

ふたつめは、nn.parameter_scope の部分の nn. がなくて、parameter_scope になっている場合は、nn. を書き足します。 

みっつ目は、最後の「return」です。 

y=network(x)のように使いたいので、ここは、「return」のままではなく、を書き足して、「return h」としておきます。 

しないと、左辺で受けた「y」がNonTypeだ・・といって、エラーになります。 

あと、以下のimportを追加で書き込む必要があります。

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_csv_dataset 

 一応、ここまではOKです。

Version1.10でエクスポートした場合 

エクスポートした状態がこれです。

import nnabla as nn
import nnabla.functions as F
import nnabla.parametric_functions as PF

def network(x, y, test=False):
    # Input -> 1,28,28
    # Convolution -> 16,22,22
    with nn.parameter_scope('Convolution'):
        h = PF.convolution(x, 16, (7,7), (0,0))
    # ReLU
    h = F.relu(h, True)
    # MaxPooling -> 16,11,11
    h = F.max_pooling(h, (2,2), (2,2), True)
    # Convolution_2 -> 30,9,9
    with nn.parameter_scope('Convolution_2'):
        h = PF.convolution(h, 30, (3,3), (0,0))
    # MaxPooling_2 -> 30,4,4
    h = F.max_pooling(h, (2,2), (2,2), True)
    # Tanh_2
    h = F.tanh(h)
    # Affine -> 150
    with nn.parameter_scope('Affine'):
        h = PF.affine(h, (150,))
    # ReLU_2
    h = F.relu(h, True)
    # Affine_2 -> 10
    with nn.parameter_scope('Affine_2'):
        h = PF.affine(h, (10,))
    # Softmax
    h = F.softmax(h)
    # CategoricalCrossEntropy -> 1
    h = F.categorical_cross_entropy(h, y)
return h

 

Version1.00で不足していたimportと、nn.の追加、および return hにするの三ヶ所は修正されています。 

なので、Version1.10で必要な加工は、「 h = F.categorical_cross_entropy(h, y)」を コメントアウトするために、「#h = F.categorical_cross_entropy(h, y)」にするだけです。 

あと、importは以下の2行だけ追加します。

import nnabla.solvers as S
from nnabla.utils.data_iterator import data_iterator_csv_dataset 

 

推論するためのデータ・セットの読み込みを記述する

 

推論するためには、データ・セットを読み込まないと話になりません。 

これも、ニューラルネットワークコンソールで用意されているデータ・セットをそのまま使ってみます。 

読み込むためのAPIは、リファレンスで、まさにそのためのAPIですと、言わんばかりのものを見つけました。 

nnabla.utils.data_iterator.data_iterator_csv_dataset(uri, batch_size, shuffle, rng=None, normalize=True, with_memory_cache=True, with_file_cache=True, cache_dir=None, epoch_begin_callbacks=, epoch_end_callbacks=)

 

これだけあればいけるんじゃないの!・・ということで、早速試してみます。 

ニューラルネットワークコンソールをインストールしたフォルダに行きます。 

そこの「sample_dataset\MNIST」フォルダの下にある「mnist_test.csv」を使うことにします。 

ニューラルネットワークコンソールのDATASETタブのこれですね。

f:id:arakan_no_boku:20170929231243j:plain

 これをフルパスで以下のように指定してみます。

test_data = data_iterator_csv_dataset("C:\\ncon\\samples\\sample_dataset\\MNIST\\mnist_test.csv",1,shuffle=False)

c:\\ncon は、ニューラルネットワークコンソールをインストールしたフォルダです。 

引数の1は、ループの中でカウントして100件毎にログを出したかったので、バッチサイズを1件にするためにしています。 

ShuffleはFalseにしておきます。 

学習の時はTrueですが、今はTrueにする意味がないので。 

あと、\ は、\\ とエスケープしないと、エラーになるので忘れないように・・と。 

 

学習済パラメータをロードする記述を記述する

 

次はパラメータです。 

学習済パラメータのLOADの方法は練習を兼ねて、前回の記事でチュートリアルを参考にやってみました。

arakan-pgm-ai.hatenablog.com

 これにならってやります。 

LeNetのプロジェクトがあるフォルダに行きます。 

自分の環境だと、以下の場所にあります。

C:\ncon\samples\sample_project\image_recognition\MNIST

 このフォルダの「LeNet.files」というフォルダの下に学習済パラメータが保存されています。 

ニューラルネットワークコンソールのEDUCATIONタグで一番成績がよかった番号と同じ名前のフォルダを探します。

f:id:arakan_no_boku:20170929232022j:plain

 その下にある「parameters.h5」を、これもフルパスで指定すれば良さそうです。 

こんな漢字です。

nn.parameter.load_parameters("C:\\ncon\\samples\\sample_project\\image_recognition\\MNIST\\LeNet.files\\20170923_103005\\parameters.h5");

 

推論を実行する部分を記述する 

 

推論をする部分のコードを書かないといけません。 

データ読み込みを行い、学習済パラメータを読み込み、それらを使って推論する。 

その部分を書くとこんな感じになります。

#テスト用データの読み込み

test_data = data_iterator_csv_dataset("C:\\ncon\\samples\\sample_dataset\\MNIST\\mnist_test.csv",1,shuffle=False)

#一致件数カウンターのクリア

mch = 0

#ネットワークの構築
nn.clear_parameters()
x = nn.Variable*1
t = nn.Variable*2
y = network(x,t)

#学習済パラメータの読み込み

nn.parameter.load_parameters("C:\\ncon\\samples\\sample_project\\image_recognition\\MNIST\\LeNet.files\\20170923_103005\\parameters.h5");

#1件ずつデータを読み、推論して結果をカウントしていく

for i in range(test_data.size):
    x.d, t.d = test_data.next()
    y.forward()
    if t.d == y.d.argmax(axis=1) :
        mch += 1

print("Accuracy:{}".format(mch / test_data.size)) 

 簡単に補足します。  

まず、以下のように書いてある部分。

f:id:arakan_no_boku:20171003193954j:plain

これは、要するにData部のshapeとLabel部のshapeです。 

MNISTなので、1,28,28で、バッチサイズが1 ということです。 

パラメータの読み込みの前に、パラメータ領域をクリアしていますが、この処理の置き場所が最大のポイントです。。

nn.clear_parameters()

 

上記のように、ネットワークを構築する前におかないとダメです。 

これを例えば、学習済パラメータのロード処理の直前とかに置いてしまうと、まったく学習されていない結果に悩むことになります。 

後は、データを1件ずつ読み込んで、forward()して、結果を比較してマッチしてたらカウントして結果を表示するだけです。 

これで保存して、F5キーを押して実行します。

f:id:arakan_no_boku:20171001170852j:plain

 

99.04%!いけました

 

2017/12/02追記

>上記の結果は、ニューラルネットワークコンソールとNNablaのバージョンによって若干差異があるようです。

 

上記は、convolutionの初期値とかがデフォルトのままにしている(エクスポートでは初期値設定とかは出力されないみたいなので)ことを考えれば、ほぼパラメータは正しく認識できてます。 

あとは、上記のネットワーク構築時に、初期値とかを適切に設定してやればよさそうですね。 

とりあえず、ニューラルネットワークコンソールで学習した結果のパラメータと、データ・セットがそのままNNablaで使えるのがわかったのは大きいですねえ。

 

2017/12/02追記

ニューラルネットワークコンソールのVersion1.10でアイコンのデザインが変更になっている主な箇所です。

f:id:arakan_no_boku:20171130202351j:plain

関連記事

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

arakan-pgm-ai.hatenablog.com

 

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

arakan-pgm-ai.hatenablog.com

f:id:arakan_no_boku:20171115215731j:plain

*1:1,1,28,28

*2:1,1