【发布时间】:2018-01-18 03:03:03
【问题描述】:
在使用张量流进行多类分类时,有没有办法获得每类精度或召回率。
例如,如果我每批都有 y_true 和 y_pred,如果我有超过 2 个类,是否有一种函数式方法可以获取每个类的精度或召回率。
【问题讨论】:
标签: python machine-learning tensorflow classification
在使用张量流进行多类分类时,有没有办法获得每类精度或召回率。
例如,如果我每批都有 y_true 和 y_pred,如果我有超过 2 个类,是否有一种函数式方法可以获取每个类的精度或召回率。
【问题讨论】:
标签: python machine-learning tensorflow classification
我相信 TF 还没有提供这样的功能。根据文档 (https://www.tensorflow.org/api_docs/python/tf/metrics/precision),它说标签和预测都将转换为 bool,因此它仅与二进制分类有关。也许可以对示例进行一次热编码并且它会起作用?但不确定这一点。
【讨论】:
tf.metrics.mean_per_class_accuracy)。这些值可能与使用不平衡数据的tf.metrics.recall 和tf.metrics.precision 获得的值不同。
tf.metrics.mean_per_class_accuracy 做了一些不同的事情,不是这个问题的好参考。
我相信您无法使用 tf.metrics.precision/recall 函数进行多类精度、召回和 f1。您可以像这样将 sklearn 用于 3 类场景:
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))
这将打印一个精度数组、召回值,但可以根据需要对其进行格式化。
【讨论】:
对于 n=6 类的问题,这是一个对我有用的解决方案。如果你有更多的类,这个解决方案可能会很慢,你应该使用某种映射而不是循环。
假设您在张量 labels 的行中有一个热编码类标签,在张量 labels 中有 logits(或后验)。然后,如果n 是类数,试试这个:
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 变量情况下一样,这允许使用该函数。
【讨论】:
在 TensorFlow 中有一种方法可以做到这一点。
tf.metrics.precision_at_k(labels, predictions, k, class_id)
设置 k = 1 并设置相应的 class_id。例如 class_id=0 计算第一类的精度。
【讨论】:
这个问题困扰我很久了。我知道这个问题可以通过 sklearn 来解决,但是我真的很想通过 Tensorflow 的 API 来解决这个问题。通过阅读它的代码,我终于弄清楚了这个 API 是如何工作的。
tf.metrics.precision_at_k(labels, predictions, k, class_id)
最后,让我们使用这个 API 来验证我们的假设。
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会混淆,结果会出错。
还有一件更重要的事情是,如果我们想要得到正确的结果,label的输入应该减1,因为class_id实际上代表了label的索引,标签下标以0开头。
【讨论】:
2 个事实:
正如其他答案所述,Tensorflow 内置指标 precision 和 recall 不支持多类(文档说 will be cast to bool)
通过指定class_id 使用precision_at_k 或简单地将labels 和predictions 转换为@,有多种方法可以获得one-versus-all 分数 987654330@以正确的方式。
因为这不令人满意且不完整,我编写了 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)
【讨论】:
这是一个从 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))
【讨论】: