当使用Tensorflow进行多类分类时,有没有一种方法可以获得每个类的精确度或召回率。
例如,如果我有来自每批次的y_true和y_pred,是否有一种功能性的方式可以在有多于2个类的情况下获取每个类的精确度或召回率。
当使用Tensorflow进行多类分类时,有没有一种方法可以获得每个类的精确度或召回率。
例如,如果我有来自每批次的y_true和y_pred,是否有一种功能性的方式可以在有多于2个类的情况下获取每个类的精确度或召回率。
y_true = tf.argmax(labels, 1)
y_pred = tf.argmax(logits, 1)
recall = [0] * n
update_op_rec = [[]] * n
for k in range(n):
recall[k], update_op_rec[k] = tf.metrics.recall(
labels=tf.equal(y_true, k),
predictions=tf.equal(y_pred, k)
)
tf.metrics.recall
中,变量labels
和predictions
被设置为布尔向量,就像在2个变量的情况下一样,这允许使用该函数。两个事实:
有一些方法可以使用precision_at_k通过指定class_id
或者简单地以正确的方式将labels
和predictions
转换为tf.bool
来获取一个对所有得分。
由于这种方法不尽人意且不完整,我编写了tf_metrics
,这是一个简单的用于多类分类度量的包,您可以在GitHub上找到。它支持多种平均方法,例如scikit-learn
。
例子
import tensorflow as tf
import tf_metrics
y_true = [0, 1, 0, 0, 0, 2, 3, 0, 0, 1]
y_pred = [0, 1, 0, 0, 1, 2, 0, 3, 3, 1]
pos_indices = [1] # Metrics for class 1 -- or
pos_indices = [1, 2, 3] # Average metrics, 0 is the 'negative' class
num_classes = 4
average = 'micro'
# Tuple of (value, update_op)
precision = tf_metrics.precision(
y_true, y_pred, num_classes, pos_indices, average=average)
recall = tf_metrics.recall(
y_true, y_pred, num_classes, pos_indices, average=average)
f2 = tf_metrics.fbeta(
y_true, y_pred, num_classes, pos_indices, average=average, beta=2)
f1 = tf_metrics.f1(
y_true, y_pred, num_classes, pos_indices, average=average)
我已经被这个问题困扰了相当长的时间。我知道可以使用sklearn来解决这个问题,但我真的想通过Tensorflow的API来解决它。通过阅读它的代码,我终于搞清楚了这个API是如何工作的。
tf.metrics.precision_at_k(labels, predictions, k, class_id)
Finally, let's use this API to verify our assumption.
import tensorflow as tf
labels = tf.constant([[2],[0]],tf.int64)
predictions = tf.constant([[0.5,0.3,0.1,0.1],[0.5,0.3,0.1,0.1]])
metric = tf.metrics.precision_at_k(labels, predictions, 1, class_id=0)
sess = tf.Session()
sess.run(tf.local_variables_initializer())
precision, update = sess.run(metric)
print(precision) # 0.5
注意
k 不是类别数量。它表示我们想要排序的项目数量,因此预测结果的最后一维必须与k的值相同。
class_id 表示我们想要二元指标的类别。
如果 k=1,则意味着我们不会对预测进行排序,因为我们实际上要做的是二元分类,但是涉及到不同的类别。因此,如果我们对预测进行排序,class_id 将会混淆,结果将会错误。
还有一件重要的事情是,如果我们想要得到正确的结果,标签的输入应该减去1,因为 class_id 实际上表示 标签的索引,而标签的下标从0开始。
我认为使用tf.metrics.precision/recall
函数无法进行多类别的精确度、召回率和f1值计算。对于三类情况,您可以像这样使用sklearn:
from sklearn.metrics import precision_recall_fscore_support as score
prediction = [1,2,3,2]
y_original = [1,2,3,3]
precision, recall, f1, _ = score(y_original, prediction)
print('precision: {}'.format(precision))
print('recall: {}'.format(recall))
print('fscore: {}'.format(f1))
tf.metrics.precision_at_k(labels, predictions, k, class_id)
将k设置为1并设置对应的class_id。例如,设置class_id=0以计算第一类的精度。
这里有一个完整的例子,从使用Tensorflow进行预测到通过scikit-learn进行报告:
import tensorflow as tf
from sklearn.metrics import classification_report
# given trained model `model` and test vector `X_test` gives `y_test`
# where `y_test` and `y_predicted` are integers, who labels are indexed in
# `labels`
y_predicted = tf.argmax(model.predict(X_test), axis=1)
# Confusion matrix
cf = tf.math.confusion_matrix(y_test, y_predicted)
plt.matshow(cf, cmap='magma')
plt.colorbar()
plt.xticks(np.arange(len(labels)), labels=labels, rotation=90)
plt.yticks(np.arange(len(labels)), labels=labels)
plt.clim(0, None)
# Report
print(classification_report(y_test, y_predicted, target_names=labels))
tf.metrics.mean_per_class_accuracy
)。使用不平衡数据时,这些值可能与使用tf.metrics.recall
和tf.metrics.precision
获得的值不同。 - Avitf.metrics.mean_per_class_accuracy
做的是不同的事情,并不是这个问题的好参考。 - Avi