zoukankan      html  css  js  c++  java
  • 【602】语义分割评价指标 IoU mIoU precision recall F1 的计算

    参考:语义分割代码阅读---评价指标mIoU的计算

    参考:(分割网络评价指标)dice系数和IOU之间的区别和联系

    参考:【621】numpy.array 的逻辑运算

    参考:numpy.bincount详解

    参考:深度学习之语义分割中的度量标准

    1. 二分类情况

      IoU: Intersection over Union 交并比,也叫作 Jaccard 系数

      在语义分割的问题中,这两个集合为真实值(ground truth)和预测值(predicted segmentation),分别用 $A$ 和 $B$ 表示:

    $$IOU(A, B) = frac{|A cap B|}{|A cup B|}$$

    $$IOU(A, B) = frac{Area\_of\_Overlap}{Area\_of\_Union}$$

      namely,

      keras 代码实现:

    def iou(y_true, y_pred):
    	# 貌似不转成一维也可以
    	y_truef = K.flatten(y_true)
    	y_predf = K.flatten(y_pred)
    	# 计算都是 1 的像素数
    	overlap = K.sum(y_truef & y_predf)
    	# 计算含有 1 的像素数
    	union = K.sum(y_truef | y_predf)
    	# 默认相除之后得到的是 tensor,转为 float
    	return float(overlap / union)   
    

                                                                    

      MIoU: Mean Intersection over Union 均交并比,其计算所有类别交集和并集之比的平均值。

      参考:Dice损失函数基础知识及代码实现

      默认是设置背景物体为 0,前景物体为 1(即使是 255,也会归一化为 1 的),因此在计算 Intersection 的时候,只需计算 [真值矩阵] * [预测值矩阵],然后再求和就行,因为只有两者都为 1 的情况下才会保留值。

    $$Dice(X, Y) = frac{2|X cap Y|}{|X| + |Y|}$$

    $$DiceLoss = 1 - frac{2|X cap Y| + smooth}{|X| + |Y| + smooth}$$

      keras 代码实现:

    # 防止分母为0
    smooth = 100
     
    # 定义Dice系数
    def dice_coef(y_true, y_pred):
        y_truef = K.flatten(y_true)  # 将 y_true 拉为一维
        y_predf = K.flatten(y_pred)
        intersection = K.sum(y_truef * y_predf)
        return (2 * intersection + smooth) / (K.sum(y_truef) + K.sum(y_predf) + smooth)
     
     
    # 定义Dice损失函数
    def dice_coef_loss(y_true, y_pred):
        return 1-dice_coef(y_true, y_pred)
    

    2. 一般情况

      $i$ 表示真实值

      $j$ 表示预测值

      $p_{ij}$ 表示将 $i$ 预测为 $j$

     

      对像素点进行遍历,然后按照公式进行计算,相当于两组矩阵进行对比,值一样(TP)的作为分子,值不一样的(FN+FP),但是还是包含对应的 class 的值,从而进行计算。

      FN:预测错误,预测为 Negative

      FP:预测错误,预测为 Positive

      TP:预测正确,预测为 Positive 

      直观理解:

       

      图中,蓝色部分为TP(True Positive),红色部分为FN(false negative),黄色部分为FP(false Positive)。根据这样的划分,重新给出IOU公式:
      在这里插入图片描述
      依据TP、TN、FP、FN的概念,重写dice系数的计算公式:
      在这里插入图片描述

      通过 keras 计算 $TP$、$FN$、$FP$,针对二分类

      $pred$:预测的值,图片对应的 numpy.array,二维

      $true$:真实的值,图片对应的 numpy.array,二维

      $TP$:true positive,判断为 1,且是正确的,就是说明 $pred$ 里面是 1 的像素点,$true$ 里面也是 1

    pred & true
    
    or 
    
    pred * true
    
    or 
    
    # bool 转为 int,最后以 1 和 0 显示
    ((pred == 1) & (true == 1)).astype('int')
    

      $FN$:false negative,判断为 0,但判断错误,就说明 $pred$ 里面是 0 的像素点,$true$ 里面是 1

    # bool 转为 int,最后以 1 和 0 显示
    ((pred == 0) & (true == 1)).astype('int')
    
    # 1 - pred 可以将 0 和 1 进行替换
    # 因此就是找对应位置都为 1 的像素点了
    (1 - pred) * true
    

      $FP$:false positive,判断为 1,但判断错误,就说明 $pred$ 里面是 1 的像素点,$true$ 里面是 0

    # bool 转为 int,最后以 1 和 0 显示
    ((pred == 1) & (true == 0)).astype('int')
    
    # 1 - true 可以将 0 和 1 进行替换
    # 因此就是找对应位置都为 1 的像素点了
    pred * (1 - true)
    

      通过下面的函数可以分别计算 $precision$, $recall$, $F_1$, $IoU$

      查准率(precision),指的是预测值为1且真实值也为1的样本在预测值为1的所有样本中所占的比例。以西瓜问题为例,算法挑出来的西瓜中有多少比例是好西瓜。

      分母:所有 $pred$ 为 1 的部分

    $$precision = frac{TP}{TP + FP} = frac{Area(pred cap true)}{Area(pred)}$$

      召回率(recall),也叫查全率,指的是预测值为1真实值也为1的样本在真实值1的所有样本中所占的比例。所有的好西瓜中有多少比例被算法挑了出来。

      分母:所有 $true$ 为 1 的部分

    $$recall = frac{TP}{TP + FN} = frac{Area(pred cap true)}{Area(true)}$$

      F1分数(F1-Score),又称为平衡F分数(BalancedScore),它被定义为精确率和召回率的调和平均数。

    $$F_1 = 2 * frac{precision * recall}{precision + recall}$$ 

      IOU(Intersection over Union)交并比。计算真实值和预测值集合的交集与并集之比。

    $$IoU = frac{TP}{TP + FP + FN}$$

    def metrics_all(pred, true):
    	tp = pred & true
    	fn = ((pred == 0) & (true == 1)).astype('int')
    	fp = ((pred == 1) & (true == 0)).astype('int')
    
    	precision = K.sum(tp) / (K.sum(tp) + K.sum(fp))
    	recall = K.sum(tp) / (K.sum(tp) + K.sum(fn))
    
    	f1 = 2 * precision * recall / (precision + recall)
    	iou = K.sum(tp) / (K.sum(tp) + K.sum(fp) + K.sum(fn))
    
    	return float(precision), float(recall), float(f1), float(iou)
    

      or

    def metrics_all2(pred, true):
    	tp = pred * true
    	fn = (1 - pred) * true
    	fp = pred * (1 - true)
    	precision = K.sum(tp) / (K.sum(tp) + K.sum(fp))
    	recall = K.sum(tp) / (K.sum(tp) + K.sum(fn))
    	f1 = 2 * precision * recall / (precision + recall)
    	iou = K.sum(tp) / (K.sum(tp) + K.sum(fp) + K.sum(fn))
    	return float(precision), float(recall), float(f1), float(iou)
    

      也可以通过 np.count_nonzero(pred) 来计算非 0 像素点的个数,对于 0 和 1 表示的数组,与 np.sum(pred) 没有区别。 

      对于多分类的问题,可以通过 np.bincount(x) 来计算每个数字的出现次数,x 需要是一维的,可以参考此链接 https://www.cnblogs.com/qqw-1995/p/10528237.html 

      可以通过混淆矩阵进行计算

  • 相关阅读:
    搞定Mac Maven
    《数学之美》读书笔记
    Scalable Web Architecture and Distributed Systems
    【程序员】修炼之书
    用平常心,做非常事(字节跳动九周年张一鸣演讲)
    动态规划题目总结
    Spring Boot 启动时,让方法自动执行的 4 种方法!
    MybatisGenerator生成mapper、dao、entity
    HTTPS的GET、POST、PUT、DELETE请求
    SpringBoot使用Slf4j进行日志配置
  • 原文地址:https://www.cnblogs.com/alex-bn-lee/p/14999934.html
Copyright © 2011-2022 走看看