【问题标题】:Class wise precision and recall for multi class classification in Tensorflow?Tensorflow 中多类分类的分类精度和召回率?
【发布时间】:2018-01-18 03:03:03
【问题描述】:

在使用张量流进行多类分类时,有没有办法获得每类精度或召回率。

例如,如果我每批都有 y_true 和 y_pred,如果我有超过 2 个类,是否有一种函数式方法可以获取每个类的精度或召回率。

【问题讨论】:

    标签: python machine-learning tensorflow classification


    【解决方案1】:

    我相信 TF 还没有提供这样的功能。根据文档 (https://www.tensorflow.org/api_docs/python/tf/metrics/precision),它说标签和预测都将转换为 bool,因此它仅与二进制分类有关。也许可以对示例进行一次热编码并且它会起作用?但不确定这一点。

    【讨论】:

    • 再一次,正如问题所问的,这些函数不会为每个类单独计算指标。如果某些类别比其他类别更频繁地出现在数据中,则这些指标将由这些频繁类别主导。通常需要为每个类计算单独的召回率和精度,然后对它们进行跨类平均以获得总体值(类似于tf.metrics.mean_per_class_accuracy)。这些值可能与使用不平衡数据的tf.metrics.recalltf.metrics.precision 获得的值不同。
    • 其实我弄错了; tf.metrics.mean_per_class_accuracy 做了一些不同的事情,不是这个问题的好参考。
    【解决方案2】:

    我相信您无法使用 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))
    

    这将打印一个精度数组、召回值,但可以根据需要对其进行格式化。

    【讨论】:

      【解决方案3】:

      对于 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 内部,变量labelspredictions 被设置为布尔向量,就像在2 变量情况下一样,这允许使用该函数。

      【讨论】:

        【解决方案4】:

        在 TensorFlow 中有一种方法可以做到这一点。

        tf.metrics.precision_at_k(labels, predictions, k, class_id)
        

        设置 k = 1 并设置相应的 class_id。例如 class_id=0 计算第一类的精度。

        【讨论】:

          【解决方案5】:

          这个问题困扰我很久了。我知道这个问题可以通过 sklearn 来解决,但是我真的很想通过 Tensorflow 的 API 来解决这个问题。通过阅读它的代码,我终于弄清楚了这个 API 是如何工作的。

          tf.metrics.precision_at_k(labels, predictions, k, class_id)
          
          • 首先,我们假设这是一个4类问题。
          • 其次,我们有两个样本,他们的标签是 3 和 1他们的预测是 [0.5,0.3,0.1,0.1], [0.5,0.3,0.1,0.1] .根据我们的预测,我们可以得到两个样本都被预测为1,1的结果。
          • 第三,如果你想得到class 1的精度,使用公式 TP/(TP+FP),我们假设结果是1/(1+1)=0.5。因为两个样本都被预测为1,但其中一个实际是3,所以TP为1 >FP 为 1结果为 0.5
          • 最后,让我们使用这个 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开头

          【讨论】:

            【解决方案6】:

            2 个事实:

            1. 正如其他答案所述,Tensorflow 内置指标 precisionrecall 不支持多类(文档说 will be cast to bool

            2. 通过指定class_id 使用precision_at_k 或简单地将labelspredictions 转换为@,有多种方法可以获得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)
            

            【讨论】:

              【解决方案7】:

              这是一个从 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))
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2023-03-08
                • 2019-03-31
                • 2019-09-29
                • 2016-06-19
                • 2013-10-01
                • 1970-01-01
                • 1970-01-01
                • 2016-01-09
                相关资源
                最近更新 更多