Bert Transformer细节总结

Self-Attention 的时间复杂度是怎么计算的?

Self-Attention时间复杂度: O ( n 2 d ) O(n^2d) O(n2d),这里,n是序列的长度,d是embedding的维度。

Self-Attention包括三个步骤:相似度计算softmax加权平均,它们分别的时间复杂度是:

相似度计算可以看作大小为(n,d)和(d,n)的两个矩阵相乘: ( n , d ) ∗ ( d , n ) = O ( n 2 d ) (n,d)*(d,n)=O(n^2d) (n,d)(d,n)=O(n2d),得到一个(n,n)的矩阵

softmax就是直接计算了,时间复杂度为 O ( n 2 ) O(n^2) O(n2)

加权平均可以看作大小为(n,n)和(n,d)的两个矩阵相乘: ( n , n ) ∗ ( n , d ) = O ( n 2 d ) (n,n)*(n,d)=O(n^2d) (n,n)(n,d)=O(n2d) ,得到一个(n,d)的矩阵

因此,Self-Attention的时间复杂度是 O ( n 2 d ) O(n^2d) O(n2d)

这里再分析一下Multi-Head Attention,它的作用类似于CNN中的多核。

多头的实现不是循环的计算每个头,而是通过 transposes and reshapes,用矩阵乘法来完成的。

In practice, the multi-headed attention are done with transposes and reshapes rather than actual separate tensors. —— 来自 google BERT 源码

Transformer/BERT中把 d ,也就是hidden_size/embedding_size这个维度做了reshape拆分,可以去看Google的TF源码或者上面的pytorch源码:

hidden_size (d) = num_attention_heads (m) * attention_head_size (a),也即 d=m*a

并将 num_attention_heads 维度transpose到前面,使得Q和K的维度都是(m,n,a),这里不考虑batch维度。

这样点积可以看作大小为(m,n,d)和(m,d,n)的两个张量相乘,得到一个(m,n,n)的矩阵,其实就相当于m个头,时间复杂度是 O ( m n 2 d ) O(m n^2d) O(mn2d)

张量乘法时间复杂度分析参见:矩阵、张量乘法的时间复杂度分析

因此Multi-Head Attention时间复杂度就是 O ( m n 2 d ) O(m n^2d) O(mn2d),而实际上,张量乘法可以加速,因此实际复杂度会更低一些。

Transformer的并行化体现在哪个地方?Decoder端可以做并行化吗?

训练时一个 batch 的句子是一起生成的,而且每个句子的每个词也是一起生成的。encoder是并行的,训练的时候decoder也是并行的,但是inference的时候不是,因为你没有golden label,只能一个一个产生,所以decoder端跟RNN一样还是自回归的。细节看源码吧,tensor2tensor或者THUMT的transformer实现。

Transformer计算attention的时候为何选择点乘而不是加法?两者计算复杂度和效果上有什么区别?


Bert Transformer细节总结_第1张图片

为什么transformer块使用LayerNorm而不是BatchNorm?LayerNorm 在Transformer的位置是哪里?

Batch Normalization 的处理对象是对一批样本, Layer Normalization 的处理对象是单个样本。Batch Normalization 是对这批样本的同一维度特征做归一化, Layer Normalization 是对这单个样本的所有维度特征做归一化。

众所周知,无论在CV还是NLP中,深度模型都离不开归一化技术(Normalization)。在CV中,深度网络中一般会嵌入批归一化(BatchNorm,BN)单元,比如ResNet;而NLP中,则往往向深度网络中插入层归一化(LayerNorm,LN)单元,比如Transformer。

为什么在归一化问题上会有分歧呢?一个最直接的理由就是,BN用在NLP任务里实在太差了(相比LN),此外,BN还难以直接用在RNN中[1],而RNN是前一个NLP时代的最流行模型。

虽然有大量的实验观测,表明NLP任务里普遍BN比LN差太多,但是迄今为止,依然没有一个非常严谨的理论来证明LN相比BN在NLP任务里的优越性。甚至,连BN自身为什么work的问题都一直存在争议。

早期对BN有效性的解释是其有助于缓解神经网络“内部协方差漂移”(Internal Covariance Shift,ICS)问题。即,后面的层的学习是基于前面层的分布来的,只有前面一层的分布是确定的,后面的层才容易学习到有效的模式,然而,由于前面的层的分布会随着batch的变化而有所变动,导致了后面的层看来“前面一直在动,我无法安心学习呀”。

而BatchNorm这类归一化技术,目的就是让每一层的分布稳定下来,让后面的层可以在前面层的基础上安心学习知识。顾名思义,BatchNorm就是通过对batch size这个维度归一化来让分布稳定下来。LayerNorm则是通过对Hidden size这个维度归一化来让某层的分布稳定。

BN、LN可以看作横向和纵向的区别。
经过归一化再输入激活函数,得到的值大部分会落入非线性函数的线性区,导数远离导数饱和区,避免了梯度消失,这样来加速训练收敛过程。

BatchNorm这类归一化技术,目的就是让每一层的分布稳定下来,让后面的层可以在前面层的基础上安心学习知识。

