当前位置:   article > 正文

【机器学习】图像语义分割常用指标Dice系数 敏感性 特异性 IOU及python代码实现

dice系数

知识铺垫

二分类和多分类的评价指标的选择
首先,对于像素点,我们要知道,当预测的像素点类别和其真实类别不同或者相同时,我们可以用混淆矩阵来表示,如下图:
在这里插入图片描述

1. Dice系数和IOU

首先,dice和IOU都是衡量两个集合之间相似性的度量,在图像分割领域用来衡量网络分割结果与金标准mask(标签)之间的相似性。
(分割网络评价指标)dice系数和IOU之间的区别和联系

IOU

IOU指标可以使用几何办法给出直观的解释,我们假设红色代表图片中的标签,黄色是分割的结果,那么他们重叠的蓝色部分就是TP(true Positive)真正例,也就是正样本被正确分类。
那么对应的红色就是预测为负但实际为正,因此是FN。
下面黄色部分,就是预测为正,但实际为负,因此是FP(false Positive)。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
结合上述图片,我们可以给出IOU的公式(结合几何意义)
I O U = T P F N + T P + F P IOU = \frac{TP}{FN+TP+FP} IOU=FN+TP+FPTP
I O U = 预测正确:蓝色 ( 红色 + 蓝色 + 黄色 ) IOU=\frac{预测正确:蓝色}{(红色+蓝色+黄色)} IOU=(红色+蓝色+黄色)预测正确:蓝色
这位是对于一个类别来说的IOU公式,而mIOU公式是对所有类别求交并比的平均值。
m I O U = 1 k ∑ i = 1 k T P F N + T P + F P mIOU = \frac{1}{k}\sum_{i=1}^{k}\frac{TP}{FN+TP+FP} mIOU=k1i=1kFN+TP+FPTP
mIOU的计算过程中首先需要计算混淆矩阵。

Dice系数

Dice系数、mIOU与Dice LOss
Dice系数是一种集合的相似度度量函数,通常用于计算两个样本的相似度,取值范围在[0,1]之间。
在这里插入图片描述
我们同样根据上图,可以得出Dice系数的公式为:

Dice系数的计算公式如下:

D i c e = 2 × T P ( T P + F N ) + ( T P + F P ) = 2 × 预测正确:蓝色 ( 真实结果:红色 + 蓝色 ) + ( 预测结果:黄色 + 蓝色 ) Dice=\frac{2\times TP}{(TP+FN)+(TP+FP)} =\frac{2\times 预测正确:蓝色}{(真实结果:红色+蓝色)+(预测结果:黄色+蓝色)} Dice=(TP+FN)+(TP+FP)2×TP=(真实结果:红色+蓝色)+(预测结果:黄色+蓝色)2×预测正确:蓝色

Dice和IOU的关系分析

Dice和IOU关系分析
集合交并比: m I O U = T P F N + T P + F P 集合交并比:mIOU = \frac{TP}{FN+TP+FP} 集合交并比:mIOU=FN+TP+FPTP
集合相似度: D i c e = 2 × T P ( T P + F N ) + ( T P + F P ) 集合相似度:Dice=\frac{2\times TP}{(TP+FN)+(TP+FP)} 集合相似度:Dice=(TP+FN)+(TP+FP)2×TP
在这里插入图片描述
集合交并比: I O U = T P F N + T P + F P = T P F N + T P + F P + T P − T P = 2 T P 2 ( F N + T P + F P + T P ) − 2 T P = D i c e 2 − D i c e 集合交并比:IOU = \frac{TP}{FN+TP+FP}\\ = \frac{TP}{FN+TP+FP+TP-TP}\\ =\frac{2TP}{2(FN+TP+FP+TP)-2TP}\\ =\frac{Dice}{2-Dice} 集合交并比:IOU=FN+TP+FPTP=FN+TP+FP+TPTPTP=2(FN+TP+FP+TP)2TP2TP=2DiceDice
由公式可知,Dice一般情况下>IOU。
曲线如下:
在这里插入图片描述

代码

由于网上给的Dice系数的求解代码基本上都是batch_size=1的,当batch_size>1的时候,就没法用了,因此在这里对网上流行的代码和自己改的代码分别进行总结。

def dice_coef(output, target): # batch_size=1
    smooth = 1e-5
    #output = torch.sigmoid(output).view(-1).data.cpu().numpy()
    output=torch.sigmoid(output)
    output[output > 0.5] = 1  #将概率输出变为于标签相匹配的矩阵
    output[output <= 0.5] = 0
    #target = target.view(-1).data.cpu().numpy()

    intersection = (output * target).sum() = TP
	# \符号有换行的作用
    return (2. * intersection + smooth) / \
        (output.sum() + target.sum() + smooth)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
