我们通过前两篇博文知道了全连接神经网络和卷积神经网络的基本工作原理,这两种网络结构的层与层之间是全连接或部分连接的,但在每层之间的节点是无连接的,这样的网络结构并不能很好的处理序列数据。当我们要建立一个模型来预测句子的下一个单词是什么时,结合n-gram语言模型思想,一般是需要用到当前单词以及前面单词,因为一个句子中每个单词的出现并不是独立的。比如,如果第一个词是“天空”,接下来的词是“很”,那么下一个词很大概率会是“蓝”,RNN则可以处理类似这样的序列数据。RNN通过每层之间节点的连接结构来记忆之前的信息,并利用这些信息来影响后面节点的输出。RNN可充分挖掘序列数据中的时序信息以及语义信息,这种在处理时序数据时比全连接神经网络和CNN更具有深度表达能力,RNN已广泛应用于语音识别、语言模型、机器翻译、时序分析等各个领域。
1.2 RNN模型我们先来看一个RNN经典结构,图1展示了一个典型按时间展开后的RNN结构。
图1 按时间展开后的RNN结构
从图1可以看出,RNN在每一个时刻都有一个输入Xt
,然后根据当前节点的状态At
计算输出值ht
,而At
是根据上一时刻的状态At-1
和当前的输入Xt
共同决定的。和卷积神经网络卷积核或池化核的参数共享类似,这里RNN结构中的参数在不同时刻中也是共享的。
1.2.1 RNN前向传播过程
图2展示了RNN的前向传播的计算过程。
图2 RNN的前向传播的计算过程
如图2所示,假设节点状态的维度为2
,节点的输入和输出维度为1
,那么在循环体的全连接层神经网络的输入维度为3
,也就是将上一时刻的状态与当前时刻的输入拼接成一维向量作为循环体的全连接层神经网络的输入,在这里t0
时刻的节点状态初始化为[0.0, 0.0]
,t0
时刻的节点输入为[1.0]
,拼接之后循环体的全连接层神经网络的输入为[0.0, 0.0, 1.0]
,循环体中的全连接层的权重表示为二维矩阵[[0.1, 0.2], [0.3, 0.4], [0.5, 0.6]]
,偏置项为[0.1, -0.1]
,我们可以看到权重矩阵和偏置项在t0
和t1
时刻的循环体中是一样的,这也说明了RNN结构中的参数在不同时刻中也是共享的。经过循环体中的全连接层神经网络后节点的状态改变为tanh([0.6, 0.5]) = [0.537, 0.462]
,当前节点状态的输出作为下一个节点状态的输入。
为了将当前时刻的状态转变为节点的最终输出,RNN中还有另外一个全连接神经网络来计算节点输出,在图2中被表示为[0.537, 0.462] * [1.0, 2.0] + [0.1] = [1.56]
,用于输出的全连接层权重为[1.0, 2.0]
,偏置项为[0.1]
,1.56
表示为t0
时刻节点的最终输出。
得到RNN的前向传播结果之后,和其他神经网络类似,定义损失函数,使用反向传播算法和梯度下降算法训练模型,但RNN唯一的区别在于:由于它每个时刻的节点都有一个输出,所以RNN的总损失为所有时刻(或部分时刻)上的损失和。
1.3 LSTM结构上节介绍的RNN模型,存在“长期依赖”的问题。模型在预测“大海的颜色是”下一个单词时,很容易判断为“蓝色”,因为这里相关信息与待预测词的位置相差不大,模型不需要记忆这个短句子之前更长的上下文信息。但当模型预测“十年前,北京的天空很蓝,但随着大量工厂的开设,废气排放监控不力,空气污染开始变得越来越严重,渐渐地,这里的天空变成了”下一个单词时,依靠“短期依赖”就不能很好的解决这类问题,因为仅仅根据“这里的天空变成了”这一小段,后一个单词可以是“蓝色”,也可以是“灰色”。上节描述的简单RNN结构可能无法学习到这种“长期依赖”的信息,LSTM可以很好的解决这类问题。图3展示了LSTM单元结构图。
图3 LSTM单元结构图
与简单RNN结构中单一tanh循环体不同的是,LSTM使用三个“门”结构来控制不同时刻的状态和输出。所谓的“门”结构就是使用了sigmoid激活函数的全连接神经网络和一个按位做乘法的操作,sigmoid激活函数会输出一个0~1之间的数值,这个数值描述的是当前有多少信息能通过“门”,0表示任何信息都无法通过,1表示全部信息都可以通过。其中,“遗忘门”和“输入门”是LSTM单元结构的核心。下面我们来详细分析下三种“门”结构。
遗忘门,用来让RNN“忘记”之前没有用的信息。比如“十年前,北京的天空是蓝色的”,但当看到“空气污染开始变得越来越严重”后,RNN应该忘记“北京的天空是蓝色的”这个信息。遗忘门会根据当前时刻节点的输入Xt
、上一时刻节点的状态C(t-1)
和上一时刻节点的输出h(t-1)
来决定哪些信息将被遗忘。
输入门,用来让RNN决定当前输入数据中哪些信息将被留下来。在RNN使用遗忘门“忘记”部分之前的信息后,还需要从当前的输入补充最新的记忆。输入门会根据当前时刻节点的输入Xt
、上一时刻节点的状态C(t-1)
和上一时刻节点的输出h(t-1)
来决定哪些信息将进入当前时刻节点的状态Ct
,比如看到“空气污染开始变得越来越严重”后,模型需要记忆这个最新的信息。
输出门,LSTM在得到最新节点状态Ct
后,结合上一时刻节点的输出h(t-1)
和当前时刻节点的输入Xt
来决定当前时刻节点的输出。比如当前时刻节点状态为被污染,那么“天空的颜色”后面的单词应该是“灰色”。
在TensorFlow中可以使用lstm = rnn_cell.BasicLSTMCell(lstm_hidden_size)
来声明一个LSTM结构。
RNN和LSTM都只能依据之前时刻的时序信息来预测下一时刻的输出,但在有些问题中,当前时刻的输出不仅和之前的状态有关,还可能和未来的状态有关系。比如预测一句话中缺失的单词不仅需要根据前文来判断,还需要考虑它后面的内容,真正做到基于上下文判断。BRNN有两个RNN上下叠加在一起组成的,输出由这两个RNN的状态共同决定。BRNN结构图如图4所示。
图4 BRNN结构图
对于每个时刻t
,输入会同时提供给两个方向相反的RNN,输出由这两个单向RNN共同决定。
DRNN可以增强模型的表达能力,主要是将每个时刻上的循环体重复多次,每一层循环体中参数是共享的,但不同层之间的参数可以不同。DRNN结构图如图5所示。
图5 DRNN结构图
TensorFlow中可以通过rnn_cell.MultiRNNCell([lstm] * number_of_layer)
来构建DRNN,其中number_of_layer
表示了有多少层。
在我们构建自己的任务模型时,往往会设置dropout来让构建的网络模型更加健壮,类似在卷积神经网络只在最后全连接层使用dropout,DRNN一般只在不同层循环体结构中使用dropout,而不在同一层的循环体结构中使用。即从时刻t-1
传递到t
时刻时,RNN不进行状态的dropout,但在同一时刻t中,不同层循环体之间会使用dropout,图6展示了DRNN中使用dropout,其中实线箭头表示不使用dropout,虚线箭头表示使用dropout。
图6 DRNN中使用dropout
TensorFlow中可以使用tf.nn.rnn_cell.DropoutWrapper
类来实现dropout功能。
在实际编程中,我们可以通过TensorFlow的高层封装工具TFLearn来自定义模型,TFLearn封装了一些常用的神经网络模型,有兴趣的可以找找教程。
热门评论
您好,我是一个初学者,学习了您的文章后,有一个问题向您请教,请问1.2.1节中,t0时刻的节点状态为什么是[0,0]而不是一个0,谢谢!