循环神经网络:语言处理与序列预测
1. 核心任务与语言模型
在自然语言处理领域,翻译和文本生成是两个重要的任务。其他任务与这两个任务有很多相似之处。逻辑流程处理尤为困难,人机协作会带来很大帮助。
1.1 翻译任务
翻译至少需要待翻译的文本以及源语言和目标语言。了解一些上下文信息也有助于理解不同地区或不同时期的习语和其他语言特征。
1.2 文本生成任务
文本生成通常从一个种子或提示开始。算法以此为文本的起点,逐词构建文本。给定一个提示,算法预测下一个单词,将其添加到提示末尾,然后使用新的更长提示预测下一个单词,如此循环,可生成句子、文章或书籍。这种技术称为自回归,自回归系统称为自回归器。更广泛地说,用算法生成文本称为自然语言生成(NLG)。
1.3 语言模型
翻译和文本生成都使用语言模型的概念。语言模型是一种将单词序列作为输入,并判断该序列成为一个结构良好句子可能性的计算方式。需要注意的是,它不判断句子是否写得特别好,甚至不判断其是否有意义或真实。通常,训练好的神经网络本身就可以被视为一个语言模型。
2. 文本数字化
为了构建有助于翻译和文本生成的系统,需要先将文本转换为计算机能够处理的形式,通常是将其转换为数字。有两种常见的方法:
2.1 基于字符的方法
对文本中可能出现的所有符号进行编号。人类语言中最广泛的字符列表是 Unicode。最新版本的 Unicode 13.0.0 涵盖 154 种书面人类语言,识别出 143,859 个不同字符。可以为这些书写系统中的每个符号分配一个从 0 到约 144,000 的唯一编号。为了简单起见,在一些文本生成示例中,仅使用英语文本中最常见的 89 个字符。
2.2 基于单词的方法
对文本中可能出现的所有单词进行编号。统计世界上所有语言的单词数量是一项艰巨的任务。在实际应用中,通常以英语为例,但即使是英语,也没有确切的单词数量统计。大多数现代英语词典约有 300,000 个词条。可以为词典中的每个词条分配一个从 0 开始的唯一编号,这些单词及其对应的编号构成词汇表。在很多示例中,采用基于单词的方法。
通过这两种方法,可以创建任何句子的计算机友好型数字表示。将这些数字列表输入训练好的自回归网络,网络预测下一个单词的编号,将该单词添加到输入中,再继续预测下一个单词。为了查看对应的文本,可以将每个数字转换回其对应的单词。
3. 微调与下游网络
在自然语言处理中,微调与下游网络是优化模型性能的重要手段。
3.1 迁移学习与微调
通常先在通用数据库上训练系统,然后进行专门化处理,这个过程称为迁移学习。例如,将通用图像分类器改进为能够识别叶子形状并判断树木种类的分类器。在分类器中使用迁移学习时,通常会冻结现有网络,在分类部分末尾添加一些新层并进行训练,这样新层可以利用现有网络从每个图像中提取的信息。
在自然语言处理(NLP)中,从通用数据库学习的系统称为预训练系统。当需要学习新的专业语言,如法律、诗歌或工程领域的语言时,使用新数据对网络进行微调。与迁移学习不同,微调时通常会修改系统中的所有权重。
3.2 下游网络
如果不想重新训练系统,可以创建第二个模型,将语言系统的输出转换为更有用的结果,这与迁移学习的理念相近。此时语言模型被冻结,其输出被输入到新模型中,这个新模型称为下游网络,执行下游任务。一些语言模型旨在创建输入文本的丰富、密集摘要,以驱动各种下游任务。
微调与下游训练这两种方法在概念上有所区别,但在实际应用中,很多系统会将这两种技术结合使用。
4. 全连接预测
为了更好地理解如何处理数字序列,暂时抛开语言,专注于数字本身。构建一个小型网络来学习从序列中获取几个数字,并预测下一个数字。采用最简单的方式,构建一个只有两层的网络:第一层是一个仅包含 5 个神经元的全连接层,使用斜率为 0.1 的 leaky ReLU 激活函数;第二层是一个包含 1 个神经元的全连接层,不使用激活函数。
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
A([输入序列]):::startend --> B(5 个神经元全连接层):::process
B --> C{leaky ReLU 激活函数}:::process
C --> D(1 个神经元全连接层):::process
D --> E([输出预测值]):::startend
4.1 测试网络
使用由多个正弦波相加生成的合成数据集来测试这个小型网络。前 500 个样本用于训练。训练时,使用滑动窗口选择输入,每次取数据集中的前 5 个值,让网络预测第 6 个值;然后取第 2 到第 6 个值,预测第 7 个值,以此类推。从 500 个初始值中可以生成 495 个样本,对网络进行 50 个周期的训练。
训练完成后,再次使用训练数据进行预测,结果显示预测效果不错。接着使用曲线后面的 250 个测试点进行测试,虽然预测并不完美,但考虑到网络规模较小,效果还是相当不错的。
4.2 更现实的数据集
使用 1749 年至 2018 年每月记录的太阳黑子平均数量这一更现实的数据集进行测试。该数据集的峰值和谷值对应约 11 年的太阳周期。尽管小型回归器不能完全达到数据的极值,但能较好地跟踪数据的总体涨跌趋势。
4.3 文本数据测试
尝试使用查尔斯·狄更斯的小说《双城记》前六章的文本数据。为了便于处理,去除所有标点符号并将文本转换为小写。由于是基于单词进行处理,需要为使用的每个单词分配一个编号。从书中构建词汇表,将书中的第一个单词赋值为 0,依次为新出现的单词分配下一个可用编号。这部分小说共有 17,267 个单词,但词汇表中只有 3,458 个唯一单词,单词编号从 0 到 3,457。
将数据库分为训练集和测试集,为避免让网络预测未训练过的单词编号,从测试集中移除任何包含超过 3000 编号单词的序列。重复之前的实验,将连续 5 个单词编号的窗口输入到小型网络中,训练 50 个周期,但误差很快停止改善,在 8 个周期后提前停止训练。结果显示,预测结果与训练数据和测试数据都不匹配。
5. 网络失败原因分析
将预测的数字转换回单词后,得到的文本质量很差。网络失败的原因主要有以下几点:
5.1 网络能力不足
这个小型网络的处理能力远远不够,要生成可读文本,需要更多的神经元和更多的层。
5.2 无法捕捉文本结构
即使是更大的全连接网络,在处理文本时也会遇到困难,因为它们无法捕捉文本的结构,即语义。语言的结构与之前处理的曲线和太阳黑子数据有根本区别。例如,“Just yesterday, I saw a” 这个片段可以用任何名词来完成,而英语中的名词数量至少有几万,网络很难准确猜测出所需的名词。
尝试增大窗口大小,让网络有更多的前文信息,从而做出更合理的选择。将小型网络的第一层神经元增加到 20 个,每次输入 20 个元素并预测第 21 个元素。对于曲线数据,虽然训练数据的预测效果还可以,但测试结果明显变差。增大窗口意味着需要更大的网络,同时也需要更多的训练数据、更多的内存、更多的计算能力、更多的电力和更多的训练时间。
5.3 预测误差导致文本不可理解
即使是微小的预测误差也会导致生成的文本无法理解。例如,在文本中 “keep” 和 “flint” 被分配了连续的编号,但它们本身并无关联。网络预测的微小数值差异可能会导致完全不同的单词输出,从而产生无意义的文本。
5.4 无法跟踪单词位置
小型网络还有一个缺陷,即它无法跟踪输入中单词的位置。例如,对于句子 “Bob told John that he was hungry” 和 “John told Bob that he was hungry”,“he” 所指代的对象不同,这取决于单词的顺序。但全连接网络在处理时会丢失单词的隐式顺序,后续层无法判断 “he” 对应的是哪个单词。
为了解决这些问题,需要更复杂的网络结构,而不是仅仅依靠全连接层和用单个数字表示的单词。虽然卷积神经网络(CNN)在处理序列数据方面有一定的研究,但这些工具仍在发展中。接下来,将介绍专门用于处理序列的循环神经网络(RNN)。
6. 循环神经网络与状态概念
为了更好地处理语言,需要构建一种能够明确处理单词有序序列的网络,循环神经网络(RNN)就是这样一种网络。在构建 RNN 之前,先了解一个重要的概念——状态。
6.1 状态的定义
状态是对系统(如神经网络)在任何给定时间的描述。以预热烤箱为例,烤箱在这个过程中有三种独特的状态:关闭、预热和达到所需温度。状态还可以包含额外的信息,例如在烤箱预热过程中,可以将其当前状态(如预热)、当前温度和目标温度这三条信息包含在烤箱的状态中。因此,状态可以表示系统的当前状况,以及任何方便记忆的其他信息。
6.2 状态的示例
假设在一家冰淇淋店学习制作简单的软糖圣代。在这个场景中,你扮演系统的角色,脑海中构建的食谱就是你的状态。在没有得到任何指示之前,你的初始状态是 “一个空杯子”。当经理告诉你第一步是放入一些香草冰淇淋时,你将内部食谱(即状态)更新为 “一个装有三勺香草冰淇淋的杯子”,并实际放入三勺冰淇淋。
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
A([初始状态:空杯子]):::startend --> B(放入香草冰淇淋):::process
B --> C([状态更新:装有三勺香草冰淇淋的杯子]):::startend
C --> D(移除一勺):::process
D --> E([状态更新:装有两勺香草冰淇淋的杯子]):::startend
E --> F(添加糖浆):::process
F --> G([状态更新:Marty 最喜欢的]):::startend
G --> H(添加樱桃):::process
H --> I([最终状态:带樱桃的 Marty 最喜欢的]):::startend
通过这个例子可以看出,状态会随着操作的进行而不断更新,并且在整个过程中保留了重要的信息。在接下来的内容中,将基于状态的概念构建循环神经网络,以更好地处理语言序列。
7. 循环神经网络的结构与原理
7.1 基本结构
循环神经网络(RNN)的核心特点是能够处理序列数据,它通过引入状态来保留序列中的信息。一个简单的 RNN 单元可以接收当前输入和上一时刻的状态,然后产生当前时刻的状态和输出。其结构可以用以下公式表示:
[
h_t = \sigma(W_{hh}h_{t - 1}+W_{xh}x_t + b_h)
]
[
y_t = W_{hy}h_t + b_y
]
其中,$x_t$ 是当前时刻的输入,$h_{t - 1}$ 是上一时刻的状态,$h_t$ 是当前时刻的状态,$y_t$ 是当前时刻的输出,$W_{hh}$、$W_{xh}$、$W_{hy}$ 是权重矩阵,$b_h$、$b_y$ 是偏置向量,$\sigma$ 是激活函数,通常使用 tanh 或 ReLU。
7.2 工作原理
RNN 按时间步展开后,可以看作是一个多层的神经网络,每一层对应一个时间步。在每个时间步,RNN 单元接收输入并结合上一时刻的状态更新当前状态,然后产生输出。这种结构使得 RNN 能够记住序列中的历史信息,从而更好地处理具有上下文依赖的任务,如语言处理。
7.3 与全连接网络的对比
与全连接网络相比,RNN 能够处理变长的序列数据,并且可以利用序列中的上下文信息。全连接网络在处理序列数据时,会将序列中的每个元素独立处理,忽略了元素之间的顺序和依赖关系。而 RNN 通过状态的传递,能够捕捉序列中的长期依赖关系。
8. 循环神经网络的应用
8.1 语言建模
RNN 在语言建模中有着广泛的应用。语言建模的目标是预测给定单词序列的下一个单词的概率。RNN 可以根据之前的单词序列生成状态,然后根据状态预测下一个单词。通过训练 RNN 在大规模的文本数据上学习语言的统计规律,从而生成自然流畅的文本。
8.2 机器翻译
在机器翻译中,RNN 可以用于将源语言的句子转换为目标语言的句子。通常使用编码器 - 解码器结构,编码器将源语言句子编码为一个固定长度的状态向量,解码器根据这个状态向量生成目标语言句子。RNN 能够处理源语言句子中的上下文信息,从而提高翻译的准确性。
8.3 语音识别
在语音识别中,RNN 可以用于将语音信号转换为文本。语音信号是一个时间序列,RNN 可以处理语音信号中的时序信息,从而更好地识别语音中的单词。通过训练 RNN 在大量的语音数据上学习语音的特征和语言的规律,提高语音识别的准确率。
9. 循环神经网络的问题与改进
9.1 梯度消失与梯度爆炸
RNN 在训练过程中容易出现梯度消失或梯度爆炸的问题。当序列长度较长时,梯度在反向传播过程中会不断乘以权重矩阵,导致梯度变得非常小或非常大。梯度消失会使得 RNN 难以学习到序列中的长期依赖关系,而梯度爆炸会导致训练不稳定。
为了解决梯度消失和梯度爆炸的问题,可以采用以下方法:
-
梯度裁剪
:在反向传播过程中,对梯度进行裁剪,限制梯度的最大值,防止梯度爆炸。
-
使用更稳定的激活函数
:如 ReLU 等激活函数可以缓解梯度消失的问题。
-
改进网络结构
:如长短期记忆网络(LSTM)和门控循环单元(GRU)等改进的 RNN 结构可以更好地处理长期依赖关系。
9.2 长序列处理困难
RNN 在处理长序列时,由于梯度消失和梯度爆炸的问题,难以学习到序列中的长期依赖关系。为了解决这个问题,可以采用以下方法:
-
分层 RNN
:将序列分成多个层次进行处理,减少每个层次的序列长度。
-
注意力机制
:注意力机制可以让 RNN 在处理序列时,选择性地关注序列中的不同部分,从而更好地处理长序列。
10. 长短期记忆网络(LSTM)和门控循环单元(GRU)
10.1 长短期记忆网络(LSTM)
LSTM 是一种特殊的 RNN 结构,它通过引入门控机制来解决梯度消失和梯度爆炸的问题,能够更好地处理长期依赖关系。LSTM 单元包含输入门、遗忘门和输出门,这些门控机制可以控制信息的流入、流出和保留。
LSTM 的核心公式如下:
[
i_t = \sigma(W_{xi}x_t + W_{hi}h_{t - 1}+b_i)
]
[
f_t = \sigma(W_{xf}x_t + W_{hf}h_{t - 1}+b_f)
]
[
o_t = \sigma(W_{xo}x_t + W_{ho}h_{t - 1}+b_o)
]
[
\tilde{C}
t = \tanh(W
{xc}x_t + W_{hc}h_{t - 1}+b_c)
]
[
C_t = f_t \odot C_{t - 1}+i_t \odot \tilde{C}_t
]
[
h_t = o_t \odot \tanh(C_t)
]
其中,$i_t$ 是输入门,$f_t$ 是遗忘门,$o_t$ 是输出门,$\tilde{C}_t$ 是候选细胞状态,$C_t$ 是细胞状态,$\odot$ 表示逐元素相乘。
10.2 门控循环单元(GRU)
GRU 是另一种改进的 RNN 结构,它在 LSTM 的基础上进行了简化,只包含更新门和重置门。GRU 的计算复杂度较低,但在处理长期依赖关系方面也有较好的表现。
GRU 的核心公式如下:
[
z_t = \sigma(W_{xz}x_t + W_{hz}h_{t - 1}+b_z)
]
[
r_t = \sigma(W_{xr}x_t + W_{hr}h_{t - 1}+b_r)
]
[
\tilde{h}
t = \tanh(W
{xh}x_t + r_t \odot W_{hh}h_{t - 1}+b_h)
]
[
h_t = (1 - z_t) \odot h_{t - 1}+z_t \odot \tilde{h}_t
]
其中,$z_t$ 是更新门,$r_t$ 是重置门。
10.3 LSTM 和 GRU 的对比
LSTM 和 GRU 都能有效解决 RNN 的梯度消失和梯度爆炸问题,提高对长期依赖关系的处理能力。LSTM 结构相对复杂,计算量较大,但在处理复杂任务时表现更好;GRU 结构相对简单,计算效率高,在一些任务中可以作为 LSTM 的替代方案。
11. 总结
循环神经网络(RNN)及其改进结构如 LSTM 和 GRU 在自然语言处理等领域有着重要的应用。RNN 通过引入状态的概念,能够处理变长的序列数据并捕捉序列中的上下文信息。然而,RNN 也存在梯度消失、梯度爆炸和长序列处理困难等问题。LSTM 和 GRU 通过门控机制解决了这些问题,提高了网络的性能和稳定性。
在实际应用中,需要根据具体的任务和数据特点选择合适的网络结构。对于简单的序列任务,RNN 可能已经足够;对于复杂的任务,如长文本处理和机器翻译,LSTM 或 GRU 可能是更好的选择。同时,还可以结合其他技术,如注意力机制和分层结构,进一步提高网络的性能。
通过不断的研究和改进,循环神经网络在自然语言处理、语音识别、图像生成等领域取得了显著的成果,为人工智能的发展做出了重要贡献。未来,随着技术的不断进步,循环神经网络有望在更多的领域得到应用和发展。
以下是 LSTM 和 GRU 的对比表格:
| 网络结构 | 优点 | 缺点 | 适用场景 |
| ---- | ---- | ---- | ---- |
| LSTM | 能有效处理长期依赖关系,结构灵活 | 计算复杂度高,训练时间长 | 复杂的序列任务,如机器翻译、长文本生成 |
| GRU | 计算效率高,参数少 | 表达能力相对较弱 | 对计算资源有限的场景,或对实时性要求较高的任务 |
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
A([输入序列]):::startend --> B(RNN 单元):::process
B --> C(状态更新):::process
C --> D([输出序列]):::startend
E([输入序列]):::startend --> F(LSTM 单元):::process
F --> G(门控机制):::process
G --> H([输出序列]):::startend
I([输入序列]):::startend --> J(GRU 单元):::process
J --> K(简化门控机制):::process
K --> L([输出序列]):::startend
这个流程图展示了 RNN、LSTM 和 GRU 处理输入序列的基本过程。RNN 通过状态更新处理序列,LSTM 和 GRU 则通过各自的门控机制处理序列。
超级会员免费看
14万+

被折叠的 条评论
为什么被折叠?



