预训练语言模型(PLM)- 基础汇总篇(一)
时间:2023-03-13 15:10:01 | 来源:电子商务
时间:2023-03-13 15:10:01 来源:电子商务
预训练语言模型(PLM)- 基础汇总篇(一)
Reference:
https://zhuanlan.zhihu.com/p/93781241 https://www.jiqizhixin.com/articles/2018-12-17-17paper&code:
https://huggingface.co/transformers/Chapter:Word Embedding
实现将one-hot representation的高维稀疏特征表示,映射到distributed representation的低维稠密特征表示,并保留原来高维空间中的structure features。常用的word embedding方法有word2vector和glove两种。
Word2Vec
Word2vector方法主要有两类,分别是CBOW和Skip-gram。
CBOW: 给定一个词语的上下文,预测这个中心词本身。
Skip-gram: 给定一个中心词,预测它的上下文词语。
由于计算过程中涉及到softmax函数,在整个词典大小规模下进行这个计算,时间复杂度大,因此,提出了两种训练优化思路,分别是
hierarchical softmax和
negative sampling 。
- 映射层将上下文词向量直接相加而不是拼接,去掉了隐藏层。
- Word2vec方法针对某个句子固定窗口大小的文本,并不是全局最优解。
- hierarchical softmax在每个分裂节点上将问题转化为二分类问题,复杂度下降到O(log N)。
- Skip-gram negative sample算法本质上是一种PPMI矩阵分解方式。
- 经验上,Skip-gram negative sample优于CBOW,一般使用输入向量。
- 经验上,训练时将低频词映射为统一符号<unk>,并加入到词表中。<unk>也表示OOV单词。
原论文1:
http://proceedings.mlr.press/v32/le14.pdf原论文2:
https://arxiv.org/pdf/1301.3781.pdf经典讲解:
https://arxiv.org/pdf/1411.2738.pdf公式推导:
https://arxiv.org/pdf/1402.3722.pdf数学原理:
https://www.cnblogs.com/peghoty/p/3857839.html源码解析:
https://blog.csdn.net/mytestmy/article/details/26969149gensim使用Word2vec:
https://rare-technologies.com/word2vec-tutorial/代码实现:
https://github.com/xixiaoyao/CS224n-winter-together/tree/master/Assignments/assignment2Golve相比于局部上下文信息的word2vec方法,Glove在局部特征的基础上,还利用了语料库的全局统计信息。为了实现这一功能,Glove提出了
共现概率矩阵。
共现矩阵:矩阵的每一行表示中心词;每一列表示上下文词;矩阵中的每一个值
X_{i,j} ,表示在整个语料库中,所在行中心词
word i 的上下文中,出现所在列的上下文词
word j 的总次数(上下文用固定窗口统计)。那么
{X_{i}} = /sum_k X_{i,k} ,表示出现在以
word i为中心词的上下文中所有单词的总次数。
共现概率矩阵:
令共现概率矩阵中的每一个元素
P_{i,j} = P(j|i) = /frac{X_{i,j}}{X_{i}} 表示
word j 出现在中心词
word i的上下文中的概率。
以原论文中Table 1的场景为例,对于矩阵中以ice为中心词
P(k|ice) 和以steam为中心词
P(k|steam) 这两行,我们可以将对应元素相除,得到
Ratio= P(k|ice) / P(k|steam) 。当
Ratio 值趋近于1时,表示单词
K 同时与单词ice和单词steam相关(或不相关)。当
Ratio 值很大时,表示单词
K 与单词ice相关,但是和单词steam不相关。
通过
Ratio = F(w_i, w_i, w_k) = /frac{P(k|i)} {P(k|j)} ,可以推导出损失函数
J = /sum_{i,k}f(X_{i,k}) (w_i^T /cdot w_k + b_i + b_k - log X_{i,k})^2 /label{eq:Glove}/tag{1} 其中,加入
f(X_{i,k}) 一项,是由于在真实场景中,
X_{i,j} 的数值不同,代表不同组词共现的次数不同,我们可以对共现次数较多的代价函数,乘上一个更大的权重。(详见参考文献及资料)
- Glove算法结合了基于全局统计信息的LSA算法的特点,但是LSA的SVD无法在线更新,且容易维度灾难,时间复杂度高。
- Glove算法也结合了基于局部上下文特征的word2vec算法的特点,同时也通过迭代训练收敛优化,但是word2vec没有充分利用统计信息。
- Glove算法的物理解释是同一个上下文中,不同中心词的语义空间相近,它们的共现概率相近。
- Glove算法使用加权平方误差作为损失函数。
- 虽然Glove算法通过无监督的方式进行迭代训练,但是在统计共现矩阵信息的时候,需要对语料进行标注。
- 经验上,Glove词向量使用中心词向量和上下文词向量之和来表示,提高鲁棒性。
原始论文:
https://www.aclweb.org/anthology/D14-1162.pdf 本站专栏:
https://zhuanlan.zhihu.com/p/42073620官方Glove下载:
https://nlp.stanford.edu/projects/glove/Glove实现与训练:
http://www.fanyeong.com/2018/02/19/glove-in-detail/#comment-1462Chapter:Context Word Embedding
The representations differ from traditional word type embeddings in that each token is assigned a representation that is a function of the entire input sentence.
从本章开始,token的向量表示不再简单有一个固定向量表示,而是基于所在的上下文来决定。此时的第二阶段fine-tune,大多是feature-based approach,仅仅把预训练向量作为input特征拼接,下游任务依旧保留Task-specific的复杂网络结构。
Cove
The ability to share a common representation of words in the context of sentences that include them could further improve transfer learning in NLP.
论文主体分为两大部分:
- 首先使用Attention Encoder-Decoder 框架,在机器翻译任务进行预训练。
- 然后将Encoder的输出作为词向量,用于多个下游Task-specific任务进行训练。
- CoVe是一种通过监督学习的方式进行预训练的方法,得到contextualized word representations。
- 将Glove embedding层+Encoder层作为CoVe向量,与Glove向量拼接,用于下游任务。
- 相比word2vec、Glove这种为词典中每个单词生成一个单独的向量表示,CoVe在迁移学习上更进一步,相同上下文的不同单词,可以共享部分表示。
- 下游任务:情感分类、问题分类、文本蕴含分类、问答QA,均达到SOTA值。
- 实验表明,预训练语料的规模,会影响下游任务的质量和效果,规模越大效果更好。
- 下游任务的Task-specific模型还是比较复杂。
原始论文:
https://papers.nips.cc/paper/2017/file/20c86a628232a67e7bd46f76fba7ce12-Paper.pdf源码实现:
https://github.com/salesforce/coveTransformer
Transformer 是一个Encoder-Decoder框架 ,Encoder是双向Multi-Head Attention (本质是Self-Attention) + Feed Forward MLP。Decorder是单向Masked Multi-Head Attention (本质是Masked Self-Attention) + Multi-Head Attention (本质是context-aware Attention) + Feed Forward MLP。
Encoder有6层,每层包括一个Multi-Head Attention模块和一个position-wise的全连接层模块。每个模块都有残差连接和Layer Normalization。所有层的输入和输出维度都是
d_{model} = 512 维。
Decoder有6层,每层包括一个Masked Multi-Head Attention模块(只关注一个方向)、基于Encoder的Multi-Head Attention模块和一个position-wise的全连接层模块。每个模块都有残差链接和Layer Normalization。所有层的输入和输出维度都是
d_{model} = 512 维。
An attention function can be described as mapping a query and a set of key-value pairs to an output, where the query, keys, values, and output are all vectors. The output is computed as a weighted sum of the values, where the weight assigned to each value is computed by a compatibility function of the query with the corresponding key.
While for small values of the two mechanisms (Additive Attention & Dot-Product Attention) perform similarly, additive attention outperforms dot product attention without scaling for larger values of . We suspect that for large values of , the dot products grow large in magnitude, pushing the softmax function into regions where it has extremely small gradients . To counteract this effect, we scale the dot products by .
缩放点积注意力机制模型 (Scaled Dot-Product Attention):
Attention(Q,K,V) = softmax(/frac{QK^T}{/sqrt d_k})V /label{eq:Scaled Dot-Product Attention}/tag{2} 多头注意力机制模型 (Multi-Head Attention):
MultiHead(Q,K,V) = Concat(head_1, head_2,...,head_h)W^o // where /, head_i = Attention(QW^Q_i, KW^K_i, VW^V_i) /tag{3} /label{eq:MultiHeadAttention} 其中,Q,K,V分别经过参数
W^Q_i, W^K_i, W^V_i 映射为维度
d_k,d_k,d_v ,经过Scaled Dot-Product Attention之后,得到
d_v 维度的output vector。
h 个output拼接之后,经过单层全连接网络映射回
d_{model} 的维度。论文中,
h = 8,
d_k = d_k = d_v = 512/h = 64 。
Position-wise的全连接层模块:对于每一个position,使用同一个两层网络。两层网络之间,用ReLU激活函数。
FFN(x) = max(0,xW_1+b_1)W_2+b_2 。输入和输出维度是
d_{model} = 512 ,网络内部维度是
d_{ffn} = 2048 。
Add&Norm模块:包括残差连接和Layer Normalization。LN把数据重新归一化为均值0方差1,防止落入激活函数的饱和区,加速收敛。LN是在一个样本的向量维度上计算均值与方差。
LN(x_i) = /alpha /times /frac{x_i - /mu_L}{/sqrt{/sigma^2_L + /epsilon}} + /beta 位置编码 (Position Encoding):为了补充并行计算的Attention的位置信息,在Encoder和Docoder的输入层,都加上了Positional Encoding。
PE_{(pos,2i)} = sin(pos/10000^{2i/d_{model}}) // PE_{(pos,2i+1)} = cos(pos/10000^{2i/d_{model}}) /tag{4}/label{eq:Position Encoding} 其中,pos是单词位置,
i 是单词维度(从0到
d_{model})。位置编码可以对绝对位置进行编码,同时也可以根据三角函数关系推导出相对位置之间的关系。
- Transformer首先在机器翻译任务取得突破,是一个典型的Encoder-Decoder框架。
- Transformer对于不同位置的计算的并行的,通过Attention的方式进行聚合,而不是RNN这种串行的单向计算方式。
- Transformer基于矩阵的并行计算,符合GPU的硬件环境,有较好的并行性。
- Transformer通过mask的方式来实现单向decode,即在softmax操作之前,对当前时刻右侧的值设置成负无穷大
-inf
。 - Position-wise的全连接层模块的效果,类似于两层的kernel为1的卷积层。
- dropout:Add-Norm之前对上一个模块的输出进行dropout;对经过PE编码之后的input使用dropout。
- BPE:有利于处理未知或罕见的词汇(OOV问题);利于模型学习词缀之间的关系;subword粒度可以trade-off单词和字符特征。BPE编码的计算量较大,训练前数据预处理阶段建立subword词表以及word词表,并建立映射关系,预先将语料单词tokenize,对于OOV,使用<unk>。
- Label Smoothing:损失函数中加入LS,正确label的目标概率 y_k 不再是0和1的二值选择,而是 y_k^{ls} = y_k(1-/epsilon) + /epsilon / labelNum ,这样损失函数中,每个label都有一项。LS的这种不确定性,会损坏ppl值,但是有助于准确率和BLEU值,论文中, /epsilon 取值为0.1。
- 如果没有位置编码,那么句子之间的单词丢失顺序关系,打乱单词顺序得到相同结果,成为一个词袋模型。
- input embedding、output embedding、以及Decoder最终softmax操作之前的pre-softmax linear transformation,三者共享参数。
- Transformer相对于RNN和CNN而言,句子中任意位置之间的计算距离为1,有效解决长期依赖的问题。
- 一般而言,句子长度
n
小于向量维度dimen
,Transformer的计算复杂度O(n*n*dimen)
,低于RNN的O(n*dimen*dimen)
和CNN的O(k*n*dimen*dimen)
。 - 后续广泛使用的BERT模型,是从Transformer的Encoder结构演化而来。
原始论文:
https://papers.nips.cc/paper/2017/file/3f5ee243547dee91fbd053c1c4a845aa-Paper.pdf经典讲解:
https://jalammar.github.io/illustrated-transformer/经典讲解中文版:
https://zhuanlan.zhihu.com/p/48508221源码浅析(PyTorch):
https://zhuanlan.zhihu.com/p/47812375源码实现(TF):
https://github.com/tensorflow/tensor2tensor (available as a part of the Tensor2Tensor package)
源码实现(pyTorch):
http://nlp.seas.harvard.edu/2018/04/03/attention.html简单使用教程(pyTorch):
https://zhuanlan.zhihu.com/p/107586681ELMo
ELMo 全称 Embeddings from Language Models,语言模型主体为双向LSTM:
前向LSTM:
P(t_1,t_2,...t_N) = /Pi_{j=1}^{N} P(t_j|t_{j-1},...,t_2,t_1) 后向LSTM:
P(t_1,t_2,...t_N) = /Pi_{j=1}^{N} P(t_j|t_{j+1},t_{j+2},...,t_N) Jointly maximize the log likelihood:
Loss = /sum_{j=1}^{N}(/log P(t_j|t_{j-1},...,t_2,t_1;/theta) + /log P(t_j|t_{j+1},t_{j+2},...,t_N; /theta)) 基本结构是一个两层的biLSTM, 每一层包含4096个unit, 每个词会被softmax layer映射为512维的向量。第一层和第二层之间增加了残差连接。
biLM预训练之后,对于fine-tune阶段:
每个时刻
k 的所有内部层(
j = 0, 1, ..., L )的表示都参与下游任务,即通过加权求和的方式得到单个token的representation,
s^{task}_j 是经过softmax-normalized
ELMo_k^{task} = /gamma^{task}/sum_{j=0}^{L} s_j^{task} h_{k,j}^{LM} /label{eq:ELMo}/tag{5} j=0 时表示token的词向量表示。可以是单词级别的word embedding,也可以是字符级别的n-gram CNN结构。本文在输入层(
j=0 时)和输出层(softmax之前)都使用char-based CNN,相比于word embedding,能更好解决OOV问题,且CNN softmax参数量远小于
|V|h 。
- ELMo是一种通过无监督学习的方式进行大规模预训练的方法,得到contextualized word representations。
- Lower level LSTM能够对语法和语义(syntax; semantics)进行建模,Higher level LSTM能对不同上下文的一词多义性(polysemy)进行建模。
- ELMo的损失函数,由前向LSTM与后向LSTM两个语言模型直接相加组成,同时考虑上下文。
- ELMo的输入层与输出层的CNN结构相同,参数不同。相比于word embedding的look-up操作,CNN耗时更多。可以在inference阶段先将词表的word embedding计算出来,tokenize转为word id,减轻计算压力。
- ELMo与CoVe的最大区别在于,ELMo层数更深,且每个input token的representation是所有内部层的线性组合,而不仅仅是最后一层。
- 在下游任务中,Eq.5 得到的向量,可以直接与词向量拼接使用(即固定ELmo模型的参数,计算出每个时刻的representation后与词向量拼接);也可以与下游RNN模型的更高层的hidden states拼接使用,在SNLI,SQUAD任务上有提升效果。
- 使用Dropout及L2正则化项,有利于 Eq.5 中的参数的调权优化。
原始论文:
https://www.aclweb.org/anthology/N18-1202.pdf源码实现(pyTorch):
https://github.com/allenai/allennlp/tree/main/allennlp源码实现(TF):
https://github.com/allenai/bilm-tfELMo主页及官方ELMo模型下载:
https://allennlp.org/elmoChapter:Pretraining Language Model
本章开始,框架整体分为Pretrain+fine-tune两大阶段。模型主要基于Transformer结构,在无监督的LM任务上进行大规模预训练,并基于结构上的微调,可以实现在多种下游任务中进行有监督的fine-tune。
GPT
GPT 全称Generative Pre-Training,本质上是用Transformer的Decoder来做单向语言模型的预训练。
Loss_{lm} = /sum_{j=1}^{N}/log P(t_j|t_{j-1},...,t_2,t_1;/theta) 在fine-tune阶段,同时考虑语言模型的目标函数以及下游任务的目标函数。
Loss = /lambda Loss_{lm} + Loss_{task-specific} 在fine-tune阶段,利用task-specific input adaptations方法,非常巧妙地将整个迁移学习的框架(fine-tune)做到非常精简和通用。
Our goal is to learn a universal representation that transfers with little adaptation to a wide range of tasks
在fine-tune阶段,输入序列经过12层Transformer-Decoder-Block之后,用最后一层的最后一个时刻的输出,feed into一个task-specific的Linear Layer,然后softmax操作来得到输出的预测概率。
Unsupervised pre-training:
- Datasets: BooksCorpus dataset主要包括document level的长文本,Word Benchmark dataset主要包括sentence level的短文本。
- Model specifications: 12-layer decoder-only transformer, d_{model} = 768 维, head = 12 , d_k = d_k = d_v = 768/h = 64 。网络内部维度是 d_{ffn} = 3072 .
- Optimization: Adam, lr先增后减,前2000 step从0线性递增到2.5e-4,然后cosine曲线递减到0.
- Hyperparameter:epoch=100,batch=64,padding=512 tokens,BPE-vocab =40000,dropout=0.1。
Supervised fine-tuning details:大部分场景下,复用预训练阶段的参数,一般epoch=3即可得到不错的结果。
- task-specific input adaptations方法源自traversal-style approaches遍历式方法,将结构化输入处理成单个连续的token序列,从而将不同下游任务的多种格式的输入,转化为统一的连续token序列格式,使得在很小改动的情况下框架可以在不同任务上进行有效fine-tune。
- Text classification:对于这类任务,不需要额外的改动,可以直接将预训练的框架应用于fine-tune阶段。
- Textual entailment:输入包括premise-hypothesis文本对,在文本对直接拼接起来,中间增加一个分隔符delimiter token。
- Sentence similarity:输入包括两个句子对,由于两个句子内部没有先后顺序,为了保留原始结构,文本对(with delimiter)拼接的时候,同时考虑了两种先后顺序关系,并分别通过Transformer,并将两个网络的最后一层的最后一个时刻的输出,相加得到最后的序列表达,输入到Linear Layer中。
- QA and Commonsense Reasoning:输入包括document,query和一组answers,首位直接将document和query拼接作为context,然后分别与每一个answer拼接(with delimiter),分别通过Transformer和Linear Layer之后,用softmax归一化来produce an output distribution over possible answers.
- 四类任务的输入文本前后,都有起始符号Start和终止符号Extract,训练阶段随机初始化之后,可以固定下来,不随网络参数迭代。
2. 与预训练阶段相比,fine-tune的训练阶段新增了两部分参数:Decoder之后的LinearLayer网络,以及delimiter token的embedding表示。
3. 去掉fine-tune的训练阶段,直接在task上进行Zero-shot预测,随着预训练的epoch越多,Task预测效果更好,说明预训练阶段能够pretrain通用基础知识。
4. 对于natural language inference (NLI)任务或者大数据集任务,fine-tune训练阶段,加上
Loss_{lm} 之后效果更好。
5. input embedding包括bpe token embedding和position embedding相加。
原始论文:
https://www.cs.ubc.ca/~amuham01/LING530/papers/radford2018improving.pdf中文翻译:
https://zhuanlan.zhihu.com/p/54754171源码实现及模型(TF):
https://github.com/openai/finetune-transformer-lm官方博客:
https://openai.com/blog/language-unsupervised/GPT-2 与GPT/BERT的区别:
- 模型&参数:
更高质量、多领域、多数据量的训练数据,更深的网络层数,更多的网络参数。 - 预训练阶段:
Layer Normalization: 将layer normalization放到每个sub-block之前,并在最后一个Self-attention后再增加一个layer normalization。
BPE: 直接在byte序列上进行bpe,减小base vocab。为了避免陷入局部最优解,除空格之外,禁止将不同类别的字节进行合并。 - fine-tune训练阶段:
GPT和BERT都是supervised fint-tune,而GPT-2是unsupervised fine-tune tasks,即zero-shot的实验设置。比如摘要生成任务,在原文后面加上<TL;DR:>分隔符,然后一个字一个字生成摘要内容。
GPT-2原始论文:
https://d4mucfpksywv.cloudfront.net/better-language-models/language-models.pdfGPT-2源码实现及模型(TF):
https://github.com/openai/gpt-2GPT-2官方博客:
https://openai.com/blog/better-language-models/GPT-2论文解读:
http://jalammar.github.io/illustrated-gpt2/ https://zhuanlan.zhihu.com/p/139840113GPT-2源码解读:
https://medium.com/analytics-vidhya/understanding-the-gpt-2-source-code-part-1-4481328ee10bGPT-2中BPE源码解读:
https://www.pythonf.cn/read/106117BERT
BERT 全称Bidirectional Encoder Representations from Transformers。本质上是用Transformer的Encoder来做双向语言模型的预训练。同时,为了利用双向信息,改进了普通语言模型成为完形填空式的 Mask-LM (Mask-Language Model)。
预训练阶段主要包括了两个任务:Mask-LM (Mask-Language Model) 和 NSP (Next Sentence Prediction)。
Loss=Loss_{MLM} + Loss_{NSP} Mask-LM:单次级别多分类任务。input sequence中的每个token有15% 的概率masked,并且用最后一层hidden states映射到词表上进行预测。由于fine-tune阶段并没有mask符号,在预训练阶段,被masked的token只有80%的情况被替换为[mask]符号,10%的情况下呗替换为词表中其他任意符号,10%的情况下不做替换。
NSP:句子级别二分类任务,补充建模句子之间的关系。input sequence包括两个句子,50%的概率两个句子有前后顺序关系,50%的概率是随机挑选的两个句子。用句首对应的hidden states映射到而分类任务上进行预测。
预训练阶段,首先构造 [CLS] Sentence_A [SEP] Sentence_B [SEP] 的形式,然后截断到512token长度,使用BPE分词,每个token有15% 的概率进行mask操作。
Fine-tune阶段,几乎所有框架和超参都与预训练阶段一致。在不同的下游任务上,各自训练一套参数,输入输出层的改造也略有不同。
- 与GPT相比,BERT通过MLM实现上下文双向信息的利用。与ELMo相比,BERT的双向信息融合更深。
- fine-tune训练阶段,除了分类任务输出层的FFN,其他结构与预训练一致。不同的下游任务都用预训练好的参数进行初始化,然后在各自的任务上fine-tune。
- 输入embedding包括了bpe token embedding、position embedding以及segment embedding。
- 与GPT在fine-tune阶段引入分隔符不同,BERT在预训练和fine-tune训练阶段,都使用[CLS]和[SEP]分隔符。[CLS]用于句首,[SEP]用于每个句子的末尾。同时还新增了表示句子A和句子B的segment embedding vector。
- 与GPT的语言模型相比,BERT仅对15%的token进行语言模型学习,因此需要更多的训练epoch,收敛更慢,大约40epoch,共1M steps。
- 为了加速预训练,同时减少开销,首先90%的steps将input sequence截断到128位,剩下的10%放宽到512位,用于学习position embedding。
- fine-tune阶段,小数据集的超参数选择比大数据集更加敏感,可以进行一定范围的网格搜索。一般batch是16或32,epoch是2到4。
原始论文:
https://www.aclweb.org/anthology/N19-1423.pdf源码实现及模型(TF 1.11):
https://github.com/google-research/bert源码实现(pyTorch 1.3 / TF 2.0):
https://github.com/huggingface/transformers简单使用教程(pyTorch):
https://zhuanlan.zhihu.com/p/113639892BERT实践博客:
https://zhuanlan.zhihu.com/p/337212893Transformer-XL
Transformer将输入序列进行一定长度的截断,比如512 tokens,不同segment之间没有信息交互,截断的时候也没有考虑语义是否完整。
Transformer-XL为了解决长距离文本建模的问题:
- 提出片段级递归机制(segment-level recurrence mechanism),引入一个记忆(memory)模块(类似于cache或cell),循环用来建模片段之间的联系。
- 使得长距离依赖的建模成为可能;
- 使得片段之间产生交互,解决上下文碎片化问题。
2. 提出
相对位置编码机制(relative position embedding scheme),代替绝对位置编码。
- 为了在memory的循环计算的实现过程中,避免时序混淆,位置编码可重用。
- 在实验中,Transformer-XL在字符级 (bpc)和词级别 (ppl)的任务上比Transformer效果更好。
- 对于长文本,Transformer-XL比Transformer在inference阶段速度更快。
- XLNet基于Transformer-XL框架对预训练任务进行了设计。
原论文:
https://www.aclweb.org/anthology/P19-1285.pdf源码实现:
https://github.com/kimiyoung/transformer-xl