import numpy as np
pi = 2.
for i in range(1000):
n = i+1
pi = pi * (2*n)**2 / ((2*n-1)*(2*n+1))
if n%200 == 0:
print("n: {}, estimated_pi: {:.3f}".format(n, pi))
上図の全体に対応しており、Encoderについて処理したのちにDecoderの処理を行います。このようなEncoder-Decoderの形式はRNNを用いた$2014$年のSequence to sequenceの研究と同様であり、この頃よく取り組まれていたタスクが機械翻訳であることにこの形式は起因すると解釈できます。
class MessagePassing3D:
def __init__(self, adj_mat_3D):
self.params, self.grads = [], []
self.graph = adj_mat_3D
self.h = None
def forward(self, h):
self.h = h
N, L, H = h.shape
m_t = np.zeros_like(h)
for i in range(self.graph.shape[1]):
ar = self.graph[:, i,:].reshape(N, L, 1).repeat(H, axis=2)
t = h * ar
m_t[:, i, :] = np.sum(t, axis=1)
return m_t
def backward(self, dm_t):
N, L, H = self.h.shape
dh = np.zeros_like(self.h)
dar = np.zeros_like(self.graph)
for i in range(self.graph.shape[1]):
ar = self.graph[:, i, :].reshape(N, L, 1).repeat(H, axis=2)
dh[:, i, :] = np.sum(dm_t * ar, axis=1)
for i in range(self.graph.shape[0]):
dar[i, :, :] = np.dot(dm_t[i, :, :], self.h[i, :, :].T)
return dh, dar
class MessagePassing:
def __init__(self, adj_mat):
self.params, self.grads = [], []
self.graph = adj_mat
self.cache = None
def forward(self, h):
N, T, H = h.shape
m_t = np.zeros_like(h)
for i in range(self.graph.shape[0]):
ar = self.graph[i,:].reshape(1, T, 1).repeat(N, axis=0).repeat(H, axis=2)
t = h * ar
m_t[:, i, :] = np.sum(t, axis=1)
self.cache = h
return m_t
def backward(self, dc):
h = self.cache
N, T, H = h.shape
dh = np.zeros_like(h)
for i in range(self.graph.shape[0]):
ar = self.graph[i, :].reshape(1, T, 1).repeat(N, axis=0).repeat(H, axis=2)
dt = dc.reshape(N, 1, H).repeat(T, axis=1)
dh[:, i, :] = np.sum(dt * ar, axis=1)
return dh
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from scipy import stats
sns.set_theme()
np.random.seed(1)
n = 500
t_a = 1.2
t_b = 0.5
x = np.random.rand(n)*10.-5.
t_p = 1./(1.+np.e**(-(t_a*x+t_b)))
t = stats.binom.rvs(size=x.shape[0],p=t_p,n=1)
x_ = np.arange(-5.0, 5.01, 0.01)
plt.scatter(x,t,color="lightgreen")
plt.plot(x_, 1./(1.+np.e**(-(t_a*x_+t_b))), color="green")
plt.show()
・実行結果
上記に対し、下記を実行することで自動微分と勾配法に基づいてパラメータ推定を行うことができる。
alpha = 0.01
a, b = 0.5, 0.
mul_coef_layer = MulLayer()
add_bias_layer = AddLayer()
calc_Sigmoid = Sigmoid()
for i in range(100):
# forward
u1 = mul_coef_layer.forward(x, a)
u2 = add_bias_layer.forward(u1, b)
y = calc_Sigmoid.forward(u2)
#loss = t*np.log(y) + (1-t)*np.log(1-y)
# backward
#dloss = 1.
dy = t/y - (1-t)/(1-y)
du2 = calc_Sigmoid.backward(dy)
du1, db = add_bias_layer.backward(du2)
dx, da = mul_coef_layer.backward(du1)
a += alpha*np.sum(da)
b += alpha*np.sum(db)
if (i+1)%10==0:
print(a,b)