​ 理论上来说从应用的角度考虑评价一个图像语义分割算法好坏应该从准确度,处理速度以及存储空间占用情况三个方面考虑,但就理论研究而言准确度往往更加重要且直观,因此以下总结的常用指标均为语义分割准确度层面的评估指标。同时由于目前研究问题主要是二分类的语义分割任务,相关实现均以二分类的语义分割为主。语义分割本质上就是像素级的分类任务,很多指标通用实现方法均可按照分类的评价指标进行实现。因此混淆矩阵的实现算是语义分割评价指标实现的关键步骤。下面先简单介绍混淆矩阵以及二分类任务下的评价指标。

混淆矩阵

混淆矩阵也称误差矩阵,是表示精度评价的一种标准格式,用n行n列的矩阵形式来表示,以下是二分类任务中的混淆矩阵。

真实情况\预测结果 正例 反例
正例 TP(真正例) FN(假反例)
反例 FP(假正例) TN(真反例)

上面表格中第二个字母代表预测的结果是正例还是反例,第一个字母代表预测正确还是错误

具体实现代码如下

1
2
3
4
5
6
7
8
def getConfusionMatrix(img,gt,num_class):
mask = (gt>=0)&(gt<num_class) #避免图像中有错误信息导致后面的bincount产生错误
label = self.num_class*gt[mask]+img[mask]
count = torch.bincount(label,minlength=self.num_class**2)
confusionMatrix = count.reshape(self.num_class,self.num_class)
return confusionMatrix
#TN FP
#FN TP

分类任务评估指标

Accuracy准确度

准确度是指所有预测正确的比例,公式为Acc=TP+TNTP+FP+TN+FNAcc=\frac{TP+TN}{TP+FP+TN+FN}

Precision 查准率

​ 查准率定义为所有预测是正例的正确率,用公式表示为P=TPTP+FPP=\frac{TP}{TP+FP}

Recall 查全率

​ 查全率是指真正例在真实情况为正例中的比例,直白一点就是在一次实验中预测正例正确占全部正例的比率,用公式表示为R=TPTP+FNR=\frac{TP}{TP+FN}

F1 Score

​ 查准率和查全率通常是一对互相矛盾的指标,并不单独来评价预测准确率,F1 是二者的调和平均数常被作为重要的评价指标。用公式表示为 F1=2PRP+RF1=\frac{2PR}{P+R}

语义分割评估指标

Pixel accuracy 像素准确度

​ 这种方式跟分类任务中的准确度一样,直接对图像的每一个像素进行判断,用预测对的像素的数量除以总的像素数量来反映预测的准确度。公式表示为PA=i=0Kpiii=0Kj=0Kpij=TP+TNTP+FP+TN+FNPA=\frac{\sum_{i=0}^K{p_{ii}}}{\sum_{i=0}^K\sum_{j=0}^K{p_{ij}}}=\frac{TP+TN}{TP+FP+TN+FN}(其中K代表分类数,加上背景总共K+1类,pij代表将类别i的像素预测为类别j)

Mean Pixel accuracy MPA

​ 这种方式是对PA的一种扩展,还是对图像的每个像素进行判断,但这次计算每个类别的正确率,最后求平均值。公式可以表示为MPA=1K+1i=0Kpiij=0KpijMPA=\frac{1}{K+1}\sum_{i=0}^{K}\frac{p_{ii}}{\sum_{j=0}^{K}{p_{ij}}}

IoU 交并比

语义分割最常用的评价指标,这个根据名字就可以理解,交并比就是指预测值跟真值的交集除以他们两个的并集,用这种方式反映预测的准确度也很好理解,一样的地方越多越好,不一样的地方越少越好。公式表示为**IoU=J(A,B)=ABAB=TPTP+FP+FNIoU=J(A,B)=\frac{A\cap B}{A\cup B}=\frac{TP}{TP+FP+FN}**

1
2
3
4
5
6
def IoU(img,gt):
assert img.shape==gt.shape
inner = (img*gt).sum(dim=(0,1))
outter = (img+gt).sum(dim=(0,1))
IoU = inner/outter
return IoU

Mean-IoU 平均交并比

​ 主要用于多分类问题,就是对所有类单独做IoU,最后求均值

Dice coefficient

Dice系数是另一种图像分割领域常用的评价指标(尤其是在医学图像分割领域),可以将其定义为预测图和真实图的重叠区域的两倍,再除以两个图像中像素的总数,用公式表示为 Dice=2ABA+B=2TP2TP+FN+FPDice=\frac{2\left | A\cap B \right |}{\left | A \right |+\left | B \right |}=\frac{2TP}{2TP+FN+FP}

在预测二值图是可以发现Dice=F1Dice=F1

1
2
3
4
5
6
7
8
def Dice(img,gt):
#einsum 爱因斯坦求和 大佬论文中都爱用的这个,试着玩点花的/doge
assert img.shape == gt.shape
inner = torch.einsum('hw->',img*gt) #和上面IoU的inner等价
X = torch.einsum('hw->',img)
Y = torch.einsum('hw->',gt)
dice = 2*inner/(X+Y)
return dice

Mean Absolute Error (MAE)

平均绝对误差是指预测图和真值图中不一样的部分占两图中总像素的比重 公式表示为:MAE=FP+FNTP+FNMAE=\frac{FP+FN}{TP+FN}

1
2
3
4
def MAE(img,gt):
assert img.shape==gt.shape
mae = (img-gt).abs().sum()/(img.shape[0]*img.shape[1])
return mae

以下混淆矩阵实现各个评估指标方式,此处仅展示PA,其他评估指标均可以根据公式以混淆矩阵的方式进行实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class SegmentationMetric():
def __init__(self):
self.num_class = 2
self.confusionMatrix = torch.zeros((self.num_class,)*2)
#TN FP
#FN TP
def addImage(self,img,gt):
assert img.shape == gt.shape
self.confusionMatrix = self.getConfusionMatrix(img,gt)

def getConfusionMatrix(self,img,gt):
mask = (gt>=0)&(gt<self.num_class)
label = self.num_class*gt[mask]+img[mask]
count = torch.bincount(label,minlength=self.num_class**2)
confusionMatrix = count.reshape(self.num_class,self.num_class)
return confusionMatrix

def reset(self):
self.confusionMatrix = torch.zeros((self.num_class,self.num_class))

def PA(self):
#像素准确率 PA = (TP+TN)/(TP+FP+FN+TN)
pa = torch.diag(self.confusionMatrix).sum()/self.confusionMatrix.sum()
return pa

def CPA(self):
#分类像素准确率 类似二分类中的查准率 TP/(TP+FP) TN/(TN+FN)
cpa = torch.diag(self.confusionMatrix)/self.confusionMatrix.sum(axis=0)
return cpa

def mPA(self):
cpa = self.CPA()
mpa = torch.mean(cpa)
return mpa

参考资料

[1] 语义分割的评价指标

[2] Minaee S , Y Boykov, Porikli F , et al. Image Segmentation Using Deep Learning: A Survey[J]. 2020.

[3] 【语义分割】评价指标:PA、CPA、MPA、IoU、MIoU详细总结和代码实现(零基础从入门到精通系列!)