今天看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
tf.metrics.mean_iou()
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} IOU=TP+FP+FNTP
函数首先根据混淆矩阵计算每个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)
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
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