大纲
- BERT的输入输出
- BERT选择mask掉15%比例的原因
- BERT中3中情况mask的作用
- BERT最多输入512的原因
- BERT为什么要在第一句前加[CLS]标志
- BERT的非线性来源于哪里
- BERT的三个embedding直接相加会对语义有影响吗
- BERT中为什么采用层归一化(LN)而不是批量归一化(BN)
- BERT如何解决长文本问题
- 为什么BERT需要额外的segment embedding(段embedding)
- BERT为什么采用warm-up
- BERT如何区分一词多义
- ELMO和BERT的区别
- BERT和Transformer中Encoder的区别
- BERT的损失函数
- BERT中的MLM和NSP预训练任务
- BERT中标注为mask的输入会被attention吗
- MASK矩阵在深度学习中有哪些应用场景
- BERT预训练任务中被选的15%的词中仅80%被真正mask的目的
- BERT为什么使用学习的position embedding而非正弦position embedding
- multi-head attention的具体结构
- multi-head-attention的意义
- 为什么BERT在mask时,把mask掉的词用[mask]替代,transformer是在attention过程中对后面的词不可见
- BERT的流程
- 分词模块FullTokenizer做了哪些事情
- BERT中如何获取词意和句意
BERT的输入输出
BERT的输入
BERT模型将字向量(token embedding)、文本向量(segment embedding)、和位置向量(position embedding)的加和作为模型输入(word embedding)
输入:word embedding = token embedding + segment embedding + position embedding
- token embedding:表示文本中各个字/词的原始词向量,该向量可以随机初始化,也可以利用word2vector等算法进行预训练以作为初始值。
- segment embedding:文本向量,该向量的取值在模型训练过程中自动学习,用于刻画文本的全局语义信息,并与单字/词的语义信息相结合。
- position embedding:位置向量**,由于出现在文本不同位置的字/词携带的语义信息存在差异**(比如“我爱你”和“你爱我”),因此BERT模型对不同位置的字/词分别附加一个不同的向量以作区分,即解决一词多义。
在BERT模型中,还可以将英文词汇作进一步切割(子词切分类似BPE),划分为更细粒度的语义单位(wordpiece),例如 将playing分割为play和ing。
BERT的输出
输出是文本中各个字/词融合了全文语义信息后的向量表示。
BERT选择mask掉15%比例的原因
BERT采用的是Masked LM,会选取语料中所有词的15%进行随机mask,论文中表示是收到完形填空的启发,类似CBOW中华东窗口的中心词,从CBOW的角度看10%-20%的比例都是可行的。
BERT中3中情况mask的作用
- 预训练在句子编码的时候将部分词mask,作用是用被mask词前后的词猜测mask掉的词是什么,因为是认为mask的,所以计算机知道mask词的正确值,所以可以判断模型猜测的词是否准确。
- Transformer模型的decoder层存在,ask,例如在翻译任务中,翻译我爱你为i love you,模型在预测love的时候不知道you的信息,所以需要把后面you的信息mask掉。但是BERT只有encoder层,所以这个是transformer模型的特征。
- attention模块有一个可选择的mask操作,主要是句子可能存在填0的操作,attention模块不需要把填0的无意义信息算进来,所以使用mask。
BERT最多输入512的原因
因为BERT预训练模型设置config的max_position_embeddings为512和type_vocab_size为2,所以最多输入512,最多两个句子合成一句。硬件条件允许的情况下可以更改config重新预训练。
- 这是初始值设置的原因,前者对应position embedding,后者对应segment embedding
- 在BERT中,token、position、segment embedding 都是通过学习得到的
- 因此在直接使用google的BERT预训练模型时,输入最多512个词(还要除掉[CLS]和[SEP]),最多两个句子合成一句。之外的词和句子没有对应的embedding。
BERT为什么要在第一句前加[CLS]标志
因为与文本中已有的其他词相比,这个无明显语义信息的符号会更公平的融合文本中各个词的语义信息,从而更好的表示整句话的意义
- BErt在第一句前会加一个[CLS]标志,最后一层该位对应向量可以作为整句话的语义表示,从而用于下游分类任务等。
- self-attention是用文本中的其他词来增强目标词的语义表示,但是目标词本身的语义还是会占主要部分,因此经过BERT的12层,每次词的embedding融合了所有词的信息,可以去更好的表示自己的语义。
- [CLS]位本身没有语义,经过12层,得到的是attention后所有词的加权平均,相比其他正常词,可以更好的表征句子语义。
- 也可以通过最后一层所有词的embedding作pooling去表征句子语义
BERT的非线性来源于哪里
前馈层的gelu激活函数和self-attention,self-attention是非线性的。
BERT的三个embedding直接相加会对语义有影响吗
BERT的三个embedding相加,本质上可以看做是一个特征的融合,BERT还有Layer Norm,会把embedding结果统一到相同的分布,所以BERT可以学到融合后特征的语义信息。
- embedding数学的本质,就是以one hot为输入的单层全连接。
- word embedding = token embedding + position embedding + segment embedding
BERT中为什么采用层归一化(LN)而不是批量归一化(BN)
norm的本质是通过把一部分不重要的复杂信息损失掉,以此来降低拟合难度以及过拟合的风险,从而加速模型的收敛,norm的目的就是让分布稳定下来降低各维度数据的方差。
- 归一化方式取决于关注数据的哪部分信息。如果某个维度信息的差异性很重要,需要被拟合,那就在那个维度进行归一化。
- 如果特征依赖于不同样本间的统计大小进行比较那么batchnorm是有效的(CV任务);如果特征依赖于样本内部不同特征为度的比较,那么layernorm更有效(例如NLP,不同batch样本的信息关联性不大),使用LN为了进一步保证在不同token上提取的稳定性。
- layer normalization 有助于得到一个球体空间中符合0均值1方差高斯分布的embedding,batch mormalization不具备这个功能。
- layernorm可以对transformer学习过程中由于多词条embedding累加可能带来的“尺度”问题施加约束,相当于对表达每个词一词多义的空间施加了约束,有效降低模型方差。
- NLP文本的本质可以看成一个时间序列,序列是不定长的,长度不同的序列原则上属于不同的统计对象,所以很难得到稳定的统计量,而LN可以让统计量更稳定。NLP任务输入的是句子,长短不一,使用mask方法补零,产生了很多没有用的信息,使用BN就会训练出没有用的东西。
- 区别主要是做规范化的维度不同,BatchNorm针对一个batch里面的数据进行规范化,针对单个神经元进行;LayerNorm则是针对单个样本内部,不依赖于其他数据。
BERT如何解决长文本问题
- Clipping(截断法) 对长输入进行截断,挑选重要的token输入模型。缺点:丢失一部分文本信息,导致结果出错。
- Polling(池化法):用一个区域内最重要的特征值来代替整个区域的特征值,也称为下采样。例如一篇1000个字的文章,可以把这1000个字的word embedding先都给拿出来,通过Polling的方式选出这1000个embedding中(假设1个字对应1个token)最重要的510个embedding挑出来代表整段话的embedding。
- Sliding Window(滑动窗口):把文档分成有重叠的若干片段,然后每一段都当作独立的文档送入BERT进行处理。最后再对于这些独立文档得到的结果进行整合。
- 参考百度提出的ERNIE预训练模型,提出三种解决长文本的问题。1.通过将文本片段重复输入2次,使得在回顾阶段的每一个文本片段可以双向建模并利用在粗读阶段获取到的全篇章语义信息。2.通过改进Recurrence Transformer模型(Transformer-XL等)为同层循环的方式,可建模无限长文本。3.该预训练目标通过让模型学习篇章级本文段落间的关系,使得模型可以对篇章整体信息进行建模。
为什么BERT需要额外的segment embedding(段embedding)
因为bert预训练的其中一个任务是判断segment A 和 segment B 之间的关系,这就需要embedding中能包含当前token属于哪个segment的信息,然而无论是token embedding还是 position embedding 都无法表示出这种信息,因此额外创建一个segment embedding matrix 用来表示当前token属于哪个segment的信息,segment vocab size就是2,其中index=0表示token输入segment A,index=1表示token属于segment B。
BERT为什么采用warm-up
- warmup需要在训练最初使用较小的学习率来启动,并很快切换到大学习率而后进行常见的decay。
- warmup有助于减缓模型在初始阶段对mini-batch的提前过拟合现象,保持分布的平稳。
- 有助于保持模型深层的稳定性,warmup有助于收敛。
- warmup_lr的初始值是跟训练语料的大小成反比的,也就是说训练语料越大,那么warmup_lr初值越小,随后增长到预设的超参initial_learning_rate相同的量级,再接下来又通过decay_rates逐步下降。
BERT如何区分一词多义
bert有position embedding,对于不同的上下文信息,最后输出的word embedding 是不同的,BERT对于一个词可以学习到上下文的信息,在上下文信息不同的情况下它最后对应的12层transformer的输出结果是不一样的。
ELMO和BERT的区别
- ELMO采用两部分双层双向LSTM进行特征提取,BERT采用Transformer进行特征提取,transformer特征提取的效果比LSTM好
- BERT 和 ELMO 都采用了双向语言模型,但ELMO实际上是两个单向语言模型(方向相反)的拼接,这种融合特征的能力比BERT一体化同贺特征方式弱。
BERT和Transformer中Encoder的区别
主要是位置编码和输入参数的不同。
- BERT的输入参数中有segment embedding 用于刻画文本的全局语义信息。
- transformer的位置编码是有sin/cos 函数计算出来的固定值。他只能标记这是某一个位置,并不能标记这个位置有什么作用。BERT的position是随机生成、在模型训练中可学习的embedding,它不仅可以标注这一个位置,还能学习这个位置的作用。
BERT的损失函数
BERT的损失 = MLM的损失 + NSP的损失
第一部分是来自MASK-LM的单词级别的分类任务,另一部分是句子级别的分类任务;通过这两个任务的联合学习,使得BERT学习到的表征既有token级别信息,同时也包含了句子级别的语义信息。
- MLM:在encoder的输入上添加一个分类层,用嵌入矩阵乘以输出向量,将其转换为词汇的维度,用softmax计算mask中每个单词的概率。
- NSP:用一个简单的分类层将[CLS]标记的输出变换为2*1形状的向量,用softmax计算IsNextSequence的概率。
BERT中的MLM和NSP预训练任务
BERT模型通过对Masked LM任务和Next Sentence Prediction任务进行联合训练,使模型输出的每个字词的向量表示都能尽可能全面、准确的刻画输入文本(单句或语句对)的整体信息,为后续的微调任务提供了更好的模型参数初始值。
MLM
- 给定一句话,随机抹去这句话中的一个或几个词,要求根据剩余词汇预测被抹去的几个词分别是什么。
- 在一句话中随机选择15%的词汇用于预测,对于在原句中被抹去的词汇,80%的情况下采用一个特殊符号[MASK]替换,10%情况下采用一个任意词替换,剩余10%情况下保持原词汇不变;
- 好处:预测一个词汇时,模型不知道输入对应位置的慈湖是否为正确的词汇(10%概率),这就迫使模型更多的依赖于上下文信息去预测词汇,并且赋予了模型一定的纠错能力。
NSP
- 给定一篇文章中的两句话,判断第二句话在文本中是否紧跟在第一句话之后。类似于[段落重排序]的任务。即:将一篇文章的各段打乱,让我们通过重新排序把原文还原出来,这其实需要对全文大意有充分、准确的理解。
- 任务实际上就是段落重排序的简化版:只考虑两句话,判断是否时一篇文章中的前后句。
- 让模型能够更准确的刻画语句乃至篇章层面的语义信息。
BERT中标注为mask的输入会被attention吗
- 会,attention_mask也就是input_mask的0值只作用在padding部分。BERT modeling前向传播过程中,直接拿input_mask赋值给attention_mask进行前向传播,因此[mask]token是会被关注到的。
- 反向一下,如果mask的位置能被attention自动忽视的话,就不需要多此一举引入特定的[MASK]标签了。自然也没必要执行80-10-10的策略。预训练中,被mask的只是词本身并不影响对应的position和segment embedding。
MASK矩阵在深度学习中有哪些应用场景
- 处理不定长输入
处理非定长序列,区分padding和非padding部分,例如在RNN等模型和Attention机制中的应用等。 - Lange model 中防止未来信息泄露。padding mask
防止标签泄漏,常常需要从一个词预测下一个词,例如transformer中的self attention,如果不做mask,在decoder的时候很容易把下一个词的信息泄漏了,不能在预测一个词时就已经知道这个词后面的词了。例如Transformer decoder 中的mask矩阵,BERT中的[MASK]位,XLNet中的mask矩阵等。sequence mask
BERT预训练任务中被选的15%的词中仅80%被真正mask的目的
- 训练模型时的数据使用方式和生产环境的实际情况存在偏差。pretrain时预测的词被[mask]住即得到的是“完全基于上下文”的深度语义向量,finetune时,再也没有[mask]这个标签了,并且当前词是可见的它会参与到语义的生成。
- 80%的词MASK,10%的词保留,10%的词随机替换,可以理解为加噪,告诉模型,输入的词有可能错误,不要完全相信,因为数据也不是100%干净的。
BERT为什么使用学习的position embedding而非正弦position embedding
- BERT的预训练数据量是比transformer的数据量大很多的,所以使用可学习的position效果更好一些,而数据量小的时候可学习和直接sin/cos计算的差别不大。
- BERT虽然使用了Transformer的结构,但对于细节策略的选择,模型的学习目标比模型结构更重要,对于NMT任务,encoder的核心任务是提取完整的句子语义信息,其实并不特别关注某个词的具体任务是什么。BERT的encoder需要建模完成的 word order,尤其是对序列标注类的下游任务,模型需要给出每个位置的预测结果,此时,完全训练来的position就比按公式赋值的psition要好。
multi-head attention的具体结构
BERT由12层transformer layer(encoder端)构成,首先word emb,pos emb,seg emb 做加和作为网络输入,每层由一个multi-head attention,一个feed forward以及两层layerNorm构成
具体可以描述为:
- 一个768维的hidden向量,被映射成query,key,value。然后三个向量分别切分成12个小的64维的向量,每一组小向量之间做attention。假设batch_size为32,seq_len为512,隐藏层维度为768,12个head。
hidden(32 * 512 * 768)->query(32512768)->32 * 12 * 512 * 64
hidden(32 * 512 * 768)->key(32 * 512 * 768)->32 * 12 * 512 * 64
hidden(32 * 512 * 768)->val(32 * 512 * 768)->32 * 12 * 512 * 64 - 然后query和key之间做attention,得到一个32 * 12 * 512 * 512的权重矩阵,然后根据这个权重矩阵加权value中切分好的向量,得到一个32 * 12 * 512 * 64的向量,拉平输出为768向量。
32 * 12 * 512 * 64(query_hidden)* 32 * 12 * 64 * 512(key_hidden)->32 * 12 * 512 * 512
32 * 12 * 64 * 512(value_hidden) * 32 * 12 * 512 * 512(权重矩阵)->21 * 12 * 512 * 64
然后再还原成->32 * 512 * 768
简言之是12个头,每个头都是一个64维度分别去与其他的所有位置的hidden embedding 做 attention 然后再合并还原。
multi-head-attention的意义
BERT中 multi-head 7686412与直接使用768*768矩阵统一计算有什么区别?
- 计算量相同,但是模型容量增加,相当于某种模型融合,带来模型表现力的提升。
- 768维的单头完全可以看做是12组64维的多头,这12组就相当于12个特征空间,然后计算12次Attention矩阵,再以某种方式整合,效果应该比单个注意力更好,因此有了多头注意力。
为什么BERT在mask时,把mask掉的词用[mask]替代,transformer是在attention过程中对后面的词不可见
举例
“北京” “大学” 运动会
做mask变成 “北京” “[mask]” “运动会”
做attention mask 变成 “北京” “运动会”
BERT和Transformer的目标是不一致的
- BERT是一个语言模型的预训练模型,需要充分利用文本的上下文信息。或者说是Transformer的堆叠。[mask]起到一个占位符,告诉模型这里有一个term,不要忽略掉。
- Transformer的任务是seq2seq,最初是为机器翻译提出,是encoder-decoder架构,序列第i个位置要充分利用到前i-1个元素的信息,而与该位置之后的其他位置信息无关。
BERT的流程
- modeling.py,首先定义处理好输入的tokens的对应id为input_id,因为不是训练所以input_mask和segment_id都是采取默认的1即可。
- 在通过embedding_lookup把input_id向量化,如果存在句子之间的位置差异则需要对segment_id进行处理,否则无操作;再进行position_embedding操作。
- 进入tansformer模块,后循环调用transformer的前向过程,次数为隐藏层个数,每次前向过程都包含self_attention_layer、add_and_norm、feed_forward和add_and_norm四个步骤
- 输出结果为句向量则取[CLS]对应的向量(需要处理成embedding_size),否则也可以取最后一层的输出作为每个词的向量组合all_encoder_layers[-1]。
分词模块FullTokenizer做了哪些事情
- BasicTokenizer:根据空格等进行普通的分词。
包括一些预处理方法:去除无意义词,跳过’\t’这些词,unicode变换,中文字符筛选等。 - WordpieceTokenizer:前者的结果再细粒度的切分为WordPiece子词切分。
- 中文不处理,因为有词缀:解决OOV
BERT中如何获取词意和句意
get_pooled_out 代表蕴含了整条语句的信息。
get_sentence_out 代表了获取每个token的output输出,用的是cls向量。
引用 https://zhuanlan.zhihu.com/p/338817680
自己做笔记使用!