简单的循环神经网络在学习长序列中的依赖关系时面临很大困难,主要原因是梯度消失和梯度爆炸。网络从较早时间步传递相关信息的能力受到影响。长短期记忆(LSTM)网络正是为了解决这一局限而开发,通过引入更复杂的单元结构,使其能够长时间保持记忆。LSTM网络的主要组成部分是LSTM单元。它用一个由门控和专用单元状态组成的复杂系统,替代了标准RNN单元中的简单变换。这种结构使得网络能够随时间选择性地添加、删除或保留信息。LSTM单元有两个主要组成部分,实现了这种受控的信息流动:单元状态 ($ C_t $): 这是LSTM的一个突出特性。你可以将其视为一条内部记忆轨道,水平贯穿一系列单元。信息可以在这条状态线上流动,只发生轻微的线性交互。这种结构使得信息(以及训练时的梯度)更容易在多个时间步中持续存在,而不会明显衰减。门控: 它们是神经网络层(通常使用Sigmoid $ \sigma $激活函数),用于调节信息进出单元状态的流动。因为Sigmoid函数的输出值介于0和1之间,这些门控就像过滤器一样发挥作用:接近0的值表示“只让很少信息通过”,而接近1的值表示“让大部分信息通过”。一个LSTM单元包含三个主要门控:遗忘门: 决定从上一时间步的单元状态 ($ C_{t-1} $) 中丢弃哪些信息。输入门: 决定将当前输入 ($ x_t $) 和上一时间步的隐藏状态 ($ h_{t-1} $) 中的哪些新信息存储到单元状态中。输出门: 控制当前单元状态 ($ C_t $) 的哪些部分应作为当前时间步的隐藏状态 ($ h_t $) 传递出去。我们来描绘这些组成部分如何在一个时间步 $ t $ 的单个LSTM单元中相互作用:digraph G { rankdir=LR; node [shape=box, style=filled, fillcolor="#e9ecef", margin=0.2]; edge [arrowsize=0.7]; subgraph cluster_cell { label = "LSTM单元 (t)"; bgcolor = "#f8f9fa"; margin = 20; xt [label="x_t", shape=ellipse, fillcolor="#a5d8ff"]; ht_1 [label="h_{t-1}", shape=ellipse, fillcolor="#bac8ff"]; Ct_1 [label="C_{t-1}", shape=ellipse, fillcolor="#b2f2bb"]; ht [label="h_t", shape=ellipse, fillcolor="#bac8ff", pos="6,0!"]; Ct [label="C_t", shape=ellipse, fillcolor="#b2f2bb", pos="6,1!"]; concat [label="连接", shape=point, width=0.1]; fg_sig [label=<σ>, shape=circle, fillcolor="#ffc9c9", width=0.5]; fg_mul [label=<×>, shape=circle, fillcolor="#e9ecef", width=0.3]; fg_label [label="遗忘门", shape=plaintext]; ig_sig [label=<σ>, shape=circle, fillcolor="#ffd8a8", width=0.5]; ig_tanh [label=<tanh>, shape=circle, fillcolor="#ffd8a8", width=0.5]; ig_mul [label=<×>, shape=circle, fillcolor="#e9ecef", width=0.3]; ig_label [label="输入门", shape=plaintext]; og_sig [label=<σ>, shape=circle, fillcolor="#a5d8ff", width=0.5]; og_tanh [label=<tanh>, shape=circle, fillcolor="#b2f2bb", width=0.5]; og_mul [label=<×>, shape=circle, fillcolor="#e9ecef", width=0.3]; og_label [label="输出门", shape=plaintext]; add [label=<+>, shape=circle, fillcolor="#e9ecef", width=0.3]; in_point [shape=point, pos="0,0.5!", width=0]; out_point [shape=point, pos="6,0.5!", width=0]; state_in [shape=point, pos="0,1!", width=0]; state_out [shape=point, pos="6,1!", width=0]; xt -> concat [label="x_t", dir=none, style=invis]; ht_1 -> concat [label="h_{t-1}", dir=none, style=invis]; Ct_1 -> state_in [color="#495057"]; {xt, ht_1} -> concat [style=dashed, color="#adb5bd"]; concat -> fg_sig [color="#495057"]; fg_sig -> fg_mul [color="#fa5252"]; fg_mul -> add [color="#495057"]; fg_sig -> fg_label [style=invis]; concat -> ig_sig [color="#495057"]; concat -> ig_tanh [color="#495057"]; ig_sig -> ig_mul [color="#fd7e14"]; ig_tanh -> ig_mul [color="#fd7e14"]; ig_mul -> add [color="#495057"]; ig_sig -> ig_label [style=invis]; add -> Ct [color="#37b24d"]; Ct -> state_out [color="#37b24d"]; state_out -> Ct [style=invis]; concat -> og_sig [color="#495057"]; Ct -> og_tanh [color="#37b24d"]; og_sig -> og_mul [color="#1c7ed6"]; og_tanh -> og_mul [color="#37b24d"]; og_mul -> ht [color="#4263eb"]; og_sig -> og_label [style=invis]; ht -> out_point [style=invis]; } input_xt [label="输入 x_t", shape=plaintext, pos="-1,0!"]; prev_ht [label="上一隐藏状态 h_{t-1}", shape=plaintext, pos="-1,-0.5!"]; prev_Ct [label="上一单元状态 C_{t-1}", shape=plaintext, pos="-1,1.5!"]; output_ht [label="输出 h_t", shape=plaintext, pos="7,-0.5!"]; next_Ct [label="下一单元状态 C_t", shape=plaintext, pos="7,1.5!"]; input_xt -> xt; prev_ht -> ht_1; prev_Ct -> Ct_1; ht -> output_ht; Ct -> next_Ct; }数据流和组成部分在一个时间步 $t$ 的单个LSTM单元中。它接收当前输入 $x_t$、上一隐藏状态 $h_{t-1}$ 和上一单元状态 $C_{t-1}$。它计算新的单元状态 $C_t$ 和新的隐藏状态 $h_t$。圆圈表示运算(Sigmoid $ \sigma $、双曲正切 $ \tanh $、元素级乘法 $ \times $、元素级加法 $ + $)。LSTM单元内的信息处理过程如下:遗忘门 ($ f_t $): 单元首先决定从上一单元状态 $ C_{t-1} $ 中丢弃哪些信息。它查看上一隐藏状态 $ h_{t-1} $ 和当前输入 $ x_t $。这些数据通过一个Sigmoid函数 $ \sigma $。输出 $ f_t $ 包含 $ C_{t-1} $ 中每个数值介于0到1之间的值。1表示“完全保留”,而0表示“完全丢弃”。 $$f_t = \sigma(W_f [h_{t-1}, x_t] + b_f)$$输入门 ($ i_t $) 和候选值 ($ \tilde{C}_t $): 接下来,单元决定要将哪些新信息存储到单元状态中。这包含两个步骤:一个Sigmoid层,称为“输入门层”,接收 $ h_{t-1} $ 和 $ x_t $,并决定更新哪些值 ($ i_t $)。一个 $ \tanh $ 层接收 $ h_{t-1} $ 和 $ x_t $,并生成一个新候选值向量 $ \tilde{C}t $,这些值有可能被添加到状态中。 $$i_t = \sigma(W_i [h{t-1}, x_t] + b_i)$$ $$\tilde{C}t = \tanh(W_C [h{t-1}, x_t] + b_C)$$单元状态更新 ($ C_t $): 现在,旧的单元状态 $ C_{t-1} $ 被更新为新的单元状态 $ C_t $。上一状态 $ C_{t-1} $ 与遗忘向量 $ f_t $ 进行元素级乘法 ($ \odot $),从而遗忘选定的部分。接着,将元素级乘法 $ i_t \odot \tilde{C}t $ 的结果(新信息,根据我们决定更新的程度进行缩放)相加。 $$C_t = f_t \odot C{t-1} + i_t \odot \tilde{C}_t$$输出门 ($ o_t $) 和隐藏状态 ($ h_t $): 最后,单元决定输出,即隐藏状态 $ h_t $。这个输出是单元状态的过滤版本。首先,一个Sigmoid层接收 $ h_{t-1} $ 和 $ x_t $,以决定单元状态的哪些部分应该作为输出 ($ o_t $)。然后,新计算出的单元状态 $ C_t $ 通过 $ \tanh $(将值压缩到-1和1之间)。这个 $ \tanh(C_t) $ 与输出门的激活值 $ o_t $ 进行元素级乘法 ($ \odot $)。这会产生隐藏状态 $ h_t $。 $$o_t = \sigma(W_o [h_{t-1}, x_t] + b_o)$$ $$h_t = o_t \odot \tanh(C_t)$$在上述方程中,$ W_f, W_i, W_C, W_o $ 代表权重矩阵,$ b_f, b_i, b_C, b_o $ 是偏置向量,它们在训练过程中被学习。符号 $ [h_{t-1}, x_t] $ 通常表示这两个向量的连接。这种门控结构,特别是独立的单元状态 $ C_t $,它仅通过门控进行轻微的加法和乘法运算,这是LSTM比简单RNN更擅长捕获长距离依赖关系的原因。信息可以在许多时间步中保持,门控学习控制哪些信息是相关的,通过提供更直接的梯度传播路径,有效地缓解了梯度消失问题。