当前位置:   article > 正文

【深度学习】NLP之Bert(2)QA_bert qa

bert qa

BERT是一个多任务模型,它的任务是由两个自监督任务组成,即MLM和NSP。

紫色是没找到答案的,黄色是重点关注的。

整体介绍 — PaddleNLP 文档

  • 这里贴一张上面链接里的图,有助于理解Bert的处理流程。

 

BERT

0、为什么要随机Mask?

在BERT的实验中,15%的WordPiece Token会被随机Mask掉。在训练模型时,一个句子会被多次喂到模型中用于参数学习,但是Google并没有在每次都mask掉这些单词,而是在确定要Mask掉的单词之后,80%的时候会直接替换为[Mask],10%的时候将其替换为其它任意单词,10%的时候会保留原始Token。

  • 80%:my dog is hairy -> my dog is [mask]
  • 10%:my dog is hairy -> my dog is apple
  • 10%:my dog is hairy -> my dog is hairy

这么做的原因是如果句子中的某个Token100%都会被mask掉,那么在fine-tuning的时候模型就会有一些没有见过的单词。加入随机Token的原因是因为Transformer要保持对每个输入token的分布式表征,否则模型就会记住这个[mask]是token ’hairy‘。至于单词带来的负面影响,因为一个单词被随机替换掉的概率只有15%*10% =1.5%,这个负面影响其实是可以忽略不计的。

另外文章指出每次只预测15%的单词,因此模型收敛的比较慢。

词向量之BERT - 大师兄的文章 - 知乎

1、为什么BERT在第一句前会加一个[CLS]标志? [1]

超细节的BERT/Transformer知识点 - 知乎

BERT在第一句前会加一个[CLS]标志,最后一层该位对应向量可以作为整句话的语义表示,从而用于下游的分类任务等。

为什么选它呢,因为与文本中已有的其它词相比,这个无明显语义信息的符号会更“公平”地融合文本中各个词的语义信息,从而更好的表示整句话的语义。

具体来说,self-attention是用文本中的其它词来增强目标词的语义表示,但是目标词本身的语义还是会占主要部分的,因此,经过BERT的12层,每次词的embedding融合了所有词的信息,可以去更好的表示自己的语义。

而[CLS]位本身没有语义,经过12层,得到的是attention后所有词的加权平均,相比其他正常词,可以更好的表征句子语义。

当然,也可以通过对最后一层所有词的embedding做pooling去表征句子语义。

这里补充一下bert的输出,有两种,在BERT TF源码中对应:

  1. 一种是get_pooled_out(),就是上述[CLS]的表示,输出shape是[batch size,hidden size]。
  2. 一种是get_sequence_out(),获取的是整个句子每一个token的向量表示,输出shape是[batch_size, seq_length, hidden_size],这里也包括[CLS],因此在做token级别的任务时要注意它。

2、BERT的三个Embedding直接相加会对语义有影响吗?[1]

BERT的三个Embedding相加,本质可以看作一个特征的融合,强大如 BERT 应该可以学到融合后特征的语义信息的。

3、在BERT中,token分3种情况做mask,分别的作用是什么?

哪3个token?

4、为什么BERT选择mask掉15%这个比例的词,可以是其他的比例吗?[1]

BERT采用的Masked LM,会选取语料中所有词的15%进行随机mask,论文中表示是受到完形填空任务的启发,但其实与CBOW也有异曲同工之妙

从CBOW的角度,这里  p=15% 有一个比较好的解释是:在一个大小为 x 的窗口中随机选一个词,类似CBOW中滑动窗口的中心词,区别是这里的滑动窗口是非重叠的。

那从CBOW的滑动窗口角度,10%~20%都是还ok的比例。

5、针对句子语义相似度/多标签分类/机器翻译翻译/文本生成的任务,利用BERT结构怎么做fine-tuning

6、使用BERT预训练模型为什么最多只能输入512个词,最多只能两个句子合成一句?[1]

  1. self.word_embeddings = Embedding(config.vocab_size, config.hidden_size)
  2. self.position_embeddings = Embedding(config.max_position_embeddings, config.hidden_size)
  3. self.token_type_embeddings = Embedding(config.type_vocab_size, config.hidden_size)

在直接使用Google 的BERT预训练模型时,输入最多512个词(还要除掉[CLS]和[SEP]),最多两个句子合成一句。这之外的词和句子会没有对应的embedding。 

7、BERT非线性的来源在哪里?multi head attention 是线性的嘛?[1]

前馈层的gelu激活函数和self-attention,self-attention是非线性的。

8、BERT 是如何区分一词多义的?

