循环神经网络(RNN, Recurrent Neural Network)是一类用于处理序列数据的神经网络,它与传统的前馈神经网络不同,具有“记忆”能力。
RNN的特点是神经元之间的连接不仅仅是前向的,还包括了“循环”连接,这样可以把之前的输出作为当前的输入,从而捕捉到时间序列中不同时间点之间的依赖关系。
主要特点:
序列数据处理:RNN擅长处理序列数据(例如文本、时间序列、语音等),可以在处理每个时间步时考虑之前的状态。
权重共享:RNN在不同时间步之间共享相同的权重参数,这使得它能够在不同的时间点上进行相似的计算。
记忆能力:通过循环结构,RNN可以保留以前输入的信息,帮助模型理解时间依赖性。
常见序列数据处理任务:语音识别,乐谱生成,情绪分类,DNA序列分析,机器翻译,视频动作识别,名称实体识别
下面以名称实体识别为例,介绍一个多对多且输出序列长度等于输入序列长度的RNN架构工作原理
名称实体识别
任务:识别文本中的实体,如人名、地名、组织机构名等
实现原理:
- 准备一个字典,将单词映射为数字表示
- 将输入句子中的每一个单词利用one-hot编码表示, 此时一个单词就是一个序列
- 将所有序列输入到RNN中,RNN会对每个序列进行处理,输出结果
- 每一个结果对应一个单词是否是名称实体
RNN 符号表示
RNN 计算过程
如果用简单卷积神经网络主要存在两个问题
- 并不是所有输入或者所有输出的序列长度都不一致,如果都填充到一个最大值,会造成表示不友好的问题
- 不能跨文本位置共享学习到的特征
- 输入层巨大(单词数*10000),会导致第一层的权重矩阵非常大
RNN 可以解决上述问题
- 不同的问题中输入或者输出的序列长度可能不一致,RNN可以处理任意长度的序列
- 学习到的特征值可以应用到不同位置的名称实体识别中,RNN可以学习到不同位置的特征值
循环过程
如果从左到右读取单词,处理完第一个单词后,在处理第二个单词时,不仅需要将第二个单词作为输入,
也需要将第一个单词的输出作为输入,以此类推,直到处理完最后一个单词,拿到所有单词的输出后
向前传播
向后传播
具体实现
符号表示
关于输入的维度描述
rnn cell vs rnn_cell_forward
rnn cell 是一个函数,输入是x^t和a^(t-1),输出是a^t
rnn cell forward 是一个函数,输入是a^t,输出是和y^t
下图是一个单个时间步的计算过程, 实线是rcc cell,虚线是rnn cell forward
这里是最基础的RNN单元的实现,后面会介绍降低梯度消失的RGU单元和LSTM单元
recurrent neural network
循环神经网络的实现就是基于时间步数循环调用rnn cell 函数,rnn cell 里面的parameters参数对于每一个时间步都相同
Situations when this RNN will perform better:
This will work well enough for some applications, but it suffers from the vanishing gradient problems.
The RNN works best when each output 𝑦̂ ⟨𝑡⟩ can be estimated using “local” context.
“Local” context refers to information that is close to the prediction’s time step 𝑡 .
More formally, local context refers to inputs 𝑥⟨𝑡′⟩ and predictions 𝑦̂ ⟨𝑡⟩ where 𝑡′ is close to 𝑡 .
不同的RNN架构
Music generation –> 1 to many
Sentiment classification –> many to 1
DNA sequence analysis –> many to many
Machine translation –> many to many Xt ===? Yt
Name entity recognition –> many to many Xt === Yt
Video activity recognition –> many to many ????
Speech recognition –> 1 to many ???
如果任务是从输入的时间序列映射到另一个时间序列(如语音转文本、逐帧动作识别),则属于多对多(Many-to-Many)。
如果任务是从整个序列映射到一个单一类别(如视频整体分类、语音情感识别),则属于多对一(Many-to-One)。
语言模型(language model)
本质上是在计算输出结果的概率是多大
比如输出一个句子,The apple and pear salad
那么这个概率代表的就是P(The)P(apple|The)P(and|The apple)…P(salad|The apple and pear salad)
其中P(and|The apple) 表示 第三个词在前两个词是 the apple 的情况下 是 and 的概率
因此评价一个语言模型的好坏标准就是对一个正常准确句子计算得到的概率高低,对正确句子计算的概率越高,说明模型准确度越高
训练过程
针对语言模型的训练过程,就一个训练样本来说
第一步就是进行分词,也就是token处理
这个过程就拿到一个训练样本的多个时间step, 一个词是一个x^t,
对于句尾符号一般用
对于词典中没有出现的词,则一般用
比如是照常输出,还是跳过重新采样
第二步开始训练
time step 训练的第一轮输入都是0向量,输出是字典里任意词语的的概率,即每个词都等概率
在后面的每一轮中,另x^t = y^(t-1),那么y^~^t 计算的就是在前一轮基础上计算下个词y^t出现的概率,最终直到出现
采样
就是根据y^~^t取出对应的词典里的词作为下一轮的输入,代替y^t
类似于训练过程,只不过在第二轮开始的输入,变成np.random.choice(y^~t), 根据计算过程的概率取词,接着预测下一个词
结束规则可以自行定义,如果词典中有
这也相当于根据前面的词预测下一个词的过程
要尽量避免如果出现
字母级语言模型
类似于上面word 级别的模型,只不过分词细化到每个字母,每个字母是一个时间序,字典就是26个英文字母加相关符号
优点是不会出现unk,
但是缺点是最终会得到太多太长的序列,捕捉句子中的依赖关系时(句子较前部分影响较后部分)不如word language model 能捕捉长范围范围内关系
另外训练计算成本高,
除非用于处理大量未知文本,未知词汇的应用,或者专有词汇的领域
梯度消失&爆炸
如果出现梯度爆炸常见的处理办法就是进行梯度修剪(gradient clipping)
即如果梯度值超过某个阈值,则对其进行缩放,始终保证其在阈值范围内,详见上面【练习】
对于梯度消失的影响,类似于深层网络,最终给到输出的权重y很难影响到靠前层的权重
对于RNN来说,梯度消失意味着后面层的输出误差很难影响前面层的计算,其实就是无法实现一个句子中的长范围影响
下面是两种处理梯度消失的解决办法,主要通过引入记忆细胞进行长范围特征传递避免梯度消失
GRU 单元
Gated Recurrent Unit (GRU) 门控循环单元
通过引入记忆细胞,存储前层数据特征,然后利用【更新门】逻辑决定是否将特征传递给后面数据实现长范围影响
更新门是个sigmod 函数,即使无限接近0,在更新候选值时可以始终保持记忆细胞的值,从而实现深层传递,实现长范围影响,缓解梯度消失的问题
Γu:控制当前状态与前一时刻状态的融合程度。
Γr:决定前一时刻的记忆细胞信息保留多少在当前时刻的记忆细胞候选值中
通过门控机制缓解梯度问题,但比 LSTM 稍弱
LSTM (long short term memory) unit
LSTM 循环单元 出现的比GRU 单元要早,相比GRU 单元更复杂
多了【遗忘门】和【输出门】
【更新门】现在决定当前输入信息有多少被存入细胞状态
【遗忘门】决定遗忘多少过去的信息
【输出门】决定细胞状态中的信息有多少影响当前的隐藏状态
激活值不再等于记忆细胞,而是由【输出门】和【记忆细胞】共同决定
LSTM 通过这三个门的组合,实现对信息的精确控制,使其能够有效处理长序列依赖问题
通过细胞状态缓解梯度消失问题,更适用于长序列
LSTM 单元的具体实现
一个LSTM单元的具体实现
各个状态和门的计算和解释
GRU 单元 VS LSTM 单元
1. 结构对比
对比项 | GRU | LSTM |
---|---|---|
门控机制 | 2 个门:更新门(Update Gate)、重置门(Reset Gate) | 3 个门:输入门(Input Gate)、遗忘门(Forget Gate)、输出门(Output Gate) |
记忆单元 | 直接更新隐藏状态 | 额外维护一个“细胞状态” |
计算复杂度 | 相对较低 | 计算量较大 |
参数数量 | 较少 | 较多 |
梯度消失/爆炸 | 通过门控机制缓解梯度问题,但比 LSTM 稍弱 | 通过细胞状态缓解梯度消失问题,更适用于长序列 |
2. 对比分析
对比项 | GRU | LSTM |
---|---|---|
训练时间 | 更快(参数较少,计算量低) | 相对较慢(参数多,计算复杂) |
表现效果 | 适用于中等长度依赖 | 更擅长长序列依赖问题 |
内存占用 | 低(因参数少) | 高(因参数多) |
适用场景 | 机器翻译、语音识别、文本生成 | 时间序列预测、长文本处理 |
3.应用场景
GRU 适用于:
计算资源有限的设备(如移动端)
需要较快训练和推理的任务
语音识别、机器翻译等
LSTM 适用于:
处理长序列依赖问题
需要更精细控制记忆存储的任务
生成式任务(如文本生成、音乐生成)
双向RNN
先正向计算每个时间步的激活值,然后再反向(从最后一个时间步开始)计算一遍一遍激活值
每个时间步的最终计算值,由正反两次计算的激活值共同决定
主要用于解决,既要考虑前文又要考虑后文的模型判断
优点是可以预测句子中任意位置信息
缺点是需要完整的数据序列,才能预测任意位置,比如语音识别,需要等人说完完整的句子后才开始识别
深度循环网络 deep RNN
使用基本RNN单元,GRU 单元,LSTM 单元构建的多层循环神经网络
常见的是三层,每层参数相同,
也可能有更深的架构但是在循环层上不在有联系
甚至有双向深度循环网络,但训练成本高,需要更多计算资源和时间