最近大创和项目需要把之前学过的知识点总结一下
RNN
循环神经网络和LSTM参考July哥的这篇博客,写的非常通俗易懂
RNN和LSTM
首先看单层神经网络
f为激活函数
但是我们做文本一般用到的是序列数据
x1可以看做是第一个单词,x2可以看做是第二个单词,依次类推。
我们将RNN展开后的结构
得到输出值的方法就是直接通过h进行计算:
这就是最经典的RNN结构,是x1, x2, …xn,输出为y1, y2, …yn,也就是说,输入和输出序列必须要是等长的。
循环神经网络其实可以看成是链式的(注:输出之前由y表示,从此处起,改为隐层输出h表示):
RNN的局限(引入LSTM的优势):
长期依赖(Long-TermDependencies)问题:在这个间隔不断增大时,RNN会丧失学习到连接如此远的信息的能力,从两个方面考虑:
- 梯度消失
获得小梯度更新的层会停止学习—— 那些通常是较早的层。 由于这些层不学习,RNN 可以忘记它在较长序列中看到的内容,因此具有短时记忆。 - 梯度爆炸
计算的难度越来越复杂导致。
LSTM
LSTM通过刻意的设计来避免长期依赖问题。记住长期的信息在实践中是LSTM的默认行为,而非需要付出很大代价才能获得的能力!
所有RNN都具有一种重复神经网络模块的链式的形式。在标准的RNN中,这个重复的模块只有一个非常简单的结构,例如一个tanh层(激活函数 Tanh 作用在于帮助调节流经网络的值,使得数值始终限制在 -1 和 1 之间)。
LSTM同样是这样的结构,但是重复的模块拥有一个不同的结构。具体来说,RNN是重复单一的神经网络层,LSTM中的重复模块则包含四个交互的层,三个Sigmoid 和一个tanh层,并以一种非常特殊的方式进行交互。
且RNN权值共享而LSTM权值不共享
上图中,σ表示的Sigmoid 激活函数与 tanh 函数类似,不同之处在于 sigmoid 是把值压缩到0~1 之间而不是 -1~1 之间。这样的设置有助于更新或忘记信息:
- 因为任何数乘以 0 都得 0,这部分信息就会剔除掉;
- 同样的,任何数乘以 1 都得到它本身,这部分信息就会完美地保存下来。
LSTM由这次的输入、上一次的输出、当前状态决定下一次的状态和输出
状态C经过两次变化,第一次为遗忘第二次为更新
LSTM的三个门
-
遗忘门
这部分通过上一次的输出和输入决定哪些维度需要被遗忘(sigmoid输出为0的维度被遗忘,为1被保留),然后与上一次的状态相乘就完成了遗忘的操作 -
输入门
输入门有两个部分,sigmoid部分确定哪些维度被更新,tanh部分用来计算每个维度如果被更新则应该变化的量,最后两者相乘为每个维度被更新的值 -
输出门
同样分为两部分,sigmoid部分确定输出的维度,tanh决定每个维度如果输出应该改输出什么值
两者相乘记位最终的输出
LSTM的变型:
peephole连接
每次sigmoid操作将当前状态考虑进来
coupled
普通的LSTM要遗忘的维度和要更新的维度没什么确定的关系,而coupled将二者统一,被遗忘的维度就是要更新的维度
GRU
与LSTM的不同:
- 状态和输出统一
- 经过一次遗忘和一次更新,遗忘和更新的维度相统一
- 确认更新值之前先进行一次事先存一份原始的(第一个sigmoid),最终在 h ~ \tilde{h} h~那做一个tanh变化
Encoder-Decoder
参考博客
Encoder-Decoder 模型主要是 NLP 领域里的概念。它并不特值某种具体的算法,而是一类算法的统称。Encoder-Decoder 算是一个通用的框架,在这个框架下可以使用不同的算法来解决不同的任务。
Encoder 又称作编码器。它的作用就是「将现实问题转化为数学问题」
Decoder 又称作解码器,他的作用是「求解数学问题,并转化为现实世界的解决方案」
关于 Encoder-Decoder,有2 点需要说明:
不论输入和输出的长度是什么,中间的「向量 c」 长度都是固定的(这也是它的缺陷,下文会详细说明)
根据不同的任务可以选择不同的编码器和解码器(可以是一个 RNN ,但通常是其变种 LSTM 或者 GRU )
seq2seq
Seq2Seq(是 Sequence-to-sequence 的缩写),就如字面意思,输入一个序列,输出另一个序列。这种结构最重要的地方在于输入序列和输出序列的长度是可变的。
「Seq2Seq」和「Encoder-Decoder」的关系
Seq2Seq(强调目的)不特指具体方法,满足「输入序列、输出序列」的目的,都可以统称为 Seq2Seq 模型。
而 Seq2Seq 使用的具体方法基本都属于Encoder-Decoder 模型(强调方法)的范畴。
总结一下的话:
Seq2Seq 属于 Encoder-Decoder 的大范畴
Seq2Seq 更强调目的,Encoder-Decoder 更强调方法
Encoder-Decoder 的缺陷:当输入信息太长时,会丢失掉一些信息,因此诞生了Attention机制
Attention
参考这篇博客
Attention 的3大优点
- 参数少
- 速度快
- 效果好
encoder-decoder中的attention
encoder是双向RNN(包含前后文的信息)
decoder产生输出序列时每次都用当前状态
s
t
−
1
s_{t-1}
st−1利用attention在原文X中得到权重a形成新的向量,即每次产生新的单词都要从原文中提取相关信息形成新的句向量,用于下一个单词的生成
Attention 并不一定要在 Encoder-Decoder 框架下使用的,他是可以脱离 Encoder-Decoder 框架的
attention原理图:
Attention 原理的3步分解:
第一步: query 和 key 进行相似度计算,得到权值
第二步:将权值进行归一化,得到直接可用的权重
第三步:将权重和 value 进行加权求和
其实整个attention可以理解为求加权和的过程
Attention 机制的变种
- 硬注意力机制
注意力机制可分为软和硬两类:
软性注意力(Soft Attention)机制是指在选择信息的时候,不是从N个信息中只选择1个,而是计算N个输入信息的加权平均,再输入到神经网络中计算。
相对的,硬性注意力(Hard Attention)就是指选择输入序列某一个位置上的信息,比如随机选择一个信息或者选择概率最高的信息。但一般还是用软性注意力机制来处理神经网络的问题。
注意,选取概率最高这一步骤通常是不可微的,因此,硬注意力更难训练。可以借助如强化学习的手段去学习。 - 多头注意力
多头注意力(multi-head attention)是利用多个查询 Q = [q1, · · · , qM],来平行地计算从输入信息中选取多个信息。每个注意力关注输入信息的不同部分,然后再进行拼接:
- 自注意力模型(self-Attention model)
给出信息输入:用 X = [x1, · · · , xN ]表示 N 个输入信息;通过线性变换得到为查询向量序列,键向量序列和值向量序列:
上面的公式可以看出,self-Attention 中的 Q 是对自身(self)输入的变换,而在传统的 Attention 中,Q 来自于外部。
注意力计算公式为:
自注意力模型(self-Attention model)中,通常使用缩放点积来作为注意力打分函数,输出向量序列可以写为:
Transformer
其实transfomer就是一个特殊的seq2seq模型
encoder部分(N=6 层,每层包括 2 个 sub-layers):
sub-layer-1:multi-head self-attention mechanism,用来进行 self-attention。
sub-layer-2:Position-wise Feed-forward Networks,简单的全连接网络,对每个 position 的向量分别进行相同的操作,包括两个线性变换和一个 ReLU 激活输出(输入输出层的维度都为 512,中间层为 2048):
每个 sub-layer 都使用了残差网络:
Decoder部分(N=6 层,每层包括 3 个 sub-layers):
sub-layer-1:Masked multi-head self-attention mechanism,用来进行 self-attention,与 Encoder 不同:由于是序列生成过程,所以在时刻 i 的时候,大于 i 的时刻都没有结果,只有小于 i 的时刻有结果,因此需要做 Mask。
sub-layer-2:Position-wise Feed-forward Networks,同 Encoder。
sub-layer-3:Encoder-Decoder attention 计算。
Encoder-Decoder attention 与 self-attention mechanism 有哪些不同?
它们都是用了 multi-head 计算,不过 Encoder-Decoder attention 采用传统的 attention 机制,其中的 Query 是 self-attention mechanism 已经计算出的上一时间 i 处的编码值,Key 和 Value 都是 Encoder 的输出。
multi-head self-attention mechanism 具体的计算过程:
因为分head计算后进行拼接,所以维度的数量必须整除head的数量
ELMO
参考了李宏毅老师的教程
视频
这就是ELMO的架构
每一层都是一个双向RNN结构,并产生隐藏层,一个隐藏层就是一个embedding,最后所有层的embedding加权得到最终的embedding。
权重由下游任务习得
Bert
bert是一个与训练模型,可以产生embedding,内部结构为transformer的encoder部分
两种训练方式:
第一种是用[MASK]随机取代一些单词并进行预测(相当于完形填空)
第二种是预测两个句子是否为上下文
两个句子中用[SEP]间隔
[CLS]作为输入输出对应的分类向量,然后借一个分类器进行分类
bert的下游任务
-
句子分类
-
句子中每个单词进性分类
-
句子间关系
-
给一个问题,根基问题再文章中找答案的位置
其实是学习两个向量做两次点乘,起点一次,终点一次
bert是预训练模型,再做下游任务时也会进行训练
GPT
其实就是根据利用attention进行文本生成
经过多层,模型比较巨大