Advertisement

[机器学习-李宏毅] 反馈神经网络笔记 (RNN、LSTM)

阅读量:

Recurrent Neural Network

Recurrent Neural Networks(RNNs)是一种基于反馈机制的人工智能模型,在序列数据处理中表现出色。与其传统的前馈架构不同,在RNN中信息能够沿着时间维度循环流动。其独特之处在于能够记住处理过程中的中间结果,并将其存储并整合到下一个计算步骤中以影响最终输出结果。这种设计背后的原因是什么呢?让我们通过一个简单的示例来探讨这一问题的本质:假设我们有一个简单的序列输入序列{x₁,x₂,x₃}……xₙ}经过模型处理后生成对应的输出{y₁,y₂,y₃}……yₙ}这一过程如何实现?

RNN 的背景

设想存在这样一个应用场景,请将一段文字输入给语音助手作为指令,请注意以下示例:"I would like to arrive at Chengdu on November 2nd"(意思是将在11月2日抵达成都)。希望语音助手能识别出成都作为我的目的城市以及将11月2日视为日期,并据此自动规划好日程安排或是查询好交通信息等

1-of-N Encoding

已知神经网络的输入通常为数值数据,难以处理字符类型。因此一种常用的方法就是 1-of-N Encoding 方法。在编码过程中我们会使用到一个词汇表(lexicon)。例如,在本例中使用的词汇表为 \rm lexicon = \{apple, bag, cat, dog\}。当我们要编码的词是 apple 时,则会得到对应的编码结果 [1,0,0,0];同理若要编码的是 cat 时,则结果即为 [0,0,1,0]。此外,在下面还有一个例子。

独热编码还有一个改版叫做 Beyond 1-of-N Encoding ,就是在 1-of-N Encoding 的基础上多一个 \rm other 表示一个词未出现在词汇表中,例如词汇表还是上面的(没有 \rm elephant),若一个词是 \rm banana 则会编码成 [0,0,0,0,1] 。改版之前是会有词无法进行编码的,因为没有出现在词汇表中,改版后所有词都能编码,但是如果词汇表设置的不好,则会有很多次都被归到 \rm other ,变的没有差别,这样训练出的网络可能会有问题。

Word Hashing

另外一种编码方法是 Word hashing ,它以三个连续字母组成的组合作为维度。即共有 26^3 种不同的组合。具体来说,则会检查单词中是否存在任何一个这样的三字母组合。例如 \rm apple 这个单词就可以分解为 \rm app, ppl, ple 这三种三字母组合,在这三种对应的维度位置上标记1,在其他位置则标记0。(需要注意的是,在某些情况下可能会遇到同一个三字母组合在同一个单词中多次出现的问题)

如何将单词输入到神经网络中后?针对最初的问题,请先考虑将输出分类为单词类型的方案。具体而言,在输入 \rm I 时输出属于 \rm other 类;在输入 \rm Chengdu 时属于 \rm destination 类;在输入 \rm November\rm 2nd 时属于 \rm time 类。这样简单的分类问题似乎可以用一个普通的神经网络轻松解决。然而,在面对更复杂的情况时,则需要更高阶的方法:当输入变为“我想要离开成都十一月二号”时(即“I would like to leave Chengdu on November 2nd”),这要求语音助手的操作会有所不同(如提醒购买纪念品)。对于之前的无记忆模型而言,则无法区分\rm Chengdu到底是目的地还是出发地(\rm departure)。但只要考虑到前一个词的存在,则很容易判断它是目的地还是出发地了。因此我们需要一种能够记住前面词语变化的神经网络来解决这个问题。

RNN 的结构及原理

Elman Network

RNN 实际上是将前一步骤产生的输出结果融入当前步骤中,并结合当前步骤中的其他信息共同决定当前状态的变化情况。比如在计算 \rm leave 这一层时各子层产生的输出,在下一步骤中会被用于下一步骤中的输入运算,并直接参与最终结果生成的过程。其中一部分特殊的情况可以被用来影响后续步骤的状态变化情况。具体结构如图所示,在这一流程中会将计算\rm leave\text{这一层}各子节点的结果分别存储起来,在后续\rm Chengdu\text{这一层}中则会将这些中间结果作为一个整体参数参与到整个网络模型中去。

