化学系エンジニアがAIを学ぶ

PyTorchでディープラーニング、強化学習を学び、主に化学工学の問題に取り組みます

ニューラルネットワークによるばらつきのあるデータへの近似

はじめに

前回は関数値そのものを学習させたが、今回は関数値をもとに作成したばらつきのあるデータを学習させて 関数をニューラルネットワークで表現できるかを見てみる。

以下の記事で同様の内容がtensorflowを用いて紹介されているが、 ここではPyTorchを使う。

ニューラルネットワークは任意の関数を表現できるのか? - Qiita

データの準備

ここでの関数はnumpy.sin(x)としている。xの値はランダムに選んだ。yの値は関数値に、正規分布に従う 乱数を加えてデータをばらつかせた。

## 必要なモジュールのインポート
import numpy
import torch
import torch.nn as nn
import torch.nn.functional as F
from matplotlib import pyplot as plt

## データ作成
data_num = 200
x = numpy.random.rand(data_num)*6 # 0 - 6 の範囲の一様乱数
y = numpy.sin(x) + numpy.random.randn(data_num)*0.3 # 正規分布に従う乱数を足す
x_train = torch.FloatTensor(x.reshape(data_num, 1))
y_train = torch.FloatTensor(y.reshape(data_num, 1))

ニューラルネットワークモデルの定義

入力1つ、出力1つ。中間層は1層とし、ノード数は2個とした。 中間層の活性化関数はReLUとし、出力層はl2の計算値をそのまま出力させた。。

class Model(nn.Module):
    def __init__(self):
        super(Model, self).__init__()
        self.l1 = nn.Linear(1, 2)
        self.l2 = nn.Linear(2, 1)

    def forward(self, x):
        x = F.relu(self.l1(x))
        x = self.l2(x)
        return x

ニューラルネットワークモデルの登録

損失関数に平均二乗誤差nn.MSELossを使用した。learning_rateは試行錯誤して 良さそうなところに決めた。

model = Model()
criterion = nn.MSELoss()
learning_rate = 1e-1
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)

学習

epoch数は試行錯誤して設定したが、計算の初期値次第で学習状況は多少変わる模様。

epoch = 100
for t in range(epoch):
    optimizer.zero_grad()
    y_model = model(x_train)
    loss = criterion(y_model, y_train)
    loss.backward()
    optimizer.step()
    print(t, loss.item()) # 学習状況の表示

学習結果の確認

plt.plot(x, y, '.', label='data')
x = numpy.linspace(0, 6, data_num)
x_model = torch.FloatTensor(x.reshape(data_num, 1))
y_model = model(x_model).detach().numpy().reshape(1, data_num)[0]
plt.plot(x, y_model, label='model', linewidth=3)
plt.legend()
plt.xlabel('x')
plt.ylabel('y')
plt.show()

結果

計算させるたびに多少結果が変わるが、下図のようにだいぶ無理矢理な感じとなった。epoch数を増やしてもほとんど状況に変化なかった。

f:id:schemer1341:20190109234003p:plain:w500
図1 データとモデル値の比較

なお、活性化関数をsigmoidに変えると無理矢理感は低下した。

f:id:schemer1341:20190109235006p:plain:w500
図2 活性化関数をsigmoidとした場合のデータとモデル値の比較

さらに中間層を2層(ノード数 20 ,40)、epoch数=1000で計算するとフィット感は改善した。

f:id:schemer1341:20190110000954p:plain:w500
図3 中間層数、epoch数を増やした場合のデータとモデル値の比較

epoch数を5000回まで増やすと合わせすぎた感じとなり、いわゆる過学習状態になっていると思われる。。

f:id:schemer1341:20190110001406p:plain:w500
図4 epoch数をさらに増やした場合のデータとモデル値の比較

所感

epoch数、中間層ノード数、層の深さなど、適切に選ぶにはそこそこの知識・経験が要りそう。

参考

ニューラルネットワークは任意の関数を表現できるのか? - Qiita