2018年google推出了bert模型,这个模型的性能要远超于之前所使用的模型,总的来讲就是很牛。可是训练bert模型是异常昂贵的,对于通常人来讲并不须要本身单独训练bert,只须要加载预训练模型,就能够完成相应的任务。下面我将以情感分类为例,介绍使用bert的方法。这里与咱们以前调用API写代码有所区别,已经有大神将bert封装成.py文件,咱们只须要简单修改一下,就能够直接调用这些.py文件了。python
我这里使用的是pytorch版本。git
不管是tf版仍是pytorch版本,预训练模型都须要三个文件(或者功能相似的)github
文档里提供了convert_tf_checkpoint_to_pytorch.py 这个脚原本进行模型转换。使用方法以下:shell
export BERT_BASE_DIR=/path/to/bert/uncased_L-12_H-768_A-12 pytorch_pretrained_bert convert_tf_checkpoint_to_pytorch \ $BERT_BASE_DIR/bert_model.ckpt \ $BERT_BASE_DIR/bert_config.json \ $BERT_BASE_DIR/pytorch_model.bin
这里是须要实现情感分类。只须要用到run_classifier_dataset_utils.py和run_classifier.py这两个文件。run_classifier_dataset_utils.py是用来处理文本的输入,咱们只须要添加一个类用来处理输入便可。json
class MyProcessor(DataProcessor): '''Processor for the sentiment classification data set''' def get_train_examples(self, data_dir): """See base class.""" logger.info("LOOKING AT {}".format(os.path.join(data_dir, "train.tsv"))) return self._create_examples( self._read_tsv(os.path.join(data_dir, "train.tsv")), "train") def get_dev_examples(self, data_dir): """See base class.""" return self._create_examples( self._read_tsv(os.path.join(data_dir, "dev.tsv")), "dev") def get_labels(self): """See base class.""" return ["-1", "1"] 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) text_a = line[0] label = line[1] examples.append( InputExample(guid=guid, text_a=text_a, text_b=None, label=label)) return examples
train.tsv和dev.tsv分别表示训练集和测试集。记得要在下面的代码加上以前定义的类。bash
def compute_metrics(task_name, preds, labels): assert len(preds) == len(labels) if task_name == "cola": return {"mcc": matthews_corrcoef(labels, preds)} elif task_name == "sst-2": return {"acc": simple_accuracy(preds, labels)} elif task_name == "mrpc": return acc_and_f1(preds, labels) elif task_name == "sts-b": return pearson_and_spearman(preds, labels) elif task_name == "qqp": return acc_and_f1(preds, labels) elif task_name == "mnli": return {"acc": simple_accuracy(preds, labels)} elif task_name == "mnli-mm": return {"acc": simple_accuracy(preds, labels)} elif task_name == "qnli": return {"acc": simple_accuracy(preds, labels)} elif task_name == "rte": return {"acc": simple_accuracy(preds, labels)} elif task_name == "wnli": return {"acc": simple_accuracy(preds, labels)} elif task_name == "my": return acc_and_f1(preds, labels) else: raise KeyError(task_name) processors = { "cola": ColaProcessor, "mnli": MnliProcessor, "mnli-mm": MnliMismatchedProcessor, "mrpc": MrpcProcessor, "sst-2": Sst2Processor, "sts-b": StsbProcessor, "qqp": QqpProcessor, "qnli": QnliProcessor, "rte": RteProcessor, "wnli": WnliProcessor, "my": MyProcessor } output_modes = { "cola": "classification", "mnli": "classification", "mrpc": "classification", "sst-2": "classification", "sts-b": "regression", "qqp": "classification", "qnli": "classification", "rte": "classification", "wnli": "classification", "my": "classification" }
编辑shell脚本:app
#!/bin/bash export TASK_NAME=my python run_classifier.py \ --task_name $TASK_NAME \ --do_train \ --do_eval \ --do_lower_case \ --data_dir /home/garvey/Yuqinfenxi/ \ --bert_model /home/garvey/uncased_L-12_H-768_A-12 \ --max_seq_length 410 \ --train_batch_size 8 \ --learning_rate 2e-5 \ --num_train_epochs 3.0 \ --output_dir /home/garvey/bertmodel
运行便可。这里要注意max_seq_length和train_batch_size这两个参数,设置过大是很容易爆掉显存的,通常来讲运行bert须要11G左右的显存。性能
max_seq_length是指词的数量而不是指字符的数量。参考代码中的注释:学习
The maximum total input sequence length after WordPiece tokenization. Sequences longer than this will be truncated, and sequences shorter than this will be padded.测试
对于sequence的理解,网上不少博客都把这个翻译为句子,我我的认为是不许确的,序列是能够包含多个句子的,而不仅是单独一个句子。
Bert开源的代码中,只提供了train和dev数据,也就是训练集和验证集。对于评测论文标准数据集的时候,只须要把训练集和测试集送进去就能够获得结果,这一过程是没有调参的(没有验证集),都是使用默认参数。可是若是用Bert来打比赛,注意这个时候的测试集是没有标签的,这就须要在源码中加上一个处理test数据集的部分,而且经过验证集来选择参数。
在大的预训练模型例如像bert-large在对小的训练集进行精细调整的时候,每每会致使性能退化:模型要么运行良好,要么根本不起做用,在咱们用bert-large对一些小数据集进行微调,直接使用默认参数的话二分类的准确率只有0.5,也就是一点做用也没有,这个时候须要对学习率和迭代次数进行一个调整才会有一个正常的结果,这个问题暂时尚未获得解决。