こんにちは。
ディープラーニングお兄さんの”はやぶさ”@Cpp_Learningです。
前回、Sony製の深層学習フレームワーク “Neural Network Libraries(NNabla)” のPython APIを使って学習から推論までを実践するチュートリアル記事を書きました↓
↑記事の終盤で学習済みモデル”MyChain.h5”を保存しました。
今回は、この学習済みモデル”MyChain.h5”を使って推論を実践していきます。
Contents
学習済みモデルとは
深層学習の一連の流れを簡単に説明すると大体こんな感じです↓
【深層学習フロー】
- データ収集
- ニューラルネットワークの構造(アーキテクチャ)設計
- 学習によりニューラルネットワークの重み(パラメータ)を調整
- 学習済みのニューラルネットワークを使って推論
言葉の定義は書籍などにより異なりますが、”学習済みニューラルネットワーク”のことを”学習済みモデル”と呼ぶことが多いです。
- 深層学習では、”重み”の自動調整のことを”学習”と呼ぶ
- “学習済みニューラルネットワーク”=”学習済みモデル”と考えて良い
ニューラルネットワークの保存形式 -構造と重み-
深層学習フレームワークで実装したニューラルネットワークは以下の形式で保存します。
ファイル | 内容 |
HDF5ファイル | ニューラルネットワークの構造(アーキテクチャ) |
JSON / YAMLファイル | ニューラルネットワークの重み(パラメータ) |
HDF5ファイル | ニューラルネットワークの構造と重み |
ファイルについては使用するフレームワークに依存するため、あくまで一例ですが…
ここでは言いたいのは、ニューラルネットワークが構造/重み/構造と重みの3パターンで保存されるという点です。
チームメンバーが以下の言葉をどういう意図で使っているのかに注意しましょう
- ニューラルネットワーク
- モデル
- 学習済みニューラルネットワーク
- 学習済みモデル
Neural Network Libraries(NNabla)と学習済みモデル
“Neural Network Libraries”の場合、ニューラルネットワークは以下の形式で保存します。
ファイル | 内容 |
net.nntxt | ニューラルネットワークの構造(アーキテクチャ) |
parameters.h5 | ニューラルネットワークの重み(パラメータ) |
net_param.nnp | ニューラルネットワークの構造と重み |
学習により自動調整されるのは”重み”なので、「学習済みモデル」または「学習済みニューラルネットワーク」といえば「学習済みの”重み”」または「構造と学習済みの”重み”」を保存したものと考えて問題ありません。
↑の記事で保存した学習済みモデルは”MyChain.h5”でした。
つまり、”重み”の情報のみが保存してあり、その重みを格納するニューラルネットワークの構造については「.nntx」を使うか、再度ソースコード上で定義する必要があります。
という人も、ソースコード見ればスッキリ理解できるかもしれないので、以降からはソースコードを交えて説明します。
【実践】学習済みモデル(HDF5ファイル)による推論
NNableのPython APIと学習済みモデル(HDF5ファイル)を使って推論を行います。
import
nnablaの各モジュールをimportします。推論では最適化アルゴリズム(Solvers)を使いません。
1 2 3 4 |
import nnabla as nn import nnabla.functions as F import nnabla.parametric_functions as PF # import nnabla.solvers as S |
その他、今回使用する数値演算モジュールなどもimportします。
1 2 |
import numpy as np import matplotlib.pyplot as plt |
NNabla用の変数定義
NNablaで学習および推論を行うために専用の変数を定義します。
1 2 |
batch_size = 1 x = nn.Variable((batch_size, 1)) |
ニューラルネットワーク設計
繰り返しますが、学習済みモデル”MyChain.h5”には”重み”の情報のみ保存してあります。
つまり、ニューラルネットワークの構造(アーキテクチャ)の情報は保存していないので、改めて”重み”を格納するためのニューラルネットワークを定義する必要があります。
1 2 3 4 5 |
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(x)”をコピペするだけでOKです。
繰り返し実装するコードは関数化しておくと移植性が向上するのでオススメ!
学習済みモデル(重み)を読込む
学習済みモデル”MyChain.h5”をロードします(”重み”を読込みます)。
1 |
nn.load_parameters("MyChain.h5") |
たった1行で学習済みモデル(HDF5ファイル)の読込みができました。
推論から推論結果のグラフ化まで
以降からは、前回書いた「NNablaによる学習から推論まで」の記事で説明した推論フェーズのコードをコピペすればOKです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# モデルの宣言 y = MyChain(x) # 推論したいデータ(学習で使用していない未知のデータ) xe = np.array([[0.5], [1.8], [2.3], [3.3], [4.5], [5.4], [6.3], [6.7], [7.4], [8.2]]) # 推論1(未知のデータ) y_list = [] for i in xe: x.d = i y.forward() y_list.append(y.d.copy()) # 推論2(学習で使用したデータ) 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 = np.reshape(y_list, [10, 1]) yt_list = np.reshape(yt_list, [10, 1]) 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() |
青線が学習で使用したデータ(x=0~9の整数)の推論結果、赤プロットが未知のデータ(x=0~9の少数)に対する推論結果です。
前回「NNablaによる学習から推論まで」の記事で描いた推論結果のグラフと比較してみます。
赤プロットの推論結果は完全に一致しています。つまり、前回と同じ学習済みモデルで推論できた!ということです。
(こちらの青線は推論結果ではなく実験データなので、僅かに不一致ですね)
学習済みモデル保存
学習済みモデル”MyChain.h5”は”重み”のみを保存していました。
ファイル | 内容 |
net.nntxt | ニューラルネットワークの構造(アーキテクチャ) |
parameters.h5 | ニューラルネットワークの重み(パラメータ) |
MyChain.nnp | ニューラルネットワークの構造と重み |
今回は、ニューラルネットワークの構造と重みを”MyChain.nnp”で保存します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
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) |
↑のようにJSONフォーマットで情報を記述して、ニューラルネットワークの重みと構造を”MyChaine.nnp”に保存します。
これで次回からは学習済みモデル”MyChaine.nnp”のみ(ニューラルネットワークの関数MyChain(x)なし)で推論ができます。
- *.nnpには学習済みモデル(重み+構造)が保存してあります。
- *.nnpをロードすれば、構造の情報も取得できるため、ソースコード上でニューラルネットワークを定義しないで推論ができます。
はやぶさの技術ノート
本記事を書く前に、Jupyter Notebookで検証を行った『メモ付きソースコード(技術ノート)』があるので、公開します。
ちょっと散らかってけど、ソースコード見るだけなら”技術ノート”の方が便利だと思います。
まとめ
Sony製の深層学習フレームワーク “Neural Network Libraries(NNabla)” と学習済みモデル(HDF5)を使った推論を実践しました。
深層学習の学習フェーズではマシンパワーを必要とする場合がほとんどです。
しかし、組込み機器(エッジディバイス)は基本的に低コスト/低消費電力/小型化が求められるため、マシンパワーが小さいものが多いです。
そのため、組込み機器では”学習済みモデル”を使い推論フェーズのみ実行するのがスマートです。
本記事を読んで「学習済みモデルの使い方が分かった」・「組込み機器で深層学習やってみたい!」という人が現れたら、ディープラーニングお兄さんはすごく嬉しい!
おまけ -組み込み深層学習-
Neural Network Librariesで生成した学習済みモデルとSony製のスマートセンシングプロセッサ搭載ボード”Spresense”を使って推論ができるそうです。ほしい…!