> 文档中心 > 解读混淆矩阵在语义分割FCN指标计算中的应用(含代码实现)

解读混淆矩阵在语义分割FCN指标计算中的应用(含代码实现)


一、混淆矩阵的概念

        混淆矩阵也称误差矩阵,是表示精度评价的一种标准格式,用n行n列的矩阵形式来表示。具体评价指标有总体精度、制图精度、用户精度等,这些精度指标从不同的侧面反映了图像分类的精度。 在人工智能中,混淆矩阵(confusion matrix)是可视化工具,特别用于监督学习,在无监督学习一般叫做匹配矩阵。在图像精度评价中,主要用于比较分类结果和实际测得值,可以把分类结果的精度显示在一个混淆矩阵里面。混淆矩阵是通过将每个实测像元的位置和分类与分类图像中的相应位置和分类相比较计算的。

        混淆矩阵的每一列代表了预测类别,每一列的总数表示预测为该类别的数据的数目;每一行代表了数据的真实归属类别,每一行的数据总数表示该类别的数据实例的数目。每一列中的数值表示真实数据被预测为该类的数目:第一行第一列中的43表示有43个实际归属第一类的实例被预测为第一类,同理,第一行第二列的2表示有2个实际归属为第一类的实例被错误预测为第二类。  

如有150个样本数据,预测为1,2,3类各为50个。分类结束后得到的混淆矩阵为:

预测

类1

类2

类3

实际

类1

43

2

0

类2

5

45

1

类3

2

3

49

每一行之和表示该类别的真实样本数量,每一列之和表示被预测为该类别的样本数量,

第一行说明有43个属于第一类的样本被正确预测为了第一类,有两个属于第一类的样本被错误预测为了第二类

二、可视化一个混淆矩阵

import torchimport torch.nn.functional as Fimport numpy as npimport siximport matplotlib.pyplot as plt# fake label datagt = np.random.rand(1, 2, 3)*12gt = gt.astype(np.int64)gt = torch.from_numpy(gt)x = torch.randn(1, 12, 2, 3)  # 假设每个像素点可以对应12个分类out = F.log_softmax(x, dim=1)pred_labels = out.max(dim=1)[1].data.cpu().numpy()  # ndarraypred_labels = [i for i in pred_labels]  # listprint(pred_labels)  # gt_labels = gt.data.cpu().numpy()gt_labels = [i for i in gt_labels]print(gt_labels)pred_label, gt_label = pred_labels[0], gt_labels[0]pred_label = pred_label.flatten()gt_label = gt_label.flatten()print(pred_label)print(gt_label)np.max((pred_label, gt_label))mask = gt_label >= 0 confusion_onedim = np.zeros((144,), dtype=np.int64)confusion_onedim += np.bincount( 12 * gt_label[mask].astype(int) + pred_label[mask],    minlength=12 ** 2)print(confusion_onedim.shape)print(confusion_onedim)confusion = np.zeros((12, 12), dtype=np.int64)confusion += np.bincount( 12 * gt_label[mask].astype(int) + pred_label[mask],    minlength=12 ** 2).reshape((12, 12))cm = confusionplt.figure()plt.grid(False)plt.imshow(cm, cmap='jet')plt.colorbar()plt.show()

三、举例说明

我们假设做一个六分类的任务,则N=6,标签值分别为:

根据相关条件,我们的网络给出的预测值为: 

 L代表真实的Label,P代表预测的标签,首先计算 N*L+P

 以L=2举例说明,N = 6 , P =2 则6*2+2=14  ,同理可得上图 n*L +P; 那上图右边的 0-35 怎么得来的呢? 35=5*6+5,对应L = 5,P = 5的时候。接下来我们要统计每一个数出现的次数,用一个列表来表示,记为bin,那么我们bin的长度就是max(N*L+P) + 1。以上述例子为例:

 这个表格什么意思呢?就是统计N*L+P中值出现的次数,看第三张图片,0出现1次,所以0下面记为1,7出现两次,所以7下面记为2。同样的道理,统计完所有数的出现次数,就可以得到第四张图片的表格。我用接下来把这个列表表示出二维的形式,总共36个数,也就是写成6*6的形式。

每一行代表预测值,每一列代表真实值,观察第四张图片中的长表格,依次填数。0出现了1次,所以第一个格子填入1;7出现了2次,所以第7个格子填上2;11出现1一次,所以第11个格子填入1 。依次把bin中统计好的数填入,即可得到上图。

从表格中我们可以看出,真实值为0,预测值为0的像素点有1个,真实值为1,预测值为1的像素点有2个;真实值为1,预测值为2的像素点有1个。很容易发现,对角线上都是预测正确的。那么,我们该如何利用这个表格进行指标的计算呢?

四、利用混淆矩阵进行指标计算

语义分割FCN中评价指标有以下几种:

1.  像素精度PA

像素精度PA =  标记正确的像素占总像素的比例 = 对角线和 / 总和

pixel_accuracy = np.diag(confusion).sum() / confusion.sum()

2.  均类像素精度MPA

MPA:每个类被正确标记的像素个数比例,再求所有类平均 = np.nanmean(对角线 / 每行和)

class_accuracy = np.diag(confusion) / (np.sum(confusion, axis=1) + 1e-10)MPA = np.nanmean(class_accuracy[:-1])

注意:加1e-10是为了防止分母为0 ,所以加上一个很小的数

3.  IoU

IoU(交并比):真实和预测的交集 / 真实和预测的并集 = 对角线和 / (行和 +列和 - 对角线和)

MIoU:np.nanmean(IoU)

iou_denominator = ( confusion.sum(axis=1) + confusion.sum(axis=0) - np.diag(confusion))     iou = np.diag(confusion) / iou_denominator    return iou[:-1]