tf.metrics.mean_iou(), tf.where(), tf.ones_like()及通过混淆矩阵计算mean_iou

今天看deeplab_v3+源码的时候研究了一下mean_iou的计算部分, 学习了几个函数, 以及根据混淆矩阵计算mean_iou的具体细节

源码是这样的:

mean_iou = tf.metrics.mean_iou(valid_labels, valid_preds, params['num_classes'])
train_mean_iou = compute_mean_iou(mean_iou[1])

def compute_mean_iou(total_cm, name='mean_iou'):
    """Compute the mean intersection-over-union via the confusion matrix."""
    # 将total_cm(混淆矩阵)的第一行和第一列置为0, 目的是在计算mean_iou的时候不考虑label为0的项(根据项目要求做的修改)
    condition = np.zeros((params['num_classes'],params['num_classes']))
    ones = np.ones((params['num_classes']-1,params['num_classes']-1))
    condition[1:,1:] = ones
    total_cm = tf.where(condition, total_cm, tf.zeros_like(total_cm))
    
    sum_over_row = tf.to_float(tf.reduce_sum(total_cm, 0))
    sum_over_col = tf.to_float(tf.reduce_sum(total_cm, 1))
    cm_diag = tf.to_float(tf.diag_part(total_cm))
    denominator = sum_over_row + sum_over_col - cm_diag

    # The mean is only computed over classes that appear in the
    # label or prediction tensor. If the denominator is 0, we need to
    # ignore the class.
    num_valid_entries = tf.reduce_sum(tf.cast(
        tf.not_equal(denominator, 0), dtype=tf.float32))

    # If the value of the denominator is 0, set it to 1 to avoid
    # zero division.
    denominator = tf.where(
        tf.greater(denominator, 0),
        denominator,
        tf.ones_like(denominator))
    iou = tf.div(cm_diag, denominator)

    for i in range(params['num_classes']):
      tf.identity(iou[i], name='train_iou_class{}'.format(i))
      tf.summary.scalar('train_iou_class{}'.format(i), iou[i])

    # If the number of valid entries is 0 (no classes) we return 0.
    result = tf.where(
        tf.greater(num_valid_entries, 0),
        tf.reduce_sum(iou, name=name) / num_valid_entries,
        0)
    return result
  1. tf.metrics.mean_iou()
    tensorflow官方文档:
tf.metrics.mean_iou(
    labels,
    predictions,
    num_classes,
    weights=None,
    metrics_collections=None,
    updates_collections=None,
    name=None
)

labels和predictions都是shape为[batch_size, ]的tensor, num_classes必须指定, 这三项可以生成混淆矩阵.

iou的计算公式为: I O U = T P T P + F P + F N IOU = \frac{TP}{TP+FP+FN}

函数首先根据混淆矩阵计算每个class的iou, 然后取平均值, 注意取平均时的分母是出现labels或predictions中出现过的classes个数, 不一定是num_classes.

函数返回值为tuple, 包括(mean_iou, update_op). update_op就是根据输入得到的混淆矩阵, 而上面的compute_mean_iou函数返回的result实际上就是sess.run(mean_iou)的结果.

之所以要这样单独写一个函数来计算mean_iou, 是因为tf.metrics.mean_iou()的返回结果有点特别. 如果不进行sess.run(update_op)而直接sess.run(mean_iou), 结果将是0. mean_iou是定义在update_op的基础上的, 根据这个混淆矩阵进行计算.

注: 必须先sess.run(tf.local_variables_initializer()), 然后才能sess.run(update_op)

  1. tf.where()
    官方文档定义:
tf.where(
    condition,
    x=None,
    y=None,
    name=None
)

condition, x, y 要求同维. condition是bool型值,True/False

返回值是对应元素,condition中元素为True的元素替换为x中的元素,为False的元素替换为y中对应元素

举例:

import tensorflow as tf
x = [[1,2,3],[4,5,6]]
y = [[7,8,9],[10,11,12]]
condition1 = [[True,False,False],
             [False,True,True]]
condition2 = [[True,False,False],
             [True,True,False]]
with tf.Session() as sess:
    print(sess.run(tf.where(condition1,x,y)))
    print(sess.run(tf.where(condition2,x,y)))  

以下为结果:
1[[ 1  8  9]
    [10  5  6]]
2[[ 1  8  9]
    [ 4  5 12]]

注: tf.where()中x, y 是list或者array均可. condition如果是list, 元素要求是bool型, 如果是numpy.array, 元素可以是整数或小数, 如0,1

  1. tf.ones_like()
tensor = tf.constant([[1, 2, 3], [4, 5, 6]])
tf.ones_like(tensor)  # [[1, 1, 1], [1, 1, 1]]

给定一个tensor(tensor 参数),该操作返回一个具有和给定tensor相同形状(shape)和相同数据类型(dtype),但是所有的元素都被设置为1的tensor。也可以为返回的tensor指定一个新的数据类型。

以上是tf.ones_like()函数的介绍,类似地也可以得到tf.zeros_like()函数的信息,只不过填充的数据是0,而不是1

猜你喜欢

转载自blog.csdn.net/weixin_42561002/article/details/87919081