我的理解,因为随机mask,导致训练时单词被迫记住上下文的含义。

9、BERT的输入是什么,哪些是必须的,为什么position id不用给,type_id 和 attention_mask没有给定的时候,默认会是什么?

attention还有mask呢?

10、BERT训练时使用的学习率 warm-up 策略是怎样的?为什么要这么做?[13]

warmup 需要在训练最初使用较小的学习率来启动,并很快切换到大学习率而后进行常见的 decay。

  • 有助于减缓模型在初始阶段对mini-batch的提前过拟合现象,保持分布的平稳;
  • 有助于保持模型深层的稳定性。

先验知识:

  • 在训练的开始阶段,模型权重迅速改变
  • mini-batch size较小,样本方差较大

第一种情况很好理解,可以认为,刚开始模型对数据的“分布”理解为零,或者是说“均匀分布”(当然这取决于你的初始化);在第一轮训练的时候,每个数据点对模型来说都是新的,模型会很快地进行数据分布修正,如果这时候学习率就很大,极有可能导致开始的时候就对该数据“过拟合”,后面要通过多轮训练才能拉回来,浪费时间。当训练了一段时间(比如两轮、三轮)后,模型已经对每个数据点看过几遍了,或者说对当前的batch而言有了一些正确的先验,较大的学习率就不那么容易会使模型学偏,所以可以适当调大学习率。这个过程就可以看做是warmup。那么为什么之后还要decay呢?当模型训到一定阶段后(比如十个epoch),模型的分布就已经比较固定了,或者说能学到的新东西就比较少了。如果还沿用较大的学习率,就会破坏这种稳定性,用我们通常的话说,就是已经接近loss的local optimal了,为了靠近这个point,我们就要慢慢来。

第二种情况其实和第一种情况是紧密联系的。在训练的过程中,如果有mini-batch内的数据分布方差特别大,这就会导致模型学习剧烈波动,使其学得的权重很不稳定,这在训练初期最为明显,最后期较为缓解(所以我们要对数据进行scale也是这个道理)。

神经网络中 warmup 策略为什么有效;有什么理论解释么? - 香侬科技的回答 - 知乎

11、Bert 采用哪种Normalization结构,LayerNorm和BatchNorm区别,LayerNorm结构有参数吗,参数的作用?[8]

采用LayerNorm结构,和BatchNorm的区别主要是做规范化的维度不同BatchNorm针对一个batch里面的数据进行规范化,针对单个神经元进行,比如batch里面有64个样本,那么规范化输入的这64个样本各自经过这个神经元后的值(64维)LayerNorm则是针对单个样本,不依赖于其他数据,常被用于小mini-batch场景、动态网络场景和 RNN,特别是自然语言处理领域,对于bert来说就是对每层输出的隐层向量(768维)做规范化,图像领域用BN比较多的原因是因为每一个卷积核的参数在不同位置的神经元当中是共享的,因此也应该被一起规范化。

归一化简单来说就是把上层的输出约束为一个正态分布。

12、为什么说ELMO是伪双向,BERT是真双向?产生这种差异的原因是什么?

13、BERT和Transformer Encoder的差异有哪些?做出这些差异化的目的是什么?

不是同一个东西吗?bert用的是encoder。

14、BERT训练过程中的损失函数是什么?

交叉熵损失函数

15、BERT 的两个任务 Masked LM 任务和 Next Sentence Prediction 任务是先后训练的还是交替训练的?

16、BERT base有多少个self attention吗?

1个multi-head attention有12个self-attention;

1个bert base有12个multi-head attention。1个bert base共有144个self-attention。

17、bert的mask为何不学习transformer在attention处进行屏蔽score的技巧?

bert的mask为何不学习transformer在attention处进行屏蔽score的技巧? - 知乎

Transformer

目前主流的attention方法都有哪些? - JayJay的回答 - 知乎

1、Transformer在哪里做了权重共享,为什么可以做权重共享?好处是什么?[1]

Transformer在两个地方进行了权重共享:

(1)(预测时)Encoder和Decoder间的input Embedding层权重共享;(我认为,在训练阶段decoder的embedding用的是groud-truth的embedding,两者是不共享的)

(2)Decoder中Embedding层和FC层权重共享。

对于(1),《Attention is all you need》中Transformer被应用在机器翻译任务中,源语言和目标语言是不一样的,但它们可以共用一张大词表,对于两种语言中共同出现的词(比如:数字,标点等等)可以得到更好的表示,而且对于Encoder和Decoder,嵌入时都只有对应语言的embedding会被激活,因此是可以共用一张词表做权重共享的。

