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 _calc_last_ksi(self, nn_y_list, sy): """ 计算最后一层 ksi :param nn_y_list: 神经网路计算的每一层结果 :param sy: 训练样本的输出 :return: 最后一层 ksi """ # 1. 计算损失函数的偏导 last_hop_y = nn_y_list[self._layer_count] loss_dy = self._loss.derivative_array(last_hop_y, sy) # 2. 计算最后一层 ksi nn_y_last = nn_y_list[self._layer_count - 1] row_last = len(nn_y_last) ksi_last = list() for i in range(0, row_last): # 计算ksi_last 的每个元素 ksi_item = loss_dy[i][0] * self._last_hop_activation.derivative(last_hop_y, i) \ * self._activation.derivative(nn_y_last[i][0]) ksi_last.append(ksi_item) ksi_last = list_2_matrix(ksi_last) return ksi_last
def create_test_sample(self, ch): """ 创建测试样本(输入) :param ch: 测试样本字符 :return: ch 的 one-hot 编码 """ sx = self._hanzi_encoder.encode(ch) sx = list_2_matrix(sx) return sx
def create_sample(self): """ 创建样本 :return: NULL """ self._sx_list = list() self._sy_list = list() count = len(self._poem) for i in range(0, count - 1): sx = self._hanzi_encoder.encode(self._poem[i]) sx = list_2_matrix(sx) self._sx_list.append(sx) sy = self._hanzi_encoder.encode(self._poem[i + 1]) sy = list_2_matrix(sy) self._sy_list.append(sy)
def _create_one_poem_sample(self, poem): """ 创建一首诗的训练样本 :param poem: 一首诗 :return: NULL """ # 1. 先对这首诗做个预处理 # 1.1 将 "\n" 替换为 “” poem = poem.replace("\n", "") # 1.2 最后加一个 END 字符 poem = poem + HanziEncoder.END # 2. 构建样本 # 2.1 初始化样本列表 sx_list, sy_list sx_list = list() sy_list = list() # 2.2 构建样本列表 count = len(poem) for i in range(0, count - 1): sx = self._hanzi_encoder.encode(poem[i]) sx = list_2_matrix(sx) sx_list.append(sx) sy = self._hanzi_encoder.encode(poem[i + 1]) sy = list_2_matrix(sy) sy_list.append(sy) # 2.3 将样本列表加入样本分组 self._sx_group.append(sx_list) self._sy_group.append(sy_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