”はやぶさ”の技術ノート

NNablaと学習済みモデル(HDF5)で推論 -Python編-

前回、Sony製の深層学習フレームワーク”NNable”で学習から推論まで実践するチュートリアル記事を書きました↓

【NNabla】実践!Neural Network Librariesで学習から推論まで|はやぶさの技術ノート

最終的に満足するモデルを生成できたので、学習済みモデルの重みを”MyChain.h5”に保存して終了しました。
今回は、この学習済みモデルを使って学習せず、いきなり推論から始める方法を説明します。

import

nnablaの各モジュールをimportします。
Solvers(最適化アルゴリズム)は推論では使いません。

In [1]:
import nnabla as nn
import nnabla.functions as F
import nnabla.parametric_functions as PF
# import nnabla.solvers as S
2019-03-11 19:50:48,133 [nnabla][INFO]: Initializing CPU extension...

その他、今回使用する(定番)モジュールもimportします。

In [2]:
import numpy as np
import matplotlib.pyplot as plt

nnabla用の入れ物を用意

In [3]:
batch_size = 1
x = nn.Variable((batch_size, 1))

ニューラルネットワーク設計

今回の場合、”学習済みモデル”というのは”重み”情報のみを保存したものです。
つまり、ニューラルネットワークの構造(アーキテクチャ)の情報までは保存していません。

そのため、改めて”重み”を格納するためのニューラルネットワークを生成する必要があります。 (なので関数化しておくと便利です)

In [4]:
def MyChain(x):    
    h1 = F.relu(PF.affine(x, 50, name = "l1"))
    h2 = F.relu(PF.affine(h1, 100, name = "l2"))
    y = PF.affine(h2, 1, name = "l3")
    return y

学習済みモデル(重み)を読込む

前回生成した学習済みモデルの”重み”を”MyChain.h5”は、以下のコード1行でロード完了!

In [5]:
nn.load_parameters("MyChain.h5")
2019-03-11 19:53:36,864 [nnabla][INFO]: Parameter load (<built-in function format>): MyChain.h5

モデルを宣言

In [6]:
y = MyChain(x)

推論したいデータ用意

本来はセンサ値を使うが、今回は適当な学習で使用していない未知のデータを生成した

In [7]:
xe = np.array([[0.5], [1.8], [2.3], [3.3], [4.5], [5.4], [6.3], [6.7], [7.4], [8.2]])

推論

In [8]:
y_list = []

for i in xe:
    x.d = i
    y.forward()
    y_list.append(y.d.copy())

推論結果

推論結果を確認します

In [9]:
print(xe)
y_list
[[0.5]
 [1.8]
 [2.3]
 [3.3]
 [4.5]
 [5.4]
 [6.3]
 [6.7]
 [7.4]
 [8.2]]
Out[9]:
[array([[0.5818206]], dtype=float32),
 array([[0.28624797]], dtype=float32),
 array([[0.2572706]], dtype=float32),
 array([[0.25293332]], dtype=float32),
 array([[0.48244265]], dtype=float32),
 array([[0.48221466]], dtype=float32),
 array([[0.02079037]], dtype=float32),
 array([[0.02079037]], dtype=float32),
 array([[0.14031371]], dtype=float32),
 array([[0.25689483]], dtype=float32)]

前回と同じ結果を得られました。一応グラフ化までしてみます。

In [10]:
yt = np.reshape(y_list, [10, 1])

# plt.plot(x, y)
plt.plot(xe, yt)
plt.plot(xe, yt, "ro")
plt.title("Predict")
plt.xlabel("input")
plt.ylabel("output")
plt.grid(True)
plt.show()

ばっちりですね!もう少し分かりやすく確認するため、学習で使用したデータ(x=0~9の整数値)でも推論してみます。

In [16]:
yt_list = []
xt_list = []
for i in range(10):
    x.d = i
    y.forward()
    yt_list.append(y.d.copy())
    xt_list.append(i)
    
yt_list = np.reshape(yt_list, [10, 1])

# plt.plot(x, y)
plt.plot(xt_list, yt_list)
plt.plot(xe, yt, "ro")
plt.title("comparison")
plt.xlabel("input")
plt.ylabel("output")
plt.grid(True)
plt.show()

yt_list
Out[16]:
array([[0.5000139 ],
       [0.5818206 ],
       [0.25947455],
       [0.28403342],
       [0.21649922],
       [0.70614535],
       [0.02079037],
       [0.06172293],
       [0.2531259 ],
       [0.27197036]], dtype=float32)

青線が学習データ(x=0~9の整数値)の推論結果、赤点が未知のデータに対する推論結果です。
一応、前回作成したグラフ↓と見比べてみます。うん!赤プロットの位置が一致してるのでOK!!

Predict.png

学習済みモデル保存(Python・C++用)

前回、学習済みモデルの”重み”のみをHDF5ファイルで保存しました。
今回は、”*.nnp(Neural Network Librariesモデルファイル)”で保存します。

”*.nnp”なら、”重み”+ネットワーク構造(アーキテクチャ)の情報を保存できるため、
ソースコード上でニューラルネットワークを定義せずに推論が行えるようになります。

つまり、コンパクトなソースコードで推論が行えます

In [12]:
import nnabla.utils.save

# Save NNP file (used in C++ inference later.).
contents = {
    'networks': [
        {'name': 'MyChain',
         'batch_size': batch_size,
         'outputs': {'y': y},
         'names': {'x': x}}],
    'executors': [
        {'name': 'runtime',
         'network': 'MyChain',
         'data': ['x'],
         'output': ['y']}]}
nnabla.utils.save.save('MyChain.nnp', contents)
2019-03-11 20:11:08,420 [nnabla][INFO]: Saving MyChain.nnp as nnp
2019-03-11 20:11:08,425 [nnabla][INFO]: Saving /tmp/tmp5umyjwo4/network.nntxt as prototxt
2019-03-11 20:11:08,458 [nnabla][INFO]: Parameter save (.protobuf): /tmp/tmp5umyjwo4/parameter.protobuf

↑のようにJSONフォーマットでnnpファイルの情報を記述して、
ニューラルネットワークの情報(重み+構造)を”MyChaine.nnp”に保存します。

次回は、nnpファイルで推論するかー

おわりに

学習にはマシンパワーが必要です。しかし、組込み機器(エッジディバイス)は基本的に低コスト/低消費電力/小型化が求められます。
そのため、組込み機器では”学習済みモデル”を使って推論のみ行うのがスマートだと考えています。