这样之后,在NLP领域中每个句子作为一个整体进行处理。现在每个句子作为一个整体进行处理。每个这样的句子由多个词语组成,在这种情况下词语彼此之间也会产生相互作用。因此,在这种情况下词语之间的关系变得紧密。因此,在这种情况下词语之间的关系变得紧密。因此,在这种情况下词语之间的关系变得紧密。然而即使两个词语的意义相同如果它们的位置互换也会导致完全不同的语义效果。同样的信息以不同顺序传递给模型时会导致输出结果的变化为了使系统能够正常运行在开始时需要设定初始状态比如说设为 0 。如图所示的是 RNN 模型的工作机制然而即使两个词语的意义相同如果它们的位置互换也会导致完全不同的语义效果。然而即使两个词语的意义相同如果它们的位置互换也会导致完全不同的语义效果.然而即使两个词语的意义相同如果它们的位置互换也会导致完全不同的语义效果.然而即使两个词语的意义相同如果它们的位置互换也会导致完全不同的语义效果.在开始时需要设定初始状态比如说设为 0 以便系统能够正常运行.

Jordan Network & Bidirectional RNN

其中一种结构中,每一层都会将当前输出传递给下一层,而另一种结构则仅将上一层最终产生的输出变量 y 传递给下一层的所有层,其名称通常被称为 Jordan Network ,其运行原理如下图所示:

另外一种方法是采用句子原始顺序输入训练第一个RNN随后反转输入顺序训练第二个RNN接着将这两个RNN的输出综合起来形成最终处理结果如上文所示这种方法被称为**Bidirection RNN(双向反馈神经网络)**从另一方面来看在传统方法中,默认情况下每当接收一个新的单词时就会立即生成相应的分类标签这些早期生成的结果并不考虑后续的信息只有当这两个子网络均完成计算后才能产生系统的综合判断每个单词的信息会与其在句子中的前后位置上的单词产生关联

Long short-term Memory (LSTM)

上文所述的记忆机制是每次memory unit中的数值都会被更新,在每一次计算过程中不仅会参与到后续输入数据的处理中去,并且这些数值在处理过程中始终保持不变的状态。这一类回环结构通常被称为简单RNN(Simple Recurrent Neural Network)。下面将重点介绍一种在复杂场景中表现更为优异的变体——长短期记忆网络(LSTM)。让我们先来了解其工作原理:如图所示。

不同于 Simple RNN 的特点在于其神经元的状态并非始终被更新也不会每次都释放存储的信息。其工作原理较为复杂具体表现为以下几个关键步骤:首先信息通过一个 Input Gate 机制进行筛选只有当输入被接收时其输出为1否则为0;接着将该信息传递给 Forget Gate 以决定是否清除当前存储的记忆内容;随后将经过遗忘机制后的信息与新的候选记忆内容结合最终形成新的 Memory Cell 值并作为后续输出的基础;最后通过 Output Gate 制定当前 Memory Cell 的输出是否被传递给下一个时间步的信息处理环节。
具体计算流程如图所示

将输入映射至整个单元的是一个向量x, 然后通过一次线性变换操作得到标量输出值\mathbf{z}, 计算式为\mathbf{z} = \mathbf{x}^T \mathbf{w} + b, 其中权重参数由\mathbf{w}表示、偏置参数由b表示. 在图示中展示的每一个Gate结构接收四个不同的输入信号: 主激活信号、遗忘激活信号、更新激活信号以及候选激活信号. 这些Gate结构的主要区别体现在使用的权重和偏置参数上. 在此过程中所有参与变换的操作都使用同一个原始输入变量x.

那么第一步就是让变量 z 经过一个激活函数 g(z) 处理,并对另一个变量 z_i 同样施加另一个激活函数 f(z_i) 的影响,并将这两个处理后的值进行相乘运算以获得 Input Gate 的输出值即 g(z)f(z_i) 。其中g(z) 实际上对应于全连接神经网络中的某个特定神经元的输出结果而f(z_i) 则决定了该输入是否被接收。

在步骤二中,在步骤二中

在第三步中,在经历了h(c')这一激活函数处理之后,在Output Gate那边也经历了f(z_o)这一激活函数的作用,并将这两个结果进行相乘得到了最终的输出a = h(z') f(z_o)

上面的激活函数 f() 常见采用 Sigmoid 函数来控制其开启或关闭状态。需要注意的是,在 Forgive Gate 区域中当 f() 输出为 0 时,则表示遗忘之前存储的记忆内容。

