语义分割评价指标
混淆矩阵和评价指标
https://cocodataset.org/#stuff-eval
混淆矩阵(Confusion Matrix)
指标 | 公式 |
---|---|
准确率、正确率 | T P + T N ТР + T N + F P + F N \frac{TP + TN}{ ТР+ TN+FP+FN} ТР+TN+FP+FNTP+TN |
精确率、精度 | P = T P ТР + F P P= \frac{TP }{ ТР+ FP} P=ТР+FPTP |
真正类率、召回率 | R = T P ТР + F N R= \frac{TP }{ ТР+ FN} R=ТР+FNTP |
F1-Score:精确度和召回率的调和平均值 | F 1 = 2 P × R P + R F1=2\frac{P×R}{P+R} F1=2P+RP×R |
举例
注:大多数博客的类别像素准确率都是 T P T P + F P \frac{TP}{TP + FP} TP+FPTP,而代码中都是 T P ТР + F N \frac{TP }{ ТР+ FN} ТР+FNTP,其实类别像素准确率应该为混淆矩阵的召回率。
指标 | 公式 | 举例 |
---|---|---|
像素准确率 | P A = T P + T N ТР + T N + F P + F N PA = \frac{TP + TN}{ ТР+ TN+FP+FN} PA=ТР+TN+FP+FNTP+TN | P A = a + e + i a + b + c + d + e + f + g + h + i PA = \frac{a+e+i}{ a+b+c+d+e+f+g+h+i} PA=a+b+c+d+e+f+g+h+ia+e+i |
类别像素准确率 | C P A i = T P i T P i + F N i CPA_i =\frac{TP_i}{TP_i + FN_i } CPAi=TPi+FNiTPi | C P A 类别 1 = a a + b + c ; C P A 类别 2 = e d + e + f ; C P A 类别 3 = i g + h + i CPA_{类别1} = \frac{a}{ a+b+c};CPA_{类别2} = \frac{e}{d+e+f};CPA_{类别3} = \frac{i}{ g+h+i} CPA类别1=a+b+ca;CPA类别2=d+e+fe;CPA类别3=g+h+ii |
类别平均像素准确率 | M P A = Σ ( C P A i ) N MPA =\frac{Σ(CPA_i)}{N} MPA=NΣ(CPAi) | M P A = C P A 类别 1 + C P A 类别 2 + C P A 类别 3 3 MPA= \frac{CPA_{类别1}+CPA_{类别2}+CPA_{类别3}}{3} MPA=3CPA类别1+CPA类别2+CPA类别3 |
交并比 | I o U i = T P i T P i + F P i + F N i IoU_i = \frac{TP_i}{TP_i + FP_i + FN_i} IoUi=TPi+FPi+FNiTPi | I o U 类别 1 = a a + b + c + d + g IoU_{类别1} = \frac{a}{ a+b+c+d+g} IoU类别1=a+b+c+d+ga I o U 类别 2 = e d + e + f + b + h IoU_{类别2} = \frac{e}{ d+e+f+b+h} IoU类别2=d+e+f+b+he I o U 类别 3 = i g + h + i + c + f IoU_{类别3} = \frac{i}{ g+h+i+c+f} IoU类别3=g+h+i+c+fi |
平均交并比 | M I o U = Σ ( I o U i ) N MIoU = \frac{Σ(IoU_i)}{N} MIoU=NΣ(IoUi) | M I o U = I o U 类别 1 + I o U 类别 2 + I o U 类别 3 3 MIoU = \frac{IoU_{类别1} +IoU_{类别2} +IoU_{类别3} }{3} MIoU=3IoU类别1+IoU类别2+IoU类别3 |
频权平均交并比 | F W M I o U = ∑ k = 1 K n k T P k ∑ k = 1 K n k ∗ ( T P k + F P k + F N k ) FWMIoU =\frac{∑_{k=1}^Kn_kTP_k}{∑_{k=1}^Kn_k*(TP_k + FP_k + FN_k)} FWMIoU=∑k=1Knk∗(TPk+FPk+FNk)∑k=1KnkTPk | f r e q 1 = a + b + c a + b + c + d + e + f + g + h + i freq1=\frac{a+b+c}{a+b+c+d+e+f+g+h+i} freq1=a+b+c+d+e+f+g+h+ia+b+c f r e q 2 = d + e + f a + b + c + d + e + f + g + h + i freq2=\frac{d+e+f}{a+b+c+d+e+f+g+h+i} freq2=a+b+c+d+e+f+g+h+id+e+f f r e q 3 = g + h + i a + b + c + d + e + f + g + h + i freq3=\frac{g+h+i}{a+b+c+d+e+f+g+h+i} freq3=a+b+c+d+e+f+g+h+ig+h+i F W M I o U = I o U 类别 1 ∗ f r e q 1 + I o U 类别 2 ∗ f r e q 2 + I o U 类别 3 ∗ f r e q 3 f r e q 1 + f r e q 2 + f r e q 3 FWMIoU =\frac{IoU_{类别1}* freq1 +IoU_{类别2} * freq2+IoU_{类别3}* freq3}{freq1 + freq2 + freq3} FWMIoU=freq1+freq2+freq3IoU类别1∗freq1+IoU类别2∗freq2+IoU类别3∗freq3 |
F 1 − s c o r e F1-score F1−score | 2 ∗ T P / ( 2 ∗ T P + F P + F N ) 2*TP / (2*TP+FP+FN) 2∗TP/(2∗TP+FP+FN) | F 1 类别 1 = 2 a 2 a + b + c + d + g + h F1_{类别1}=\frac{2a}{2a+b+c+d+g+h} F1类别1=2a+b+c+d+g+h2a F 1 类别 2 = 2 e 2 e + d + f + b + e + h F1_{类别2}=\frac{2e}{2e+d+f+b+e+h} F1类别2=2e+d+f+b+e+h2e F 1 类别 3 = 2 i 2 i + g + h + c + f F1_{类别3}=\frac{2i }{2i+g+h+c+f} F1类别3=2i+g+h+c+f2i F 1 = F 1 类别 1 + F 1 类别 2 + F 1 类别 3 3 F1=\frac{F1_{类别1}+F1_{类别2}+F1_{类别3}}{3} F1=3F1类别1+F1类别2+F1类别3 |
Dice系数 | ||
ROC和AUC | ||
RR/MRR | ||
"""
refer to https://github.com/jfzhang95/pytorch-deeplab-xception/blob/master/utils/metrics.py
"""
import numpy as np
__all__ = ['SegmentationMetric']
"""
预测
P N
P TP FN
真实
N FP TN
"""
class SegmentationMetric(object):
def __init__(self, numClass):
self.numClass = numClass
self.confusionMatrix = np.zeros((self.numClass,) * 2)
def genConfusionMatrix(self, imgPredict, imgLabel): # 同FCN中score.py的fast_hist()函数
# remove classes from unlabeled pixels in gt image and predict
mask = (imgLabel >= 0) & (imgLabel < self.numClass)
label = self.numClass * imgLabel[mask] + imgPredict[mask]
count = np.bincount(label, minlength=self.numClass ** 2)
confusionMatrix = count.reshape(self.numClass, self.numClass)
return confusionMatrix
def addBatch(self, imgPredict, imgLabel):
assert imgPredict.shape == imgLabel.shape
self.confusionMatrix += self.genConfusionMatrix(imgPredict, imgLabel)
def pixelAccuracy(self):
# 返回所有类别的整体像素准确度
# PA = acc = (TP + TN) / (TP + TN + FP + TN)
acc = np.diag(self.confusionMatrix).sum() / self.confusionMatrix.sum()
return acc
def classPixelAccuracy(self):
# 返回每个类别的像素精度(称为精度的更准确方法)
# acc = (TP) / TP + FN
classAcc = np.diag(self.confusionMatrix) / self.confusionMatrix.sum(axis=1)
return classAcc # 返回的是一个列表值,如:[0.90, 0.80, 0.96],表示类别1 2 3各类别的预测准确率
def meanPixelAccuracy(self):
classAcc = self.classPixelAccuracy()
meanAcc = np.nanmean(classAcc) # np.nanmean 求平均值,nan表示遇到Nan类型,其值取为0
return meanAcc # 返回单个值,如:np.nanmean([0.90, 0.80, 0.96, nan, nan]) = (0.90 + 0.80 + 0.96) / 3 = 0.89
def IntersectionOverUnion(self):
# Intersection = TP Union = TP + FP + FN
# IoU = TP / (TP + FP + FN)
intersection = np.diag(self.confusionMatrix) # 取对角元素的值,返回列表
union = np.sum(self.confusionMatrix, axis=1) + np.sum(self.confusionMatrix, axis=0) - np.diag(
self.confusionMatrix) # axis = 1表示混淆矩阵行的值,返回列表; axis = 0表示取混淆矩阵列的值,返回列表
IoU = intersection / union # 返回列表,其值为各个类别的IoU
return IoU
def meanIntersectionOverUnion(self):
IoU = self.IntersectionOverUnion()
mIoU = np.nanmean(IoU) # 求各类别IoU的平均
return mIoU
def FrequencyWeightedIntersectionOverUnion(self):
# FWIOU = [(TP+FN)/(TP+FP+TN+FN)] *[TP / (TP + FP + FN)]
freq = np.sum(self.confusionMatrix, axis=1) / np.sum(self.confusionMatrix)
iu = np.diag(self.confusionMatrix) / (
np.sum(self.confusionMatrix, axis=1) + np.sum(self.confusionMatrix, axis=0) -
np.diag(self.confusionMatrix))
FWIoU = (freq[freq > 0] * iu[freq > 0]).sum()
return FWIoU
def reset(self):
self.confusionMatrix = np.zeros((self.numClass, self.numClass))
if __name__ == '__main__':
imgPredict = np.array([0, 1, 2, 2, 0, 1])
imgLabel = np.array([0, 1, 2, 2, 1, 2])
metric = SegmentationMetric(3) # 3表示有3个分类
metric.addBatch(imgPredict, imgLabel)
pa = metric.pixelAccuracy()
cpa = metric.classPixelAccuracy()
mpa = metric.meanPixelAccuracy()
IoU = metric.IntersectionOverUnion()
mIoU = metric.meanIntersectionOverUnion()
fwmIoU = metric.FrequencyWeightedIntersectionOverUnion()
print('混淆矩阵:\n', metric.confusionMatrix)
print('pa:\t', pa)
print('cpa:\t', cpa)
print('mpa:\t', mpa)
print('IoU:\t', IoU)
print('mIoU:\t', mIoU)
print('FWmIoU:\t', fwmIoU)
结果
混淆矩阵:
[[1. 0. 0.]
[1. 1. 0.]
[0. 1. 2.]]
pa: 0.6666666666666666
cpa: [1. 0.5 0.66666667]
mpa: 0.7222222222222222
IoU: [0.5 0.33333333 0.66666667]
mIoU: 0.5
FWmIoU: 0.5277777777777777