1.BERT模型的初步认识
BERT(Pre-training of Deep Bidirectional Transformers,原文链接:BERT)是近年来NLP圈中最火爆的模型,让我们来看一些数据。
自从2018年BERT模型发布以来,BERT模型仅用 2019 年一年的时间,便以势如破竹的姿态成为了 NLP 领域首屈一指的红人,BERT 相关的论文也如涌潮般发表出来。2019 年,可谓是 NLP 发展历程中具有里程碑意义的一年,而其背后的最大功臣当属 BERT !在NLP领域,如果把2019年称为“BERT年”也不为过。
据统计,2019以BERT为主要内容的论文发表数量近200篇,具体数据可以看看下面图片的github链接呦。
不过话说回来,第一个使用Transformer的预训练模型不是bert,而是GPT。想要进一步了解GPT模型的同学,可以阅读补充资料(OpenAI GPT: Generative Pre-Training for Language Understanding),如果你不了解Transformer结构,我建议你先不要阅读,等阅读完系列文章后,再来品味一下GPT与BERT的不同。
提前透露一下GPT和BERT的最大的不同,GPT里的基本结构是由单向的Transformer-Decoder结构组成,而BERT是由双向的Transformer-Encoder结构组成。
不管是ELMo、GPT还是BERT,他们改变解决NLP的重要思路是预训练+微调的模式。如图所示,预训练+微调的模式是一种迁移学习的思想,预训练阶段可以使用大规模的数据(比如wiki),使得一个强大的模型学习到大量的知识,而且这些知识的学习方式是无监督的。通过预训练的学习之后,模型就已经具备大量的先验知识,在微调阶段继续使用预训练好的模型参数,采用业务自身标注数据在此基础上完成最后一步的监督学习。
了解到这,大家对于BERT应该有了一个初步的认识,那顺便思考一下。
BERT采用了迁移学习的思想,如果在相同的NLP任务上达到传统模型(如RNN等)一样的性能指标,比如准确度都是90%,在准备数据成本上有优势么,什么样的优势?
3.带你读BERT原论文
该部分会精读一下BERT的原文,我也已经将重要的信息做了标注和解释。
把标注的地方全部弄清楚,就可以进行下面的学习了,一个新的算法,理论啃完,在把源码吃透,才算真的掌握,希望大家多注意细节。
完整解读版,可以自行下载,链接: https://pan.baidu.com/s/1Q0DcoIR1boHd4qi7vkwoTg 密码: ee20
4.跑通BERT代码
BERT当年发表时就在SQuAD v1.1上,获得了93.2%的 F1 分数,超过了之前最高水准的分数91.6%,同时超过了人类的分数91.2%。
BERT 还在极具挑战性的 GLUE 基准测试中将准确性的标准提高了7.6%。这个基准测试包含 9 种不同的自然语言理解(NLU)任务。在这些任务中,具有人类标签的训练数据跨度从 2,500 个样本到 400,000 个样本不等。BERT 在所有任务中都大大提高了准确性。
上述的微调任务介绍如下表
- MNLI:给定一个前提 (Premise) ,根据这个前提去推断假设 (Hypothesis) 与前提的关系。该任务的关系分为三种,蕴含关系 (Entailment)、矛盾关系 (Contradiction) 以及中立关系 (Neutral)。所以这个问题本质上是一个分类问题,我们需要做的是去发掘前提和假设这两个句子对之间的交互信息。
- QQP:基于Quora,判断 Quora 上的两个问题句是否表示的是一样的意思。
- QNLI:用于判断文本是否包含问题的答案,类似于我们做阅读理解定位问题所在的段落。
- STS-B:预测两个句子的相似性,包括5个级别。
- MRPC:也是判断两个句子是否是等价的。
- RTE:类似于MNLI,但是只是对蕴含关系的二分类判断,而且数据集更小。
- SWAG:从四个句子中选择为可能为前句下文的那个。
- SST-2:电影评价的情感分析。
- CoLA:句子语义判断,是否是可接受的(Acceptable)。
初步了解了BERT以后,我们就简单跑一个BERT的例子吧,让大家有一个整体的认识。
!python -m pip install --upgrade paddlenlp -i https://pypi.org/simple
from functools import partial
import argparse
import os
import random
import timeimport numpy as np
import paddle
import paddle.nn.functional as Fimport paddlenlp as ppnlp
from paddlenlp.data import Stack, Tuple, Pad
from paddlenlp.datasets import load_dataset
from paddlenlp.transformers import LinearDecayWithWarmup
train_ds, dev_ds, test_ds = load_dataset("chnsenticorp", splits=["train", "dev", "test"])
for idx, example in enumerate(train_ds):if idx <&#61; 10:print(example)
EPOCHS &#61; 10
BATCH_SIZE &#61; 8
MAX_LEN &#61; 300
LR &#61; 1e-5
WARMUP_STEPS &#61; 100
T_TOTAL &#61; 1000
tokenizer &#61; ppnlp.transformers.BertTokenizer.from_pretrained(&#39;bert-base-chinese&#39;)
def convert_example(example, tokenizer, max_seq_length&#61;512, is_test&#61;False):"""Builds model inputs from a sequence or a pair of sequence for sequence classification tasksby concatenating and adding special tokens. And creates a mask from the two sequences passed to be used in a sequence-pair classification task."""encoded_inputs &#61; tokenizer(text&#61;example["text"], max_seq_len&#61;max_seq_length)input_ids &#61; encoded_inputs["input_ids"]token_type_ids &#61; encoded_inputs["token_type_ids"]if not is_test:label &#61; np.array([example["label"]], dtype&#61;"int64")return input_ids, token_type_ids, labelelse:return input_ids, token_type_ids
def create_dataloader(dataset,mode&#61;&#39;train&#39;,batch_size&#61;1,batchify_fn&#61;None,trans_fn&#61;None):if trans_fn:dataset &#61; dataset.map(trans_fn)shuffle &#61; True if mode &#61;&#61; &#39;train&#39; else Falseif mode &#61;&#61; &#39;train&#39;:batch_sampler &#61; paddle.io.DistributedBatchSampler(dataset, batch_size&#61;batch_size, shuffle&#61;shuffle)else:batch_sampler &#61; paddle.io.BatchSampler(dataset, batch_size&#61;batch_size, shuffle&#61;shuffle)return paddle.io.DataLoader(dataset&#61;dataset,batch_sampler&#61;batch_sampler,collate_fn&#61;batchify_fn,return_list&#61;True)
trans_func &#61; partial(convert_example,tokenizer&#61;tokenizer,max_seq_length&#61;MAX_LEN)
batchify_fn &#61; lambda samples, fn&#61;Tuple(Pad(axis&#61;0, pad_val&#61;tokenizer.pad_token_id), Pad(axis&#61;0, pad_val&#61;tokenizer.pad_token_type_id), Stack(dtype&#61;"int64") ): [data for data in fn(samples)]
train_data_loader &#61; create_dataloader(train_ds,mode&#61;&#39;train&#39;,batch_size&#61;BATCH_SIZE,batchify_fn&#61;batchify_fn,trans_fn&#61;trans_func)
dev_data_loader &#61; create_dataloader(dev_ds,mode&#61;&#39;dev&#39;,batch_size&#61;BATCH_SIZE,batchify_fn&#61;batchify_fn,trans_fn&#61;trans_func)
test_data_loader &#61; create_dataloader(test_ds,mode&#61;&#39;test&#39;,batch_size&#61;BATCH_SIZE,batchify_fn&#61;batchify_fn,trans_fn&#61;trans_func)
model &#61; ppnlp.transformers.BertForSequenceClassification.from_pretrained(&#39;bert-base-chinese&#39;, num_classes&#61;len(train_ds.label_list))
num_training_steps &#61; len(train_data_loader) * EPOCHSlr_scheduler &#61; LinearDecayWithWarmup(LR, num_training_steps, WARMUP_STEPS)
decay_params &#61; [p.name for n, p in model.named_parameters()if not any(nd in n for nd in ["bias", "norm"])
]
optimizer &#61; paddle.optimizer.AdamW(learning_rate&#61;lr_scheduler,parameters&#61;model.parameters(),weight_decay&#61;0.0,apply_decay_param_fun&#61;lambda x: x in decay_params)criterion &#61; paddle.nn.loss.CrossEntropyLoss()
metric &#61; paddle.metric.Accuracy()
global_step &#61; 0
tic_train &#61; time.time()
for epoch in range(1, EPOCHS &#43; 1):for step, batch in enumerate(train_data_loader, start&#61;1):input_ids, token_type_ids, labels &#61; batchlogits &#61; model(input_ids, token_type_ids)loss &#61; criterion(logits, labels)probs &#61; F.softmax(logits, axis&#61;1)correct &#61; metric.compute(probs, labels)metric.update(correct)acc &#61; metric.accumulate()global_step &#43;&#61; 1if global_step % 10 &#61;&#61; 0:print("global step %d, epoch: %d, batch: %d, loss: %.5f, accu: %.5f, speed: %.2f step/s"% (global_step, epoch, step, loss, acc,10 / (time.time() - tic_train)))tic_train &#61; time.time()loss.backward()optimizer.step()lr_scheduler.step()optimizer.clear_grad()if global_step % 100 &#61;&#61; 0:breakbreakprint(&#39;bert训练Demo完成了...&#39;)
ok&#xff0c;终于可以完成一个BERT的训练demo了。
5.后续计划
本节课内容就这些&#xff0c;喜欢的同学可以关注后续内容。
计划&#xff1a;
《BERT模型的核心架构》
《BERT如何完成预训练》
《BERT微调细节详解》
《使用BERT完成任务》
《。。。》