BERT从零详细解读:如何微调BERT,提升BERT在下游任务中的效果

在这里插入图片描述
a)是句子对的分类任务
b)是单个句子的分类任务
c) 是问答任务
d)是序列标注任务

首先我自己最常用的就是:文本分类、序列标注和文本匹配。
这四个都是比较简单的,我们来看d)序列标注,其实就是把所有的token输出,做了一个softmax,去看它属于实体中的哪一个。对于单个样本,它的一个文本分类就是使用CLS这边,第一个CLS的输出,去做一个微调,做一个二分类,或者是多分类。
a)这个其实本质是一个文本匹配的一个任务,文本匹配就是把两个句子拼接起来,去判断它是否相似。左上角也是用CLS输出判断,0不相似,1相似。基本上其实就是这样,其实在下游任务中它使用还是比较简单的。

如何提升BERT在下游任务中的效果或者是表现。因为我们在实际应用中,很少会让你自己去从头训练一个bert。一般都是用训练好的,就是大公司放出来的bert,然后我们自己在自己的任务中做一些微调。

很多朋友的做法都是,先获取谷歌中文或者是其它公司的bert,然后基于自己的任务数据去做微调。但是我们想要更好的性能的话,现在有很多tirck需要去做。

首先,我想提的第一点就是去做 Post training。

四步骤

比如做微博文本情感分析:

  1. 在大量通用预料上训练一个LM(pretrain);- 中文谷歌BERT
  2. 在相同领域上继续训练LM(Domain transfer); - 在大量微博文本上继续训练这个BERT
  3. 在任务相关的小数据上继续训练LM(Task transfer);- 在微博情感文本上(有的文本不属于情感分析的范畴)
  4. 在任务相关数据上做具体任务(Fine-tune)。

一般经验是,先做Domain transfer,再进行 Task transfer,最后Fine-tune 性能是最好的。

如何再相同领域数据中进行further pre-training

  1. 动态mask:就是每次epoch去训练的时候mask,而不是一直使用同一个。

    bert在训练的时候使用的是固定的mask,就是把文本mask之后存在本地,然后每次训练的时候都是使用同一个文件,也就是说每次训练的时候我们使用的都是同样的mask标志。比如之前的例子【我爱吃饭】,每次训练的时候都是mask掉了这个”吃“,这样其实不太好。然后动态mask呢,就是每个epoch训练之前,去对数据进行mask。
    刚才说bert一直使用同一套mask,也不太准确,它是有做一些改进,他有复制一些文本,大家具体去看一下论文。

  2. n-gram mask:其实比如ERINE 和 SpanBert都是类似于做了实体词的mask。

    我们可以退一步,就是如果你自己训练的时候,你没有特别准确的实体词,你可以不做实体词的mask,你可以做n-gram mask.

我们在做的时候参数一定要设置得特别的好,Batch size其实16,32,64,128影响不太大;Learning rate(Adam)5e-5,3e-5,2e-5,尽可能小一点避免灾难性遗忘;在微调的时候number of epochs,一般是3、4个,一般不会太大;weighted decay修改后的adam,使用warmup,搭配线性衰减,这个是比较重要的;

还有就是比如在预训练的时候做数据增强(一些简单的EDA)、自蒸馏、外部知识的融入(比如融入知识图谱的知识,或者加一些实体词的信息),这些都可以,不过比较吃机器。

具体使用方法可以看我的博客:https://blog.csdn.net/weixin_40015791/article/details/90410083 下面也会简单介绍一下:在bert开源代码的run_classifier.py找到 processors = { "cola": ColaProcessor, "mnli": MnliProcessor, "mrpc": MrpcProcessor, "xnli": XnliProcessor, "intentdetection":IntentDetectionProcessor, "emotion":EmotionProcessor, #新加上这一行 } 然后在该文件增加一个class: class EmotionProcessor(DataProcessor): """Processor for the MRPC data set (GLUE version).""" def get_train_examples(self, data_dir): """See base class.""" return self._create_examples( self._read_tsv(os.path.join(data_dir, "fine_tuning_train_data.tsv")), "train") #此处的名字和文件夹的训练集的名字要保持一致 def get_dev_examples(self, data_dir): """See base class.""" return self._create_examples( self._read_tsv(os.path.join(data_dir, "fine_tuning_val_data.tsv")), "dev") def get_test_examples(self, data_dir): """See base class.""" return self._create_examples( self._read_tsv(os.path.join(data_dir, "fine_tuning_test_data.tsv")), "test") def get_labels(self): """See base class.""" return ["0", "1","2","3","4","5","6"] #七分类则从0到6 def _create_examples(self, lines, set_type): """Creates examples for the training and dev sets.""" examples = [] for (i, line) in enumerate(lines): if i == 0: continue guid = "%s-%s" % (set_type, i) if set_type == "test": label = "0" text_a = tokenization.convert_to_unicode(line[0]) else: label = tokenization.convert_to_unicode(line[0]) text_a = tokenization.convert_to_unicode(line[1]) examples.append( InputExample(guid=guid, text_a=text_a, text_b=None, label=label)) return examples 最后直接调用即可,运行的命令如下: python run_classifier.py \ --task_name=emotion \ --do_train=true \ --do_eval=true \ --data_dir=data \ #把数据解压到同一级的文件夹,此处是该文件夹名字data --vocab_file=chinese_L-12_H-768_A-12/vocab.txt \ #文数据要微调的原始bert模型 --bert_config_file=chinese_L-12_H-768_A-12/bert_config.json \ --init_checkpoint=chinese_L-12_H-768_A-12/bert_model.ckpt \ --max_seq_length=128 \ --train_batch_size=32 \ --learning_rate=2e-5 \ --num_train_epochs=3.0 \ --output_dir=output #生成文件所在的文件夹 大概9个小时,最后文件夹会有三个文件 后缀分别为index/meta/00000-of-00001,分别将这个改成bert_model.ckpt.index/bert_model.ckpt.meta/bert_model.ckpt.data-00000-of-00001,再在同一个文件夹放入chinese_L-12_H-768_A-12的vocab.txt和bert_config.json 即最后该文件夹有5个文件。然后像调用chinese_L-12_H-768_A-12一样将文件夹名改成自己的文件夹名即可。 bert-serving-start -model_dir output -num_worfer=3 即可调用微调后的语言通用模型。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值