循环神经网络(Rerrent Neural Network, RNN)

**是神经网络的一种,****RNN 对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,**利用了 RNN 的这种能力,使深度学习模型在解决语音识别、语言模型、机器翻译以及时序分析等 NLP 领域的问题时有所突破。

A. 挖掘“时序信息” (Mining Temporal Information)

这指的是 RNN 处理数据****顺序的能力。传统的神经网络(如全连接网络)在处理输入时,通常不考虑元素的顺序。例如,对于句子“我打你”和“你打我”,传统网络可能会得到相似的表示,因为它忽略了词序。

RNN 通过其独特的****循环结构解决了这个问题:

  • 链式处理:RNN 像人阅读一样,一个词一个词地处理序列。
    隐藏状态(记忆):RNN 的核心是一个“隐藏状态”(Hidden State),可以看作是网络的记忆。在处理序列的每一步,RNN 都会将当前的输入信息和上一步的记忆结合起来,形成新的记忆,然后传递给下一步 。

简单来说,当 RNN 处理到“你”这个词时,它的记忆里已经包含了“我”和“打”的信息。这种“先处理了 A,再处理 B”的机制,就是它挖掘时序信息的方式。

B. 挖掘“语义信息” (Mining Semantic Information)

语言的语义(含义)与语序密切相关。正是因为 RNN 能够捕捉到时序信息,它才能更好地理解语义。

  • 上下文决定意义:一个词的真正含义取决于它的上下文。例如,“bank”在“river bank”(河岸)和“investment bank”(投资银行)中的意思完全不同。
  • 构建上下文表示:RNN 通过一步步处理序列,其隐藏状态会不断累积和更新整个句子的上下文信息。处理完整个句子后,RNN 最终的隐藏状态就相当于对整个句子语义的概括和编码。这个包含了丰富上下文信息的向量,就是对句子语义的深度表示。

二.为什么要发明循环神经网络:

我们先来看一个 NLP 很常见的问题,命名实体识别,举个例子,现在有两句话:

第一句话:I like eating apple!(我喜欢吃苹果!)

第二句话:The Apple is a great company!(苹果真是一家很棒的公司!)

**现在的任务是要给 apple 打 Label,我们都知道第一个 apple 是一种水果,第二个 apple 是苹果公司,假设我们现在有大量的已经标记好的数据以供训练模型,当我们使用全连接的神经网络时,我们做法是把 apple 这个单词的特征向量输入到我们的模型中(如下图),在输出结果时,让我们的 label 里,正确的 label 概率最大,来训练模型,但我们的语料库中,有的 apple 的 label 是水果,有的 label 是公司,这将导致,模型在训练的过程中,预测的准确程度,取决于训练集中哪个 label 多一些,这样的模型对于我们来说完全没有作用。**问题就出在了我们没有结合上下文去训练模型,而是单独的在训练 apple 这个单词的 label,这也是全连接神经网络模型所不能做到的,于是就有了我们的循环神经网络。

img

三。循环神经网络的结构及原理:

img

我们先来讲解一下上面这幅图,首先不要管右边的 W,只看 X,U,S,V,O,这幅图就变成了,如下:

img

等等,这图看着有点眼熟啊,这不就是全连接神经网络结构吗?对,没错,不看 W 的话,上面那幅图展开就是全连接神经网络,

其中 X 是一个向量,也就是某个字或词的特征向量,作为输入层,如上图也就是 3 维向量,U 是输入层到隐藏层的参数矩阵,在上图中其维度就是 3X4,S 是隐藏层的向量,如上图维度就是 4,V 是隐藏层到输出层的参数矩阵,在上图中就是 4X2,O 是输出层的向量,在上图中维度为 2img

img

值得注意的一点是,在整个训练过程中,每一时刻所用的都是同样的 W。

x1 → h1 → y1 x2 → h2 → y2 x3 → h3 → y3

每个隐藏状态 h_t 不仅依赖当前输入 x_t,还依赖上一时刻的隐藏状态 h_{t-1}

权重矩阵在每个时间步都是共享的,例如:

  • W_{xh}:输入到隐藏层
  • W_{hh}:隐藏层到隐藏层
  • W_{hy}:隐藏层到输出层

3. RNN 的公式

每个时间步的计算公式如下:

隐藏状态更新: h_t = f(W_{xh} x_t + W_{hh} h_{t-1} + b_h)

输出计算: y_t = g(W_{hy} h_t + b_y)

  • f 通常是 tanh 或 ReLU
  • g 通常是 softmax(用于分类,如 NER 标签)

4. 举例对应到 “I love you”

时间步t 输入x_t 上一隐藏状态h_{t-1} 当前隐藏状态h_t 输出y_t
1 I h_0(初始化为 0) h_1 y_1
2 love h_1 h_2 y_2
3 you h_2 h_3 y_3

输出 y_t 可以预测每个单词的实体标签,如 O(非实体)、PER(人名)、LOC(地点)等。

每个 h_t 都 “记住” 了到目前为止的序列信息,所以 RNN 可以捕捉前后文依赖。

四。举个例子,方便理解:

假设现在我们已经训练好了一个 RNN,如图,我们假设每个单词的特征向量是二维的,也就是输入层的维度是二维,且隐藏层也假设是二维,输出也假设是二维,所有权重的值都为 1 且没有偏差且所有激活函数都是线性函数,现在输入一个序列,到该模型中,我们来一步步求解出输出序列:

img

W 在实际的计算中,在图像中表示非常困难 ,所以我们可以想象上一时刻的隐藏层的值是被存起来,等下一时刻的隐藏层进来时,上一时刻的隐藏层的值通过与权重相乘,两者相加便得到了下一时刻真正的隐藏层

a_1a_2的值初始值都是 0,可以作为每一时刻存下来的值,所以我们可以得到:img

当我们输入第一个序列,【1,1】,如下图,其中隐藏层的值,也就是绿色神经元,是通过公式 S_t = f(U \cdot X_t + W \cdot S_{t-1}) 计算得到的。因为所有权重都是 1,所以也就是 1 \cdot 1 + 1 \cdot 1 + 1 \cdot 0 + 1 \cdot 0 = 2(我把向量 X 拆开计算的,由于篇幅关系,我只详细列了其中一个神经元的计算过程,希望大家可以看懂,看不懂的请留言),输出层的值 4 是通过公式 O_t = g(V \cdot S_t) 计算得到的,也就是 2 \cdot 1 + 2 \cdot 1 = 4(同上,也是只举例其中一个神经元),得到输出向量【4,4】:


img

当【1,1】输入过后,我们的记忆里的 (a1,a2) 已经不是 0 了,而是把这一时刻的隐藏状态放在里面,即变成了 2;如图,输入下一个向量【1,1】,隐藏层的值通过公式 S_t = f(U \cdot X_t + W \cdot S_ {t-1}) 得到,1 \times 1 + 1 \times 1 + 1 \times 2 + 1 \times 2 = 6;输出层的值通过公式 O_t = g(V \cdot S_t) 得到,6 \times 1 + 6 \times 1 = 12,最终得到输出向量【12,12】

img

同理,该时刻过后值变成了 6,也就是输入第二个【1,1】过后所存下来的值,同理,输入第三个向量【2,2】,如图,细节过程不再描述,得到输出向量【32,32】:

img

由此,我们得到了最终的输出序列为:

img

至此,一个完整的 RNN 结构我们已经经历了一遍,我们注意到,每一时刻的输出结果都与上一时刻的输入有着非常大的关系,如果我们将输入序列换个顺序,那么我们得到的结果也将是截然不同,这就是 RNN 的特性,可以处理序列数据,同时对序列也很敏感