论文中,Transformer词表用了bpe来处理,所以最小的单元是subword。英语和德语同属日耳曼语族,有很多相同的subword,可以共享类似的语义。而像中英这样相差较大的语系,语义共享作用可能不会很大。

但是,共用词表会使得词表数量增大,增加softmax的计算时间,因此实际使用中是否共享可能要根据情况权衡。

该点参考:为什么transformer可以在embedding层之间共享参数? - 知乎

对于(2),Embedding层可以说是通过onehot去取到对应的embedding向量,FC层可以说是相反的,通过向量(定义为 x)去得到它可能是某个词的softmax概率,取概率最大(贪婪情况下)的作为预测值。

那哪一个会是概率最大的呢?在FC层的每一行量级相同的前提下,理论上和 x 相同的那一行对应的点积和softmax概率会是最大的(可类比本文问题1)。

因此,Embedding层和FC层权重共享,Embedding层中和向量 x 最接近的那一行对应的词,会获得更大的预测概率。实际上,Decoder中的Embedding层和FC层有点像互为逆过程

通过这样的权重共享可以减少参数的数量,加快收敛。

但开始我有一个困惑是:Embedding层参数维度是:(v,d),FC层参数维度是:(d,v),可以直接共享嘛,还是要转置?其中v是词表大小,d是embedding维度。

查看 pytorch 源码发现真的可以直接共享:

  1. fc = nn.Linear(d, v, bias=False) # Decoder FC层定义
  2. weight = Parameter(torch.Tensor(out_features, in_features)) # Linear层权重定义

Linear 层的权重定义中,是按照 (out_features, in_features) 顺序来的,实际计算会先将 weight 转置在乘以输入矩阵。所以 FC层 对应的 Linear 权重维度也是 (v,d),可以直接共享。

2、Transformer的点积模型做缩放的原因是什么?[1]

参考:transformer中的attention为什么scaled? - 知乎

可以参考xavier初始化的动机,保持输入输出方差一致,有利于缓解梯度消失和爆炸。

导致的问题:在数量级较大时,softmax将几乎全部的概率分布都分配给了最大值对应的标签梯度消失为0,造成参数更新困难

维度与点积大小的关系是怎么样的,为什么使用维度的根号来放缩?

大维度导致点积的方差很大,在均值为0的前提下意味着点积的值更可能取大值,大的点积值导致梯度很小,导致梯度消失。

假设向量 q 和 k 的各个分量是互相独立的随机变量,均值是0,方差是1,那么点积 q*k 的均值是0,方差是 d_k

方差越大也就说明,点积的数量级越大(以越大的概率取大值)。那么一个自然的做法就是把方差稳定到1,做法是将点积除以根号dk。将方差控制为1,也就有效地控制了前面提到的梯度消失的问题

3、Transformer中是怎么做multi head attention的,这样做multi head attention,会增加它的时间复杂度嘛?[1]

Multi-Head Attention,它的作用类似于CNN中的多核。

多头的实现不是循环的计算每个头,而是通过 transposes and reshapes,用矩阵乘法来完成的。不会增加时间复杂度。主要还是transposes and reshapes 的操作,相当于把一个大矩阵相乘变成了多个小矩阵的相乘。

4、为什么Transformer 要做 Multi-head Attention? 它的好处在哪? [6]

Attention is all you need论文中讲模型分为多个头,形成多个子空间,每个头关注不同方面的信息。如果Multi-Head作用是关注句子的不同方面,那么不同的head就应该关注不同的Token;当然也有可能是关注的pattern相同,但是关注的内容不同,即V不同。

但是大量的paper表明,transformer或Bert的特定层有独特的功能,底层更偏向于关注语法;顶层更偏向于关注语义。

所以对Multi-head而言,同一层Transformer_block关注的方面应该整体是一致的。不同的head关注点也是一样。但是可视化同一层的head后,发现总有那么一两个头独一无二的,和其他头的关注不一样。

众多研究表明Multi-Head其实不是必须的,去掉一些头效果依然有不错的效果(而且效果下降可能是因为参数量下降),这是因为在头足够的情况下,这些头已经能够有关注位置信息、关注语法信息、关注罕见词的能力了,再多一些头,无非是一种enhance或noise而已。

5、Transformer的Encoder端和Decoder端是如何进行交互的?和一般的seq2seq有什么差别?

6、Transformer中multi-head attention中每个head为什么要进行降维?[14]

不增加时间复杂度的情况下,同时,借鉴CNN多核的思想,在更低的维度,在多个独立的特征空间更容易学习到更丰富的特征信息。

7、Transformer如何并行化的?解码器端可以做并行化吗?