Network Structure

如前所述所述的是单一神经元的工作机制。基于 LSTM 的神经网络架构本质上与传统全连接网络具有相似性只不过其独特的细胞结构取代了普通层中的线性变换操作。原始输入构成向量 x 作为当前层 LSTM 单元接收输入信号;该层所有 LSTM 单元产生的输出结果 a 联合作为整体向量传递至下一层。如同所示图中所示的方式排列分布后会发现其权重数量从原先每层两个单元共四个参数扩展至当前层每个单元拥有四个权重参数共计八个参数使得总参数数增加了四倍同时还需要额外维护一个用于存储当前时刻信息的记忆单元向量记为 c

通过向量表示将上层图形转换为下层图形,在GRU结构中x^t代表上一层在第t个时间步的输出结果。需要注意的是其中存在一定的困惑或不明确之处或者说存在一定的问题即每个z的实际输出值应依据其所在的特定位置进行计算例如最左边位置上的各个门单元接收的不同输入信号对应于各自特定的目标神经元

以某一层神经元为例分析其向量运算流程。输入变量x^t通过四组不同的权重矩阵进行线性变换得到四个中间结果:z^{f}z^{i}z^{*}z^{o}。随后的过程如右图所示,这一流程与前述的方法具有相同的机制。

该神经单元在当前时段计算出c^t值后,在下一时间段将这一数值整合到运算中以生成y^{t+1}和新的c^{t+1}

这一类模型并非LSTM网络体系的理想呈现形态,在其真正结构中不仅需要关注前一步骤的状态信息 c^{t-1} 还需要整合前一个时间步输出信息 y^{t-1} 将其视为当前状态变量 h^{t-1} 进行处理。进一步地不仅将 c^{t-1} 融入到中间计算环节而且还将其直接作为运算过程中的输入参数引入系统中这被称作具有peephole连接机制的作用机制。如图所示展示了该改进后的网络架构运行流程。

多层的 LSTM 就会长成下面这样:

How to train RNN

放弃LSTM模型后重新审视最初的Simple RNN架构时会发现一个尚未解决的关键挑战。我们在前面讨论了如何通过Gradient Descent(梯度下降)来训练传统的人工神经网络模型。这里的关键区别在于反向传播过程中不仅要处理权重参数还需要考虑输入序列的时间依赖关系。为了深入理解这一过程及其在RNN中的应用我们需要理解其工作原理以及如何将其应用于RNN结构中。因此,在这种情况下使用Backpropagation through time(BPTT)方法更为合适。

在课程中并没有深入探讨这一细节具体来说,在课程中并没有深入探讨这一细节而我倾向于认为应该采用的方法下面说的是我自己觉得应该更新的方法在传统的神经网络中输入之间被认为是相互独立的例如最开始那个分类单词的例子\rm other、destination、time、departure中每个词都是独立处理的不会影响其他词的结果而在RNN中单词之间并不是完全独立而是基于句子层面进行处理因此在处理一句话时首先需要初始化记忆单元为0或者特定数值随后进行正向传播计算最终输出结果这个输出结果是一个向量与标签向量通过交叉熵损失函数进行比较得到该单词上的分类损失值随后进行反向传播过程与传统神经网络类似只不过增加了输入层和权重参数因此能够为每个权重参数计算出相应的梯度值同时记忆单元的内容也会随着正向传播过程被不断更新当输入第二个词时会重复相同的操作直至处理完所有词语从而获得多个梯度值和损失值这些值通常是通过损失函数求均值得到最终这句话的整体梯度和损失值接下来当输入第二句话时同样需要重新初始化记忆单元并重复上述步骤最终能够得到每句话的所有单词对应的梯度值和损失值将这些数值求均值得到总的损失和梯度进而完成权重参数的更新

Terrible Problem

通过上述内容的学习与实践,则可以获取训练你的 RNN 的方法。然而并非总是如此——通常情况下,
你想要的训练过程可能是下图中蓝线所示的情况。
但实际上这通常是绿线所示的情况,
并且这种情况并非因代码错误导致,
而是由模型固有的特性所决定。

