今回のレポートでは、①オートエンコーダの作成、②再帰型ニューラルネットワークの作成を試みた。
①コブダクラス型生産関数を再現できるオートエンコーダの作成が目標である。
In [15]:
%matplotlib inline
import numpy as np
import pylab as pl
import math
from sympy import *
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from mpl_toolkits.mplot3d import Axes3D
In [16]:
from NN import NN
定義域は0≤x≤1である。
コブ・ダグラス型生産関数は以下の通りである。
z = x_1**0.5*x_2*0.5
In [17]:
def example1(x_1, x_2):
z = x_1**0.5*x_2*0.5
return z
fig = pl.figure()
ax = Axes3D(fig)
X = np.arange(0, 1, 0.1)
Y = np.arange(0, 1, 0.1)
X, Y = np.meshgrid(X, Y)
Z = example1(X, Y)
ax.plot_surface(X, Y, Z, rstride=1, cstride=1)
pl.show()
NNのクラスはすでにNN.pyからimportしてある。
In [19]:
nn = NN()
以下に使い方を説明する。
初めに、このコブ・ダグラス型生産関数を用いる。
In [20]:
x_1 = Symbol('x_1')
x_2 = Symbol('x_2')
f = x_1**0.5*x_2*0.5
入力層、中間層、出力層を作る関数を実行する。引数には層の数を用いる。
In [21]:
nn.set_input_layer(2)
Out[21]:
In [22]:
nn.set_hidden_layer(2)
Out[22]:
In [23]:
nn.set_output_layer(2)
Out[23]:
nn.set_hidden_layer()は同時にシグモイド関数で変換する前の中間層も作る。
set_output_layer()は同時にシグモイド関数で変換する前の出力層、さらに教師データを入れる配列も作る。
nn.setup()で入力層ー中間層、中間層ー出力層間の重みを入れる配列を作成する。
nn.initialize()で重みを初期化する。重みは-1/√d ≤ w ≤ 1/√d (dは入力層及び中間層の数)の範囲で一様分布から決定される。
In [24]:
nn.setup()
nn.initialize()
nn.supervised_function(f, idata)は教師データを作成する。引数は関数とサンプルデータをとる。
In [25]:
idata = [1, 2]
In [26]:
nn.supervised_function(f, idata)
nn.simulate(N, eta)は引数に更新回数と学習率をとる。普通はN=1で行うべきかもしれないが、工夫として作成してみた。N回学習した後に出力層を返す。
In [27]:
nn.simulate(1, 0.1)
Out[27]:
nn.calculation()は学習せずに入力層から出力層の計算を行う。nn.simulate()内にも用いられている。
次に実際に学習を行う。サンプルデータは、
In [28]:
X = np.arange(0, 1, 0.2)
Y = np.arange(0, 1, 0.2)
print X, Y
の組み合わせである。
In [29]:
X = np.arange(0, 1, 0.2)
Y = np.arange(0, 1, 0.2)
a = np.array([])
b = np.array([])
c = np.array([])
nn = NN()
nn.set_network()
for x in X:
for y in Y:
a = np.append(a, x)
b = np.append(b, y)
for i in range(100):
l = np.random.choice([i for i in range(len(a))])
m = nn.main2(1, f, [a[l], b[l]], 0.5)
for x in X:
for y in Y:
idata = [x, y]
c = np.append(c, nn.realize(f, idata))
In [30]:
a
Out[30]:
In [31]:
b
Out[31]:
In [32]:
c
Out[32]:
例えば(0, 0)を入力すると0.52328635を返している(つまりa[0]とb[0]を入力して、c[0]の値を返している)。
ここでは交差検定は用いていない。
In [33]:
fig = pl.figure()
ax = Axes3D(fig)
ax.scatter(a, b, c)
pl.show()
確率的勾配降下法を100回繰り返したが見た感じから近づいている。回数を10000回に増やしてみる。
In [38]:
X = np.arange(0, 1, 0.2)
Y = np.arange(0, 1, 0.2)
a = np.array([])
b = np.array([])
c = np.array([])
nn = NN()
nn.set_network()
for x in X:
for y in Y:
a = np.append(a, x)
b = np.append(b, y)
for i in range(10000):
l = np.random.choice([i for i in range(len(a))])
m = nn.main2(1, f, [a[l], b[l]], 0.5)
for x in X:
for y in Y:
idata = [x, y]
c = np.append(c, nn.realize(f, idata))
In [39]:
fig = pl.figure()
ax = Axes3D(fig)
ax.scatter(a, b, c)
pl.show()
見た感じ随分近づいているように見える。
最後に交差検定を行う。
初めに学習回数が極めて少ないNNである。
In [178]:
X = np.arange(0, 1, 0.2)
Y = np.arange(0, 1, 0.2)
a = np.array([])
b = np.array([])
c = np.array([])
for x in X:
for y in Y:
a = np.append(a, x)
b = np.append(b, y)
evl = np.array([])
for i in range(len(a)):
nn = NN()
nn.set_network()
for j in range(1):
l = np.random.choice([i for i in range(len(a))])
if l != i:
nn.main2(1, f, [a[l], b[l]], 0.5)
idata = [a[i], b[i]]
est = nn.realize(f, idata)
evl = np.append(evl, math.fabs(est - nn.supervised_data))
In [179]:
np.average(evl)
Out[179]:
次に十分大きく(100回に)してみる。
In [201]:
X = np.arange(0, 1, 0.2)
Y = np.arange(0, 1, 0.2)
a = np.array([])
b = np.array([])
c = np.array([])
nn = NN()
nn.set_network(h=7)
for x in X:
for y in Y:
a = np.append(a, x)
b = np.append(b, y)
evl = np.array([])
for i in range(len(a)):
nn = NN()
nn.set_network()
for j in range(100):
l = np.random.choice([i for i in range(len(a))])
if l != i:
nn.main2(1, f, [a[l], b[l]], 0.5)
idata = [a[i], b[i]]
evl = np.append(evl, math.fabs(nn.realize(f, idata) - nn.supervised_data))
In [202]:
np.average(evl)
Out[202]:
誤差の平均であるので小さい方よい。 学習回数を増やした結果、精度が上がった。
最後にオートエンコーダを作成する。回数を増やした方がよいことが分かったため、10000回学習させてみる。
In [203]:
nn = NN()
nn.set_network()
In [204]:
X = np.arange(0, 1, 0.05)
Y = np.arange(0, 1, 0.05)
a = np.array([])
b = np.array([])
c = np.array([])
for x in X:
for y in Y:
a = np.append(a, x)
b = np.append(b, y)
evl = np.array([])
s = [i for i in range(len(a))]
for j in range(1000):
l = np.random.choice(s)
nn.main2(1, f, [a[l], b[l]], 0.5)
In [176]:
c = np.array([])
for i in range(len(a)):
idata = [a[i], b[i]]
c = np.append(c, nn.realize(f, idata))
In [177]:
fig = pl.figure()
ax = Axes3D(fig)
ax.scatter(a, b, c)
pl.show()
十分再現できていることが分かる。
②ゲーム理論で用いられるTit for Tatを再現してみる。二人のプレーヤーが互いにRNNで相手の行動を予測し、相手の行動に対してTit for Tatに基づいた行動を選択する。
In [205]:
from NN import RNN
最初の行動はRNNで指定できないので、所与となる。この初期値と裏切りに対する感応度で収束の仕方が決まる。
協調を1、裏切りを0としている。RNNの予測値は整数値でないが、p=(RNNの出力値)で次回に協調を行う。
例1:1期目に、プレーヤー1が協力、プレーヤー2が裏切り。
In [ ]:
nn1 = RNN()
nn1.set_network()
nn2 = RNN()
nn2.set_network()
idata1 = [[1, 0]]
idata2 = [[0, 1]]
sdata1 = [[0]]
sdata2 = [[1]]
for t in range(20):
for i in range(10):
nn1.main2(idata1, sdata2, 0.9)
nn2.main2(idata2, sdata1, 0.9)
idata1.append([sdata1[-1][0], sdata2[-1][0]])
idata2.append([idata1[-1][1], idata1[-1][0]])
n1r = nn1.realize(idata1)
n2r = nn2.realize(idata1)
sdata1.append([np.random.choice([1, 0], p=[n1r, 1-n1r])])
sdata2.append([np.random.choice([1, 0], p=[n2r, 1-n2r])])
idata.append([sdata1[-1][0], sdata2[-1][0]])
print nn1.realize(idata1), nn2.realize(idata), idata1
下の図より、最初は交互に相手にしっぺ返しをしているが、やがて両者が裏切り合うこと状態に収束する。
In [ ]:
p1 = []
p2 = []
for i in range(len(idata1)):
p1.append(idata1[i][0])
for i in range(len(idata2)):
p2.append(idata2[i][0])
plt.plot(p1, label='player1')
plt.plot(p2, label='player2')
例2:1期目に、プレーヤー1が協力、プレーヤー2が協力。ただし、プレーヤー2は相手の裏切りをかなり警戒している。
警戒を表すためにp=(RNNの出力値 - 0.2)とする。p<0の場合はp=0に直す。
In [ ]:
nn1 = RNN()
nn1.set_network()
nn2 = RNN()
nn2.set_network()
idata1 = [[1, 1]]
idata2 = [[1, 1]]
sdata1 = [[1]]
sdata2 = [[1]]
for t in range(20):
for i in range(10):
nn1.main2(idata1, sdata2, 0.9)
nn2.main2(idata2, sdata1, 0.9)
idata1.append([sdata1[-1][0], sdata2[-1][0]])
idata2.append([idata1[-1][1], idata1[-1][0]])
n1r = nn1.realize(idata1)
n2r = nn2.realize(idata1)
prob1 = n1r
prob2 = n2r - 0.3
if prob2 < 0:
prob2 = 0
sdata1.append([np.random.choice([1, 0], p=[prob1, 1-prob1])])
sdata2.append([np.random.choice([1, 0], p=[prob2, 1-prob2])])
idata.append([sdata1[-1][0], sdata2[-1][0]])
print nn1.realize(idata1), nn2.realize(idata), idata1
In [ ]:
p1 = []
p2 = []
for i in range(len(idata1)):
p1.append(idata1[i][0])
for i in range(len(idata2)):
p2.append(idata2[i][0])
plt.plot(p1, label='player1')
plt.plot(p2, label='player2')
例3:次に相手の行動を完全には観測できない場合を考える。t期の相手の行動をt+1期にノイズが加わって知る。例えば、1期目に相手が協調したことを、確率90%で2期目に正しく知れるが、10%で裏切りと誤って伝わる場合である。
ノイズは20%の確率で加わるものとする。その他の条件は例1と同じにした。
In [ ]:
nn1 = RNN()
nn1.set_network()
nn2 = RNN()
nn2.set_network()
idata1 = [[1, 0]]
idata2 = [[0, 1]]
sdata1 = [[0]]
sdata2 = [[1]]
for t in range(20):
for i in range(10):
nn1.main2(idata1, sdata2, 0.9)
nn2.main2(idata2, sdata1, 0.9)
idata1.append([sdata1[-1][0], np.random.choice([sdata2[-1][0], 1-sdata2[-1][0]], p=[0.8, 0.2])])
idata2.append([sdata2[-1][0], np.random.choice([sdata1[-1][0], 1-sdata1[-1][0]], p=[0.8, 0.2])])
n1r = nn1.realize(idata1)
n2r = nn2.realize(idata1)
prob1 = n1r
prob2 = n2r
sdata1.append([np.random.choice([1, 0], p=[prob1, 1-prob1])])
sdata2.append([np.random.choice([1, 0], p=[prob2, 1-prob2])])
idata.append([sdata1[-1][0], sdata2[-1][0]])
print nn1.realize(idata1), nn2.realize(idata), idata1
In [ ]:
p1 = []
p2 = []
for i in range(len(idata1)):
p1.append(idata1[i][0])
for i in range(len(idata2)):
p2.append(idata2[i][0])
plt.plot(p1, label='player1')
plt.plot(p2, label='player2')