卷积神经网络CNN已经足够强大,为什么还需要RNN?

RNN的独特价值

卷积神经网络 – CNN 和普通的算法大部分都是输入和输出的一一对应,也就是一个输入得到一个输出。不同的输入之间是没有联系的。

比如下图中的X1和X2互换一下位置,对结果是没有任何影响的。
循环神经网络 – Recurrent Neural Network | RNN

可是还存在这样场景,某些任务需要能够更好的处理序列的信息,即前面的输入和后面的输入是有关系的。如白雪和雪白就是两种不同的意思。

基于序列的模型可以用在很多领域中。

在音乐中,一首曲子的下一个音符肯定取决于前面的音符,而在视频领域,电影中的下一帧肯定与先前的帧有关。
此外,在某些情况下,视频的当前帧、单词、字符或音符不仅仅取决于过去的信号,而且还取决于未来的信号。

例如,如果你想写一个文档,单词的顺序很重要,当前的单词肯定取决于以前的单词。如果把注意力放在文字写作上…一个单词中的下一个字符取决于之前的字符(例如,The quick brown f…,下一个字母是 o 的概率很高),如下图所示。关键思想是在给定上下文的情况下产生下一个字符的分布,然后从分布中取样产生下一个候选字符:
循环神经网络 – Recurrent Neural Network | RNN

  • 关于“The quick brown fox”句子的预测示例

一个简单的变体是存储多个预测值,并创建一个预测扩展树,如下图所示:
循环神经网络 – Recurrent Neural Network | RNN
这种需要处理 序列数据 (一串相互依赖的数据流) 的场景就需要使用 RNN 来解决了。

RNN的原理

回顾一下传统神经网络的结构,如下图,比较简单地分为:输入层 – 隐藏层 – 输出层。
循环神经网络 – Recurrent Neural Network | RNN

RNN 跟传统神经网络最大的区别在于每次都会将前一次的输出结果,带到下一次的隐藏层中,一起训练。如下图所示:

循环神经网络 – Recurrent Neural Network | RNN

把上图按照时间线展开就得到(
X
t
X_t
Xt
代表t时刻的X值,U是输入层到隐藏层的权重矩阵,o也是一个向量,它表示输出层的值;V是隐藏层到输出层的权重矩阵。):
循环神经网络 – Recurrent Neural Network | RNN
也许第一次看到会有点难以理解,网络在t时刻接收到输入
X
t
X_t
Xt
之后,隐藏层的值是
S
t
S_t
St
,输出值是
O
t
O_t
Ot
。关键的是,
S
t
S_t
St
的值不仅仅取决于
X
t
X_t
Xt
,还取决于
S
t

1
S_{t-1}
St1

请对照上面的展开图,我们可以用下面的公式来表示循环神经网络的计算方法(f,g是**函数,且公式中并没有包含偏置项):


Q
t
=
g
(
V

S
t
)
(a)
Q_t=g(V\cdot S_t) \tag a
Qt=g(VSt)(a)


S
t
=
f
(
U

X
t
+
W

S
t

1
)
(b)
S_t=f(U \cdot X_t +W \cdot S_{t-1}) \tag b
St=f(UXt+WSt1)(b)

注意各状态的W、V、U的值是相同的,循环神经元的特点是权重共享

RNN在实际实现的时候把隐藏层的输出叫作state,将前一刻的state和当前时刻的输入作为共同输入,输出给下一隐藏层。

上述两个公式完成了RNN的前向传播。总结一下:
(1) t时刻的输入 + t-1时刻的状态
S
t

1
S_{t-1}
St1
(第一个输入的state可以看作0),应用循环递推公式,得到下一时刻的状态
S
t
S_t
St

(2) 对t+1时刻的输入和
S
t
S_t
St
应用循环递推公式,得到
S
t
+
1
S_{t+1}
St+1

以此类推,直至完成所有时间步,得到最后的状态输出
(n) 对最后的状态应用公式a,得到最后的输出。

再加上以下两步即构成完整的循环神经元的计算步骤:
(a)输出与真实标签进行比较并得到误差。
(b)误差通过反向传播对权重进行更新,进而网络训练完成。

RNN的优化算法

RNN基于这样的机制,信息的结果依赖于前面的状态或前N个时间步。普通的RNN可能在学习长距离依赖性方面存在困难。例如,如果我们有这样一句话,“The man who ate my pizza has purple hair”。在这种情况下,purple hair描述的是The man,而不是pizza。所以这是一个长距离的依赖关系。

RNN 到 LSTM – 长短期记忆网络

RNN 是一种死板的逻辑,越晚的输入影响越大,越早的输入影响越小,且无法改变这个逻辑。