那么为什么损失值曲线会出现如此不稳定的跳跃呢?让我们从损失值与权重参数之间的曲面关系来进行分析。通过分析图形可以看出,在RNN模型训练过程中存在两个主要问题:其一是在平坦区域可能导致梯度消失;其二是在陡峭区域可能导致梯度爆炸。具体而言,在平坦区域中如果损失函数呈现出平缓的变化趋势,则可能会导致模型难以有效优化;而在陡峭区域中则容易出现计算出过大的梯度从而导致更新后的参数偏离正常范围。为了应对这些问题曾经有人提出了一种解决方法即设定一个适当的阈值限制当某次迭代计算出的梯度超过该阈值时就将其限制在该阈值以内以此来防止出现不合理的大规模参数更新进而影响模型训练效果。

为了更好地理解梯度更新过程中的权值矛盾问题,请考虑一个仅包含一层隐藏单元、每个单元只有一个神经元的简单RNN模型。该模型中所有记忆单元的权重系数均为相同的值w(此处我们将其设为变量),其余参数默认设为单位权重系数(即数值上等于1)。假设输入序列的第一个元素为1(即x^t= [x_{}^t_{}= ¹, x_{i}^t_{i≠} } = ⁰]),其余均为零值(即x_i^t= ⁰),并持续共计有T= ¹⁰⁰₀个时间步。假设在第T=T时间步后的输出结果为y^{T} = w^{T-₁} (此处我们取T= ¹⁰⁰₀)。在这种情况下,在权值参数w=₁时(即初始状态下),最终预测结果y^{T}=₁可被视为理想状态。然而,在权值参数被设定略大于或小于₁的情况下(例如:当w被设定为略大于₁时如取w=₁.₀₁或者被设定在较小范围内如取w=₀.₉₉),预测结果将显著放大或缩小至接近零的状态(例如:当w被设定为略大于₁时如取w=₁.₀₁,则预测结果将显著放大至约2万2千左右;而当其被设定在较小范围内如取w=₀.₉₉,则预测结果将趋近于零)。这种现象表明,在当前学习率设置下可能面临两种极端情况:当权值参数处于较小范围时(例如:当前情况下若令权值参数从初始状态逐步减小到接近零的状态),此时其对应的梯度变化将趋于平缓甚至趋近于零状态;而如果令其发生较大的变化,则可能导致预测结果出现剧烈震荡甚至出现爆炸性增长的情况。基于此,在实际训练过程中需要综合考虑多个因素来调节学习率的变化幅度以实现期望的学习效果

Helpful Techniques

该技巧旨在设定梯度更新的最大值以防止梯度爆炸问题的发生

LSTM 的一种变体是 GRU(加aved recurrent unit),它减少了一个门控机制(gate),将输入门(Input Gate)和遗忘门(Forget Gate)的功能合并为一个统一的操作。其基本思想是:新的候选状态不去考虑过时的信息,默认新旧信息会相互替代;当输入门允许新值进入时,则会丢弃之前存储的信息;反之,则使用之前保存的状态参与后续计算。具体来说,在输入门开启的情况下(即允许新值进入系统),会舍弃原有的信息;而当输入门关闭时,则会将当前的状态传递给下一个运算环节作为输出来源

还有一个有趣的结果是,在Simple RNN架构中,默认情况下门单元通常采用Sigmoid激活函数以实现门控功能。然而,在某些特定场景下选择ReLU激活函数可能会导致性能下降。值得注意的是,在参数随机初始化的情况下这一现象较为明显:当采用单位矩阵作为初始值时,则可以通过ReLU激活函数获得更好的性能表现,并且这种表现甚至超越了LSTM架构的表现

Application of RNN

后续课程中介绍的主要内容是关于 RNN 的应用。其中一些应用采用了变形的 RNN 结构,并且还有一些其他模型的思想被结合进来,例如GAN和结构化SVM等。由于观看者所关注的知识点在主讲者讲解顺序中缺失了一些基础内容,导致理解起来较为吃力,仅能获得感性认识,每个具体实现的思想也较为简略,因此后面的笔记不做详细记录

为了解决因课程顺序难以接受的问题,请参考 2017 年版与 2020 年版的具体安排进行学习。李宏毅老师的课程每年都会对原有视频内容进行部分更新,并补充新增知识。值得注意的是许多公开发布的 2020 版课程实际上是基于过去教学视频重新排序整理而成因此回归最初的观看顺序能够显著提升接受度。此外北邮陈光老师的视频资源因其高质量而备受推荐(B站账号:爱可可-爱生活)。

全部评论 (0)

还没有任何评论哟~