LSTM ä½ã£ã¦ã¿ã
ããã®ç¶ãã
éä¼æã®èª¬æã飲ã¿è¾¼ãã®ã«è¶ 絶è¦å´ãããâ¦æ°å¦åç¡ãèªåãæ¨ãããï¼æ±
å種å¾é ã¯é ä¼æå¼ãåå¾®åå¼è¨ç®ããå¿ è¦ããã
- å ¥åã«ãããéã¿å¾é
- åã®åºåã«ãããå¾é
- ãã¤ã¢ã¹å¾é
åæå»ã§ã以ä¸ã®å¾é ãè¨ç®ããã
- å ¥åã®å¾é
- åã®æå»ã®åºåã®å¾é
- åã®æå»ã®è¨æ¶ã»ã«ã®å¾é
ãã®å¾®åãããªãããããªãâ¦ãããâ¦
ã£ã¦ãã¨ã§ãå°åºéç¨ã端æã£ã¦ãã¾ãã¨
å¿å´ã²ã¼ãã¯
å ¥åã²ã¼ã
æ°ããè¨æ¶
åºåã²ã¼ã
å°åºéç¨ã¨ãç´°ããè«çã¨ãã¯ããåç
§ã
ãããè¦ãªããé å¼µãã°ãªãã¨ãå°åºãç解ã§ããã
å®è£ ãã¦ã¿ãï¼ï¼ã¤ã£ã¦ãã ãããåçµã«ãªã£ã¡ãã£ããã©â¦ï¼
ã®ã¶ã®ã¶ãã¦ã波形ãå¦ç¿ãã¼ã¿ã
é»è²ç·ãããããäºæ¸¬ããå¤ã
å®è¡çµæã¯ãããªæãã
ã§ãããæ ªä¾¡ã«åãå
¥ãããã¨ããã¨ããå®ã¯èª¤å·®ãåã¾ããªãã£ãâ¦
ããããªããã¨è¨ãã¨ãæ ªä¾¡ã調ã¹ã¦ã¿ãã¨ãããã®ã ãã©ãç±³å½æ ª 2020-2021ï¼8æï¼ã¾ã§ã¯ãã¬ã³ãã©ã¤ã³ã«æ²¿ã£ãä¸æãã¬ã³ãã§ãåç´ã«ä¿æãã¦ãã°å²ãã£ãã¨ããç¶æ³ã
ããã9æãããã¼ããªã³ã°ã®è©±ãæã¡ä¸ãã£ã¦ä¹±é«ä¸â¦æ¥å¹´ã¯ã¹ã¿ã°ãã¬ã¼ã·ã§ã³ãåå ã¨ããããã¯ã¹ç¸å ´ï¼çæçãªä¸ããä¸ããã ããã¦ãå¹³åæ ªä¾¡ãåæ»ããï¼ã¨äºæ¸¬ããã¦ãã
æ£ç´ãã®ãããªç¶æ³ããã¨ãã¨ãã£ã¦ãããããå±é¢ãå¤ããã¿ã¤ãã³ã°ã¯ããã¾ã§æ¿æ²»ã»çµæ¸ã¤ãã³ãã«ããããããã®ã¿ã¤ãã³ã°ãAIã§äºæ¸¬ãããã¨ãé£ããã¨ãã話ã
è¦ããã«å¤§ããªè»¢ææã«ããå§ããã¨çãç®è¦ããâ¦ã£ã¦ãã¨ï¼æ³£ï¼
å®è£ ã¯ä»¥ä¸
import numpy as np import matplotlib.pyplot as plt n_time = 10 # æç³»åã®æ° n_in = 1 # å ¥å層ã®ãã¥ã¼ãã³æ° n_mid = 30 # ä¸é層ã®ãã¥ã¼ãã³æ° n_out = 1 # åºå層ã®ãã¥ã¼ãã³æ° eta = 0.01 # å¦ç¿ä¿æ° epochs = 101 # å¦ç¿ãã¼ã¿ã®å¦ç¿åæ° batch_size = 8 # 1åã®å¦ç¿ã®å¦çæ° interval = 10 # çµéã®è¡¨ç¤ºéé def sigmoid(x): return 1/(1+np.exp(-x)) # è¨ç·´ãã¼ã¿ã®ä½æ # -2Ïãã2Ïã¾ã§ã®æ³¢ç·ä½æ sin_x = np.linspace(-2*np.pi, 2*np.pi) # æ³¢ç·ã«ãã¤ãºãå ãã sin_y = np.sin(sin_x) + 0.1*np.random.randn(len(sin_x)) # ãµã³ãã«æ° n_sample = len(sin_x)-n_time # å ¥å input_data = np.zeros((n_sample, n_time, n_in)) # æ£è§£ãã¼ã¿ correct_data = np.zeros((n_sample, n_out)) for i in range(0, n_sample): input_data[i] = sin_y[i : i+n_time].reshape(-1, 1) # æ£è§£ã¯å ¥åãããä¸ã¤å¾ correct_data[i] = sin_y[i+n_time : i+n_time+1] # LSTM層 class LSTMLayer: def __init__(self, n_upper, n): self.w = np.random.randn(4, n_upper, n) / np.sqrt(n_upper) # Xavierã®åæå¤ self.v = np.random.randn(4, n, n) / np.sqrt(n) self.b = np.zeros((4, n)) def forward(self, x, y_prev, c_prev): # y_prev, c_prev: åã®æå»ã®åºåã¨è¨æ¶ã»ã« u = np.matmul(x, self.w) + np.matmul(y_prev, self.v) + self.b.reshape(4, 1, -1) a0 = sigmoid(u[0]) # å¿å´ã²ã¼ã a1 = sigmoid(u[1]) # å ¥åã²ã¼ã a2 = np.tanh(u[2]) # æ°ããè¨æ¶ a3 = sigmoid(u[3]) # åºåã²ã¼ã self.gates = np.stack((a0, a1, a2, a3)) self.c = a0 * c_prev + a1 * a2 # è¨æ¶ã»ã« self.y = a3 * np.tanh(self.c) # åºå def backward(self, x, y, c, y_prev, c_prev, gates, grad_y, grad_c): a0, a1, a2, a3 = gates tanh_c = np.tanh(c) r = grad_c + (grad_y*a3) * (1-tanh_c**2) # ådeltaå¤ delta_a0 = r * c_prev * a0 * (1-a0) delta_a1 = r * a2 * a1 * (1-a1) delta_a2 = r * a1 * (1 - a2**2) delta_a3 = grad_y * tanh_c * a3 * (1 - a3) deltas = np.stack((delta_a0, delta_a1, delta_a2, delta_a3)) # åãã©ã¡ã¼ã¿ã®å¾é self.grad_w += np.matmul(x.T, deltas) self.grad_v += np.matmul(y_prev.T, deltas) self.grad_b += np.sum(deltas, axis=1) # x grad_x = np.matmul(deltas, self.w.transpose(0, 2, 1)) self.grad_x = np.sum(grad_x, axis=0) # y_prev grad_y_prev = np.matmul(deltas, self.v.transpose(0, 2, 1)) self.grad_y_prev = np.sum(grad_y_prev, axis=0) # c_prevã®å¾é self.grad_c_prev = r * a0 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 # å ¨çµå åºå層 class OutputLayer: def __init__(self, n_upper, n): self.w = np.random.randn(n_upper, n) / np.sqrt(n_upper) # Xavierã®åæå¤ self.b = np.zeros(n) def forward(self, x): self.x = x u = np.dot(x, self.w) + self.b self.y = u # æçé¢æ° def backward(self, t): delta = self.y - t self.grad_w = np.dot(self.x.T, delta) self.grad_b = np.sum(delta, axis=0) self.grad_x = np.dot(delta, self.w.T) def update(self, eta): self.w -= eta * self.grad_w self.b -= eta * self.grad_b # å層ã®åæå lstm_layer = LSTMLayer(n_in, n_mid) output_layer = OutputLayer(n_mid, n_out) # è¨ç·´ def train(x_mb, t_mb): # é ä¼æ LSTM層 y_rnn = np.zeros((len(x_mb), n_time+1, n_mid)) c_rnn = np.zeros((len(x_mb), n_time+1, n_mid)) gates_rnn = np.zeros((4, len(x_mb), n_time, n_mid)) y_prev = y_rnn[:, 0, :] c_prev = c_rnn[:, 0, :] for i in range(n_time): x = x_mb[:, i, :] lstm_layer.forward(x, y_prev, c_prev) y = lstm_layer.y y_rnn[:, i+1, :] = y y_prev = y c = lstm_layer.c c_rnn[:, i+1, :] = c c_prev = c gates = lstm_layer.gates gates_rnn[:, :, i, :] = gates # é ä¼æ åºå層 output_layer.forward(y) # éä¼æ åºå層 output_layer.backward(t_mb) grad_y = output_layer.grad_x grad_c = np.zeros_like(lstm_layer.c) # éä¼æ LSTM層 lstm_layer.reset_sum_grad() for i in reversed(range(n_time)): x = x_mb[:, i, :] y = y_rnn[:, i+1, :] c = c_rnn[:, i+1, :] y_prev = y_rnn[:, i, :] c_prev = c_rnn[:, i, :] gates = gates_rnn[:, :, i, :] lstm_layer.backward(x, y, c, y_prev, c_prev, gates, grad_y, grad_c) grad_y = lstm_layer.grad_y_prev grad_c = lstm_layer.grad_c_prev # ãã©ã¡ã¼ã¿ã®æ´æ° lstm_layer.update(eta) output_layer.update(eta) # äºæ¸¬ def predict(x_mb): # é ä¼æ LSTM層 y_prev = np.zeros((len(x_mb), n_mid)) c_prev = np.zeros((len(x_mb), n_mid)) for i in range(n_time): x = x_mb[:, i, :] lstm_layer.forward(x, y_prev, c_prev) y = lstm_layer.y y_prev = y c = lstm_layer.c c_prev = c # é ä¼æ åºå層 output_layer.forward(y) return output_layer.y # 誤差ãè¨ç® def get_error(x, t): y = predict(x) return 1.0/2.0*np.sum(np.square(y - t)) # äºä¹å誤差 error_record = [] n_batch = len(input_data) // batch_size # 1ã¨ããã¯ãããã®ãããæ° for i in range(epochs): # å¦ç¿ index_random = np.arange(len(input_data)) np.random.shuffle(index_random) # ã¤ã³ããã¯ã¹ãã·ã£ããã«ãã for j in range(n_batch): # ããããããåãåºã mb_index = index_random[j*batch_size : (j+1)*batch_size] x_mb = input_data[mb_index, :] t_mb = correct_data[mb_index, :] train(x_mb, t_mb) # 誤差ãæ±ãã error = get_error(input_data, correct_data) error_record.append(error) # çµéã®è¡¨ç¤º if i%interval == 0: print("Epoch:"+str(i+1)+"/"+str(epochs), "Error:"+str(error)) predicted = input_data[0].reshape(-1).tolist() # æåã®å ¥å for i in range(n_sample): x = np.array(predicted[-n_time:]).reshape(1, n_time, 1) y = predict(x) predicted.append(float(y[0, 0])) # åºåãpredictedã«è¿½å ãã plt.plot(range(len(sin_y)), sin_y.tolist(), label="Correct") plt.plot(range(len(predicted)), predicted, label="Predicted") plt.legend() plt.show() plt.plot(range(1, len(error_record)+1), error_record) plt.xlabel("Epochs") plt.ylabel("Error") plt.show()