1.视频网站:mooc慕课https://mooc.study.163.com/university/deeplearning_ai#/c
2.详细笔记网站(中文):http://www.ai-start.com/dl2017/
3.github课件+作业+答案:https://github.com/stormstone/deeplearning.ai
1.11 双向神经网络 Bidirectional RNN
现在,你已经了解了大部分RNN模型的关键的构件,还有两个方法可以让你构建更好的模型,
- 其中之一就是双向RNN模型,这个模型可以让你在序列的某点处不仅可以获取之前的信息,还可以获取未来的信息,我们会在这节课里讲解。
- 第二个就是深层的RNN,我们会在下节课里见到,现在先从双向RNN开始吧。
为了了解双向RNN的动机,我们先看一下之前在命名实体识别中已经见过多次的NN。
如上图,这个网络有一个问题,在判断第三个词 Teddy 是不是人名的一部分时,光看句子前面部分是不够的,为了判断 y ^ < 3 > \hat y^{<3>} y^<3> 是0还是1,除了前3个单词,你还需要更多的信息,因为根据前3个单词无法判断他们说的是Teddy熊,还是前美国总统Teddy Roosevelt,所以这是一个非双向的或者说只有前向的RNN。
我刚才所说的总是成立的,不管上图中的这些单元是标准的RNN块,还是GRU单元或者是LSTM单元,只要这些构件都是只有前向的。
那么一个双向的RNN是如何解决这个问题的?
下面解释双向RNN的工作原理。
为了简单,我们用四个输入或者说一个只有4个单词的句子,这样输入只有4个, x < 1 > x^{<1>} x<1>到 x < 4 > x^{<4>} x<4>。如上图,这个网络会有一个前向的循环单元叫做 a → < 1 > \overrightarrow{a}^{<1>} a<1>, a → < 2 > \overrightarrow{a}^{<2>} a<2>, a → < 3 > \overrightarrow{a}^{<3>} a<3>还有 a → < 4 > \overrightarrow{a}^{<4>} a<4>,我在这上面加个向右的箭头来表示前向的循环单元,并且他们这样连接,这四个循环单元都有一个当前 x x x输入进去,得到预测的 y ^ < 1 > \hat y^{<1>} y^<1>, y ^ < 2 > \hat y^{<2>} y^<2>, y ^ < 3 > \hat y^{<3>} y^<3>和 y ^ < 4 > \hat y^{<4>} y^<4>。
到目前为止,我还没做什么,仅仅是把前面的RNN画在了这里,只是在图上画上了箭头。我之所以在这些地方画上了箭头是因为我们想要增加一个反向循环层,这里有个
a
←
<
1
>
\overleftarrow{a}^{<1>}
a<1>,左箭头代表反向连接,
a
←
<
2
>
\overleftarrow{a}^{<2>}
a<2>反向连接,
a
←
<
3
>
\overleftarrow{a}^{<3>}
a<3>反向连接,
a
←
<
4
>
\overleftarrow{a}^{<4>}
a<4>反向连接,所以这里的左箭头代表反向连接。
同样,我们把网络这样向上连接, a a a反向连接就依次反向向前连接。这样,这个网络就构成了一个无环图。给定一个输入序列 x < 1 > x^{<1>} x<1>到 x < 4 > x^{<4>} x<4>,这个序列首先计算前向的 a → < 1 > \overrightarrow{a}^{<1>} a<1>,然后计算前向的 a → < 2 > \overrightarrow{a}^{<2>} a<2>,接着 a → < 3 > \overrightarrow{a}^{<3>} a<3>, a ⃗ < 4 > \vec{a}^{<4>} a<4>。而反向序列从计算 a ← < 4 > \overleftarrow{a}^{<4>} a<4>开始,反向进行,计算反向的 a ← < 3 > \overleftarrow{a}^{<3>} a<3>。
你计算的是网络激活值,这不是反向而是前向的传播,而图中这个前向传播一部分计算是从左到右,一部分计算是从右到左。计算完了反向的 a ← < 3 > \overleftarrow{a}^{<3>} a<3>,可以用这些激活值计算反向的 a ← < 2 > \overleftarrow{a}^{<2>} a<2>,然后是反向的 a ← < 1 > \overleftarrow{a}^{<1>} a<1>,把所有这些激活值都计算完了就可以计算预测结果了。
举个例子,为了预测结果,你的网络会有激活函数
y
^
<
t
>
\hat y^{<t>}
y^<t>,
y
^
<
t
>
=
g
(
W
g
[
a
→
<
t
>
,
a
←
<
t
>
]
+
b
y
)
\hat y^{<t>}=g(W_g[\overrightarrow{a}^{<t>},\overleftarrow{a}^{<t>}]+b_y)
y^<t>=g(Wg[a<t>,a<t>]+by)
- a → < t > \overrightarrow{a}^{<t>} a<t>,t时刻前向激活值
- a ← < t > \overleftarrow{a}^{<t>} a<t>,t时刻反向激活值
比如你要观察时间3这里的预测结果 y ^ < 3 > \hat y^{<3>} y^<3>,信息从 x < 1 > x^{<1>} x<1>过来,流经:前向 a → < 1 > \overrightarrow{a}^{<1>} a<1>的到前向的 a → < 2 > \overrightarrow{a}^{<2>} a<2>,这些函数里都有表达,到前向的 a → < 3 > \overrightarrow{a}^{<3>} a<3>再到 y ^ < 3 > \hat y^{<3>} y^<3>,所以从 x < 1 > x^{<1>} x<1>, x < 2 > x^{<2>} x<2>, x < 3 > x^{<3>} x<3>来的信息都会考虑在内。
而从 x < 4 > x^{<4>} x<4>来的信息会流过反向的 a → < 4 > \overrightarrow{a}^{<4>} a<4>,到反向的 a → < 3 > \overrightarrow{a}^{<3>} a<3>再到 y ^ < 3 > \hat y^{<3>} y^<3>。
这样使得时间3的预测结果不仅输入了过去的信息,还有现在的信息,这一步涉及了前向和反向的传播信息以及未来的信息。给定一个句子"He said Teddy Roosevelt…"来预测Teddy是不是人名的一部分,你需要同时考虑过去和未来的信息。
这就是双向循环神经网络,并且这些基本单元不仅仅是标准RNN单元,也可以是GRU单元或者LSTM单元。事实上,很多的自然语言处理NLP问题,对于大量有自然语言处理问题的文本,有LSTM单元的双向RNN模型是用的最多的。所以如果有NLP问题,并且文本句子都是完整的,首先需要标定这些句子,一个有LSTM单元的双向RNN模型,有前向和反向过程是一个不错的首选。
以上就是双向RNN的内容,这个改进的方法不仅能用于基本的RNN结构,也能用于GRU和LSTM。通过这些改变,你就可以用一个用RNN或GRU或LSTM构建的模型,并且能够预测任意位置,即使在句子的中间,因为模型能够考虑整个句子的信息。
这个双向RNN网络模型的缺点就是你需要完整的数据的序列,你才能预测任意位置。比如说你要构建一个语音识别系统,那么双向RNN模型需要你考虑整个语音表达,但是如果直接用这个去实现的话,你需要等待这个人说完,然后获取整个语音表达才能处理这段语音,并进一步做语音识别。对于实际的语音识别的应用通常会有更加复杂的模块,而不是仅仅用我们见过的标准的双向RNN模型。但是对于很多自然语言处理的应用,如果你总是可以获取整个句子,这个标准的双向RNN算法实际上很高效。
好的,这就是双向RNN,下一节课,也是这周的最后一个,我们会讨论如何用这些概念,标准的RNN,LSTM单元,GRU单元,还有双向的版本,构建更深的网络。