# dice=2*TP/(TP+FN)+(TP+FP)
def dice_coef(output, target):  # Batch_size>1时
    smooth = 1e-5
    #output = torch.sigmoid(output).view(-1).data.cpu().numpy()
    output=torch.sigmoid(output).data.cpu().numpy()
    output[output > 0.5] = 1  #将概率输出变为于标签相匹配的矩阵
    output[output <= 0.5] = 0
    # target = target.view(-1).data.cpu().numpy()
    target = target.data.cpu().numpy()
    dice=0.
    # ipdb.set_trace() # 用于断掉调试
    if len(output)>1:# 如果样本量>1,则逐样本累加
        for i in range(len(output)):
            intersection = (output[i] * target[i]).sum()
            dice += (2. * intersection + smooth)/(output[i].sum() + target[i].sum() + smooth)
    else:
        intersection = (output * target).sum() # 一个数字,=TP
        dice = (2. * intersection + smooth) /(output.sum() + target.sum() + smooth)
    return dice
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

IOU的计算公式如下:
D i c e = T P T P + F N + F P Dice=\frac{TP}{TP+FN+FP} Dice=TP+FN+FPTP

# batch_size = 1
def iou_score(output, target):
    smooth = 1e-5

    if torch.is_tensor(output):
        output = torch.sigmoid(output).data.cpu().numpy()
    if torch.is_tensor(target):
        target = target.data.cpu().numpy()
    output_ = output > 0.5
    target_ = target > 0.5
    intersection = (output_ & target_).sum()
    union = (output_ | target_).sum()

    return (intersection + smooth) / (union + smooth)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
#batch_size > 1
def iou_score(output, target):
    smooth = 1e-5

    if torch.is_tensor(output):
        output = torch.sigmoid(output).data.cpu().numpy()
    if torch.is_tensor(target):
        target = target.data.cpu().numpy()
    output_ = output > 0.5
    target_ = target > 0.5
    # intersection = (output_ & target_).sum()
    # union = (output_ | target_).sum()
    iou = 0.
    if len(output)>1:
        for i in range(len(output)):
            union = (output_[i] | target_[i]).sum()
            intersection = (output_[i] & target_[i]).sum()
            iou += (intersection + smooth) / (union + smooth)
    else:
        intersection = (output_ & target_).sum()
        union = (output_ | target_).sum()
        iou = (intersection + smooth) / (union + smooth)
    return iou
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

2.敏感性(=Recall)、特异性和精确度(=precision=PPV)

2.1 敏感性(召回率)和特异性

Recall公式

def get_sensitivity(output, gt): # 求敏感度 se=TP/(TP+FN)
    SE = 0.
    output = output > 0.5
    gt = gt > 0.5
    TP = ((output==1).byte() + (gt==1).byte()) == 2
    FN = ((output==0).byte() + (gt==1).byte()) == 2
    #wfy:batch_num>1时,改进
    if len(output)>1:
        for i in range(len(output)):
            SE += float(torch.sum(TP[i])) / (float(torch.sum(TP[i]+FN[i])) + 1e-6)
    else:
        SE = float(torch.sum(TP)) / (float(torch.sum(TP+FN)) + 1e-6) #原本只用这一句
    #SE = float(torch.sum(TP)) / (float(torch.sum(TP + FN)) + 1e-6)  # 原本只用这一句
    return SE  #返回batch中所有样本的SE和
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

特异性:

def get_specificity(SR, GT, threshold=0.5):#求特异性 sp=TN/(FP+TN)
    SR = SR > threshold #得到true和false
    GT = GT > threshold
    SP=0.# wfy
    # TN : True Negative
    # FP : False Positive
    TN = ((SR == 0).byte() + (GT == 0).byte()) == 2
    FP = ((SR == 1).byte() + (GT == 0).byte()) == 2
    #wfy:batch_num>1时,改进
    if len(SR)>1:
        for i in range(len(SR)):
            SP += float(torch.sum(TN[i])) / (float(torch.sum(TN[i] + FP[i])) + 1e-6)
    else:
        SP = float(torch.sum(TN)) / (float(torch.sum(TN + FP)) + 1e-6) # 原本只用这一句
    #
    # SP = float(torch.sum(TN)) / (float(torch.sum(TN + FP)) + 1e-6)
    return SP
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

这两个指标在医疗领域很常用,而在机器学习领域常用的是Recall和Precision。

2.2 敏感性和特异性之间的关系

暂略

2.3 Recall和Precision之间的关系

ppv=precision

def ppv(output, target): #阳性预测值,准确率(precision)pr = TP/(TP+FP)
    smooth = 1e-5

    if torch.is_tensor(output):
        output = torch.sigmoid(output).data.cpu().numpy()
    if torch.is_tensor(target):
        target = target.data.cpu().numpy()
    ppv=0.
    if len(output)>1:
        for i in range(len(output)):
            intersection = (output[i] * target[i]).sum()
            ppv += (intersection + smooth)/(output[i].sum() + smooth)
    else:
        intersection = (output * target).sum() # 一个数字,=TP
        ppv = (intersection + smooth)/(output.sum() + smooth)

    # intersection = (output * target).sum() # TP
    return ppv
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

3. F1

def get_F1(output, gt):
    se = get_sensitivity(output, gt)
    pc = get_precision(output, gt)
    f1 = 2*se*pc / (se+pc+1e-6)
    return f1
  • 1
  • 2
  • 3
  • 4
  • 5
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/114117?site
推荐阅读
相关标签
  

闽ICP备14008679号