BERT模型在多类别文本分类时的precision, recall, f1值的计算
BERT预训练模型在诸多NLP任务中都取得最优的结果。在处理文本分类问题时,即可以直接用BERT模型作为文本分类的模型,也可以将BERT模型的最后层输出的结果作为word embedding导入到我们定制的文本分类模型中(如text-CNN等)。总之现在只要你的计算资源能满足,一般问题都可以用BERT来处理,此次针对公司的一个实际项目——一个多类别(61类)的文本分类问题,其就取得了很好的结果。
我们此次的任务是一个数据分布极度不平衡的多类别文本分类(有的类别下只有几个或者十几个样本,有的类别下又有几千个样本),在不做不平衡数据处理且不采用BERT模型时,其取得的F1值只有50%,而在不做不平衡数据处理但采用BERT模型时,其F1值能达到65%,但是在用bert模型时获得F1值时却存在一些问题。
在tensorflow中只提供了二分类的precision,recall,f1值的计算接口,而bert源代码中的run_classifier.py文件中训练模型,验证模型等都是用的estimator API,这些高层API极大的限制了修改代码的灵活性。好在tensorflow源码中有一个方法可以计算混淆矩阵的方法,并且会返回一个operation。注意:这个和tf.confusion_matrix()不同,具体看源代码中下面这段代码:
elif mode == tf.estimator.ModeKeys.EVAL:
def metric_fn(per_example_loss, label_ids, logits, num_labels):
predictions = tf.argmax(logits, axis=-1, output_type=tf.int32)
accuracy = tf.metrics.accuracy(
labels=label_ids, predictions=predictions)
# 这里的metrics时我们定义的一个python文件,在下面会介绍
conf_mat = metrics.get_metrics_ops(label_ids, predictions, num_labels)
loss = tf.metrics.mean(values=per_example_loss)
return {
"eval_accuracy": accuracy,
"eval_cm": conf_mat,
"eval_loss": loss,
}
验证时的性能指标计算都在这个方法里面,而且在return的这个字典中每个值必须是一个tuple。以accuracy为例,tf.metrics.accuracy返回的是一个(accuracy, update_op)这样一个tuple,而我们上一段说的tf.confusion_matrix只返回一个混淆矩阵。因此在这里我们使用一个内部的方法,方法导入如下:
from tensorflow.python.ops.metrics_impl import _streaming_confusion_matrix
这个方法会返回一个(confusion_matrix, update_op)的tuple。我们新建一个metrics.py文件,里面的代码如下:
import numpy as np
import tensorflow as tf
from tensorflow.python.ops.metrics_impl import _streaming_confusion_matrix def get_metrics_ops(labels, predictions, num_labels):
# 得到混淆矩阵和update_op,在这里我们需要将生成的混淆矩阵转换成tensor
cm, op = _streaming_confusion_matrix(labels, predictions, num_labels)
tf.logging.info(type(cm))
tf.logging.info(type(op)) return (tf.convert_to_tensor(cm), op) def get_metrics(conf_mat, num_labels):
# 得到numpy类型的混淆矩阵,然后计算precision,recall,f1值。
precisions = []
recalls = []
for i in range(num_labels):
tp = conf_mat[i][i].sum()
col_sum = conf_mat[:, i].sum()
row_sum = conf_mat[i].sum() precision = tp / col_sum if col_sum > 0 else 0
recall = tp / row_sum if row_sum > 0 else 0 precisions.append(precision)
recalls.append(recall) pre = sum(precisions) / len(precisions)
rec = sum(recalls) / len(recalls)
f1 = 2 * pre * rec / (pre + rec) return pre, rec, f1
最上面一段代码中return的字典中的值可以在run_classifier.py中main函数中的下面一段代码中得到:
if FLAGS.do_eval:
eval_examples = processor.get_dev_examples(FLAGS.data_dir)
num_actual_eval_examples = len(eval_examples)
if FLAGS.use_tpu:
# TPU requires a fixed batch size for all batches, therefore the number
# of examples must be a multiple of the batch size, or else examples
# will get dropped. So we pad with fake examples which are ignored
# later on. These do NOT count towards the metric (all tf.metrics
# support a per-instance weight, and these get a weight of 0.0).
while len(eval_examples) % FLAGS.eval_batch_size != 0:
eval_examples.append(PaddingInputExample()) eval_file = os.path.join(FLAGS.output_dir, "eval.tf_record")
file_based_convert_examples_to_features(
eval_examples, label_list, FLAGS.max_seq_length, tokenizer, eval_file) tf.logging.info("***** Running evaluation *****")
tf.logging.info(" Num examples = %d (%d actual, %d padding)",
len(eval_examples), num_actual_eval_examples,
len(eval_examples) - num_actual_eval_examples)
tf.logging.info(" Batch size = %d", FLAGS.eval_batch_size) # This tells the estimator to run through the entire set.
eval_steps = None
# However, if running eval on the TPU, you will need to specify the
# number of steps.
if FLAGS.use_tpu:
assert len(eval_examples) % FLAGS.eval_batch_size == 0
eval_steps = int(len(eval_examples) // FLAGS.eval_batch_size) eval_drop_remainder = True if FLAGS.use_tpu else False
eval_input_fn = file_based_input_fn_builder(
input_file=eval_file,
seq_length=FLAGS.max_seq_length,
is_training=False,
drop_remainder=eval_drop_remainder)
# result中就是return返回的字典
result = estimator.evaluate(input_fn=eval_input_fn, steps=eval_steps) output_eval_file = os.path.join(FLAGS.output_dir, "eval_results.txt")
with tf.gfile.GFile(output_eval_file, "w") as writer:
tf.logging.info("***** Eval results *****")
# 我们可以拿到混淆矩阵(现在时numpy的形式),调用metrics.py文件中的方法来得到precision,recall,f1值
pre, rec, f1 = metrics.get_metrics(result["eval_cm"], len(label_list))
tf.logging.info("eval_precision: {}".format(pre))
tf.logging.info("eval_recall: {}".format(rec))
tf.logging.info("eval_f1: {}".format(f1))
tf.logging.info("eval_accuracy: {}".format(result["eval_accuracy"]))
tf.logging.info("eval_loss: {}".format(result["eval_loss"])) np.save("conf_mat.npy", result["eval_cm"])
通过上面的代码拿到混淆矩阵后,调用metrics.py文件中的get_metrics方法就可以得到precision,recall,f1值。
BERT模型在多类别文本分类时的precision, recall, f1值的计算的更多相关文章
- NLP(十五)让模型来告诉你文本中的时间
背景介绍 在文章NLP入门(十一)从文本中提取时间 中,笔者演示了如何利用分词.词性标注的方法从文本中获取时间.当时的想法比较简单快捷,只是利用了词性标注这个功能而已,因此,在某些地方,时间的识别 ...
- 从Word Embedding到Bert模型—自然语言处理中的预训练技术发展史(转载)
转载 https://zhuanlan.zhihu.com/p/49271699 首发于深度学习前沿笔记 写文章 从Word Embedding到Bert模型—自然语言处理中的预训练技术发展史 张 ...
- zz从Word Embedding到Bert模型—自然语言处理中的预训练技术发展史
从Word Embedding到Bert模型—自然语言处理中的预训练技术发展史 Bert最近很火,应该是最近最火爆的AI进展,网上的评价很高,那么Bert值得这么高的评价吗?我个人判断是值得.那为什么 ...
- BERT模型图解
转载于 腾讯Bugly 发表于 腾讯Bugly的专栏 原文链接:https://cloud.tencent.com/developer/article/1389555 本文首先介绍BERT模型要做什么 ...
- 想研究BERT模型?先看看这篇文章吧!
最近,笔者想研究BERT模型,然而发现想弄懂BERT模型,还得先了解Transformer. 本文尽量贴合Transformer的原论文,但考虑到要易于理解,所以并非逐句翻译,而是根据笔者的个人理解进 ...
- 图示详解BERT模型的输入与输出
一.BERT整体结构 BERT主要用了Transformer的Encoder,而没有用其Decoder,我想是因为BERT是一个预训练模型,只要学到其中语义关系即可,不需要去解码完成具体的任务.整体架 ...
- NLP学习(3)---Bert模型
一.BERT模型: 前提:Seq2Seq模型 前提:transformer模型 bert实战教程1 使用BERT生成句向量,BERT做文本分类.文本相似度计算 bert中文分类实践 用bert做中文命 ...
- [NLP自然语言处理]谷歌BERT模型深度解析
我的机器学习教程「美团」算法工程师带你入门机器学习 已经开始更新了,欢迎大家订阅~ 任何关于算法.编程.AI行业知识或博客内容的问题,可以随时扫码关注公众号「图灵的猫」,加入”学习小组“,沙雕博主 ...
- Bert模型实现垃圾邮件分类
近日,对近些年在NLP领域很火的BERT模型进行了学习,并进行实践.今天在这里做一下笔记. 本篇博客包含下列内容: BERT模型简介 概览 BERT模型结构 BERT项目学习及代码走读 项目基本特性介 ...
随机推荐
- Java对象引用/JVM分级引用——强引用、软引用、弱引用、虚引用
无论是通过引用计数法判断对象的引用数量,还是通过可达性分析算法判断对象的引用链是否可达,判断对象是否存活都与“引用”有关, 相关资料:如何判断对象是否存活/死去 那么引用究竟是什么?让我们一起来看一下 ...
- 再谈AbstractQueuedSynchronizer3:基于AbstractQueuedSynchronizer的并发类实现
公平模式ReentrantLock实现原理 前面的文章研究了AbstractQueuedSynchronizer的独占锁和共享锁,有了前两篇文章的基础,就可以乘胜追击,看一下基于AbstractQue ...
- JQuery 常用的那些东西
CDN Google CDN Microsoft CDN CDNJS CDN jsDelivr CDN 选择器 jQuery 元素选择器和属性选择器允许您通过标签名.属性名或内容对 HTML 元素进行 ...
- 使用mysql事件定时执行岗位七天下线任务
最近做了一个招聘的项目,在项目中有一个定时下线的需求.在做之前我一直在考虑到底使用window 服务,还是使用调度,最终我选择使用mysql定时事件,因为这样简单方便. 思路:首先创建一个存储过程,通 ...
- win10激活(免费+永久)视频教程
U盘重装Win10系统视频教程 好久不见,不知同学们有没有想我~ 最近因为工作太忙所以好久都没有写文章了,很多朋友希望我推一期win10激活教程,所以今天带三胖打完针后,开始写一期win10激活教程: ...
- webstorm使用问题总结
webstorm 打断点调试配置 run/edit configurations中,把nodejs里的历史都删除:然后打开Defaults/Node.js将node的可执行程序放到Node inter ...
- ASP.NET Core 3.0 上的gRPC服务模板初体验(多图)
早就听说ASP.NET Core 3.0中引入了gRPC的服务模板,正好趁着家里电脑刚做了新系统,然后装了VS2019的功夫来体验一把.同时记录体验的过程.如果你也想按照本文的步骤体验的话,那你得先安 ...
- Elasticsearch Java高级客户端
1. 概述 Java REST Client 有两种风格: Java Low Level REST Client :用于Elasticsearch的官方低级客户端.它允许通过http与Elastic ...
- HttpUtil 【判断网络连接的封装类】
版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 该封装类主要包括以下功能: 判断是否有网络连接.判断是否有可用的网络连接: 判断是否是3G网络.判断mobile网络是否可用: 判断 ...
- ES 08 - 创建、查看、修改、删除、关闭Elasticsearch的index
目录 1 创建index(配置mapping[映射]) 2 查看index 3 修改index 4 删除index 5 打开/关闭index 6 常见问题及解决方法 index相当于RDBMS(关系型 ...