循环神经网路(RNN)在工作时一个重要的优点在于,其能够在输入和输出序列之间的映射过程中利用上下文相关信息。然而不幸的是,标准的循环神经网络(RNN)能够存取的上下文信息范围很有限。这个问题就使得隐含层的输入对于网络输出的影响随着网络环路的不断递归而衰退。因此,为了解决这个问题,**长短时记忆(LSTM)**结构诞生了。与其说长短时记忆是一种循环神经网络,倒不如说是一个加强版的组件被放在了循环神经网络中。具体地说,就是把循环神经网络中隐含层的小圆圈换成长短时记忆的模块。
LSTM处理序列问题有效的关键在于门结构,通过门结构去除或者增加信息到细胞状态的能力。
**
1.Bi-directional Long Short-Term Memory(双向LSTM)结构
**
简单来说双向LSTM就是把BRNN中隐含层的小圆圈换成了长短时记忆的模块。与其说长短时记忆是一种循环神经网络,倒不如说是一个加强版的组件被放在了循环神经网络中。这个模块的样子如下图所示:
参数介绍:
计算公式:
**
- 遗忘门
遗忘门能决定应丢弃或保留哪些信息。来自先前隐藏状态的信息和当前输入的信息同时输入到Sigmoid函数,输出值处于0和1之间,越接近0意味着越应该忘记,越接近1意味着越应该保留。这个f就可以用来操控遗忘哪些数据。 - 输入门
f是forget的意思,i是input的意思。
输入门用来更新单元状态。先将先前隐藏状态的信息和当前输入的信息输入到Sigmoid函数,在0和1之间调整输出值来决定更新哪些信息,0表示不重要,1表示重要。也可将隐藏状态和当前输入传输给Tanh函数,并在-1和1之间压缩数值以调节网络,然后把Tanh输出和Sigmoid输出相乘,Sigmoid输出将决定在Tanh输出中哪些信息是重要的且需要进行保留。
** - 更新细胞状态:下图展示了两个门是如何控制遗忘和输出的。
** - 输出门
我们确定了当前的状态,那么当前状态的多少可以进行输出呢?控制Ct输出的门叫输出门,用Ot表示。
输出门能决定下个隐藏状态的值,隐藏状态中包含了先前输入的相关信息。当然,隐藏状态也可用于预测。首先把先前的隐藏状态和当前输入传递给Sigmoid函数;接着把新得到的单元状态传递给Tanh函数;然后把Tanh输出和Sigmoid输出相乘,以确定隐藏状态应携带的信息;最后把隐藏状态作为当前单元输出,把新的单元状态和新的隐藏状态传输给下个时间步。
LSTM的变种GRU
**
**
**
知乎中讨论LSTM为何如此有效
**
2.双向LSTM
**
RNN和LSTM都只能依据之前时刻的时序信息来预测下一时刻的输出,但在有些问题中,当前时刻的输出不仅和之前的状态有关,还可能和未来的状态有关系。比如预测一句话中缺失的单词不仅需要根据前文来判断,还需要考虑它后面的内容,真正做到基于上下文判断。即:
对于每个时刻t,输入会同时提供给两个方向相反的RNN,输出由这两个单向RNN共同决定。
#Tensorflow中实现双向RNNs
在tensorflow中已经提供了双向RNNs的接口,使用**tf.contrib.rnn.bidirectional_dynamic_rnn()**这个函数,就可以很方便的构建双向RNN网络。
def bidirectional_dynamic_rnn(
cell_fw, # 前向RNN
cell_bw, # 后向RNN
inputs, # 输入
sequence_length=None,# 输入序列的实际长度(可选,默认为输入序列的最大长度)
initial_state_fw=None, # 前向的初始化状态(可选)
initial_state_bw=None, # 后向的初始化状态(可选)
dtype=None, # 初始化和输出的数据类型(可选)
parallel_iterations=None,
swap_memory=False,
time_major=False,
# 决定了输入输出tensor的格式:如果为true, 向量的形状必须为 `[max_time, batch_size, depth]`.
# 如果为false, tensor的形状必须为`[batch_size, max_time, depth]`.
scope=None
)
当输入的inputs张量的维度为:[batch_size,max_len,embeddings_num],此时time_major = False(一般设为这个);当输入的inputs张量的维度为:[max_len,batch_size,embeddings_num],此时time_major = True
返回值:
元组: (outputs, output_states)
- outputs为(output_fw, output_bw),是一个包含前向cell输出tensor和后向cell输出tensor组成的元组。假设
time_major=false, output_fw和output_bw的shape为**[batch_size, max_len,
hiddens_num]。在此情况下,最终的outputs可以用tf.concat([output_fw,
output_bw],-1)或tf.cocat([output_fw, output_bw],2)** - output_states为(output_state_fw, output_state_bw),包含了前向和后向最后的隐藏状态的组成的元组。 output_state_fw和output_state_bw的类型为LSTMStateTuple。 LSTMStateTuple由**(c,h)**组成,分别代表memory cell和hidden state。
最近在做文本分类,使用到了双向LSTM(BiLSTM),其具体实现为:
#前向LSTM
fw_cell = tf.nn.rnn_cell.LSTMCell(self.cell_hidden_size, name="fw_lstm")
#后向LSTM
bw_cell = tf.nn.rnn_cell.LSTMCell(self.cell_hidden_size, name ="bw_lstm")
#构建双向LSTM网络
outputs, _ = tf.nn.bidirectional_dynamic_rnn(fw_cell,bw_cell,embedding_inputs_dense,sen_len,dtype=tf.float32)
#outputs包含一个前向的cell和后向的cell组成的元组
lstm_contact = tf.concat(outputs, 2)
lstm_contact = tf.reduce_mean(lstm_contact, axis=1)