Bert介绍
Bert模型是Google在2018年10月发布的语言表示模型,Bert在NLP领域横扫了11项任务的最优结果,可以说是现今最近NLP中最重要的突破。Bert模型的全称是Bidirectional Encoder Representations from Transformers,是通过训练Masked Language Model和预测下一句任务得到的模型。关于Bert具体训练的细节和更多的原理,有兴趣的读者可以去看在arXiv上的原文。本篇文章从实践入手,带领大家进行Bert的中文文本分类和作为句子向量进行使用的教程。
准备工作
1.下载bert
1 | git clone https://github.com/google-research/bert.git |
2.下载bert预训练模型
Google提供了多种预训练好的bert模型,有针对不同语言的和不同模型大小的。对于中文模型,我们使用Bert-Base, Chinese。为了下载该模型,可能需要使用梯子。如果需要下载其他的模型(英文以及其他语言),可以在Bert里的Pre-trained models找到下载链接。
3.(可选项)安装bert-as-service,这是一个可以利用bert模型将句子映射到固定长度向量的服务。
1 | pip install bert-serving-server # server |
该服务要求tensorflow的最低版本为1.10。
准备数据
数据格式
作为中文文本分类问题,需要先将数据集整理成可用的形式。不同的格式对应了不同的DataProcessor类。可以将数据保存成如下格式:
1 | game APEX是个新出的吃鸡游戏。 |
一行代表一个文本,由标签加上一个tab加上正文组成。
将文本分割为三个文件,train.tsv(训练集),dev.tsv(验证集),test.tsv(测试集);然后放置在同一个data_dir文件夹下。
编写DataProcessor类
在run_classifier.py中的def main(_):函数中将processors的内容增加为
1 | processors = { |
实现如下的MyTaskProcessor(DataProcessor)类,并将这一段代码放置在run_classifier.py和其他Processor并列的位置。
__init__(self)中的self.labels含有所有的分类label。
1 | class MyTaskProcessor(DataProcessor): |
如果数据格式并不是一个label,一个tab,一段文本;则需要更改_create_examples()的实现。
编写运行脚本
新建一个运行脚本文件名为run.sh,将文件内容编辑为:
1 | export DATA_DIR=/media/ganjinzero/Code/bert/data/ |
其中DATA_DIR是你的要训练的文本的数据所在的文件夹,BERT_BASE_DIR是你的bert预训练模型存放的地址。task_name要求和你的DataProcessor类中的名称一致。下面的几个参数,do_train代表是否进行fine tune,do_eval代表是否进行evaluation,还有未出现的参数do_predict代表是否进行预测。max_seq_length代表了句子的最长长度,当显存不足时,可以适当降低max_seq_length。
进行预测
运行脚本
1 | ./run.sh |
可以得到类似如下样式的结果
1 | ***** Eval results ***** |
如果出现了这样的输出,就是运行成功了。在run.sh里指定的output_dir文件夹下可以看到模型的evaluation结果和fine-tune之后的模型文件。
以句子向量的形式使用Bert
如果想要将bert模型的编码和其他模型一起使用,将bert模型作为句子向量使用很有意义。我们可以使用bert-as-service来完成这个目标。
安装完bert-as-service以后,就可以利用bert模型将句子映射到固定长度的向量上。在终端中用一下命令启动服务:
1 | bert-serving-start -model_dir /media/ganjinzero/Code/bert/chinese_L-12_H-768_A-12 -num_worker=4 |
model_dir后面的参数是bert预训练模型所在的文件夹。num_worker的数量应该取决于你的CPU/GPU数量。
这时就可以在Python中调用如下的命令:
1 | from bert_serving.client import BertClient |
最好以列表的形式,而非单个字符串传给bc.encode()参数,这样程序运行的效率较高。