読者です 読者をやめる 読者になる 読者になる

ツタンラーメンの忘備録

プログラミングや精神疾患、ラーメンについて書いていきます。たぶん。

chainerのサンプルコードを理解する。

pc.atsuhiro-me.net
このサイトをコピペしたら動かしたら動いたのだが、何をしているのかを調べていきたいと思います

import json, sys, glob, datetime, math
import numpy as np
import matplotlib.pyplot as plt

import chainer
from chainer import computational_graph as c
from chainer import cuda
import chainer.functions as F
from chainer import optimizers

class RegressionFNN:
    def __init__(self, n_units=64, batchsize=100):
        self.n_units = n_units
        self.batchsize = batchsize
        self.plotcount=0

    def load(self, train_x, train_y):
        if len(train_x)!=len(train_y):
            raise ValueError
        self.N = len(train_y)
        self.I = 1
        self.x_train = np.array(train_x, np.float32).reshape(len(train_x),1)
        self.y_train = np.array(train_y, np.float32).reshape(len(train_y),)
        #
        self.model = chainer.FunctionSet(l1=F.Linear(self.I, self.n_units),
                                        l2=F.Linear(self.n_units, self.n_units),
                                        l3=F.Linear(self.n_units, self.n_units),
                                        l4=F.Linear(self.n_units, 1))
        #
        self.optimizer = optimizers.Adam()
        self.optimizer.setup(self.model.collect_parameters())


    def forward(self, x_data, y_data, train=True):
        x = chainer.Variable(x_data)
        t = chainer.Variable(y_data)
        h1 = F.relu(self.model.l1(x))
        h2 = F.relu(self.model.l2(h1))
        h3 = F.relu(self.model.l3(h2))
        y = F.reshape(self.model.l4(h3), (len(y_data), ))
        return F.mean_squared_error(y, t), y

    def calc(self, n_epoch):
        for epoch in range(n_epoch):
            perm = np.random.permutation(self.N)
            sum_loss = 0
            #
            for i in range(0, self.N, self.batchsize):
                x_batch = self.x_train[perm[i:i + self.batchsize]]
                y_batch = self.y_train[perm[i:i + self.batchsize]]
                #
                self.optimizer.zero_grads()
                loss, y = self.forward(x_batch, y_batch)
                loss.backward()
                self.optimizer.update()
                #
                sum_loss += float(loss.data) * len(y_batch)
            #
            print('epoch = {}, train mean loss={}\r'.format(epoch, sum_loss / self.N), end="")

    def getY(self, test_x, test_y):
        if len(test_x)!=len(test_y):
            raise ValueError
        x_test = np.array(test_x, np.float32).reshape(len(test_x),1)
        y_test = np.array(test_y, np.float32).reshape(len(test_y),)
        loss, y = self.forward(x_test, y_test, train=False)
        #
        with open("output/{}.csv".format(self.plotcount), "w") as f:
            f.write("\n".join(["{},{}".format(ux,uy) for ux,uy in zip(y.data, y_test)]))

        #
        plt.clf()
        plt.plot(x_test, y_test, color="b", label="original")
        plt.plot(x_test, y.data, color="g", label="RegFNN")
        plt.legend(loc = 'lower left')
        plt.ylim(-1.2,1.2)
        plt.grid(True)
        plt.savefig("output/{}.png".format(self.plotcount))
        self.plotcount+=1


def f(d):
    return [math.sin(u) for u in d]
if __name__=="__main__":
    rf = RegressionFNN(n_units=64, batchsize=314)
    d = [u*0.02 for u in range(314)]
    rf.load(d,f(d))
    rf.calc(1000) # epoch
    rf.getY(d,f(d))
    print("\ndone.")

ここの部分を見る。

        self.x_train = np.array(train_x, np.float32).reshape(len(train_x),1)
        self.y_train = np.array(train_y, np.float32).reshape(len(train_y),)

NumPy 配列の基礎 — 機械学習の Python との出会い

ここを参考にした。

arrayは配列を作れる。pythonの普通の配列と違うけど、そこは割愛する。

array(配列もしくはタプル, 型)

でざっくり言うと行列が作れる。たとえば

array([[1,2,3], [2,4,6]], float32)

とすると

[[1.0, 2.0, 3.0], 
[2.0, 4.0, 6.0]]

という具合らしい。
二重にネストしている点に注意する。
また第二引数はfloat32とかint64とかcomplex128(複素数)とかが入る。

配列の次元数や大きさの操作 — 機械学習の Python との出会い
reshapeは配列を望んだ形に変える。

reshape([1,2,3,2,4,6], (2, 3))

だと

[[1, 2, 3],
[2, 4, 6]]

となる。1×6の行列を2×3にした。積が一緒でないとエラーが出る。
また-1をしていすると、うまいぐあいに調節してくれる。
(2, -1)と書いた場合2×3行列にしてくれる。

では

np.array(train_x, np.float32).reshape(len(train_x),1)

はなにをしているのかというと、train_xの長さ×1、つまり縦ベクトルに変換していることになる。(らしい)
numpyの1d-arrayを2d-arrayに変換 - keisukeのブログ

np.array(train_y, np.float32).reshape(len(train_y),)

は、横のまま?わからぬ。

Linear(変換前の行列の次元, 変換後の行列の次元)

> Linearは全ての入力と出力がつながっているようなニューラルネットワークを表します。 Linearはニューラルネットワークの文脈では総結合層,数学の用語では線形変換,アフィン変換とよびます。 たとえば,次の例では5個のユニットから,2個のユニットへの変換を表します。
ただし、これはlinks.Linearの場合なので違うかも。