NNの構成
# initialize mlp = MLP(n_input_units=2, n_hidden_units=3, n_output_units=1)
XORを実現する3層のニューラルネットワークを例として実装します。入力層は2、隠れ層は3、出力層は1つのニューロンを持ちます。
class MLP(object): """ 3 Layered Perceptron """ def __init__(self, n_input_units, n_hidden_units, n_output_units): self.nin = n_input_units self.nhid = n_hidden_units self.nout = n_output_units self.v = np.random.uniform(-1.0, 1.0, (self.nhid, self.nin+1)) self.w = np.random.uniform(-1.0, 1.0, (self.nout, self.nhid+1))
ただし、入力層と隠れ層の間の重みvと、隠れ層と出力層の間の重みwにはバイアス項を加えるので+1とします。つまり、vは3x3の行列、wは1x4の行列となります。
--- NN configuration --- Num of input layer units: 2 Num of hidden layer units: 3 Num of output layer units: 1 Shape of first layer weight(v): (3, 3) Shape of second layer weight(w): (1, 4)
NNの学習
以前のエントリーで書いた誤差逆伝播法と最急降下法を用いた各層の重みの更新式をコードにします。
def fit(self, inputs, targets, learning_rate=0.2, epochs=10000): inputs = self.__add_bias(inputs, axis=1) targets = np.array(targets) for loop_cnt in xrange(epochs): # randomise the order of the inputs p = np.random.randint(inputs.shape[0]) xp = inputs[p] bkp = targets[p] # forward phase gjp = self.__sigmoid(np.dot(self.v, xp)) gjp = self.__add_bias(gjp) gkp = self.__sigmoid(np.dot(self.w, gjp)) # backward phase(back prop) eps2 = self.__sigmoid_deriv(gkp) * (gkp - bkp) eps = self.__sigmoid_deriv(gjp) * np.dot(self.w.T, eps2) gjp = np.atleast_2d(gjp) eps2 = np.atleast_2d(eps2) self.w = self.w - learning_rate * np.dot(eps2.T, gjp) xp = np.atleast_2d(xp) eps = np.atleast_2d(eps) self.v = self.v - learning_rate * np.dot(eps.T, xp)[1:, :]
def __add_bias(self, x, axis=None): return np.insert(x, 0, 1, axis=axis) def __sigmoid(self, u): """ Sigmoid function(Activation function) """ return (1.0 / (1.0 + np.exp(-u))) def __sigmoid_deriv(self, u): return (u * (1 - u))
実装するときは、各式で出てくるベクトルや行列の次元を表示して、自分の意図通りになっているかを確認しながら進めていくと良いと思います(下に挙げた参考情報の二つ目を参照)。
XORのテスト
XORが実現できているかを確認します。
inputs = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]) targets = np.array([0, 1, 1, 0]) # training mlp.fit(inputs, targets) # predict print '--- predict ---' for i in [[0, 0], [0, 1], [1, 0], [1, 1]]: print i, mlp.predict(i)
--- predict --- [0, 0] [ 0.07955348] [0, 1] [ 0.92560327] [1, 0] [ 0.93024106] [1, 1] [ 0.06766488]
確かにXOR学習ができているようです。