赞
踩
目录
4.6.1 预训练的模型(Pre-trained models)
bert 的本质是学习单词的词向量表达。那我们先来回顾 word2vec,和 bert 预训练产生词向量的不同吧!
完美的解决了这上述两个缺点,可以学习动态的基于上下文的词向量;利用句子的双向信息。
BERT能够同时利用前后两个方向的信息,而ELMo和GPT只能使用单个方向的。
BERT使用的是Transformer模型,使用的是transformer的encoder部分。那它是怎么解决语言模型只能利用一个方向的信息的问题呢?答案是它的pretraining训练的不是普通的语言模型,而是Mask语言模型。
BERT模型具有以下两个特点:
第一,是这个模型非常的深,12层,并不宽(wide),中间层只有1024,而之前的Transformer模型中间层有2048。这似乎又印证了计算机图像处理的一个观点——深而窄 比 浅而宽 的模型更好。
第二,MLM(Masked Language Model)同时利用左侧和右侧的词语,这个在ELMo上已经出现了,绝对不是原创。但是解决双向问题(上下文信息)。
BERT目前已经刷新的11项自然语言处理任务的最新记录包括:将GLUE基准推至80.4%(绝对改进7.6%),MultiNLI准确度达到86.7% (绝对改进率5.6%),将SQuAD v1.1问答测试F1得分纪录刷新为93.2分(绝对提升1.5分),超过人类表现2.0分。
因为它首先尝试解决word2vec的缺点。
总结起来:
即:
1. 深度双向lstm,特点:deep,为什么要做深层??类似于图像识别一样,网络层越深,越能提取到图片中物体的具体信息。放到文本特征提取上,网络层越深,那么能提取的特征也依次具体化: 词特征 --> 语法特征 --> 语义特征。
2. 保留每一层lstm的隐层状态,包括正向和反向 [ →hi | hi←]
3. 最终某个单词的词向量是 该单词位置上所有隐层状态的加权和。
举个栗子:
这个模型有些致命的缺点:
BERT 的五个关键词 Pre-training、Deep、Bidirectional、Transformer、Language Understanding 分别是什么意思?
《A Neural Probabilistic Language Model》这篇论文讲的 Language Model,严格讲是语言生成模型(Language Generative Model),预测语句中下一个将会出现的词汇。语言生成模型能不能直接移用到其它 NLP 问题上去?
譬如,淘宝上有很多用户评论,能否把每一条用户转换成评分?-2、-1、0、1、2,其中 -2 是极差,+2 是极好。假如有这样一条用户评语,“买了一件鹿晗同款衬衫,没想到,穿在自己身上,不像小鲜肉,倒像是厨师”,请问这条评语,等同于 -2,还是其它?
语言生成模型,能不能很好地解决上述问题?进一步问,有没有 “通用的” 语言模型,能够理解语言的语义,适用于各种 NLP 问题?BERT 这篇论文的题目很直白,《BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding》,一眼看去,就能猜得到这篇文章会讲哪些内容。
这个题目有五个关键词,分别是 Pre-training、Deep、Bidirectional、Transformers、和 Language Understanding。其中 pre-training 的意思是,作者认为,确实存在通用的语言模型,先用文章预训练通用模型,然后再根据具体应用,用 supervised 训练数据,精加工(fine tuning)模型,使之适用于具体应用。为了区别于针对语言生成的 Language Model,作者给通用的语言模型,取了一个名字,叫语言表征模型 Language Representation Model。
能实现语言表征目标的模型,可能会有很多种,具体用哪一种呢?作者提议,用 Deep Bidirectional Transformers 模型。假如给一个句子 “能实现语言表征[mask]的模型”,遮盖住其中“目标”一词。从前往后预测[mask],也就是用“能/实现/语言/表征”,来预测[mask];或者,从后往前预测[mask],也就是用“模型/的”,来预测[mask],称之为单向预测 unidirectional。单向预测,不能完整地理解整个语句的语义。于是研究者们尝试双向预测。把从前往后,与从后往前的两个预测,拼接在一起 [mask1/mask2],这就是双向预测 bi-directional。细节参阅《Neural Machine Translation by Jointly Learning to Align and Translate》。
BERT 的作者认为,bi-directional 仍然不能完整地理解整个语句的语义,更好的办法是用上下文全向来预测[mask],也就是用 “能/实现/语言/表征/../的/模型”,来预测[mask]。BERT 作者把上下文全向的预测方法,称之为 deep bi-directional。如何来实现上下文全向预测呢?BERT 的作者建议使用 Transformer 模型。这个模型由《Attention Is All You Need》一文发明。
现在才开始介绍我们的主角:bert
这里需要用到transformer的知识,大家可以看transformer
Transformer的网络架构如图所示,Transformer是一个encoder-decoder的结构,由编码器和解码器构成。图中的左侧部分为编码器,由若干个(论文中6个)encoder堆叠而成,
右侧部分为解码器,由若干个(论文中6个)decoder堆叠而成。
Bert只用到了Transformer的编码器部分,它的结构图如下:
其中Trm表示一个Transformer的编码器部分
真实应用中Trm 不止图中的 2 个,通常有两种结构
L表示网络的层数(即Transformer 编码器的数量),A表示Multi-Head Attention中self-Attention的头数,H是隐层单元的维度。
BERT的输入表示如下图所示。比如输入的是两个句子”my dog is cute”,”he likes playing”。后面会解释为什么需要两个句子。这里采用类似GPT的两个句子的表示方法,首先会在第一个句子的开头增加一个特殊的Token [CLS],在cute的后面增加一个[SEP]表示第一个句子结束,在##ing后面也会增加一个[SEP]。注意这里的分词会把”playing”分成”play”和”##ing”两个Token,这种把词分成更细粒度的Word Piece(Wu et al., 2016)的方法是一种解决未登录词的常见办法,后面的代码部分也会简单介绍。接着对每个Token进行3个Embedding:词的Embedding;位置的Embedding和Segment的Embedding。词的Embedding大家都很熟悉了,而位置的Embedding和词类似,把一个位置(比如2)映射成一个低维稠密的向量。而Segment只有两个,要么是属于第一个句子(segment)要么属于第二个句子,不管哪个句子,它都对应一个Embedding向量。同一个句子的Segment Embedding是共享的,这样它能够学习到属于不同Segment的信息。对于情感分类这样的任务,只有一个句子,因此Segment id总是0;而对于Entailment任务,输入是两个句子,因此Segment是0或者1。
BERT模型要求有一个固定的Sequence的长度,比如128。如果不够就在后面padding,否则就截取掉多余的Token,从而保证输入是一个固定长度的Token序列,后面的代码会详细的介绍。第一个Token总是特殊的[CLS],它本身没有任何语义,因此它会(必须)编码整个句子(其它词)的语义。
bert将输入句子转化为词向量,是经过了3 个Embedding 的加和, 即
input_embed = Token_embed + Sentence_embed + Position_embed.
源码是:
maxLen:批训练时,最大句子长度。d_model:词嵌入的维度,n_segments:表示输入多少句话,一般最大取2。
具体如下:
用pytorch调用模型的话,我们只需要输入:
与Peters et al. (2018) 和 Radford et al. (2018)不同,论文不使用传统的从左到右或从右到左的语言模型来预训练BERT。相反,使用两个新的无监督预测任务对BERT进行预训练。
这个模型的核心是聚焦机制,对于一个语句,可以同时启用多个聚焦点,而不必局限于从前往后的,或者从后往前的,序列串行处理。不仅要正确地选择模型的结构,而且还要正确地训练模型的参数,这样才能保障模型能够准确地理解语句的语义。BERT 用了两个步骤,试图去正确地训练模型的参数。第一个步骤是把一篇文章中,15% 的词汇遮盖,让模型根据上下文全向地预测被遮盖的词。假如有 1 万篇文章,每篇文章平均有 100 个词汇,随机遮盖 15% 的词汇,模型的任务是正确地预测这 15 万个被遮盖的词汇。通过全向预测被遮盖住的词汇,来初步训练 Transformer 模型的参数。然后,用第二个步骤继续训练模型的参数。譬如从上述 1 万篇文章中,挑选 20 万对语句,总共 40 万条语句。挑选语句对的时候,其中 2*10 万对语句,是连续的两条上下文语句,另外 2*10 万对语句,不是连续的语句。然后让 Transformer 模型来识别这 20 万对语句,哪些是连续的,哪些不连续。
这两步训练合在一起,称为预训练 pre-training。训练结束后的 Transformer 模型,包括它的参数,是作者期待的通用的语言表征模型。
从直觉上看,研究团队有理由相信,深度双向模型比left-to-right 模型或left-to-right and right-to-left模型的浅层连接更强大。遗憾的是,标准条件语言模型只能从左到右或从右到左进行训练,因为双向条件作用将允许每个单词在多层上下文中间接地“see itself”。
为了训练一个深度双向表示(deep bidirectional representation),研究团队采用了一种简单的方法,即随机屏蔽(masking)部分输入token,然后只预测那些被屏蔽的token。论文将这个过程称为“masked LM”(MLM),尽管在文献中它经常被称为Cloze任务(Taylor, 1953)。
在这个例子中,与masked token对应的最终隐藏向量被输入到词汇表上的输出softmax中,就像在标准LM中一样。在团队所有实验中,随机地屏蔽了每个序列中15%的WordPiece token。与去噪的自动编码器(Vincent et al., 2008)相反,只预测masked words而不是重建整个输入。
掩码语言模型的提出就是为了防止:自己看见自己。
Masked Language Model(MLM)是指在训练的时候随机从输入语料上mask掉一些单词,然后通过它的上下文预测该单词,该任务非常像我们在中学时期经常做的完形填空。这一点是非常不同于RNN语言模型的。比如输入 A, B,C
为了使模型更加稳定,作者不单单是随机mask掉 15%的单词,然后让BERT来预测这些Mask的词,通过调整模型的参数使得模型预测正确的概率尽可能大,这等价于交叉熵的损失函数。这样的Transformer在编码一个词的时候会(必须)参考上下文的信息。
虽然这确实能让团队获得双向预训练模型,但这种方法有两个缺点。首先,预训练和finetuning之间不匹配,因为在finetuning期间从未看到[MASK]token。为了解决这个问题,团队并不总是用实际的[MASK]token替换被“masked”的词汇。相反,训练数据生成器随机选择15%的token。随机mask语料中15%的token,对于[Mask]这个符号,由于在测试集中不存在,为了减轻训练和预测之间的不匹配,作者按一定的比例在需要预测的token上动了手脚,如:my dog is hairy,则:在15%的单词当中
Transformer encoder不知道它将被要求预测哪些单词或哪些单词已被随机单词替换,因此它被迫保持每个输入token的分布式上下文表示。此外,因为随机替换只发生在所有token的1.5%(即15%的10%),这似乎不会损害模型的语言理解能力。
使用MLM的第二个缺点是每个batch只预测了15%的token,这表明模型可能需要更多的预训练步骤才能收敛。团队证明MLM的收敛速度略慢于 left-to-right的模型(预测每个token),但MLM模型在实验上获得的提升远远超过增加的训练成本。
这样做的好处是,BERT并不知道[MASK]替换的是哪一个词,而且任何一个词都有可能是被替换掉的,比如它看到的apple可能是被替换的词。这样强迫模型在编码当前时刻的时候不能太依赖于当前的词,而要考虑它的上下文,甚至更加依赖上下文进行”纠错”。比如上面的例子模型在编码apple是根据上下文my dog is应该把apple(部分)编码成hairy的语义而不是apple的语义。
“下一句预测”(next sentence prediction)任务。
许多重要的下游任务,如问答(QA)和自然语言推理(NLI)都是基于理解两个句子之间的关系,这并没有通过语言建模直接获得。
在为了训练一个理解句子的模型关系,预先训练一个二进制化的下一句预测任务,这一任务可以从任何单语语料库中生成。具体地说,当选择句子A和B作为预训练样本时,B有50%的可能是A的下一个句子,也有50%的可能是来自语料库的随机句子。例如:
Input = [CLS] the man went to [MASK] store [SEP]
he bought a gallon [MASK] milk [SEP]
Label = IsNext
Input = [CLS] the man [MASK] to the store [SEP]
penguin [MASK] are flight ##less birds [SEP]
Label = NotNext
团队完全随机地选择了NotNext语句,最终的预训练模型在此任务上实现了97%-98%的准确率。
特殊字符也需要编码。如下图左边的句子是应该连在一起的情况,但是右边的两个句子是不应该连在一起的情况。[cls]在进行编码的时候会考虑右边的所有结果,在编码时会判断是否应该连在一起。在对[cls]进行编码的时候也需要做一个分类任务,就是一个二分类任务,输出结果是判断两个句子是否应该连在一起。
BERT在第一句前会加一个[CLS]标志,最后一层该位对应向量可以作为整句话的语义表示,从而用于下游的分类任务等。
为什么选它呢,因为与文本中已有的其它词相比,这个无明显语义信息的符号会更“公平”地融合文本中各个词的语义信息,从而更好的表示整句话的语义。
4.3.2.1 bert句子级别任务
(1) 假如我们要做一个分类任务
(2) 假如我们要做一个问答系统,也就是输入有两句话,那么bert又做了什么呢??
–为什么要提出这个预训练任务呢,主要也是很多譬如问答、推理之类的任务,更多的是要学习句子之间的关系,这是语言模型无法做到的,因为语言模型根据token预测token,是在句子内部进行学习的。
bert在训练时会判断这两个输入句子是否是连续的,相关的,也就是它会做一个二分类任务,若两个句子是挨在一起的,那么预测为1,否则为0。每个句子的结尾以 [SEP] 作为分隔符。
那么句子如何选取呢??训练的时候,输入到模型的第二个句子会以50%的可能从全部文本中随机选取,剩下50%的可能从紧挨着第一个句子的文本中选取
这样看来,模型就有两个损失函数了,一个是做完形填空时产生的,一个是做二分类时产生的,两个损失函数之和就是bert总的损失函数了。源码片段:
至于哪一层效果最好,我们有这个实验
效果最好的是:最后四层的拼接。
图中:我们的面向特定任务的模型是将BERT与一个额外的输出层结合而形成的,因此需要从头开始学习最小数量的参数。在这些任务中,(a)和(b)是序列级任务,而(c)和(d)是token级任务。在图中,E表示输入嵌入,Ti表示tokeni的上下文表示,[CLS]是用于分类输出的特殊符号,[SEP]是用于分隔非连续token序列的特殊符号。
MNLI(Multi-Genre Natural Language Inference):给定一对句子,目标是预测第二句子和第一个句子是相关的、无关的还是矛盾的。
QQP(Quora Question Pairs):判断两个问句是否是同一个意思。
QNLI(Question Natural Language Inference):样本是(question,sentence)在一段文本中sentence是否是question的答案。
STS-B(Semantic Textual Similarity Benchmark):给出一对句子, 使用1~5的评分评价两者在语义上的相似程度。
MRPC (Microsoft Research Paraphrase Corpus):句子对来源于对同一条新闻的评论. 判断这一对句子在语义上是否相同。
RTE(Recognizing Textual Entailment):是一个二分类问题, 类似于MNLI, 但是数据量少很多。
SST-2(The Stanford Sentiment Treebank):单句的二分类问题, 句子来源于人们对一部电影的评价, 判断这个句子的情感。
CoLA (The Corpus of Linguistic Acceptability):单句的二分类问题, 判断一个英文句子在语法上是不是可接受的。
SQuAD(Standford Question Answering Dataset):给定一个问题和一个来自包含答案的Wikipedia段落,任务是预测答案在段落中所在的位置。
CoNLL-2003 NER命名实体识别任务,应该是大家最熟悉的了,预测每个字的标签是什么。
总体来说对于(a)(b)中的任务,我们取得的是最终CLS位置的输出C。对于(c)中的任务主要是预测start和end标记所在的最大值,且是start的id值小于end的id值,其中start是答案所在段落中的起始位置,end是结束位置。对于(d)NER任务,自然是取得每一个单词的输出的表达,后面再接一个CRF。
Google提供的BERT代码在https://github.com/google-research/bert,我们可以直接git clone下来。注意运行它需要Tensorflow 1.11及其以上的版本,低版本的Tensorflow不能运行。
由于从头开始(from scratch)训练需要巨大的计算资源,因此Google提供了预训练的模型(的checkpoint),目前包括英语、汉语和多语言3类模型,而英语又包括4个版本:
BERT-Base, Uncased 12层,768个隐单元,12个Attention head,需要训练的模型参数总数是 12 * 768 * 12 = 110M参数
BERT-Large, Uncased 24层,1024个隐单元,16个head,340M参数
BERT-Base, Cased 12层,768个隐单元,12个Attention head,110M参数
BERT-Large, Uncased 24层,1024个隐单元,16个head,340M参数。
Uncased的意思是保留大小写,而cased是在预处理的时候都变成了小写。
对于汉语只有一个版本:BERT-Base, Chinese: 包括简体和繁体汉字,共12层,768个隐单元,12个Attention head,110M参数。另外一个多语言的版本是BERT-Base, Multilingual Cased (New, recommended),它包括104种不同语言,12层,768个隐单元,12个Attention head,110M参数。它是用所有这104中语言的维基百科文章混在一起训练出来的模型。所有这些模型的下载地址都在https://github.com/google-research/bert#pre-trained-models。
常用的中文汉字有 3500 个,这些字组合成词汇,中文词汇数量高达 50 万个。假如词向量的维度是 512,那么语言模型的参数数量,至少是 512 * 50万 = 256M。模型参数数量这么大,必然需要海量的训练语料。从哪里收集这些海量的训练语料?《A Neural Probabilistic Language Model》这篇论文说,每一篇文章,天生是训练语料。难道不需要人工标注吗?回答,不需要。
这么多版本我们应该选择哪一个呢?如果我们处理的问题只包含英文,那么我们应该选择英语的版本(模型大效果好但是参数多训练慢而且需要更多内存/显存)。如果我们只处理中文,那么应该使用中文的版本。如果是其他语言就使用多语言的版本。
在压缩包里面有三类文件:
用bert来做一个fine-tuning。由于MRPC中数据集没有那么多,方面进行学习和测试,这里我们已GLUE的MRPC为例子,我们首先需要下载预训练的模型然后解压。下载GLUE数据好像需要代理,这里提供一个国内我已经下载好的数据,https://download.csdn.net/download/one_super_dreamer/12264680
需要下载的有三个,第一个是bert训练好的模型,第二个是bert-master,第三个是fine-tuning用的数据MRPC,我的目录结构如下所示:,我是用的是pycharm环境。
接下来就可以运行如下命令来进行Fine-Tuning了:
- python run_classifier.py \
- --task_name=MRPC \
- --do_train=true \
- --do_eval=true \
- --data_dir=$GLUE_DIR/MRPC \
- --vocab_file=$BERT_BASE_DIR/vocab.txt \
- --bert_config_file=$BERT_BASE_DIR/bert_config.json \
- --init_checkpoint=$BERT_BASE_DIR/bert_model.ckpt \
- --max_seq_length=128 \
- --train_batch_size=8 \
- --learning_rate=2e-5 \
- --num_train_epochs=3.0 \
- --output_dir=/tmp/mrpc_output/
这里简单的解释一下参数的含义,在后面的代码阅读里读者可以更加详细的了解其意义。
这里最常见的问题就是内存不够,通常我们的GPU只有8G作用的显存,因此对于小的模型(bert-base),我们最多使用batchsize=8,而如果要使用bert-large,那么batchsize只能设置成1。运行结束后可能得到类似如下的结果:
- ***** Eval results *****
- eval_accuracy = 0.845588
- eval_loss = 0.505248
- global_step = 343
- loss = 0.505248
大家可以对不同的任务进行训练测试,对于中文模型会在后面的文章里面讲解。
有两种masking方法:
(1)WordPiece token masking
例如:Input Text: the man jumped up , put his basket on phil ##am ##mon ' s head
Original
Masked Input: [MASK] man [MASK] up , put his [MASK] on phil [MASK] ##mon ' s head
(2)Whole word masking
例如:Whole Word Masked Input: the man [MASK] up , put his basket on [MASK] [MASK] [MASK] ' s head
在Bert中,是可以设置使用哪一种的。
推荐相关文章链接:
https://blog.csdn.net/one_super_dreamer/article/details/105181690?spm=1001.2014.3001.5502
http://fancyerii.github.io/2019/03/09/bert-theory/
https://blog.csdn.net/qq_39521554/article/details/83062188
https://blog.csdn.net/one_super_dreamer/article/details/105206692
https://blog.csdn.net/one_super_dreamer/article/details/105206692
https://www.pianshen.com/article/31881994004/
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。