Transformer的并行化主要体现在self-attention模块,在Encoder端Transformer可以并行处理整个序列,并得到整个输入序列经过Encoder端的输出,在self-attention模块,对于某个序列​ x1,x2,...,xn,self-attention模块可以直接计算​xi*xj的点乘结果,而RNN系列的模型就必须按照顺序从x1​计算到xn​。

8、为什么在进行多头关注的时候需要对每个head进行切割?

Transformer的多头注意力看上去是借鉴了CNN中同一卷积层内使用多个卷积核的思想,原文中使用了 8 个“scaled dot-product attention”,在同一“multi-head attention”层中,输入均为“KQV”,同时进行注意力的计算,彼此之前参数不共享,最终将结果拼接起来,这样可以允许模型在不同的表示子空间里学习到相关的信息,在此之前的 A Structured Self-attentive Sentence Embedding 也有着类似的思想。简而言之,就是希望每个注意力头,只关注最终输出序列中一个子空间,互相独立其核心思想在于,抽取到更加丰富的特征信息。
回到题主的问题上来,如果只使用 one head 并且维度为 d_model ,相较于 8 head 并且维度为 。首先存在计算量极大的问题,并且高维空间下的学习难度也会相应提升,这就难免文中实验出现的参数量大且效果不佳的情况,于是将原有的高维空间转化为多个低维空间并再最后进行拼接,形成同样维度的输出,借此丰富特性信息,降低了计算量,而且取得了更好的效果十分巧妙。Transformer和Bert相关知识解答 - sliderSun的文章 - 知乎

Self Attention

Transformer中的multi-head attention(多头attention),简单来说就是多个self-attention的组合,它的作用类似于CNN中的多核。

深入思考,会发现它真的是一个很神奇的存在,它是BERT乃至整个预训练语言模型的基石,是接棒CNN/RNN,成为特征抽取的新利器。Attention is all you need !

0、深度学习中Attention与全连接层的区别何在?[15]

注:这是一个检验你是否真正理解Attention的问题

深度学习中Attention与全连接层的区别何在? - SleepyBag的回答 - 知乎

与全连接层的区别在于,注意力机制可以利用输入的特征信息来确定哪些部分更重要。

注意力机制的意义是引入了权重函数f,使得权重与输入相关,从而避免了全连接层中权重固定的问题。

1、self-attention 的本质是什么?包括哪几个步骤?和普通 Attention 的差别在哪里?[4]

Self-Attention的核心是用文本中的其它词来增强目标词的语义表示,从而更好的利用上下文的信息。

Self-Attention包括三个步骤:相似度计算,softmax和加权平均:

和普通 Attention 的差别在哪里?self-attention的qkv都是同一向量(同一个input embedding)。

而普通attention,?。。。  

注意力机制可以被描述为一个将 Query 和一系列的 Key-Value Pairs 映射到 Output 的函数,其中 Query,Key,Value 和 Output 都是向量,Output 被计算为 Value 的加权和,其中分配给每个 Value 的权重由 Query 与对应 Key 的打分函数计算。

阿里深度召回模型实践

一般attention也有Key=Value=X。

目前主流的attention方法都有哪些? - JayJay的回答 - 知乎

2、不考虑多头的原因,self-attention中词向量不乘QKV参数矩阵,会有什么问题?[4]

self-attention中,sequence中的每个词都会和sequence中的每个词做点积去计算相似度,也包括这个词本身。

对于 self-attention,一般会说它的 q=k=v,这里的相等实际上是指它们来自同一个基础向量,而在实际计算时,它们是不一样的,因为这三者都是乘了QKV参数矩阵的。那如果不乘,每个词对应的q,k,v就是完全一样的。

在相同量级的情况下,qi与ki点积的值会是最大的(可以从“两数和相同的情况下,两数相等对应的积最大”类比过来)。

那在softmax后的加权平均中,该词本身所占的比重将会是最大的,使得其他词的比重很少,无法有效利用上下文信息来增强当前词的语义表示。

而乘以QKV参数矩阵,会使得每个词的q,k,v都不一样,能很大程度上减轻上述的影响。

当然,QKV参数矩阵也使得多头,类似于CNN中的多核,去捕捉更丰富的特征/信息成为可能。

3、在普通 attention 中,一般有 k=v,那 self-attention 可以嘛?[4]

self-attention实际只是attention中的一种特殊情况,因此k=v是没有问题的,也即K,V参数矩阵相同(self-attention中输入的emb是相同的,但是QKV矩阵是不同的)。

扩展到multi-head attention中,乘以Q、K、V参数矩阵之后,其实就已经保障了多头之间的差异性,在q和k点积+softmax得到相似度之后,从常规attention的角度,觉得再去乘以和k相等的v会更合理一些。

