目录
自然语言处理1(分词)
自然语言处理2(神经网络)
自然语言处理3(词向量)
自然语言处理4(循环神经网络)
自然语言处理5(seq2seq)
自然语言处理6(transformer)
自然语言处理7(从EMLo到Bert)
知乎:https://zhuanlan.zhihu.com/p/109054674
1、序列正向匹配与反向匹配:
正向最大匹配思想MM
1.从左向右取待切分汉语句的m个字符作为匹配字段,m为大机器词典中最长词条个数。
2. 查找大机器词典并进行匹配。若匹配成功,则将这个匹配字段作为一个词切分出来。
若匹配不成功,则将这个匹配字段的最后一个字去掉,剩下的字符串作为新的匹配字段,进行再次匹配,重复以上过程,直到切分出所有词为止。
逆向最大匹配算法RMM
该算法是正向最大匹配的逆向思维,匹配不成功,将匹配字段的最前一个字去掉,实验表明,逆向最大匹配算法要优于正向最大匹配算法。
2、n-gram:
N-gram的第一个特点是某个词的出现依赖于其他若干个词,第二个特点是我们获得的信息越多,预测越准确。正式来说,N-gram模型是一种语言模型(Language Model,LM),语言模型是一个基于概率的判别模型,它的输入是一句话(单词的顺序序列),输出是这句话的概率,即这些单词的联合概率(joint probability)。
N-gram本身也指一个由N个单词组成的集合,各单词具有先后顺序,且不要求单词之间互不相同。常用的有 Bi-gram (N=2) 和 Tri-gram (N=3),一般已经够用了。例如在上面这句话里,可以分解的 Bi-gram 和 Tri-gram :
Bi-gram : {I, love}, {love, deep}, {love, deep}, {deep, learning} Tri-gram : {I, love, deep}, {love, deep, learning}
假设一个字符串s由m个词组成,因此我们需要计算出P(w1,w2,⋯,wm)的概率,根据概率论中的链式法则得到如下:
直接计算这个概率的难度有点大,因此引入马尔科夫假设(Markov Assumption):一个词的出现仅与它之前的若干个词有关,即
其中i为某个词的位置,n为定义的相关的前几个词,因此得到如下:
n=2时,即二元模型(Bi-gram):
当n=3时,即三元模型(Tri-gram):
N可以取很高,然而现实中一般 bi-gram 和 tri-gram 就够用了;而且N取得太大,会导致参数空间过大和数据稀疏严重等问题,因为词同时出现的情况可能没有。
如何计算其中的每一项条件概率呢?答案是极大似然估计(Maximum Likelihood Estimation,MLE),简单点就是计算频率:
举例:
3、BEMS标签、转移概率:
BEMS标签:
举例:
序列标注,就是将输入句子和分词结果当作两个序列,句子为观测序列,分词结果为状态序列,当完成状态序列的标注,也就得到了分词结果。
以“去北京大学玩”为例,我们知道“去北京大学玩”的分词结果是“去 / 北京大学 / 玩”。对于分词状态,由于jieba分词中使用的是4-tag,因此我们以4-tag进行计算。4-tag,也就是每个字处在词语中的4种可能状态,B、M、E、S,分别表示Begin(这个字处于词的开始位置)、Middle(这个字处于词的中间位置)、End(这个字处于词的结束位置)、Single(这个字是单字成词)。具体如下图所示,“去”和“玩”都是单字成词,因此状态就是S,“北京大学”是多字组合成的词,因此“北”、“京”、“大”、“学”分别位于“北京大学”中的B、M、M、E。
转移概率:
*HMM模型中的五元组表示:*
1.观测序列;
2.隐藏状态序列;
3.状态初始概率;
4.状态转移概率;
5.状态发射概率;
jieba中的状态转移概率,其实就是一个嵌套的词典,数值是概率值求对数后的值,如下所示,
P={'B': {'E': -0.510825623765990, 'M': -0.916290731874155},
'E': {'B': -0.5897149736854513, 'S': -0.8085250474669937},
'M': {'E': -0.33344856811948514, 'M': -1.2603623820268226},
'S': {'B': -0.7211965654669841, 'S': -0.6658631448798212}}
P['B']['E']代表的含义就是从状态B转移到状态E的概率,由P['B']['E'] = -0.5897149736854513,表示当前状态是B,下一个状态是E的概率对数是-0.5897149736854513,对应的概率值是0.6,相应的,当前状态是B,下一个状态是M的概率是0.4,说明当我们处于一个词的开头时,下一个字是结尾的概率要远高于下一个字是中间字的概率,符合我们的直觉,因为二个字的词比多个字的词更常见。
4、维特比算法(Verterbi):
Viterbi算法实际上是用动态规划求解HMM模型预测问题,即用动态规划求概率路径最大(最优路径)。这时候,一条路径对应着一个状态序列。
viterbi算法其实就是多步骤每步多选择模型的最优选择问题,其在每一步的所有选择都保存了前续所有步骤到当前步骤当前选择的最小总代价(或者最大价值)以及当前代价的情况下前继步骤的选择。依次计算完所有步骤后,通过回溯的方法找到最优选择路径。
viterbi算法的大致流程:
维特比算法的时间复杂度为,其中T为观测序列长度,N为隐藏状态数目。
知乎:https://zhuanlan.zhihu.com/p/113313445
关键:感知机、阶跃函数、激活函数、反向传播
这个简单的模型完整的用数学方式表达了神经元信号传递的方式——整合多个信号输入并转化为一个信号输出给其他神经元。同时神经生物学认为一个神经元细胞要么处于激活状态,要么是抑制状态,为了模拟这一机制,按照这个机理设计了二值化激活过程,也就是说超过某一个阈值就取值1,代表激活,低于某个阈值就取值0,代表抑制。这里的轴突就是0-1二值化激活,也是著名的阶跃函数(step function)。
大脑的工作是如果一个神经元持续激活另一个神经元,前者的轴突将会生长出突触小体(如果已有,则会继续长大)和后者的胞体相连接。也即有些神经元之间的连接更紧密,而另外一些之间则相对较弱,因此,不同的输入需要区别对待。(增加输入的权重)
受这个对于人脑学习方式的认知的启发,1956年弗兰克·罗森布拉特进一步改善了人工神经元设计,增加了类似于人脑的学习机制,这个模型叫做感知器(Perceptron)。
- 输入向量(input),即为用来训练感知器的原始数据
- 阶跃函数(step function),可以通过生物上的神经元阈值来理解,当输入向量和权重相乘之后,如果结果大于阈值(比如0),则神经元激活(返回1),反之则神经元未激活(返回0)
- 权重(weight),感知器通过数据训练,学习到的权向量通过将它和输入向量点乘,把乘积带入阶梯函数后我们可以得到我们期待的结果
在神经网络的发展历史中,感知器不能解决非线性问题,譬如像简单的异或的问题是它面临的第一项严峻的考验。解决:使用多层感知机解决问题,这就是神经网络。
单层感知机不能解决的问题,通过多个单层连接在一起就可以解决了。我们把连接在一起的多层的系统称作神经网络,单个感知机称为是神经元;神经元和感知器本质上是一样的,只不过我们说感知器的时候,它的激活函数是阶跃函数;而当我们说神经元时,激活函数往往选择为sigmoid函数或tanh函数,同时,在使用了sigmoid函数之后,一般使用交叉熵作为损失函数。
sigmoid函数:
tanh函数:
Sigmoid 和 tanh 的异同:
sigmoid:
1、作为激活函数,sigmoid函数存在梯度弥散的问题,即当x的取值特别大或者特别小的时候,其梯度几乎为零,这会导致参数的值无法更新。即所说的梯度消失。
2、作为激活函数,sigmoid的不是中心对称的,且总是输出正数,这会导致在做非线性变换时,其只能“同意(正)”上一层的结果,这也会导致随着深度的增加,结点的取值会“爆炸”,即所说的梯度爆炸。因为随着层数增加,样本的分布会从0-1高斯分布逐渐偏移,偏移至sigmoid的饱和区域,导致反向传播很难进行,所以其收敛较慢。
3、输出总是正数也会导致其优化路径出现“zigzag”现象,即所有权值的优化方向总是相同的(同时增大或减小)。
tanh:
1、作为激活函数,其同样存在梯度弥散问题。
2、tanh函数相较于sigmoid函数的优点在于其是中心对称的,均值为0的分布,其能将一个0-1高斯分布依然映射到0附近的分布,保持零均值的特性,而且由于其有正有负,所以他可以对来自上一层的结果 “支持”(正)、“反对”(负)、“弃权”(0)。所以其收敛速度较sigmoid快一些。
问:哪些方法有助于解决深度网络的梯度消失问题?为什么?
答:控制网络深度,预训练+微调,使用ReLU激活函数
ReLU函数(Rectified Linear Units)其实就是一个取最大值函数。
sigmoid,tanh 会出现梯度消失问题,ReLU 的导数就不存在这样的问题。虽然它形式非常简单,但是它比较好地解决了梯度消失的问题,而且计算速度非常快,只需要判断输入是否大于0,收敛速度远快于sigmoid和tanh。它是比较常用的激活函数。
relu对比于sigmoid:
relu的缺点:
实际应用中,特别是深层网络在训练时,tanh和sigmoid会在端值趋于饱和,造成训练速度减慢,故深层网络的激活函数默认大多采用relu函数,浅层网络可以采用sigmoid和tanh函数。
softmax:
softmax或称归一化指数函数,将输出向量中的每一个值【对应于多个类别或待挑选的值】,映射到(0,1)区间内,并且所有元素的和为1。这样就可以使得可以以概率来理解输出的值,并且可以选择值最大的分类或值。
知乎:https://zhuanlan.zhihu.com/p/115532919
one-hot(独热编码):
one-hot又称为一位有效编码。在NLP中,譬如一个系统中有10000个词汇,每个词汇有一个序号,通常是字典序,那么每个词汇使用10000*1的向量表示,这个向量在词汇对应的序号的位置上是1,其他的位置上全部是0。
举例:
一个系统有12个单词:[cat,fox,mouse,run,after, is,chase,rabbit,kid,play,with,the],那么这12个单词就可以用如下方法表示:
cat = [ 1 0 0 0 0 0 0 0 0 0 0 0]
fox = [ 0 1 0 0 0 0 0 0 0 0 0 0]
mouse = [ 0 0 1 0 0 0 0 0 0 0 0 0]
run = [ 0 0 0 1 0 0 0 0 0 0 0 0]
after = [0 0 0 0 1 0 0 0 0 0 0 0]
is = [ 0 0 0 0 0 0 1 0 0 0 0 0]
chase = [ 0 0 0 0 0 0 1 0 0 0 0 0]
rabbit = [ 0 0 0 0 0 0 0 1 0 0 0 0]
kid = [ 0 0 0 0 0 0 0 0 1 0 0 0]
play = [ 0 0 0 0 0 0 0 0 0 1 0 0]
with = [ 0 0 0 0 0 0 0 0 0 0 1 0]
the = [ 0 0 0 0 0 0 0 0 0 0 0 1]
one-hot的缺点:
1. 向量维度很大
2. 仅仅与词汇在系统中的位置相关,没有办法表达词汇的意义
word embedding(词向量):
word embedding的主要目的是为了表达词的含义,词汇之间的内在联系,实现对词语更精确的描述。
概括地说,实现word embedding就是为每个单词构造一组特征。向量空间模型 (VSMs)将词汇表达(嵌套)于一个连续的向量空间中,语义近似的词汇被映射为相邻的数据点。那如何将语义融入到词表示中?Harris 提出的分布假说为这一设想提供了理论基础:上下文相似的词,其语义也相似。
也即,通过使用一个词周围的词来代表这个词。这也是现代统计NLP最成功的一个idea。采用这一假设的研究方法大致分为以下两类:基于计数的方法 (e.g. 潜在语义分析, Glove), 和 预测方法 (e.g. 神经概率化语言模型,word2vec).
word2vec:
word2vec就是通过使用大量文本,根据词的上下文,使用一个带有单个隐藏层的简单神经网络,这个神经网络并不是用于预测任务,目的只是学习输入层到隐藏层的权重,这些权重实际上就构成了我们试图学习的“词向量”。
两个算法:
1. skip-grams(SG) 给定目标单词,预测上下文单词
2. Continuous Bag of Words(CBOW),从词袋上下文中预测目标单词
两个训练方法:
1. hierarchical softmax
2. negative sampling
word2vec维度矩阵计算:
举例:
说明:输入的是x1,x2...x8的矩阵,都是独热编码表示,比如x1=[1,0,0,0,0,0,0,0],输入矩阵随机初始化,然后隐藏层就是前两个矩阵相乘的结果。隐藏层再跟输出矩阵相乘,得到预测的矩阵Y。比如预测的y1=
然后进行softmax,得到y1=[a,b,c,d,e,f,g,h],(具体多少没有算),然后选取其中最大的值,置为1,其他置为0(相当于恢复为一个独热编码的表示)假如a最大,则变成y1=[1,0,0,0,0,0,0,0] ,但是假如真实的y1是 y1=[0,1,0,0,0,0,0,0],这样预测值与真实值存在误差,然后我们进行相减,然后反向传播。调整矩阵的权重参数。这个训练过程如此反复,直到误差最小。(反向传播以及权重的调整具体计算参考郭老师的知乎文章词向量)
注:softmax的好处是可以将所有的值转换在(0,1)之间,和为1,并且保持大小关系。使用softmax之后,将生成类似于概率的向量。
多词上下文:
word2vec中的多词模型分为CBOW(Continuous Bag-of-Words 与Skip-Gram两种模型
CBOW:
CBOW模型的训练输入是某一个特征词的上下文(context)相关的词对应的词向量,而输出就是这特定的一个词(目标单词target)的词向量。
由于CBOW使用的是词袋模型,因此这上下文单词都是平等的,也就是不考虑上下文单词和目标单词之间的距离大小,只要在我们上下文之内即可。
举例:
比如下面这个例子,上下文大小取值为1,上下文对应的词有2个,前后各1个,这2个词是我们模型的输入。
以上面的小例子理解这个网络图:
Skip-gram模型
skip-gram模型和CBOW模型相反,目标单词现在在输入层,上下文单词在输出层
skip-gram的计算量要比CBOW大很多。skip-gram进行预测的次数是要多于cbow,因为每个词在作为中心词时,都要对上下文词预测一次,都要进行2C次的预测、调整,当数据量较少,或者词为生僻词出现次数较少时, 这种多次的调整会使得词向量相对的更加准确。
word2vec的层次softmax(哈夫曼树):
上面大概介绍了CBOW和skip-gram过程。但是和word2vec中的具体实现有很大的不同。一个最主要的问题是这种模型的处理过程非常耗时。词汇表一般在百万级别以上(word2evc中的max_size是3千万),这意味着输出层需要进行softmax计算各个词的输出概率的的计算量很大。Word2vec为此进行了各种优化。
hierarchical softmax用huffman树来取代隐藏层和输出层的结构,叶子节点对应着词表中的单词,叶子节点的个数即为词汇表的小大。 而内部节点则起到隐藏层神经元的作用。
Huffman树有什么好处呢?得到Huffman树后我们会对叶子节点进行Huffman编码,由于权重高的叶子节点越靠近根节点,而权重低的叶子节点会远离根节点,这样我们的高权重节点编码值较短,而低权重值编码值较长。这保证的树的带权路径最短,也符合我们的信息论,即我们希望越常用的词拥有更短的编码。
使用huffman树对效率的改进有两方面,首先,由于是二叉树,之前计算量为V ,现在变成了 。第二,由于huffman树中,高频的词靠近树根,这样高频词需要更少的时间会被找到,符合优化思想。
知乎:https://zhuanlan.zhihu.com/p/129293598
RNN记忆功能:
RNN的主要思想就是把隐藏层/输出层的值保存在memory中,参与到新的输入的计算中。RNN为什么会有记忆功能呢?因为在下一次的计算中,隐藏单元也和输入一起参与了运算。我们知道隐藏单元是输入的计算结果;因此可以在一定程度上保留输入的信息。
举例:
LSTM记忆效果:
隔较近,RNN预测有效:
隔得太远,RNN会失效:
LSTM是long short-term memory,长短期记忆网络。LSTM提出的主要目标是让网络具有较长远的记忆。
LSTM和RNN的整体架构是一样的,但是相比于一般的RNN,中间的模块的结构不同。
这里有三个门。为什么叫“门gate”呢?因为像sigmoid的输出,在0~1之间,而注意到sigmoid的输出都是进行点乘。这样,如果sigmoid的输出是0,也就意味着和它相乘的那个输入变成了0,也就像是这个输入不被通过。这里有三个门,分别是 forget gate(遗忘门),input gate(输入门)和output gate(输出门)。input gate用于控制有多少的输入可以被加入到cell中;output gate用于控制新的cell中的内容有多少可以被输出;forget gate用于控制旧的cell中的内容有多少可以保存。至于门到底是打开,还是关闭,这就是网络自己学习到的。下图是典型的门结构:
步骤:
step1:遗忘门
LSTM的第一步是决定需要从cell状态中扔掉什么样的信息。由“遗忘门(forget gate)”的sigmoid层决定。
step2:输入门
决定我们需要在cell state里存储什么样的信息。第一,一个sigmoid层调用“输入门(input gate)”以决定哪些数据是需要更新的。然后,一个tanh层为新的候选值创建一个向量 ,这些值能够加入state中。下一步,我们要将这两个部分合并以创建对state的更新。
通过遗忘门的信息与通过输入门的信息相加形成新的记忆信息Ct:
在决定需要遗忘和需要加入的记忆之后,就可以更新旧的cell state到新的cell state了
step3:输出门
我们需要决定要输出的东西。
这个输出基于我们的cell state,但会是一个过滤后的值。首先,我们运行一个sigmoid层,这个也就是输出门(output gate),以决定cell state中的那个部分是我们将要输出的。然后把cell state放进tanh(将数值压到-1和1之间),最后将它与sigmoid门的输出相乘,这样就只输出了我们想要的部分了。
举例:
知乎:https://zhuanlan.zhihu.com/p/136559171
seq2seq:
seq2seq又叫Encoder-Decoder模型。它可以实现从一个序列到任意一个序列的转换,模型如下所示,其左半部分为Encoder部分,右半部分为Decoder部分。
其中 h0为初始化隐状态, x1,x2等是输入序列,y1,y2 等是输出序列,c 由Encoder的最后一个隐状态得到。模型将输入序列经过一个RNN得到隐状态c 后,在用另一个RNN来进行对c的解码,得到输出。
最基础的Seq2Seq模型包含了三个部分,即Encoder、Decoder以及连接两者的中间状态向量,Encoder通过学习输入,将其编码成一个固定大小的状态向量S,继而将S传给Decoder,Decoder再通过对状态向量S的学习来进行输出。
seq2seq的缺点:
因为Encoder将输入编码为固定大小状态向量的过程实际上是一“信息有损压缩”的过程,如果信息量越大,那么这个转化向量的过程对信息的损失就越大,基础的模型连接Encoder和Decoder模块的组件仅仅是一个固定大小的状态向量,这使得Decoder无法直接去关注到输入信息的更多细节。(引入注意力机制解决问题)
attention注意力机制:
没有引入注意力的模型在输入句子比较短的时候估计问题不大,但是如果输入句子比较长,此时所有语义完全通过一个中间语义向量来表示,单词自身的信息已经消失,可想而知会丢失很多细节信息,这也是为何要引入注意力模型的重要原因。
从概念上理解,把Attention仍然理解为从大量信息中有选择地筛选出少量重要信息并聚焦到这些重要信息上,忽略大多不重要的信息,这种思路仍然成立。聚焦的过程体现在权重系数的计算上,权重越大越聚焦于其对应的Value值上,即权重代表了信息的重要性,而Value是其对应的信息。
attention计算:第一个过程是根据Query和Key计算权重系数,第二个过程根据权重系数对Value进行加权求和。而第一个过程又可以细分为两个阶段:第一个阶段根据Query和Key计算两者的相似性或者相关性;第二个阶段对第一阶段的原始分值进行归一化处理;
举例:
上述过程如下图:
过程如下图:
self-attention自注意力机制:
引入Self Attention后会更容易捕获句子中长距离的相互依赖的特征,因为如果是RNN或者LSTM,需要依次序序列计算,对于远距离的相互依赖的特征,要经过若干时间步步骤的信息累积才能将两者联系起来,而距离越远,有效捕获的可能性越小。
但是Self Attention在计算过程中会直接将句子中任意两个单词的联系通过一个计算步骤直接联系起来,所以远距离依赖特征之间的距离被极大缩短,有利于有效地利用这些特征。除此外,Self Attention对于增加计算的并行性也有直接帮助作用。这是为何Self Attention逐渐被广泛使用的主要原因。
知乎:https://zhuanlan.zhihu.com/p/137615798
transformer:
Transformer 实际上就是一个带self-attention的seq2seq,包括encoder和decoder两部分,但是它是第一个完全依赖于 Self-Attention 来计算其输入和输出表示的模型,而不使用 RNN 或 CNN。Transformer 由且仅由 self-Attention 和 Feed Forward Neural Network 组成。Transformer中包括了编码器和解码器各 6 层,总共 12 层的 Encoder-Decoder。
多头注意力机制:
由于不同的 Attention 的权重侧重点不一样,所以将这个任务交给不同的 Attention 一起做,最后取综合结果会更好,有点像 CNN 中的 Kernel。在Transformer的论文中指出,将 Q、K、V 通过一个线性映射后,分成 h 份,对每份进行 Scaled Dot-Product Attention 效果更好, 再把这几个部分 Concat 起来,过一个线性层的效果更好,可以综合不同位置的不同表征子空间的信息。不同的头关注的点不同。
transformer的结构:
神经网络越深越好吗?
理论上,在训练集上,深层网络不会比浅层网络差。但是为什么出现下面这种情况呢?随着层数增加,训练集上效果反而变差,这被称为退化问题。原因是随着网络越来越深,训练和优化变得越来越难,过深的网络会产生退化问题,效果反而不如相对较浅的网络。而残差网络可以解决这个问题,残差网络越深,训练集上效果越好。
Add残差网络:
残差网络通过加入 shortcut connections,变得更加容易被优化。包含一个 shortcut connection 的几层网络被称为一个残差块(residual block)。残差块分成两部分:直接映射部分和残差部分。 残差网络由残差块组成,一个残差块可以表示为:
残差网络有什么好处呢?显而易见:因为增加了 x 项,那么该网络求 x 的偏导的时候,多了一项常数 1,所以反向传播过程,梯度连乘,也不会造成梯度消失。 残差网络的实现非常简单:
def residual(sublayer_fn,x): return sublayer_fn(x)+x
Norm归一化:
Normalization 有很多种,但是它们都有一个共同的目的,那就是把输入转化成均值为 0 方差为 1 的数据。在把数据送入激活函数之前进行 Normalization(归一化),因为我们不希望输入数据落在激活函数的饱和区。【举例,sigmoid函数的饱和区,是指左下角和右上角的平缓区域,如果数据落在饱和区,会造成梯度消失问题(平缓区梯度几乎为0),以及对于输入x,输出y的区分度不高】。
各个参数解释如下:
深度网络中的数据维度一般是[N, C, H, W]或者[N, H, W,C]格式,N是batch size,H/W是feature的高/宽,C是feature的channel,压缩H/W至一个维度
- BN在batch的维度上norm,归一化维度为[N,H,W],对batch中对应的channel归一化;
- LN避开了batch维度,归一化的维度为[C,H,W];
- IN 归一化的维度为[H,W];
- 而GN介于LN和IN之间,其首先将channel分为许多组(group),对每一组做归一化,及先将feature的维度由[N, C, H, W]reshape为[N, G,C//G , H, W],归一化的维度为[C//G , H, W]
Layer Normalization :它也是归一化数据的一种方式,不过 LN 是在每一个样本上计算均值和方差,而不是 BN 那种在批方向计算均值和方差。
Mask:
mask就是对某些值进行掩盖,使其不产生效果。
Transformer 模型里面涉及两种 Mask。分别是 Padding Mask 和 Sequence Mask。
其中,Padding Mask 在所有的 Scaled Dot-Product Attention 里面都需要用到,而 Sequence Mask 只有在 Decoder 的 Self-Attention 里面用到。
padding mask:处理非定长序列,区分padding和非padding部分,如在RNN等模型和Attention机制中的应用等
在NLP中,文本一般是不定长的,所以在进行 batch训练之前,要先进行长度的统一,过长的句子可以通过truncating 截断到固定的长度,过短的句子可以通过 padding 增加到固定的长度,但是 padding 对应的字符只是为了统一长度,并没有实际的价值,因此希望在之后的计算中屏蔽它们,这时候就需要 Mask。
具体做法:
这些填充的位置,其实是没什么意义的,所以我们的 attention 机制不应该把注意力放在这些位置上,所以我们需要进行一些处理。 具体的做法是,把这些位置的值加上一个非常大的负数(负无穷),这样的话,经过 Softmax,这些位置的概率就会接近 0 。而 Padding Mask 实际上是一个张量,每个值都是一个 Boolen,值为 False 的地方就是我们要进行处理的地方。
sequence mask:防止标签泄露,如:Transformer decoder中的mask矩阵,BERT中的[Mask]位,XLNet中的mask矩阵等。所以, Scaled Dot-Product Attention 的 forward 方法里面的参数 attn_mask 在不同的地方会有不同的含义。
Sequence Mask 是为了使得 Decoder 不能看见未来的信息。也就是对于一个序列,在 time_step 为 t 的时刻,我们的解码输出应该只能依赖于 t 时刻之前的输出,而不能依赖 t 之后的输出。因此我们需要想一个办法,把 t 之后的信息给隐藏起来。
具体做法:
Mask 操作是在 Self-Attention 进行 Softmax 之前进行的,具体做法是将要 Mask 的位置用一个无穷小的数替换 -inf,然后再 Softmax。
可以看到,经过 Mask 和 Softmax 之后,当 根据单词 A 预测单词 B 时,只能使用单词 A 的信息,根据 [A, B] 预测单词 C 时只能使用单词 A, B 的信息。这样就可以防止信息泄露。
知乎:https://zhuanlan.zhihu.com/p/141588904
EMLo:
word embeding的问题:
word embedding 是现在自然语言处理中最常用的 word representation 的方法,常用的word embedding 是word2vec的方法,然而word2vec本质上是一个静态模型,也就是说利用word2vec训练完每个词之后,词的表示就固定了,之后使用的时候,无论新句子上下文的信息是什么,这个词的word embedding 都不会跟随上下文的场景发生变化,这种情况对于多义词是非常不友好的。
EMLo的提出:
EMLo的提出就是为了解决这种语境问题,动态的去更新词的word embedding。ELMO的本质思想是:事先用语言模型在一个大的语料库上学习好词的word embedding,但此时的多义词仍然无法区分,不过没关系,我们接着用我们的训练数据(去除标签)来运行预训练好的ELMO 模型。
EMLo的缺点:
首先,一个非常明显的缺点在特征抽取器选择方面,ELMO使用了LSTM而不是新贵Transformer,Transformer是谷歌在17年做机器翻译任务的“Attention is all you need”的论文中提出的,引起了相当大的反响,很多研究已经证明了Transformer提取特征的能力是要远强于LSTM的。
另外一点,ELMO采取双向拼接这种融合特征的能力可能比Bert一体化的融合特征方式弱,但是,这只是一种从道理推断产生的怀疑,目前并没有具体实验说明这一点。“不完全双向”是指模型的前向和后向LSTM两个模型是分别训练的,从图中也可以看出,对于一个序列,前向遍历一遍获得左边的LSTM,后向遍历一遍获得右边的LSTM,最后得到的隐层向量直接拼接得到结果向量(前向的hidden state1 + 后向的hidden state2 = 总的hidden state,+是concat),并且在最后的Loss function中也是前向和后向的loss function直接相加,并非完全同时的双向计算。
GPT:
GPT的提出:
GPT是“Generative Pre-Training”的简称,从名字看其含义是指的生成式的预训练。GPT也采用两阶段过程,第一个阶段是利用语言模型进行预训练,第二阶段通过Fine-tuning的模式解决下游任务。下图是GPT的结构图。
GPT与EMLo的区别:
主要不同在于两点:首先,特征抽取器不是用的RNN,而是用的Transformer的decoder;其次,GPT的预训练虽然仍然是以语言模型作为目标任务,但是采用的是单向的语言模型。
“单向”的含义是指:语言模型训练的任务目标是根据 Wi单词的上下文去正确预测单词 Wi,Wi 之前的单词序列Context-before称为上文,Wi之后的单词序列Context-after称为下文。ELMO在做语言模型预训练的时候,预测单词 Wi 同时使用了上文和下文,而GPT则只采用Context-before这个单词的上文来进行预测,而抛开了下文。这个选择现在看不是个太好的选择,原因很简单,它没有把单词的下文融合进来,这限制了其在更多应用场景的效果,比如阅读理解这种任务,在做任务的时候是可以允许同时看到上文和下文一起做决策的。如果预训练时候不把单词的下文嵌入到Word Embedding中,是很吃亏的,丢掉了一些信息。
GPT为啥会用transformer中的decoder?
“自己看见自己”。是指要预测的下一个词在给定的序列中已经出现的情况。传统语言模型的数学原理决定了它的单向性。传统语言模型的目标是获得在给定序列从头到尾条件概率相乘后概率最大的下一词,而双向模型会导致预测的下一词已经在给定序列中出现了的问题,这就是“自己看见自己”。
举例:
如下图所示(图片从下往上看),最下行是训练数据A B C D,经过两个bi-lstm操作,需要预测某个词位置的内容。比如第二行第二列A|CD这个结果是第一层bi-lstm在B位置输出内容,包括正向A和反向CD,直接拼接成A|CD。比如第三行第二例ABCD这个结果是前向BCD和反向AB|D拼接结果,而当前位置需要预测的是B,已经在ABCD中出现了,这就会有问题。因而对于Bi-LSTM,只要层数增加,就是会存在“自己看见自己”的问题。
Bert:
Bert的提出:
BERT(基于Transformer的双向编码器表示形式,(Bidirectional Encoder Representations from Transformers))BERT的主要技术创新是将流行的注意力模型,Transformer的双向训练应用于语言建模。 这与以前的工作不同,之前的工作从左到右或从左到右和从右到左的训练的组合,来查看文本序列。 论文的结果表明,经过双向训练的语言模型比单向语言模型具有更深的语言背景和流程感。
Bert与EMLo、GPT模型的对比:
Bert其实和ELMO及GPT存在千丝万缕的关系,比如如果我们把GPT预训练阶段换成双向语言模型,那么就得到了Bert;而如果我们把ELMO的特征抽取器换成Transformer,那么我们也会得到Bert。所以可以看出:Bert最关键两点,一点是特征抽取器采用Transformer;第二点是预训练的时候采用双向语言模型。