为什么要舍弃 BN 改用 LN 呢?朴素版的 BN 是为 CNN 任务提出的,需要较大的 BatchSize 来保证统计量的可靠性,并在训练阶段记录全局的 μ \mu μ σ \sigma σ供预测任务使用。对于天然变长的 RNN 任务,需要对每个神经元进行在每个时序的状态进行统计。这不仅把原本非常简单的 BN 流程变复杂,更导致偏长的序列位置统计量不足。相比之下,LN 的使用限制就小很多,不需要在预测中使用训练阶段的统计量,即使 BatchSize = 1 也毫无影响。

个人理解,对于 CNN 图像类任务,每个卷积核可以看做特定的特征抽取器,对其输出做统计是有理可循的;对于 RNN 序列类任务,统计特定时序每个隐层的输出,毫无道理可言——序列中的绝对位置并没有什么显著的相关性。相反,同一样本同一时序同一层内,不同神经元节点处理的是相同的输入,在它们的输出间做统计合理得多。

简单描述一下wordpiece model 和 byte pair encoding,有实际应用过吗

传统词表示方法无法很好的处理未知或罕见的词汇(OOV问题)
传统词tokenization方法不利于模型学习词缀之间的关系
E.g. 模型学到的“old”, “older”, and “oldest”之间的关系无法泛化到“smart”, “smarter”, and “smartest”。
Character embedding作为OOV的解决方法粒度太细
Subword粒度在词与字符之间,能够较好的平衡OOV问题

BPE(字节对)编码或二元编码是一种简单的数据压缩形式,其中最常见的一对连续字节数据被替换为该数据中不存在的字节[2]。 后期使用时需要一个替换表来重建原始数据。OpenAI GPT-2 与Facebook RoBERTa均采用此方法构建subword vector.

优点
可以有效地平衡词汇表大小和步数(编码句子所需的token数量)。
缺点
基于贪婪和确定的符号替换,不能提供带概率的多个分片结果。

WordPiece算法可以看作是BPE的变种。不同点在于,WordPiece基于概率生成新的subword而不是下一最高频字节对。
From https://zhuanlan.zhihu.com/p/86965595

Decoder阶段的多头自注意力和encoder的多头自注意力有什么区别?(为什么需要decoder自注意力需要进行 sequence mask)

Transformer在训练的时候是并行执行的,所以在decoder的第一个sublayer里需要seq mask,其目的就是为了在预测未来数据时把这些未来的数据屏蔽掉,防止数据泄露。如果我们非要去串行执行training,seq mask其实就不需要了。

From: https://www.zhihu.com/question/369075515/answer/994819222

Transformer在哪里做了权重共享,为什么可以做权重共享?

(1)Encoder和Decoder间的Embedding层权重共享;

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

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

“In our model, we share the same weight matrix between the two embedding layers and the pre-softmax linear transformation, similar to [30].”

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

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

该点参考:https://www.zhihu.com/question/333419099/answer/743341017

