FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

Chainerを使って関数フィッティングに挑戦する(1. ニューラルネットワークの構築方法)

Chainerでのニューラルネットワーク構築方法について実践的な方法を勉強するために、ニューラルネットワークを使って関数フィッティングに挑戦してみる。

以前、CNTKやTensorFlowを使って同様のニューラルネットワーク構築を行なったことがある。

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com

解くべき問題 - 関数フィッティング

以下のような関数を持つデータが存在し、この関数にフィッティングできるようなニューラルネットワークを構築する。

f:id:msyksphinz:20160714014452p:plain

データは以下のようなプログラムを使って発生させる。function()が生成したい関数である。

github.com

float function (float x)
{
  return -1.0f * sinf (x) + 0.2f;
}
int main()
{
  std::ofstream      fp;
  std::random_device rnd;
  fp.open ("input_data.txt");

  for (int i = 0; i < 100000; i++) {
    float float_rand = ((static_cast<float>(rnd()) / UINT32_MAX) - 0.5f) * 4.0f;
    fp << float_rand << ", " << function(float_rand) << '\n';
  }
  fp.close();

  return 0;
}

以下のようなデータセットが生成される。

0.137679, 0.0627557
-0.413383, 0.60171
-1.20963, 1.13548
1.16802, -0.719974
1.9593, -0.725477
0.0846508, 0.11545
1.08912, -0.686222
-1.14595, 1.1111
0.875998, -0.568183
-1.22355, 1.14031

Chainerでのネットワーク構築方法

github.com

Chainerでのネットワークの構築は、Pythonで計算データフローを構築しているのに似ている。

class Function3DimentionModel(chainer.FunctionSet):
    def __init__(self):
        super(Function3DimentionModel, self).__init__(
            fc1=chainer.functions.Linear( 1,16),
            fc2=chainer.functions.Linear(16,32),
            fc3=chainer.functions.Linear(32, 1),
    )

    def forward(self, x):
        h1 = self.fc1(x)
        h2 = self.fc2(h1)
        h3 = self.fc3(h2)
        return h3

ここでは、入力値1つを受け取り、それを16次元→32次元→1次元へと収束させるネットワークを構築している。このあたりは、以下のサイトを参考にさせて頂いている。

qiita.com

トレーニング関数

トレーニング関数では、トレーニングデータセットを入力し、解答との誤差を最小にするように仕向ける。

    def train(self, x_data, y_data):
        x = chainer.Variable(x_data.astype(np.float32), volatile=False)
        y = chainer.Variable(y_data.astype(np.float32), volatile=False)
        h = self.forward(x)

        optimizer.zero_grads()
        # error = chainer.functions.sigmoid(h, y)
        error = F.mean_squared_error(h, y)
        error.backward()
        optimizer.update()

これをデータセット分だけ繰替えす訳だ。

for epoch in six.moves.range(1, n_epoch + 1):
    print('epoch', epoch)

    perm = np.random.permutation(N)

    for i in six.moves.range(0, N, batchsize):
        x_part = x_train[perm[i:i + batchsize]].reshape(batchsize, 1)
        y_part = y_train[perm[i:i + batchsize]].reshape(batchsize, 1)

        model.train (x_part, y_part)

実際にトレーニングさせた結果でテストデータを入力すると、以下のような結果になってしまった。

f:id:msyksphinz:20160714015009p:plain

単なる一次元のデータじゃないか!どこかで間違えているのか、学習量が足りないのか、まだ精査していく必要がある。