Bert模型全称Bidirectional Encoder Representations from Transformers,主要分为两个部分:1训练语言模型(language model)的预训练(pretrain)部分,2训练具体任务(task)的fine-tune部分。Bert在NLP领域横扫了11项任务的最优结果,可以说是现今最近NLP中最重要的突破。
相比之前的Word Embedding模型,Bert 模型具有双向,多层,随机Mask,并且融合了自然语言处理前沿技术transformer 权重处理多种优点,可以说是ELMO、GPT、Word2Vec的集大成者。具体原理上的理解各位可以移步至张俊林博士解读BERT非常详尽清晰,有助于各位从理论上加深理解Bert的原理。本文主要从Bert实践角度,拎出实用的代码片段,来完成文本情感分类。
首先下载Bert预训练模型:
google公布了一个参数较小的BERT预训练模型,点击下载。文件里有五个文件,其中bert_model.ckpt开头的文件是负责模型变量载入的,而vocab.txt是训练时中文文本采用的字典,最后bert_config.json是BERT在训练时,可选调整的一些参数。
修改 processor
任何模型的训练、预测都是需要有一个明确的输入,而BERT代码中processor就是负责对模型的输入进行处理。我们以分类任务的为例,介绍如何修改processor来运行自己数据集上的fine-tune。在run_classsifier.py文件中我们可以看到,google对于一些公开数据集已经写了一些processor,如XnliProcessor,MnliProcessor,MrpcProcessor和ColaProcessor。这给我们提供了一个很好的示例,指导我们如何针对自己的数据集来写processor。
对于一个需要执行训练、交叉验证和测试完整过程的模型而言,自定义的processor里需要继承DataProcessor,并重载获取label的get_labels和获取单个输入的get_train_examples,get_dev_examples和get_test_examples函数。其分别会在main函数的FLAGS.do_train、FLAGS.do_eval和FLAGS.do_predict阶段被调用。这三个函数的内容是相差无几的,区别只在于需要指定各自读入文件的地址。
以get_train_examples为例,函数需要返回一个由InputExample类组成的list。InputExample类是一个很简单的类,只有初始化函数,需要传入的参数中guid是用来区分每个example的,可以按照train-%d’%(i)的方式进行定义。text_a是一串字符串,text_b则是另一串字符串。在进行后续输入处理后(BERT代码中已包含,不需要自己完成) text_a和text_b将组合成[CLS] text_a [SEP] text_b [SEP]的形式传入模型。最后一个参数label也是字符串的形式,label的内容需要保证出现在get_labels函数返回的list里。
打开run_classifier.py,在XnliProcessor,MnliProcessor,MrpcProcessor和ColaProcessor后,可以添加自定义数据处理任务:
Class WeiboProcessor(Dataprocessor):
def get_train_examples(self, data_dir):
file_path = os.path.join(data_dir, 'train.csv')
with open(file_path, 'r') as f:
reader = f.readlines()
examples = []
for index, line in enumerate(reader):
guid = 'train-%d'%index
split_line = line.strip().split(',')
text_a = tokenization.convert_to_unicode(split_line[1])
text_b = tokenization.convert_to_unicode(split_line[2])
label = split_line[0]
examples.append(InputExample(guid=guid, text_a=text_a,
text_b=text_b, label=label))
return examples1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
同时对应判断label为三分类标签,get_labels函数可以写成如下的形式:
def get_labels(self):
return ['0','1',‘2’]1
2
在对get_dev_examples和get_test_examples函数做类似get_train_examples的操作后,便完成了对processor的修改。其中get_test_examples可以传入一个随意的label数值,因为在模型的预测(prediction)中label将不会参与计算。
修改 processor 字典
修改完成processor后,需要在在原本main函数的processor字典里,加入修改后的processor类,即可在运行参数里指定调用该processor。
processors = {
"cola": ColaProcessor,
"mnli": MnliProcessor,
"mrpc": MrpcProcessor,
"xnli": XnliProcessor,
"WeiboProc": WeiboProcessor #添加自己的processor
}1
2
3
4
5
6
7
运行 fine-tune
之后就可以直接运行run_classsifier.py进行模型的训练。在运行时需要制定一些参数,一个较为完整的运行参数如下所示:
python run_classifier.py \
--task_name=selfsim \ #自己添加processor在processors字典里的key名
--do_train=true \
--do_eval=true \
--dopredict=true \
--data_dir=$MY_DATASET \
--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=32 \
--learning_rate=5e-5 \
--num_train_epochs=2.0 \
--output_dir=/tmp/selfsim_output/ #模型输出路径1
2
3
4
5
6
7
8
9
10
11
12
13
14
配置的阿里云ESC云服务器,大概跑了几个小时,部分过程图如下:
train 和 dev 验证结果如下:
eval_accuracy = 0.9049439
eval_loss = 0.30998465
global_step = 1605
loss = 0.309919421
2
3
4
实现预测的话,在python run_classifier.py \中修改相应参数,设置do_predict=true。
以句子向量的形式使用Bert
如果想要将bert模型的编码和其他模型一起使用,将bert模型作为句子向量使用很有意义。我们可以使用bert-as-service来完成这个目标。
安装完bert-as-service以后,就可以利用bert模型将句子映射到固定长度的向量上。在终端中用一下命令启动服务:
bert-serving-start -model_dir /media/ganjinzero/Code/bert/chinese_L-12_H-768_A-12 -num_worker=41
2
model_dir后面的参数是bert预训练模型所在的文件夹。num_worker的数量应该取决于你的CPU/GPU数量。
这时就可以在Python中调用如下的命令:
from bert_serving.client import BertClient
bc = BertClient()
bc.encode(['一二三四五六七八', '今天您吃了吗?'])1
2
3
4
由于GPU深度学习整套装备还没有配置,本人采用了阿里云ESC服务器,选用NGC镜像,配置tf1.0-GPU-TP4,安装了jupyter notebook,整体完成的。
如何各位对配置深度学习环境有疑问,可以留下阿里云账号,我把已经建立好的深度学习环境镜像(包含[tf1.0-gpu,anaconda,])在阿里云站发送给留言的童鞋。
附赠个人的阿里云优惠券目前我是按量和按周,土豪可以包月包年~~任性。
后面我也会更博,专门拆解下如何快速搭建快速可用的深度学习环境。目前以tf1.0-gpu为主。
感谢本文参考来源:
作者:GjZr
/weixin_43837634/article/details/88049783
作者:奇点机智
链接:/p/aa2eff7ec5c1