Neural Network Libraries (Nnabla) を使って「Auto Encoder」を実装してみた! [AI]
ディープラーニング・トーシローの私が、Neural Network Libraries を使って簡単な「Auto Encoder」を実装してみました!Auto Encoder は、たくさんのデータを使って、おおまかな形を覚えさせ、ノイズの入ったデータもそれらしく出力するというものです。
Auto Encoder は Deep Learning の中では比較的簡単なものですので、入門にはちょうど良い例題だと思います。(もうちょっと簡単にできるとよかったのですが…)
今回、学習させるデータはSin波です。トレーニングデータは、Sin派に±0.3のノイズを加えて生成しました。まずは Python のコードの全体を貼っておきます。(そのうち github に上げます)
ここから細かくコードを解説していきます。(トーシローなんで間違っているかも知れません。もし間違っていたら指摘いただけると助かります)
■ Import する各種ライブラリ
nnabla の各種ライブラリと、numpyとグラフを表示のための matplot をインポートします。
■ AutoEncoder のニューラルネットワークを構築する
Auto Encoder は Affine と Relu で構成してみました。層やノードの数は適当に決めています。適当に値を変えてみたり、活性化関数を変えてみて様子を見てみると面白いかもしれません。
■ ニューラルネットワークをセットアップする
・Nnabla のパラメータの消去
nnabla が保持しているパラメータをnn.clear_parameters()で消去しておきます。これがないと、ニューラルネットの構成を変えるとエラーが出ます。
・バッチサイズの指定
batch_size は1にしてみました。都度データを生成して学習させるので、複数のデータを一度に与えるのが面倒だったからというのが真相です。
・コンテナの定義
nn.Variableは、ニューラルネットにデータを渡すためのコンテナです。学習や推論を行うときはデータをこのコンテナに格納して渡します。
■ 損失関数をセットアップする
ここでは損失関数と学習を進めるための Solver を設定します。Solver は平たく言えば最小二乗法のような損失を小さくするための数学的な道具です。
・損失関数:F.mean(F.squared_error(output_data, input_training_data))
ここでは出力値と入力値の二乗平均誤差を出しています。いわゆる教師なし学習です。コメントアウトしているコードは、入力データに誤差のない純粋な Sin波を教師データとして与えています。教師ありと教師無しデータでどのように結果が違うかぜひ試してみてください。
・ソルバー:S.Adam()
正直よく知りません。与えるパラメータが少なく便利なので使ってみました。他のソルバーで試してみて結果がどう変わるか観察してみると面白いかもしれません。詳しくはこちらを参照してください。
■ 教師データならびにグラフ描画用の変数の設定
教師データを使った学習を行う場合は、teacher_data を使ってください。他はグラフプロット用の変数宣言です。
■ 学習(ディープラーニング)用のループ処理
学習回数(Epoch)は1000回としました。
・学習用データを生成
training_data = [np.sin(n) + random.uniform(-0.3, 0.3) for n in x] がそれにあたります。少しトリッキーなコードですが、0.0~6.3 までのサインデータに±0.3 のランダムデータを加えて学習用データとしています。
・コンテナの学習用データを格納
input_training_data.d = training_data で、コンテナに学習用データを設定しています。こうすることで、ニューラルネットワークにデータを渡すことができます。
・学習を実施
loss.forward() / solver.zero_grad() / loss.backward() / solver.update() が学習の基本ルーチンと思ってください。損失関数で値を出して、前回との差分を勾配降下法で逆伝搬させパラメータを調整して差を縮めていくという処理です。使う側にとっては、この程度の理解で十分かと。
■ 推論を実行する
学習が終わったので、推論を実行します。
・テスト用データの生成
val_data = [np.sin(n) + random.uniform(-0.3, 0.3) for n in x] で学習用データと同じ要領でデータ生成します。
・ニューラルネットワークの設定
input_data = nn.Variable((batch_size, 64)) , result = network(input_data) で、コンテナの準備とニューラルネットワークの設定を行います。
・推論を実行
input_data.d = val_data でテスト用データをコンテナに格納し、 result.forward() で推論が実行されます。
・出力データを取得
出力したデータの次元は (1, 64) になっているので、output = result.d.copy().reshape(64,).tolist() で出力を 64要素を持つリストにして出力します。グラフに描画するための処理です。
■ 出力結果をみてみる
学習用データをすべてグラフにマップしたものです。このデータを使って学習しました。
学習の過程を示したグラフです。うまく収束しているみたいですね。
これが結果です。青がテスト用データ。オレンジが AutoEncoder の出力。点線が純粋な Sin波です。
結果はまぁまぁかな。教師ありでの学習もぜひ試してみてください。もっと良い結果が出ると思います。🙂
(^^)/~
Auto Encoder は Deep Learning の中では比較的簡単なものですので、入門にはちょうど良い例題だと思います。(もうちょっと簡単にできるとよかったのですが…)
今回、学習させるデータはSin波です。トレーニングデータは、Sin派に±0.3のノイズを加えて生成しました。まずは Python のコードの全体を貼っておきます。(そのうち github に上げます)
# neural network libraries import nnabla as nn import nnabla.functions as F import nnabla.parametric_functions as PF import nnabla.solvers as S # other libraries import random import numpy as np import matplotlib.pyplot as plt # define the neural network def network(y): h = PF.affine(y, 256, name = "a1") h = F.relu(h) h = PF.affine(y, 128, name = "a2") h = F.relu(h) h = PF.affine(h, 32, name = "a3") h = F.relu(h) h = PF.affine(y, 128, name = "a4") h = F.relu(h) h = PF.affine(h, 256, name = "a5") h = F.relu(h) h = PF.affine(h, 64, name = 'a6') return h ## setup neuralnetwork nn.clear_parameters() batch_size = 1 input_teacher_data = nn.Variable((batch_size, 64)) input_training_data = nn.Variable((batch_size, 64)) output_data = network(input_test_data) ## setup loss function #loss = F.mean(F.squared_error(output_data, input_teacher_data)) loss = F.mean(F.squared_error(output_data, input_training_data)) solver = S.Adam() solver.set_parameters(nn.get_parameters()) ## generate teacher data x = [n for n in np.arange(0.0, 6.4, 0.1)] teacher_data = [np.sin(n) for n in x] ## for graph plot loss_list = [] step = [] y_list = [] ## do training epoch = 1000 for i in range(epoch): # generate training data training_data = [np.sin(n) + random.uniform(-0.3, 0.3) for n in x] y_list.append(training_data) #input_teacher_data.d = teacher_data input_training_data.d = training_data # do deep learning loss.forward() solver.zero_grad() loss.backward() solver.update() loss_list.append(loss.d.copy()) step.append(i) ## display test data for i in range(epoch): plt.plot(x, y_list[i]) plt.title("Training Data") plt.grid(True) plt.show() ## display training progress plt.plot(step, loss_list) plt.title("Training Error") plt.xlabel("step") plt.ylabel("loss") plt.grid(True) plt.show() ## generate validation data val_data = [np.sin(n) + random.uniform(-0.3, 0.3) for n in x] ## do inference batch_size = 1 input_data = nn.Variable((batch_size, 64)) result = network(input_data) input_data.d = val_data result.forward() output = result.d.copy().reshape(64,).tolist() ## display the result sin = [np.sin(n) for n in x] plt.plot(x, val_data, label="input data") plt.plot(x, output, label="result data", linewidth=3.0) plt.plot(x, sin, label="sin data", color="red", linestyle="dashed") plt.legend() plt.title("Input and Result") plt.grid(True) plt.show()
ここから細かくコードを解説していきます。(トーシローなんで間違っているかも知れません。もし間違っていたら指摘いただけると助かります)
■ Import する各種ライブラリ
nnabla の各種ライブラリと、numpyとグラフを表示のための matplot をインポートします。
# neural network libraries import nnabla as nn import nnabla.functions as F import nnabla.parametric_functions as PF import nnabla.solvers as S # other libraries import random import numpy as np import matplotlib.pyplot as plt
■ AutoEncoder のニューラルネットワークを構築する
Auto Encoder は Affine と Relu で構成してみました。層やノードの数は適当に決めています。適当に値を変えてみたり、活性化関数を変えてみて様子を見てみると面白いかもしれません。
# define the neural network def network(y): h = PF.affine(y, 256, name = "a1") h = F.relu(h) h = PF.affine(y, 128, name = "a2") h = F.relu(h) h = PF.affine(h, 32, name = "a3") h = F.relu(h) h = PF.affine(y, 128, name = "a4") h = F.relu(h) h = PF.affine(h, 256, name = "a5") h = F.relu(h) h = PF.affine(h, 64, name = 'a6') return h
■ ニューラルネットワークをセットアップする
・Nnabla のパラメータの消去
nnabla が保持しているパラメータをnn.clear_parameters()で消去しておきます。これがないと、ニューラルネットの構成を変えるとエラーが出ます。
・バッチサイズの指定
batch_size は1にしてみました。都度データを生成して学習させるので、複数のデータを一度に与えるのが面倒だったからというのが真相です。
・コンテナの定義
nn.Variableは、ニューラルネットにデータを渡すためのコンテナです。学習や推論を行うときはデータをこのコンテナに格納して渡します。
## setup neuralnetwork nn.clear_parameters() batch_size = 1 input_teacher_data = nn.Variable((batch_size, 64)) input_training_data = nn.Variable((batch_size, 64)) output_data = network(input_test_data)
■ 損失関数をセットアップする
ここでは損失関数と学習を進めるための Solver を設定します。Solver は平たく言えば最小二乗法のような損失を小さくするための数学的な道具です。
・損失関数:F.mean(F.squared_error(output_data, input_training_data))
ここでは出力値と入力値の二乗平均誤差を出しています。いわゆる教師なし学習です。コメントアウトしているコードは、入力データに誤差のない純粋な Sin波を教師データとして与えています。教師ありと教師無しデータでどのように結果が違うかぜひ試してみてください。
・ソルバー:S.Adam()
正直よく知りません。与えるパラメータが少なく便利なので使ってみました。他のソルバーで試してみて結果がどう変わるか観察してみると面白いかもしれません。詳しくはこちらを参照してください。
## setup loss function #loss = F.mean(F.squared_error(output_data, input_teacher_data)) loss = F.mean(F.squared_error(output_data, input_training_data)) solver = S.Adam() solver.set_parameters(nn.get_parameters())
■ 教師データならびにグラフ描画用の変数の設定
教師データを使った学習を行う場合は、teacher_data を使ってください。他はグラフプロット用の変数宣言です。
## generate teacher data x = [n for n in np.arange(0.0, 6.4, 0.1)] #teacher_data = [np.sin(n) for n in x] ## for graph plot loss_list = [] step = [] y_list = []
■ 学習(ディープラーニング)用のループ処理
学習回数(Epoch)は1000回としました。
・学習用データを生成
training_data = [np.sin(n) + random.uniform(-0.3, 0.3) for n in x] がそれにあたります。少しトリッキーなコードですが、0.0~6.3 までのサインデータに±0.3 のランダムデータを加えて学習用データとしています。
・コンテナの学習用データを格納
input_training_data.d = training_data で、コンテナに学習用データを設定しています。こうすることで、ニューラルネットワークにデータを渡すことができます。
・学習を実施
loss.forward() / solver.zero_grad() / loss.backward() / solver.update() が学習の基本ルーチンと思ってください。損失関数で値を出して、前回との差分を勾配降下法で逆伝搬させパラメータを調整して差を縮めていくという処理です。使う側にとっては、この程度の理解で十分かと。
## do training epoch = 1000 for i in range(epoch): # generate training data training_data = [np.sin(n) + random.uniform(-0.3, 0.3) for n in x] y_list.append(training_data) #input_teacher_data.d = teacher_data input_training_data.d = training_data # do deep learning loss.forward() solver.zero_grad() loss.backward() solver.update() loss_list.append(loss.d.copy()) step.append(i)
■ 推論を実行する
学習が終わったので、推論を実行します。
・テスト用データの生成
val_data = [np.sin(n) + random.uniform(-0.3, 0.3) for n in x] で学習用データと同じ要領でデータ生成します。
・ニューラルネットワークの設定
input_data = nn.Variable((batch_size, 64)) , result = network(input_data) で、コンテナの準備とニューラルネットワークの設定を行います。
・推論を実行
input_data.d = val_data でテスト用データをコンテナに格納し、 result.forward() で推論が実行されます。
・出力データを取得
出力したデータの次元は (1, 64) になっているので、output = result.d.copy().reshape(64,).tolist() で出力を 64要素を持つリストにして出力します。グラフに描画するための処理です。
## generate validation data val_data = [np.sin(n) + random.uniform(-0.3, 0.3) for n in x] ## do inference batch_size = 1 input_data = nn.Variable((batch_size, 64)) result = network(input_data) input_data.d = val_data result.forward() output = result.d.copy().reshape(64,).tolist()
■ 出力結果をみてみる
学習用データをすべてグラフにマップしたものです。このデータを使って学習しました。
学習の過程を示したグラフです。うまく収束しているみたいですね。
これが結果です。青がテスト用データ。オレンジが AutoEncoder の出力。点線が純粋な Sin波です。
結果はまぁまぁかな。教師ありでの学習もぜひ試してみてください。もっと良い結果が出ると思います。🙂
(^^)/~
ソニー開発のNeural Network Console入門【増補改訂・クラウド対応版】--数式なし、コーディングなしのディープラーニング
- 出版社/メーカー: リックテレコム
- 発売日: 2018/11/14
- メディア: 単行本(ソフトカバー)
ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装
- 作者: 斎藤 康毅
- 出版社/メーカー: オライリージャパン
- 発売日: 2016/09/24
- メディア: 単行本(ソフトカバー)