预训练语言模型的学习方法有三类:自编码(auto-encode, AE)、自回归(auto regressive, AR),Encoder-Decoder结构。
决定PTM模型表现的真正原因主要有以下几点:
- 更高质量、更多数量的预训练数据
- 增加模型容量及复杂度,例如Google T5增加纵向复杂度,ALBERT增加横向复杂度,GPT 3结合两者。
- 更充分地训练模型,例如RoBERTa,增大batch_size和epoch训练步数
- 有难度的预训练任务,例如不同的mask方式(单词、短语),不同的句子级别任务(NSP,SOP)。
参考:
深度学习中的注意力模型
抛除RNN的Self-Attention模型以及谷歌的Transformer架构
attention及transformer在自然语言处理及图像处理等方面的应用
BERT大火却不懂transformer?读这一篇就够了
一文读懂bert(原理篇)
从word embedding到bert模型--自然语言处理中的预训练技术发展史
乘风破浪的PTM:两年来预训练模型的技术发展
语言模型
语言模型是为了量化地衡量哪个句子更有可能出现。核心函数P的思想是根据句子里面前面的一系列前导单词预测后面跟哪个单词的概率大小(理论上除了上文之外,也可以引入单词的下文联合起来预测单词出现概率)。
NNLM(神经网络语言模型,2003年发表,是后续NLP模型的鼻祖)的学习任务是输入某个句中单词W_t = "bert"前面句子的t-1个单词,要求网络正确预测单词Bert。
原始输入:onehot编码
上一层:单词embedding向量
再上一层:神经网络层
输出:softmax预测单词
word Embedding:Word2vec
Word2vec(2013年提出,最火的用语言模型做word embedding的工具)
Word2Vec有两种训练方法,一种叫CBOW,核心思想是从一个句子里面把一个词抠掉,用这个词的上文和下文去预测被抠掉的这个词;第二种叫做Skip-gram,和CBOW正好反过来,输入某个单词,要求网络预测它的上下文单词。
如何应用在下游任务中?
word embedding等价于将onehot层到embedding层的网络用预训练好的参数矩阵Q初始化了。下游任务使用word embedding有两种方式:一种是Frozen,就是Word Embedding那层网络参数固定不动;另外一种是Fine-Tuning,就是Word Embedding这层参数使用新的训练集合训练也需要跟着训练过程更新掉。
原理
word2vec的核心假设是拥有相似上下文的词相似。
技巧
skip-gram方法适用于小型语料库或者专业术语中,因为使用这种方式可以得到更多的训练数据,例如在5-grams中可以得到4个训练对。可用经验采样频率公式进行采样。
skip-gram的算法数据计算样本非常多。为了降低计算量,有两个方法:
- 对高频词抽样。它的基本思想如下:对于我们在训练原始文本中遇到的每一个单词,它们都有一定概率被我们从文本中删掉,而这个被删除的概率与单词的频率有关。抽样率与单词在所有语料中出现的频次有关,频次越高,保留这个单词的概率就越低。P(w_i)=(\sqrt \frac{Z(w_i)}{0.001}+1)\times \frac{0.001}{Z(w_i)}【出现频次低于0.26%的词是100%被保留的。】
- negative sampling负采样。负采样每次随机选择一小部分的negative words来更新对应的权重,假设vocab共有10000个词,隐藏层有300个节点,而负采样5个负样本,则需要更新的参数量就由原来的300*10000降为0.06%,这样计算效率大幅提高【多维的softmax多分类器转化为5个sigmoid函数输出的二分类器】。一个单词被选作negative sample的概率跟它出现的频次有关,出现频次越高的单词越容易被选作negative words。P(w_i)=\frac{f(w_i)^{3/4}}{\sum_{j=0}^n f(w_j)^{3/4}}
- 工程实现:有一个包含一亿个元素的数组,数组是由词汇表中每个单词的索引号填充的,并且这个数组中有重复,也就是说有些单词会出现多次,单词出现次数为P(w_i)*1亿。因此在做负采样的时候,随机在0~1亿中生成一个数,然后选择表中索引号为这个随机数的那个单词作为我们的negative word即可。
使用cbow方法可以对出现频次较高的词提高精度,并且训练速度更快。
对于小规模数据集,建议选择 5-20 个 negative words,对于大规模数据集选择 2-5个 negative words.
局限性?
1.无法解决一词多义的现象;2.无法区分同义词和反义词,例如最大/最小,苹果/香蕉。
encoder-decoder模型
transformer
Attention is All You Need,2017年谷歌发表
tansformer本身是一个典型的encoder-decoder模型。encoder端由N个结构相同的大模块block堆叠而成(文章中N=6),每个大模块又由两个子模块构成,分别为多头自注意力模块和前馈神经网络,decoder端也是由相同数量的大模块堆叠而成,每个大模块由三个子模块构成,分别为多头自注意力, 多头编码-解码注意力层,前馈神经网络。
一、Multi-Head attention模块
self-attention模块
self-attention的过程对应Q,K,V矩阵得到Z的过程。
Attention(Q,K,V)= softmax(\frac{QK^T}{\sqrt{d_k}})V
这里的d_k指的是key向量的维度,例如文章中取的是64,那么下根号之后就是8。除\sqrt{d_k}是为了把注意力矩阵变成标准正态分布,使得softmax归一化之后的结果更加稳定,以便反向传播的时候获取平衡的梯度。不做softmax的话某个输入太大就会使权重接近1,导致梯度很小。
在编码某个单词的时候,将所有单词的值向量value进行加权求和,而权重是通过该词的查询向量query与其他所有词的键向量key的点积并通过softmax得到。q与k点积的含义是将当前词作为搜索的query,与句子中所有词的key去匹配,得到相关性。
multihead(多头)就是我们使用多个Q,K,V的参数矩阵,最后再将其结果结合拼接起来,送入一个全连接层得到输出Z。
多头主要是扩展了模型专注于不同位置的能力,提取多重语义。
例如在翻译"The animal didn't cross the street because it was too tired"时,需要知道这个it指的是什么。这时一个注意力头集中在animal上,另一个则集中在tired上。
self-attention的计算量:dN^2,其中d是embedding size, N是句子输入长度,因为每两个输入之间都要计算一遍,每次计算的复杂度为d。
使用Q/K不相同可以保证在不同空间进行投影,增强了表达能力,提高了泛化能力。
二、encoder端
输入:
embedding + position coding
为了让模型学习位置信息,添加position encoding并将其叠加在word embedding上。可选择正弦和余弦函数。为什么用正弦余弦函数?因为这样操作之后position encoding矩阵乘它本身的转置得到的矩阵可看到两个字之间的关系,这时两个字离的越近,相关程度越高,离的越远系数会越低,这与我们的认知是一致的。
【bert后来是用的position embedding,也就是说它的位置编码是学习的值,而不是直接用正弦余弦函数。】
结构:
encoder端有6层,每层由两个子层组成。第一个子层是多头自注意力模块+残差连接+LN,第二层是前馈神经网络+残差连接+LN。
自注意力模块前面已经讲过了,下面介绍下其他模块。
- Add & Norm:Add表示Residual Connection(残差连接),训练的时候可以使梯度直接走捷径反传到最初始层,避免梯度消失;norm指的是layer norm,作用是把神经网络中隐藏层归一为标准正态分布,以起到加快训练速度,加速收敛的作用。
【LN和BN的区别主要是规范化的维度不同,bn针对一个batch里面的数据做归一化,针对单个神经元进行,而l n针对单个样本做归一化,就bert而言就是对每层输出的隐藏层向量做规范化。
因为在文本领域中,按照位置对单词特征进行缩放,是违背直觉的。】 - Feed forward network 前馈神经网络,由两个线性变换+一个relu激活函数。第一个线性变换拓展维度,第二次压缩维度。
三、decoder端
decoder的基本单元与encoder的基本单元不同的地方在于:
- 第一级的Multi-head加入了Masked操作。这是因为我们只能attend到前面已经翻译过的输出的词语,因为翻译过程中我们当前还不知道下一个输出词语。具体操作是将Q、K矩阵获得的attention score矩阵的右上对角线用一个-∞进行替换,这样经过softmax之后对应位置会变成0,这样每个词向量的生成与它后面的词向量无关。
- 第二级的Multi-Head Attention也称为encoder-decoder attention layer,它的query来自于之前一级的decoder层的输出,但其key 和value来自于encoder的输出,这使得decoder的每一个位置都可以attend到输入序列的每一个位置。
最终经过线性变换Linear和softmax层。线性变换层是一个简单的全连接神经网络,它可以把解码组件产生的向量投射到一个比它大得多的,被称作对数几率(logits)的向量里。
Google T5
在进行预训练的时候,Encoder和Decoder会同时对不同Mask部分进行预测:Encoder侧双向语言模型生成被随机Mask掉的部分单词;Decoder侧单向语言模型从左到右生成被Mask掉的一部分连续片断。两个任务联合训练,这样Encoder和Decoder两侧都可以得到比较充分地训练。
CPT 【参数量base: 121M, large: 393M】
CPT: A Pre-Trained Unbalanced Transformer for Both Chinese Language Understanding and Generation
模型结构:
- 不均衡的transformer,较多层的encoder端和较少层的decoder端
- 有两个decoder端,能够同时完成NLU和NLG任务
预训练任务:
MLM+DAE(denoting auto-encoding)
特点: - 可以有至少五种方式去fine-tune完成分类任务:直接用U-dec;或者直接用G-dec的最后一个输出;或者结合U-dec和G-dec;
对比之前的模型框架,优势:1.同时兼顾NLU和NLG;2.是中文版本;3.多任务预训练。
单向语言模型:GPT, GPT-2, GPT-3
GPT: Improving Language Understanding by Generative Pre-Training,2018年6月提出)
GPT也采用两阶段过程,第一个阶段是利用语言模型进行预训练,第二阶段通过Fine-tuning的模式解决下游任务。
模型结构:transformer的解码器;
预训练任务:单向的语言模型,即根据前面k个词语预测下一个词语。
GPT-2: Language Models are Unsupervised Multitask Learners 参数量:1.5B
GPT-2的模型结构与GPT基本一致,只是用了更大的模型和更大的数据集。
亮点是提出了模型不需要根据下游任务进行微调,而是直接通过prompt(提示词)来生成补全提示词的句子。
GPT-3:Language Models are Few-Shot Learners (2020年5月) 参数量:200B
GPT3主要的卖点有两个:1. 不需要fine_tuning,直接通过zero-shot,one-shot, few_shot的方式来告诉模型要完成什么任务;2.大的模型,大的数据集。
它的主要特点如下:
1.语言生成:通过prompt来生成补全提示词的句子;
2.上下文学习(in-context learning):指在不进行参数更新的情况下,只在输入中加入几个示例就能让模型进行学习;【in-context learning的核心是类比学习。三个优势:1,演示样例用自然语言格式编写,十分简易;2.类似于人类通过类比学习的决策过程;3.无需重新训练模型】
GPT-3拥有的In-context learning能力可以说有很大程度来自于其庞大的参数量和训练数据,但是具体能力来源仍然难以溯源。
3.世界知识。
GTP3在上下文学习中,获得了一种Chain-of-thought能力,对输入的Prompt采用Chain-of-thought的思想进行改写。在这种方式下,模型能回答一些原本直接输出会产生错误的题。
GPT,GPT-2, GPT-3都是自回归语言模型(AutoRegressive,简称AR)。自回归模型的定义是上一个时刻模型的输出会接到模型输入的后面,一起成为这一个时刻的模型输入。第一次采用这种方式的模型是RNN,这些模型的预训练任务都是从左至右的单项语言模型。
双向语言模型:BERT
BERT
BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding,2018年10月
一、 模型结构
模型结构:transformer的encoder端,由12层transformer layer构成。
预训练阶段用两种预训练方式:
1.Masked LM(language model),这点和CBOW相似。15%的token中,80%的几率替换成mask,10%的几率被替换为任意一个其他的token,10%的几率原封不动,模型预测和还原被遮盖掉或替换掉的部分。
2.next sentence prediction,判断两个句子是否在文章中互为上下句,然后使用了大规模的语料去预训练。
bert的输入部分是个线性序列,两个句子通过分隔符分割,最前面和最后增加两个标识符号。每个单词有三个embedding: word embedding + position embedding + segment embedding。
文章中的参数细节:
以BERT base为例
transformer_block=12, embedding_dimension = 768, num_heads=12
- embedding 层参数
- 词嵌入部分。分为三块:token embedding ,segment embedding和position embedding。其中词表有30522个词/token;Segment Embedding包括2个取值,分别表示当前token属于第一个句子还是第二个句子;Position Embedding包括512个取值,这里对应的Bert编码长度不超过512,因为设计时位置编码只有512种可能。每种embedding都会把token映射到768维的隐向量中。因此总数是
- Layer Norm部分。参数包括均值和方差。因此这一层对应的参数为。【每一维都有均值和方差】
- encoder层参数
- multi-head attention。有12个、、矩阵,每个矩阵都会把768维的向量映射成768/12维的向量,所以每个矩阵的大小都是768*(768/12),对应的偏置是768/12。因此这一块的参数是。接着要把拼接好的多头输出经过一个全连接层,这部分的参数是。
- add&Norm。add没有参数量,Norm的参数量是=1536
- Feed Forward。这里有两层全连接层,第一层全连接层升维扩充到4倍当前维度的中间层,第二层会降维,将其降到初始维度。总的参数量:
- add&Norm。add没有参数量,Norm的参数量是
- BERT base共有12层这样的transformer encoder结构,所以这里的参数量:12*(1771776+590592+1536+4722432+1536)=85054464
- pooling层
- 输入是encoder层输出的768维结果,输出维度保持不变。所以参数量为
- 总参数量:23837184+85054464+590592=109482240
- bert预训练技巧:1.对于句子中的英文单词,应该将英文单词所在区域一起遮盖掉,让模型预测这个部分;2.对句子中的数字,应该将原文中的数字都替换成一个特殊的token,#NUM#,模型只有预测出这个地方是某些数字即可。
- 二、 bert的应用
- NLP的四大类任务:
- 序列标注:分词/POS tag(词性标注)/NER(命名实体识别)/语义标注
- 分类任务:文本分类/情感计算
- 句子关系判断:Entailment/QA问答/自然语言推理
- 生成式任务:机器翻译/文本摘要
- 第一类任务的特点是句子中每个单词要求模型根据上下文都要给出一个分类类别;
- 第二类任务的特点是不管文章有多长,总体给出一个分类类别即可;
- 第三类任务是句子关系判断,他的特点是给定两个句子,判断出两个句子是否具备某种语义关系;
- 第四类是生成式任务,特点是输入文本内容后,需要自主生成另一段文字。【bert效果不好】
- BERT对不同任务的改造方法:
- 对于分类任务,对输入加上一个起始和终结符号即可;输出把第一个起始符号对应的transformer最后一层位置上面串联一个softmax分类层即可;
- 对于句子关系类任务,加上一个起始和终结符号,句子之间加个间隔符即可;输出和前面相同;
- 对于标注问题,输入部分和单句分类相同,只需要输出部分Transformer最后一层每个单词对应位置都进行分类即可;
- 对于生成式任务,只需要附着在S2S结构上,encoder部分是个深度Transformer结构,decoder部分也是个深度Transformer结构。根据任务选择不同的预训练数据初始化encoder和decoder即可。
- BERT擅于解决具备什么样特征的NLP任务?
- 1.偏向于语言本身信息,而不特别依赖文本外其他特征。例如QA和阅读理解就比搜索场景更适合用BERT;
- 2.更适合解决句子或段落的匹配类任务,即句子对任务。这可能是由于NSP预训练任务导致的;
- 3.BERT更适合对深层语义特征需求较高的任务,例如QA,而浅层特征性任务比如分词,NER等就发挥余地不大;
- 4.BERT比较适合处理输入长度不太长的NLP任务,因为输入n太长会导致self attention编码的时间复杂度为O(n^2)
- 三、优点和不足之处
- 优点:
- attention机制解决一词多义,并且因为是双向学习,学到的embedding向量信息更丰富;而且可以并行计算;
- 多头可以注意到不同子空间的信息;
- 预训练任务用的无监督数据,因此可以使用大量数据;
- 能够学习到词的多层特征。高层中产生的特征更多地体现了抽象的、依赖于上下文的部分,而低层产生的特征更关注语法层面的部分
- BERT在做文本表达任务时存在两个明显的问题:
- Bert encode出来的向量表达具有各向异性。也就是说向量不能完整的衡量出bert向量中的全部语义信息,采用cos或dot是无法很好的衡量出两个句子的相似度的,因为bert向量不是基于一个标准正交基得到的。
- 分布不均匀,低频词分布稀疏,高频词分布紧密。也就是高频词会集中在头部,离原点近,低频词会集中在尾部,离原点远。这说明低频词没有得到很好的训练,而且因为高频词与低频词分布在不同的区域,那高频词与低频词之间的相识度也就没法计算了。
预训练模型中的强基准:RoberTa
- https://arxiv.org/abs/1907.11692 2019年
- 预训练模型中的强基准:RoBERTa
- 可以把RoBERTa看作是得到充分训练的Bert模型,而原始版本的Bert模型训练不够充分。
- 在原始Bert模型的基础上,RoBERTa通过实验,证明了如下几点:
- 进一步增加预训练数据数量,能够改善模型效果;
- 延长预训练时间或增加预训练步数,能够改善模型效果;
- 急剧放大预训练的每个batch的batch size, 能够明显改善模型效果;(每次迭代更稳定,但受性能限制)
- 拿掉预训练任务中的next sentence prediction子任务,它不必要存在;
- 输入文本的动态masking策略有帮助。即每一次都对同样的sentence产生不同的掩码。在对更大的数据进行更长时间的预训练时,动态掩码比静态掩码效果更好。
- 对于追求落地效果的人来说,比如公司里做业务的同学,建议以RoBERTa为基础模型来做应用。
Albert
- https://openreview.net/pdf?id=H1eA7AEtvS 2020年
- https://github.com/brightmart/albert_zh
- 提出两种方法去降低内存消耗,提升模型训练速度:
- a factorized embedding parameterization (embdding向量的因式分解)
- O(V * H) to O(V * E + E * H)
如以ALBert_xxlarge为例,V=30000, H=4096, E=128
那么原先参数为V * H= 30000 * 4096 = 1.23亿个参数,现在则为V * E + E * H = 30000128+1284096 = 384万 + 52万 = 436万,
词嵌入相关的参数变化前是变换后的28倍。
-
原因是transformer学习到的隐向量应该是要比初始的embedding向量学习到的东西更多的。
-
cross-layer parameter sharing (跨层参数共享)
-
inter-sentence coherence loss (段落连续性任务)
使用段落连续性任务(sentence order prediction)。正例,使用从一个文档中连续的两个文本段落;负例,使用从一个文档中连续的两个文本段落,但位置调换了。
避免使用原有的NSP任务,原有的任务包含隐含了预测主题这类过于简单的任务。
- 其他改动:
- 1.去掉dropout,因为发现bert本身就是欠拟合的。
sentence-bert
- Sentence-BERT: Sentence Embeddings using Siamese BERT-Networks 2019年
- 文本相似度
- jaccard距离
- 编辑距离
- tf-idf
- BM25
- 丢弃无意义词之后判断
- 语义相似度
- 传统语义相关性:LSA、LDA
- 深度学习语义匹配:
- 基于表征学习【一般用于召回,可以离线计算doc的编码,在线时只需编码query即可,效率高,但精度低】:word2vec,DSSM;
- 基于交互学习【一般用于精排。需要在线编码query和doc,当doc较多时,效率是很低的。】:BERT;
- 基于表征+交互:poly-encoder
- 文本相似度
- 仅仅使用bert来分别表示query和doc,然后通过点积或者余弦相似度计算query和doc的分数的方法精度较低。原因是在不fine-tuning的情况下,因为CLS本身在预训练时候的任务就是在编码NSP任务,并不是在学习sentence语义的。
- sentence-bert就是用siamese network孪生网络的方式训练bert,上层通过cosine做判别,能够让bert学习到一种适用于cosine作为最终相似度判别的sentence embedding。
- 使用文档:https://www.sbert.net/index.html
NEZHA
- nezha在bert的基础上做了一些改进:
- Functional Relative Positional Encoding 相对位置编码;
- Whole Word Masking 词掩码而不是字掩码;
- Mixed precision training
- LAMB Optimizer