SSブログ

Neural Network Libraries (Nnabla) を使って「Auto Encoder」を実装してみた! [AI]

ディープラーニング・トーシローの私が、Neural Network Libraries を使って簡単な「Auto Encoder」を実装してみました!Auto Encoder は、たくさんのデータを使って、おおまかな形を覚えさせ、ノイズの入ったデータもそれらしく出力するというものです。


AutoEncoder.png


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()



■ 出力結果をみてみる
学習用データをすべてグラフにマップしたものです。このデータを使って学習しました。

2020-05-30.png


学習の過程を示したグラフです。うまく収束しているみたいですね。

2020-05-30 (1).png


これが結果です。青がテスト用データ。オレンジが AutoEncoder の出力。点線が純粋な Sin波です。

2020-05-30 (1).png


結果はまぁまぁかな。教師ありでの学習もぜひ試してみてください。もっと良い結果が出ると思います。🙂
(^^)/~




ソニー開発のNeural Network Console入門【増補改訂・クラウド対応版】--数式なし、コーディングなしのディープラーニング

ソニー開発のNeural Network Console入門【増補改訂・クラウド対応版】--数式なし、コーディングなしのディープラーニング

  • 出版社/メーカー: リックテレコム
  • 発売日: 2018/11/14
  • メディア: 単行本(ソフトカバー)



はじめての「SonyNNC」 (I・O BOOKS)

はじめての「SonyNNC」 (I・O BOOKS)

  • 作者: 良一, 柴田
  • 出版社/メーカー: 工学社
  • 発売日: 2019/08/01
  • メディア: 単行本



ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装

ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装

  • 作者: 斎藤 康毅
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2016/09/24
  • メディア: 単行本(ソフトカバー)




nice!(24)  コメント(0) 
共通テーマ:趣味・カルチャー