在transformer、bert中,完全独立的QKV参数矩阵,可以扩大模型的容量和表达能力。但采用Q,K=V这样的参数模型,个人认为是没有问题的,也能减少模型参数,又不影响多头的实现。

4、self-attention 在计算的过程中,如何对padding位做mask?[2]

构建和输入矩阵同样的mask矩阵,1表示有效字,0代表无效字。

5、bert的mask为何不学习transformer在attention处进行屏蔽score的技巧?[11]

bert的mask为何不学习transformer在attention处进行屏蔽score的技巧? - 知乎

用[MASK]多了一个位置信息,position embedding是有的,表示原文这个位置有一个词。如果按attention mask的方式,等于这个被遮掩的token永远不会参与计算,他就少了一个信息:“位置x有一个词”。

6、在计算attention score的时候如何对padding做mask操作?

Transformer和Bert相关知识解答 - sliderSun的文章 - 知乎

mask是将一些不要用的值掩盖掉,使其不产生作用。有两种mask,第一种是padding mask,在所有scaled dot-product attention都用到;第二种是sequence mask,在decoder的self-attention里面用到。

padding mask:因为一个批量输入中,所有序列的长度使不同的。为了符合模型的输入方式,会用padding的方式来填充(比如填0),使所有序列的长度一致。但填充部分是没有意义的,所以在计算注意力的时候,不需要也不应该有注意力分配到这些填充的值上面。所以解决方式就是在填充的位置赋予一个很小的负值/负无穷(-np.inf)的值,经过softmax后的得分为0,即没有注意力分配到这个上面。

  1. def padding_mask(seq_k, seq_q):
  2. # shape(seq_k)=(B,L_k), shape(seq_q)=(B,L_q)
  3. # 因为要计算seq_k和seq_q的相似程度,来表示注意力的得分
  4. # padding mask要作用在QK^T上,所以padding mask是跟seq_k和seq_q序列长度相关的矩阵
  5. # shape(padding mask)=(B, L_q, L_k)
  6. len_q = seq_q.size(1)
  7. # `PAD` is 0,这里要计算seq_k序列中,padding为0的地方,并将相应位置变为True,方便后面处理
  8. pad_mask = seq_k.eq(0)
  9. # 将每个seq_k序列扩展len_q次,shape=[B, L_q, L_k]
  10. pad_mask = pad_mask.unsqueeze(1).expand(-1, len_q, -1)
  11. return pad_mask
  • 以上方法为大部分padding mask的计算形式,但实际上,这里做了seq_q全部有效的假设(没有padding),并不够精确 。自己的看法:上述代码expand操作,只是将seq_k中padding的部分重复了L_q次,并没有注意到,seq_q也有padding的部分。即在一个(L_q,L_k)矩阵中,只有最后几列需要掩码,实际矩阵的最后几行也需要掩码。(以后上图更形象)

sequence mask:在decoder部分,因为不能见到下文信息(防止泄漏),所以用mask的方式掩盖掉当前时刻t及之后的下文信息。具体,可产生一个对角线为0的上三角矩阵,将其作用到每个decoder的输入列上。代码如下:

  1. def sequence_mask(seq):
  2. batch_size, seq_len = seq.size()
  3. mask = torch.triu(torch.ones((seq_len, seq_len), dtype=torch.uint8),
  4. diagonal=1)
  5. mask = mask.unsqueeze(0).expand(batch_size, -1, -1) # [B, L, L]
  6. # 三角矩阵中,为1的部分是需要被掩码掉的
  7. return mask
  • decoder-block有两个multi-head attention,下面的multi-head attention是目标输入的self-attention,需要用到1.padding mask:去除padding位置的影响;2.sequence mask:去掉下文穿越的影响。上面的multi-head attention只需要padding mask,因为下面的多头注意力已经磨平了下文信息。当encoder和decoder的输入序列长度一样时,可以通过padding mask+sequence mask作为scaled dot-product attention的attn_mask来实现。
  • 其他情况的attn_mask(代码中的表达)等于padding mask。

来源:

史上最细节的自然语言处理NLP/Transformer/BERT/Attention面试问题与答案 - 海晨威的文章 - 知乎

超细节的BERT/Transformer知识点 - 海晨威的文章 - 知乎 https://zhuanlan.zhihu.com/p/132554155

NLP 中的Mask全解 - 海晨威的文章 - 知乎 https://zhuanlan.zhihu.com/p/139595546

transformer Transformer和Bert相关知识解答 - sliderSun的文章 - 知乎

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/573160
推荐阅读
相关标签
  

闽ICP备14008679号