BERT模型在NLP各项任务中大杀四方,那么我们如何使用这一利器来为我们日常的NLP任务来服务呢?我们首先介绍使用BERT做文本分类任务。
重写读取数据的类 需要根据文件格式重写读取数据的类,只要能够正常读取数据即可。以下代码将x文本记为不含标签训练数据,y文本记为标签数据。
class StatutesProcessor(DataProcessor):def _read_txt_(self, data_dir, x_file_name, y_file_name):
# 定义我们的读取方式,我的工程中已经将x文本和y文本分别存入txt文件中,没有分隔符
# 用gfile读取,打开一个没有线程锁的的文件IO Wrapper
# 基本上和python原生的open是一样的,只是在某些方面更高效一点
with tf.gfile.Open(data_dir + x_file_name, 'r') as f:
lines_x = [x.strip() for x in f.readlines()]
with tf.gfile.Open(data_dir + y_file_name, 'r') as f:
lines_y = [x.strip() for x in f.readlines()]
return lines_x, lines_ydef get_train_examples(self, data_dir):
lines_x, lines_y = self._read_txt_(data_dir, 'train_x_no_seg.txt', 'train_y.txt')
examples = []
for (i, line) in enumerate(zip(lines_x, lines_y)):
guid = 'train-%d' % i
# 规范输入编码
text_a = tokenization.convert_to_unicode(line[0])
label = tokenization.convert_to_unicode(line[1])
# 这里有一些特殊的任务,一般任务直接用上面的就行,下面的label操作可以注释掉
# 这里因为y会有多个标签,这里按单标签来做
label = label.strip().split()[0]# 这里不做匹配任务,text_b为None
examples.append(
InputExample(guid=guid, text_a=text_a, label=label)
)
return examplesdef get_dev_examples(self, data_dir):
lines_x, lines_y = self._read_txt_(data_dir, 'val_x_no_seg.txt', 'val_y.txt')
examples = []
for (i, line) in enumerate(zip(lines_x, lines_y)):
guid = 'train-%d' % i
# 规范输入编码
text_a = tokenization.convert_to_unicode(line[0])
label = tokenization.convert_to_unicode(line[1])
label = label.strip().split()[0]# 这里不做匹配任务,text_b为None
examples.append(
InputExample(guid=guid, text_a=text_a, label=label)
)
return examplesdef get_test_examples(self, data_dir):
lines_x, lines_y = self._read_txt_(data_dir, 'test_x_no_seg.txt', 'test_y.txt')
examples = []
for (i, line) in enumerate(zip(lines_x, lines_y)):
guid = 'train-%d' % i
# 规范输入编码
text_a = tokenization.convert_to_unicode(line[0])
label = tokenization.convert_to_unicode(line[1])
label = label.strip().split()[0]# 这里不做匹配任务,text_b为None
examples.append(
InputExample(guid=guid, text_a=text_a, label=label)
)
return examplesdef get_labels(self):
# 我事先统计了所有出现的y值,放在了vocab_y.txt里
# 因为这里没有原生的接口,这里暂时这么做了,只要保证能读到所有的类别就行了
with tf.gfile.Open('data/statutes_small/vocab_y.txt', 'r') as f:
vocab_y = [x.strip() for x in f.readlines()]
return vocab_y
重写之后,需要加到processors的字典中
def main(_):
tf.logging.set_verbosity(tf.logging.INFO)processors = {
"cola": ColaProcessor,
"mnli": MnliProcessor,
"mrpc": MrpcProcessor,
"xnli": XnliProcessor,
"News2019": StatutesProcessor
}
这里面的News2019就是我们新添加的读取数据的类
根据需要重写评估指标的类
def metric_fn(per_example_loss, label_ids, logits, is_real_example):
predictions = tf.argmax(logits, axis=-1, output_type=tf.int32)
accuracy = tf.metrics.accuracy(
labels=label_ids, predictions=predictions, weights=is_real_example)
loss = tf.metrics.mean(values=per_example_loss, weights=is_real_example)
f1_macro = f1_score(label_ids, predictions, average='macro', sample_weight=is_real_example)return {
"eval_accuracy": accuracy,
"eval_loss": loss,
"eval_f1": f1_macro
}
可在metric_fn()函数中比啊那些自己需要的测评指标比如Precision,Recall,F,AUC或者其他测评指标。
加载预训练的模型
if __name__ == "__main__":
flags.mark_flag_as_required("data_dir")
flags.mark_flag_as_required("task_name")
flags.mark_flag_as_required("vocab_file")
flags.mark_flag_as_required("bert_config_file")
flags.mark_flag_as_required("init_checkpoint")
flags.mark_flag_as_required("output_dir")
flags.mark_flag_as_required("do_train")
flags.mark_flag_as_required("do_eval")
flags.mark_flag_as_required("do_predict")
tf.app.run()
需要我们事先下载预训练好的中文模型,这其中上面的vocab_file:vocab.txt和bert_config_file: bert_config.json和init_checkpoint:bert_model.ckpt均在下载好的中文模型压缩包中。接下来只需要在命令行输入相关命令即可执行。
小结 对BERT进行微调来解决下游任务比较简单。主要包含步骤如下:
- 根据数据格式重写读取数据类或利用现有的数据读取函数来对数据格式进行修改
- 根据要求增删相关评估指标
- 调用预训练模型进行训练
推荐阅读
- 人工智能|hugginface-introduction 案例介绍
- 中文分词预处理之N最短路径法小结(转)
- 深度学习|2019年CS224N课程笔记-Lecture 17:Multitask Learning
- 深度学习|2018年度总结和2019年度计划
- 【学习笔记】自然语言处理实践(新闻文本分类)- 基于深度学习的文本分类Bert
- 【学习笔记】自然语言处理实践(新闻文本分类)- 基于深度学习的文本分类Word2Vec
- 自然语言处理|答案选择|语义匹配任务目前表现最好的几个模型
- 深度学习|NLP重铸篇之BERT如何微调文本分类
- NLP实践-Task1