【问题标题】:How to correctly use the Tensorflow MeanIOU metric?如何正确使用 Tensorflow MeanIOU 指标?
【发布时间】:2020-06-15 19:52:00
【问题描述】:

我想在 keras (doc link) 中使用 MeanIoU 指标。但我真的不明白它如何与 keras api 集成。在示例中,预测和基本事实以二进制值的形式给出,但使用 keras 我们应该得到概率,特别是因为损失是 mse... 我们应该有类似的东西:

m = tf.keras.metrics.MeanIoU(num_classes=2)
m.update_state([0, 0, 1, 1], [0.3, 0.6, 0.2, 0.9])

但现在结果不一样了,我们有:

# <tf.Variable 'UnreadVariable' shape=(2, 2) dtype=float64, numpy=array([[2., 0.],
#                                                                        [2., 0.]])>
m.result().numpy() # 0.25

所以我的问题是,如果模型的输出是概率,我们应该如何使用这个指标?二进制甚至是多类设置(一个热)?

对于准确性,BinaryAccuracy 和 CategoricalAccuracy 之间存在区别,它们都采用y_pred 中的概率。 MeanIoU 不应该是一样的吗?

【问题讨论】:

    标签: python tensorflow tensorflow2.0 tf.keras


    【解决方案1】:

    我有同样的问题,我查看了源代码。

    在tf2.0中,update_state函数的末尾有:

    current_cm = confusion_matrix.confusion_matrix(
            y_true,
            y_pred,
            self.num_classes,
            weights=sample_weight,
            dtype=dtypes.float64)
    

    我研究了confusion_matrix 函数,

    with ops.name_scope(name, 'confusion_matrix',
                          (predictions, labels, num_classes, weights)) as name:
        labels, predictions = remove_squeezable_dimensions(
            ops.convert_to_tensor(labels, name='labels'),
            ops.convert_to_tensor(
                predictions, name='predictions'))
        predictions = math_ops.cast(predictions, dtypes.int64)
        labels = math_ops.cast(labels, dtypes.int64)
    
        # Sanity checks - underflow or overflow can cause memory corruption.
        labels = control_flow_ops.with_dependencies(
            [check_ops.assert_non_negative(
                labels, message='`labels` contains negative values')],
            labels)
        predictions = control_flow_ops.with_dependencies(
            [check_ops.assert_non_negative(
                predictions, message='`predictions` contains negative values')],
            predictions)
    
        if num_classes is None:
          num_classes = math_ops.maximum(math_ops.reduce_max(predictions),
                                         math_ops.reduce_max(labels)) + 1
        else:
          num_classes_int64 = math_ops.cast(num_classes, dtypes.int64)
          labels = control_flow_ops.with_dependencies(
              [check_ops.assert_less(
                  labels, num_classes_int64, message='`labels` out of bound')],
              labels)
          predictions = control_flow_ops.with_dependencies(
              [check_ops.assert_less(
                  predictions, num_classes_int64,
                  message='`predictions` out of bound')],
              predictions)
    
        if weights is not None:
          weights = ops.convert_to_tensor(weights, name='weights')
          predictions.get_shape().assert_is_compatible_with(weights.get_shape())
          weights = math_ops.cast(weights, dtype)
    
        shape = array_ops.stack([num_classes, num_classes])
        indices = array_ops.stack([labels, predictions], axis=1)
        values = (array_ops.ones_like(predictions, dtype)
                  if weights is None else weights)
        cm_sparse = sparse_tensor.SparseTensor(
            indices=indices,
            values=values,
            dense_shape=math_ops.cast(shape, dtypes.int64))
        zero_matrix = array_ops.zeros(math_ops.cast(shape, dtypes.int32), dtype)
    
        return sparse_ops.sparse_add(zero_matrix, cm_sparse)
    

    诀窍在代码的 第 6 行,tf 使用 math_ops.cast 将预测转换为 int64,因此当您将 [0.3, 0.6, 0.2, 0.9] 发送到转换函数时,它会返回 [0, 0, 0, 0]

    所以,这就是你得到一个混淆 maxtrix 的原因

    [[2., 0.],
    [2., 0.]]

    【讨论】:

      【解决方案2】:

      我也有类似的问题。尽管在网上寻找示例,但所有演示都是在模型输出上应用argmax 之后进行的。

      我现在的解决方法是继承tf.keras.metrics.MeanIoU

      class MyMeanIOU(tf.keras.metrics.MeanIoU):
          def update_state(self, y_true, y_pred, sample_weight=None):
              return super().update_state(tf.argmax(y_true, axis=-1), tf.argmax(y_pred, axis=-1), sample_weight)
      

      也可以创建自己的函数,但如果您希望从分布式策略等额外功能中受益,建议继承tf.keras.metrics.Metric

      我仍在寻找更清洁的解决方案。

      【讨论】:

      • 请注意,这仅在您的 y_truey_pred 格式正确的情况下返回有效结果。由于tf.argmax() 在遇到多个最大值时返回最小索引的性质,这可能会使结果产生偏差。就我而言,我尝试将MeanIoU 应用于一个热编码类标签。但是如果有一个不完美的标签(例如全零或多个零),我会得到错误的结果。如果有人知道如何处理它,将不胜感激。
      猜你喜欢
      • 1970-01-01
      • 2021-08-02
      • 2020-06-10
      • 2018-02-07
      • 1970-01-01
      • 2018-12-09
      • 2018-03-16
      • 2019-03-31
      • 1970-01-01
      相关资源
      最近更新 更多