LSTM 做的最大的改变就是打破了这个死板的逻辑,而改用了一套灵活了逻辑——只保留重要的信息。

简单说就是:抓重点!
循环神经网络 – Recurrent Neural Network | RNN

长短时记忆网络(LSTM)

长短时记忆网络可以控制何时让输入进入神经元,何时记住之前时序中学到的东西,以及何时让输出传递到下一个时间戳。所有这些决策仅仅基于输入就能自我调整。

LSTM 被明确设计用来避免长期依赖性问题。长时间记住信息实际上是 LSTM 的默认行为,而不是需要努力学习的东西!

所有递归神经网络都具有神经网络的链式重复模块。在标准的 RNN 中,这个重复模块具有非常简单的结构,例如只有单个 tanh 层。

乍一看,LSTM 看起来很难理解,但事实并非如此。我们用下图来解释它是如何工作的:
循环神经网络 – Recurrent Neural Network | RNN
LSTM 的关键是细胞状态,即图中上方的水平线。

细胞状态有点像传送带。它贯穿整个链条,只有一些次要的线性交互作用。信息很容易以不变的方式流过。

循环神经网络 – Recurrent Neural Network | RNN
LSTM 可以通过所谓“门”的精细结构向细胞状态添加或移除信息。

门可以选择性地以让信息通过。它们由 S 形神经网络层和逐点乘法运算组成。

循环神经网络 – Recurrent Neural Network | RNN

S 形网络的输出值介于 0 和 1 之间,表示有多大比例的信息通过。0 值表示“没有信息通过”,1 值表示“所有信息通过”。

一个 LSTM 有三种这样的门用来保持和控制细胞状态。

详细一点解释的话:

首先,需要一个逻辑函数 σ 计算出介于 0 和 1 之间的值,并且控制哪个信息片段流经 LSTM 门。请记住,logisitic 函数是可微的,所以它允许反向传播。

然后需要一个运算符 ⊗ 对两个相同维数的矩阵进行点乘产生一个新矩阵,其中新矩阵的第 ij 个元素是两个原始矩阵第 ij 个元素的乘积。同样,需要一个运算符 ⊕ 将两个相同维数的矩阵相加,其中新矩阵的第 ij 个元素是两个原始矩阵第 ij 个元素的和。在这些基本模块中,将 i 时刻的输入 xi 与前一步的输出 yi 放在一起。

方程 fi=σ(Wf·[yi-1,xi]+bf) 是逻辑回归函数,通过控制**门 ⊗ 决定前一个单元状态 Ci-1 中有多少信息应该传输给下一个单元状态 Ci(Wf 是权重矩阵,bf 是偏置)。逻辑输出 1 意味着完全保留先前单元状态 Ct-1,输出 0 代表完全忘记 Ci-1 ,输出(0,1)中的数值则代表要传递的信息量。

接着,方程根据当前输入产生新信息,方程 si=σ(Wc·[Yi-1,Xi]+bc) 则能控制有多少新信息通过运算符 ⊕ 被加入到单元状态 Ci 中。利用运算符 ⊗ 和 ⊕,给出公式对单元状态进行更新。

最后,需要确定当前单元状态的哪些信息输出到 Yi。很简单,再次采用逻辑回归方程,通过 ⊗ 运算符控制候选值的哪一部分应该输出。在这里有一点需要注意,单元状态是通过 tanh 函数压缩到 [-1,1]。这部分对应的方程是 Yi=ti*tanh(Ci)。

这看起来像很多数学理论,但有两个好消息。首先,如果你明白想要达到的目标,那么数学部分就不是那么难;其次,你可以使用 LSTM 单元作为标准 RNN 元的黑盒替换,并立即解决梯度消失问题。

处理向量序列

真正使 RNN 强大的是它能够处理向量序列,其中 RNN 的输入和输出可以是序列,下图很好地说明了这一点,最左边的例子是一个传统(非递归)网络,后面跟着一个序列输出的 RNN,接着跟着一个序列输入的 RNN,其次跟着序列输入和序列输出不同步的 RNN,最后是序列输入和序列输出同步的 RNN。
循环神经网络 – Recurrent Neural Network | RNN
机器翻译是输入序列和输出序列中不同步的一个例子:网络将输入文本作为一个序列读取,读完全文后输出目标语言。

视频分类是输入序列和输出序列同步的一个例子:视频输入是一系列帧,对于每一帧,在输出中提供分类标签。

参考:

https://easyai.tech/ai-definition/rnn/

http://c.biancheng.net/view/1946.html

一些有趣的应用:
http://karpathy.github.io/2015/05/21/rnn-effectiveness/