本文記錄了語義分割準確性評價指標的總結以及代碼實現python
對於像素級別的分類,最經常使用的評價指標是Pixel Accuracy(像素準確率)和Mean Inetersection over Union(平均交併比),兩者的計算都是創建在混淆矩陣的基礎上的。所以首先來介紹一下混淆矩陣,以後分別介紹PA,MPA,MIoU,FWIoU,最後附上代碼實現。git
首先假定數據集中有n+1類(0~n+1),0一般表示背景。使用Pii表示本來爲i類同時預測爲i類,即真正(TP)和真負(TN), Pij表示本來爲i類被預測爲j類,即假正(FP)和假負(FN),若是第i類爲正類,i!=j時,那麼Pii表示TP,Pjj表示TN,Pij表示FP,Pji表示FN。github
像素準確率是全部分類正確的像素數佔像素總數的比例。公式化以下:spa
利用混淆矩陣計算則爲(對角線元素之和除以矩陣全部元素之和)
平均像素準確率是分別計算每一個類別分類正確的像素數佔全部預測爲該類別像素數的比例,即精確率,而後累加求平均。公式化以下:3d
利用混淆矩陣計算公式爲(每一類的精確率Pi都等於對角線上的TP除以對應列的像素數) blog
平均交併比是對每一類預測的結果和真實值的交集與並集的比值求和平均的結果。公式化以下ci
IoU利用混淆矩陣計算:rem
解釋以下:
如圖所示,僅僅針對某一類來講,紅色部分表明真實值,真實值有兩部分組成TP,FN;黃色部分表明預測值,預測值有兩部分組成TP,FP;白色部分表明TN(真負);
因此他們的交集就是TP+FP+FN,並集爲TP
頻權交併比是根據每一類出現的頻率設置權重,權重乘以每一類的IoU並進行求和。公式化以下:it
利用混淆矩陣計算:每一個類別的真實數目爲TP+FN,總數爲TP+FP+TN+FN,其中每一類的權重和其IoU的乘積計算公式以下,在將全部類別的求和便可io
""" refer to https://github.com/jfzhang95/pytorch-deeplab-xception/blob/master/utils/metrics.py """ import numpy as np __all__ = ['SegmentationMetric'] """ confusionMetric P\L P N P TP FP N FN TN """ class SegmentationMetric(object): def __init__(self, numClass): self.numClass = numClass self.confusionMatrix = np.zeros((self.numClass,)*2) def pixelAccuracy(self): # return all class overall pixel accuracy # acc = (TP + TN) / (TP + TN + FP + TN) acc = np.diag(self.confusionMatrix).sum() / self.confusionMatrix.sum() return acc def classPixelAccuracy(self): # return each category pixel accuracy(A more accurate way to call it precision) # acc = (TP) / TP + FP classAcc = np.diag(self.confusionMatrix) / self.confusionMatrix.sum(axis=1) return classAcc def meanPixelAccuracy(self): classAcc = self.classPixelAccuracy() meanAcc = np.nanmean(classAcc) return meanAcc def meanIntersectionOverUnion(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) IoU = intersection / union mIoU = np.nanmean(IoU) return mIoU def genConfusionMatrix(self, imgPredict, imgLabel): # 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 Frequency_Weighted_Intersection_over_Union(self): # FWIOU = [(TP+FN)/(TP+FP+TN+FN)] *[TP / (TP + FP + FN)] freq = np.sum(self.confusion_matrix, axis=1) / np.sum(self.confusion_matrix) iu = np.diag(self.confusion_matrix) / ( np.sum(self.confusion_matrix, axis=1) + np.sum(self.confusion_matrix, axis=0) - np.diag(self.confusion_matrix)) FWIoU = (freq[freq > 0] * iu[freq > 0]).sum() return FWIoU def addBatch(self, imgPredict, imgLabel): assert imgPredict.shape == imgLabel.shape self.confusionMatrix += self.genConfusionMatrix(imgPredict, imgLabel) def reset(self): self.confusionMatrix = np.zeros((self.numClass, self.numClass)) if __name__ == '__main__': imgPredict = np.array([0, 0, 1, 1, 2, 2]) imgLabel = np.array([0, 0, 1, 1, 2, 2]) metric = SegmentationMetric(3) metric.addBatch(imgPredict, imgLabel) acc = metric.pixelAccuracy() mIoU = metric.meanIntersectionOverUnion() print(acc, mIoU)