RNN ã«è¨ç®åé¡ã解ããã
ãã®è¾ºã®ç¶ãã
åèã¯
å®è£ ããããããã¯å¾è¿°
RNN ãæç³»åãã¼ã¿ãã次ã®å¤ãäºæ¸¬ãããã®ãªãã°ããæç³»åãã¼ã¿ï¼è¶³ãç®ããã¹ãäºã¤ã®ãããåãæå®ãäºæ¸¬ãããå¤ï¼è¶³ããçµæã®ãããåãã§å¦ç¿ãããã°ã確ãã«è¨ç®å¨ãä½æãããã¨ã¯å¯è½ãããããªãã
ãã®ä½¿ãæ¹ã¯æãã¤ãã¾ããã§ããã
ããã次å
æ°å¢ããã°ããã ãã§ããªãè¤éãªå¤å®ã¨ãåºããããªæ°ããã¾ãã
ä¾ãã°å
¥å系統ãå¢ããã¦ããªãã¬ã¼ã¿ãæå®ãã¦ã¿ãã¨ãâ¦
å¼æ°ã®ç¶æ
äºã¤ï¼æç³»åãã¼ã¿äºã¤ï¼ããã®ã¿çµæãå°ãåºãããåæãããã2 åç®ä»¥éã®å¦ç¿ã§ååã¾ã§ã®å¾é
ãæã£ã¦ããã¨æ£å¸¸ã«æ©è½ããªãã®ã§ã reset_sum_grad
ã§å¦ç¿ããªã»ãããã¦ãã
ãªãã»ã©ãªã£ã¦æã
def reset_sum_grad(self): self.grad_w = np.zeros_like(self.w) self.grad_b = np.zeros_like(self.b)
å®è£
ã®æ¬ç·¨ã¯ãããªæãã
åºå層㨠RNN ã¬ã¤ã¤ã¼ã ããåºå層ã¯ã·ã°ã¢ã¤ãé¢æ°ã¦ã ãã§ãä¸é層ã®å®è£
ã¯ååã®ãã¯ãªã
eta = 0.1 # å¦ç¿ä¿æ° n_learn = 5001 # å¦ç¿åæ° interval = 500 # çµéã®è¡¨ç¤ºéé class OutputLayer: def __init__(self, n_upper, n): self.w = np.random.randn(n_upper, n) / np.sqrt(n_upper) self.b = np.zeros(n) def activate_func(self, u): # sigmoid function return 1 / (1 + np.exp(-u)) def diff_func(self, grad_y, y): # differencial sigmoid return grad_y * (1 - y) * y def forward(self, x): self.x = x u = np.dot(x, self.w) + self.b self.y = self.activate_func(u) return self.y def backward(self, x, y, t): delta = self.diff_func(y - t, y) self.grad_w = np.dot(x.T, delta) self.grad_b = np.sum(delta, axis=0) self.grad_x = np.dot(delta, self.w.T) return self.grad_x def reset_sum_grad(self): self.grad_w = np.zeros_like(self.w) self.grad_b = np.zeros_like(self.b) def update(self, eta): self.w -= eta * self.grad_w self.b -= eta * self.grad_b class RnnBaseLayer: def __init__(self, n_upper, n): self.w = np.random.randn(n_upper, n) / np.sqrt(n_upper) self.v = np.random.randn(n, n) / np.sqrt(n) self.b = np.zeros(n) def forward(self, x, prev_y): u = np.dot(x, self.w) + np.dot(prev_y, self.v) + self.b self.y = np.tanh(u) return self.y def backward(self, x, y, prev_y, grad_y): delta = grad_y * (1 - y**2) self.grad_w += np.dot(x.T, delta) self.grad_v += np.dot(prev_y.T, delta) self.grad_b += np.sum(delta, axis=0) self.grad_x = np.dot(delta, self.w.T) self.grad_prev_y = np.dot(delta, self.v.T) return self.grad_prev_y def reset_sum_grad(self): self.grad_w = np.zeros_like(self.w) self.grad_v = np.zeros_like(self.v) self.grad_b = np.zeros_like(self.b) def update(self, eta): self.w -= eta * self.grad_w self.v -= eta * self.grad_v self.b -= eta * self.grad_b
ããã«é£ãããå¦ç¿ãã¼ã¿ã ãã©ãããã§å¦ç¿ãããã®ã¯ã2é²æ°ã®è¶³ãç®è¨ç·´ã
ãã®æã®å¦ç¿ãã¼ã¿ã®å½¢ç¶ã¯
n_time = 8 # æç³»åã®æ°(ä»åã¯æ大ãããæ°) n_in = 2 # å ¥å層ãã¥ã¼ãã³æ°(äºã¤ã®å¤ã足ãåãããç®çãªã®ã§) n_mid = 32 # ä¸é層ãã¥ã¼ãã³æ°(é©å½) n_out = 1 # åºå層ãã¥ã¼ãã³æ°(çå®ã¯ãã¤ãä¸ã¤ï¼) max_num = 2**n_time # = 256 binaries = np.zeros((max_num, n_time), dtype=int) for i in range(max_num): num10 = i for j in range(n_time): pow2 = 2 ** (n_time - 1 - j) binaries[i, j] = num10 // pow2 num10 %= pow2
ãããªæãã«æ¸ãã¦ãã¾ãããbinaries
ã®ä¸èº«ã¯
[0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 1] [0 0 0 0 0 0 1 0] [0 0 0 0 0 0 1 1] ... [1 1 1 1 1 1 1 1]
ã¨ã256 è¡ 8 åã®ãããåã
ãã®è¡åã¯å
é ãã 0, 1, 2, 3, ... ã¨ç¶ãã¦ããã®ã§ã32 ã®å¤ã¯ã¤ã³ããã¯ã¹ 32 ã«å½ããã
足ãåãããäºã¤ã®å¤ã¯ MAX(256) ã 2 ã§å²ã£ãå¤(ãã㧠128 以ä¸ã®å¤äºã¤ã«åãã)
num1 = np.random.randint(max_num//2) num2 = np.random.randint(max_num//2) # ããããããé åã«ç½®ãæã㦠x1= binaries[num1] x2= binaries[num2] # å¼æ°ã®å½¢ç¶ã«ã¾ã¨ãã x_in = np.zeros((1, n_time, n_in)) x_in[0, :, 0] = x1 x_in[0, :, 1] = x2 x_in = np.flip(x_in, axis=1)
å½¢ç¶çã«ã¯ãããªæã
13 㨠33 ã®ä¾ [[[1. 1.] [0. 0.] [1. 0.] [1. 0.] [0. 0.] [0. 1.] [0. 0.] [0. 0.]]]
13 + 33 = 46 = b00101110
ã¨ãªãã®ã§ã
# çµæãã¼ã¿ t = binaries[num1+num2] t_in = t.reshape(1, n_time, n_out) t_in = np.flip(t_in , axis=1)
ã³ã¬ã®çµæã¯
[[[0], [1], [1], [1], [0], [1], [0], [0]]]
ãããé£ããã¦ã·ã°ã¢ã¤ãé¢æ°åºåï¼MAX =1ï¼ã§ã0.5 ãé¾å¤ã« 01 å¤å®ãã¦å¦ç¿ããã¦ããã¨ããæ§å¼ã
å¦ç¿é¨åã®å ¨ä½åã¯ãããªæã
rnnLayer = RnnBaseLayer(n_in, n_mid) outputLayer = OutputLayer(n_mid, n_out) def train(x_mb, t_mb): y_rnn = np.zeros((len(x_mb), n_time+1, n_mid)) y_out = np.zeros((len(x_mb), n_time, n_out)) # Forward propergation y_prev = y_rnn[:, 0, :] for i in range(n_time): # RNN layer x = x_mb[:, i, :] y = rnnLayer.forward(x, y_prev) y_rnn[:, i + 1, :] = y y_prev = y # output layer y_out[:, i, :] = outputLayer.forward(y) # back propergation outputLayer.reset_sum_grad() rnnLayer.reset_sum_grad() grad_y = 0 for i in reversed(range(n_time)): # output layer x = y_rnn[:, i+1, :] y = y_out[:, i, :] t = t_mb[:, i, :] grad_x_out = outputLayer.backward(x, y, t) # Rnn layer x = x_mb[:, i, :] y = y_rnn[:, i+1, :] y_prev = y_rnn[:, i, :] grad_y = rnnLayer.backward(x, y, y_prev, grad_y + grad_x_out) # update rnnLayer.update(eta) outputLayer.update(eta) return y_out def get_error(y, t): return 1.0/2.0*np.sum(np.square(y - t)) for i in range(n_learn): # ã©ã³ãã ãªã¤ã³ããã¯ã¹ãä½æ num1 = np.random.randint(max_num//2) num2 = np.random.randint(max_num//2) # ããããããé åã«ç½®ãæã㦠x1= binaries[num1] x2= binaries[num2] # å¼æ°ã®å½¢ç¶ã«ã¾ã¨ãã x_in = np.zeros((1, n_time, n_in)) x_in[0, :, 0] = x1 x_in[0, :, 1] = x2 x_in = np.flip(x_in, axis=1) # çµæãã¼ã¿ t = binaries[num1+num2] t_in = t.reshape(1, n_time, n_out) t_in = np.flip(t_in , axis=1) # å¦ç¿ y_out = train(x_in, t_in) y = np.flip(y_out, axis=1).reshape(-1) error = get_error(y_out, t_in) if i % interval == 0: y2 = np.where(y<0.5, 0, 1) y10 = 0 for j in range(len(y)): pow2 = 2 ** (n_time-1-j) y10 += y2[j] * pow2 print("learn count:", i) print("error rate:", error) c = "Success : " if (y2 == t).all() else "Failure : " print(c + str(num1) + " + " + str(num2) + " = " + str(y10)) print("========================")