def _bp_ksi(self, nn_y_list, ksi_list): """ 反向传播,计算:倒数第2层 ~ 第1层的 ksi :param nn_y_list: 神经网路计算的每一层结果 :param ksi_list: 存储每一层的 ksi :return: NULL """ # 反向传播 for layer in range(self._layer_count - 2, -1, -1): # 1. 求解当前层激活函数的导数 # 1.1 当前层神经网络的计算结果 nn_y_cur = nn_y_list[layer] # 1.2 求导 dy_cur_activiation = self._activation.derivative_array(nn_y_cur) # 1.3 将求导结果转化为对角矩阵 diag_dy = np.diag(matrix_2_list(dy_cur_activiation)) # 2. 下一层的 w 的转置 w_next_T = (self._w_layer[layer + 1]).T # 3. 下一层的 ksi ksi_next = ksi_list[layer + 1] # 4. 计算当前层的 ksi: ksi_cur = diag_y * w_next_T, ksi_next ksi_cur = np.matmul(w_next_T, ksi_next) ksi_cur = np.matmul(diag_dy, ksi_cur) # 5. 将本层计算出的 ksi 加入到 ksi_list ksi_list[layer] = ksi_cur
def _handle_lhr(self, lhr_y): """ 处理最后一跳修正后的输出 :param lhr_y: 最后一跳修正后的输出 :return: recurrent_flag,是否继续递归;recurrent_sx,如果递归,其 sx = recurrent_sx """ # 将矩阵 lhr_y 转成 list lst = matrix_2_list(lhr_y) # 解码 ch = self._hanzi_encoder.decode(lst) # 如果 ch == END,那么结束递归 if self._hanzi_encoder.is_end(ch): r_flag = False r_sx = None # 否则,递归下去 else: # 将 ch 编码 r_sx = self._hanzi_encoder.encode(ch) # 将 r_sx 转换为矩阵 r_sx = list_2_matrix(r_sx) r_flag = True return r_flag, ch, r_sx
def _bptt(self, ksi_list, layer=0): """ 随时间反向传播(backpropagation through time, bttt),计算沿着时间轴的 eta_list :param ksi_list: 当前时间轴的每一层的 ksi 列表 :param layer: 计算某一层的 bptt, layer 默认值是0 :return: eta_list """ # 1. 当前时刻 cur_t = len(self._hidden_out_sequence) # 如果当前是 t0 时刻(cur_t = 1),则无须 bptt if cur_t <= 1: return None # 2. eta_list 初始化 eta_list = [0] * (cur_t - 1) # 3. 按照时间反向传播,计算 eta # 3.1 eta_last,等于该层纵向的 ksi eta_last = ksi_list[layer] # 3.2 该层(layer)的 u 参数的转置(u.T) uT = self._u_layer[layer].T # 3.3 反向计算该层(layer)的 eta eta_pre = eta_last for t in range((cur_t - 2), -1, -1): # 本时刻隐藏层的输出 hidden_out = self._hidden_out_sequence[t][layer] # 本时刻隐藏层输出的导数 dh = self._activation.derivative_array(hidden_out) # 将导数变为对角线矩阵 diag_dh = np.diag(matrix_2_list(dh)) # 计算 eta eta = np.matmul(uT, eta_pre) eta = np.matmul(diag_dh, eta) # 存储 delta eta_list[t] = eta # 递归(循环) eta_pre = eta # 返回 eta_list return eta_list
def predict_r(self, sx, py_list): """ 预测 :param sx: 待预测的样本 :param py_list: 预测结果 :return: NULL """ # 由于是递归调用,所以设置一个保护,防止死循环 count = len(py_list) if count >= 30: return nn_y_list = self._calc_nn(sx) # 最后一层的 nn_y,才是神经网络的最终输出 nn_y = nn_y_list[len(nn_y_list) - 1] # 最后一跳激活 last_hop_y = self._last_hop_activation.active_array(nn_y) # 将矩阵转成 list last_hop_y = matrix_2_list(last_hop_y) # 将 list 修正一下 RecurrentNN._revise(last_hop_y) # 解码 ch = self._hanzi_encoder.decode(last_hop_y) # 将 ch 加入预测结果列表 py_list.append(ch) # 如果 ch == END,那么结束递归 if self._hanzi_encoder.is_end(ch): return # 否则,递归下去,继续预测 else: # 将 ch 编码 ec = self._hanzi_encoder.encode(ch) # 将 ec 转换为矩阵 ec = list_2_matrix(ec) self.predict_r(ec, py_list)
def _bptt(self, cur_t, ksi_list, layer=0): """ 随时间反向传播(backpropagation through time, bttt),计算沿着时间轴的 delta_list :param cur_t: 当前时刻 :param ksi_list: 当前时间轴的每一层的 ksi 列表 :param layer: 计算某一层的 bptt, layer 默认值是0 :return: delta_list """ # 如果当前是 t0 时刻(cur_t = 1),则无须 bptt if cur_t <= 1: return None # delta_list 初始化 delta_list = [0] * (cur_t - 1) # delta 初始化 delta = list_2_matrix(ksi_list[layer]) # 获取该层(layer)的 u.T uT = self._u_layer[layer].T # 反向计算 delta for t in range((cur_t - 2), -1, -1): # 上一时刻的输出 hidden_out_pre = self._hidden_out_sequence[t][layer] # 上一时刻输出的导数 dh = self._activation.derivative_array(hidden_out_pre) # 将导数变为对角线矩阵 diag_dh = np.diag(matrix_2_list(dh)) # 计算 delta delta = np.matmul(uT, delta) delta = np.matmul(diag_dh, delta) # 存储 delta delta_list[t] = delta return delta_list