对于(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 源码发现真的可以直接共享:

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

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

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

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

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

这里补充一下bert的输出,有两种:

一种是get_pooled_out(),就是上述[CLS]的表示,输出shape是[batch size,hidden size]。

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

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

概括来说,两个原因:

  1. 实现多头,类似于CNN中的多核,去捕捉更丰富的特征/信息成为可能。
  2. Self-Attention的核心是用文本中的其它词来增强目标词的语义表示,从而更好的利用上下文的信息。self-attention中,sequence中的每个词都会和sequence中的每个词做点积去计算相似度,也包括这个词本身。如果不乘QKV参数矩阵,那这个词对应的q,k,v就是完全一样的。

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

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

如果不乘QKV参数矩阵,那这个词对应的q,k,v就是完全一样的。

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

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

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

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

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

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

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

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

上述非官方解释,是来自我的一位朋友提供的一个理解切入的角度,供参考。

BERT非线性的来源在哪里?

前馈层的gelu激活函数和self-attention,self-attention是非线性的,感谢评论区指出。

Transformer的正则化

  • 正则化: We apply dropout [33] to the output of each sub-layer, before it is added to the
    sub-layer input and normalized. In addition, we apply dropout to the sums of the embeddings and the positional encodings in both the encoder and decoder stacks
  • Label Smoothing:这样真实类别概率和其他类别的概率均值之间的gap(倍数)就会下降一些,降低模型过度自信,提升模型的泛华能力。
    Bert Transformer细节总结_第2张图片

Bert 如何解决长文本问题?

举例: 在阅读理解问题中,article 常常长达1000+, 而Bert 对于这个量级的表示并不支持, 诸位有没有什么好的解决办法, 除了分段来做?或者提一提如何分段来做。感谢诸位大佬。
这是个好问题,可以看下Amazon今年EMNLP的这篇文章:Multi-passage BERT 主要思路是global norm + passage rank + sliding window实验做的很扎实,从ablation study看这几个trick都很有用。如果不想切passages就上XLNet吧。

Transformer为何使用多头注意力机制?(为什么不使用一个头)

简单回答就是,多头保证了transformer可以注意到不同子空间的信息,捕捉到更加丰富的特征信息。其实本质上是论文原作者发现这样效果确实好。举个例子例如“川普”

BERT的三个Embedding直接相加会对语义有影响吗?

Embedding的数学本质,就是以one hot为输入的单层全连接。请参考: https://kexue.fm/archives/4122也就是说,世界上本没什么Embedding,有的只是one hot。现在我们将token,position,segment三者都用one hot表示,然后concat起来,然后才去过一个单层全连接,等价的效果就是三个Embedding相加

作者:苏剑林
链接:https://www.zhihu.com/question/374835153/answer/1042845667
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

transformer中的attention为什么scaled?

假设向量 q和 k 的各个分量是互相独立的随机变量,均值是0,方差是1,那么点积qk 的均值是0,方差是 d k d_k dk将方差控制为1,也就有效地控制了前面提到的梯度消失的问题。这里我给出一点更详细的推导:
Bert Transformer细节总结_第3张图片
Bert Transformer细节总结_第4张图片

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

这是Google BERT预训练模型初始设置的原因,前者对应Position Embeddings,后者对应Segment Embeddings

在BERT中,Token,Position,Segment Embeddings 都是通过学习来得到的,pytorch代码中它们是这样的

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

上述BERT pytorch代码来自:https://github.com/xieyufei1993/Bert-Pytorch-Chinese-TextClassification,结构层次非常清晰。

而在BERT config中

"max_position_embeddings": 512
"type_vocab_size": 2

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

当然,如果有足够的硬件资源自己重新训练BERT,可以更改 BERT config,设置更大max_position_embeddings 和 type_vocab_size值去满足自己的需求。

Bert后的模型改进

  • XLNet: Attention Mask的机制,核心就是说,尽管当前输入看上去仍然是x1->x2->x3->x4,但是我们已经改成随机排列组合的另外一个顺序x3->x2->x4->x1了,如果用这个例子用来从左到右训练LM,意味着当预测x2的时候,它只能看到上文x3;当预测x4的时候,只能看到上文x3和x2,以此类推……这样,比如对于x2来说,就看到了下文x3了。这种在输入侧维持表面的X句子单词顺序,但是其实在Transformer内部,看到的已经是被重新排列组合后的顺序,是通过Attention掩码来实现的。如上图所示,输入看上去仍然是x1,x2,x3,x4,可以通过不同的掩码矩阵,让当前单词Xi只能看到被排列组合后的顺序x3->x2->x4->x1中自己前面的单词。这样就在内部改成了被预测单词同时看到上下文单词,但是输入侧看上去仍然维持原先的单词顺序了。关键要看明白上图右侧那个掩码矩阵,我相信很多人刚开始没看明白,因为我刚开始也没看明白,因为没有标出掩码矩阵的单词坐标,它的坐标是1-2-3-4,就是表面那个X的单词顺序,通过掩码矩阵,就能改成你想要的排列组合,并让当前单词看到它该看到的所谓上文,其实是掺杂了上文和下文的内容。这是attention mask来实现排列组合的背后的意思。 上面讲的Permutation Language Model是XLNet的主要理论创新,所以介绍的比较多,从模型角度讲,这个创新还是挺有意思的,因为它开启了自回归语言模型如何引入下文的一个思路,相信对于后续工作会有启发。当然,XLNet不仅仅做了这些,它还引入了其它的因素,也算是一个当前有效技术的集成体。感觉XLNet就是Bert、GPT 2.0和Transformer XL的综合体变身,首先,它通过PLM预训练目标,吸收了Bert的双向语言模型;然后,GPT2.0的核心其实是更多更高质量的预训练数据,这个明显也被XLNet吸收进来了;再然后,Transformer XL的主要思想也被吸收进来,它的主要目标是解决Transformer对于长文档NLP应用不够友好的问题。
  • RoBERTa:一开始把预训练的数据复制10份,每一份都随机选择15%的Tokens进行Masking,也就是说,同样的一句话有10种不同的mask方式。然后每份数据都训练N/10个epoch。这就相当于在这N个epoch的训练中,每个序列的被mask的tokens是会变化的。这就叫做动态Masking
  • 基于Knowledge Graph的改进: KG-BERT(a),输入为三元组 (h,r,t)的形式,当然还有BERT自带的special tokens。举个栗子,对于三元组 ( S t e v e n J o b s , F o u n d e r , A p p l e ) (Steven Jobs, Founder, Apple) (StevenJobs,Founder,Apple) ,上图中的Head Entity输入可以表示为Steven Paul Jobs was an American business magnate, entrepreneur and investor或者Steve Jobs,而Tail Entity可以表示为Apple Inc. is an American multinational technology company headquartered in Cupertino, California或Apple Inc。也就是说,头尾实体的输入可以是实体描述句子或者实体名本身。

简单介绍一下Transformer的位置编码?有什么意义和优缺点?

Bert Transformer细节总结_第5张图片
Bert Transformer细节总结_第6张图片
部分转载自: https://zhuanlan.zhihu.com/p/60821628

你可能感兴趣的:(机器学习,算法)