深度学习100问
Author:louwill
Machine Learning Lab
语义分割作为经典的图像分割问题,其本质上还是一种图像像素分类。既然是分类,我们就可以使用常见的分类评价指标来评估模型好坏。语义分割常见的评价指标包括像素准确率(Pixel Accuracy)、平均像素准确率(Mean Pixel Accuracy)、平均交并比(Mean IoU)、频权交并比(FWIoU)和Dice系数(Dice Coeffcient)等。
这些指标看似跟常见的分类指标不太一样,但本质上都是基于分类混淆矩阵进行计算的。像素准确率也就是分类评价指标中的准确率(Accuracy)、平均准确率就是分类中的平均精确率(Mean Precision)、Dice系数则是F1-Score,只有平均交并比(MIoU)和频权交并比(FWIoU)在分类指标中找不对对应,但也可以基于混淆矩阵进行计算。
假设图像中有n个目标类,那么加上背景类则是n+1,其中p_ii表示原本为i类同时也预测为i类,对应到混淆矩阵中则是TP(真阳)+TN(真阴),p_ij表示为原本为i类预测为j类,可以表示为FP(假阳),p_ji则为FN(假阴)。根据像素分类混淆矩阵,我们就可以计算如下指标。
像素准确率(PA)
像素准确率跟分类中的准确率含义一样,即所有分类正确的像素数占全部像素的比例。PA的计算公式如下:
对应到混淆矩阵中,则可以计算为:
平均像素准确率(MPA)
平均像素准确率其实更应该叫平均像素精确率,是指分别计算每个类别分类正确的像素数占所有预测为该类别像素数比例的平均值。所以,从定义上看,这是精确率(Precision)的定义,MPA的计算公式如下:
对应到混淆矩阵中,Precison可计算为:
平均交并比(MIoU)
交并比(Interp over Union)的定义很简单,将标签图像和预测图像看成是两个集合,计算两个集合的交集和并集的比值。而平均交并比则是将所有类的IoU取平均。MIoU的计算公式如下:
这里注意公式中的分母,p_ii在前两项中都被计算了一次,所以还需要单独减掉一次。
对应到混淆矩阵中,IoU可以计算为:
具体如下图所示。交集为TP,并集为TP+FP+FN。
以一张具体图像为例感受下IoU,下图是Ground Truth和预测图像,可以看到预测和真值还是有些差距的。
两张图像的交集和并集对应到图像中,计算两张图像的比值即可。
频权交并比(FWIoU)
频权交并比顾名思义,就是以每一类别的频率为权重和其IoU加权计算出来的结果。FWIoU的设计思想很明确,语义分割很多时候会面临图像中各目标类别不平衡的情况,对各类别IoU直接求平均不是很合理,所以考虑各类别的权重就非常重要了。FWIoU的计算公式如下:
对应到混淆矩阵中可以计算为:
其中每个类别的真实像素量为TP+FN,除以总像素量即可得到每个类别像素权重。
Dice系数
Dice系数是一种度量两个集合相似性的函数,是语义分割中最常用的评价指标之一。Dice系数定义为两倍的交集除以像素和,跟IoU有点类似,其计算公式如下:
Dice系数对应到分类指标中则是F1得分,其计算公式为精确率和召回率的调和平均数。对应到混淆矩阵中,用precision和recall的公式可以推导Dice的计算公式为:
可以看到Dice系数对应于IoU,分子分母中的TP都取了两倍。通常1-Dice可作为语义分割的损失函数。Dice作为笔者常用的语义分割评价指标,这里给出Dice在Keras和PyTorch中的实现方式。
Keras实现方式:
from keras import backend as K
def dice_coef(y_true, y_pred, smooth=1):
"""
Dice = (2*|X & Y|)/ (|X|+ |Y|)
= 2*sum(|A*B|)/(sum(A^2)+sum(B^2))
"""
y_true = K.flatten(y_true)
y_pred = K.flatten(y_pred)
interp = K.sum(K.abs(y_true * y_pred))
dice = (2. * interp + smooth) / (K.sum(K.square(y_true)) + K.sum(K.square(y_pred)) + smooth)
return dice
PyTorch实现方式:
import torch
def dice_coef(pred, target):
"""
Dice = (2*|X & Y|)/ (|X|+ |Y|)
= 2*sum(|A*B|)/(sum(A^2)+sum(B^2))
"""
smooth = 1.
m1 = pred.view(-1).float()
m2 = target.view(-1).float()
interp = (m1 * m2).sum().float()
dice = (2. * interp + smooth) / (torch.pow(m1, 2).sum() + torch.pow(m2,2).sum() + smooth)
return dice
最后基于numpy实现一个包含全部分割指标的类:
import numpy as np
class SegMetrics(object):
def __init__(self, num_class):
self.num_class = num_class
self.confusion_matrix = np.zeros((self.num_class,)*2)
# 像素准确率
def Pixel_Accuracy(self):
Acc = np.diag(self.confusion_matrix).sum() / self.confusion_matrix.sum()
return Acc
# 平均像素准确率
def Mean_Pixel_Accuracy(self):
# Precision=TP/(TP+FP)
Acc = np.diag(self.confusion_matrix) / self.confusion_matrix.sum(axis=1)
Acc = np.nanmean(Acc)
return Acc
# 平均IoU
def Mean_IoU(self):
MIoU = np.diag(self.confusion_matrix) / (
np.sum(self.confusion_matrix, axis=1) + np.sum(self.confusion_matrix, axis=0) -
np.diag(self.confusion_matrix))
MIoU = np.nanmean(MIoU)
return MIoU
# 频权IoU
def Freq_Weighted_IoU(self):
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
# Dice系数
def dice(self):
dice_coef = 2*np.diag(self.confusion_matrix) / (
np.sum(self.confusion_matrix, axis=1) + np.sum(self.confusion_matrix, axis=0))
return dice_coef
# 生成混淆矩阵
def _generate_matrix(self, gt_image, pre_image):
mask = (gt_image >= 0) & (gt_image < self.num_class)
label = self.num_class * gt_image[mask] + pre_image[mask]
count = np.bincount(label, minlength=self.num_class**2)
confusion_matrix = count.reshape(self.num_class, self.num_class)
return confusion_matrix
# 为真值和预测值生成混淆矩阵
def add_batch(self, gt_image, pre_image):
assert gt_image.shape == pre_image.shape
self.confusion_matrix += self._generate_matrix(gt_image, pre_image)
# 重置混淆矩阵
def reset(self):
self.confusion_matrix = np.zeros((self.num_class,) * 2)
以上就是本节内容。
参考资料:
https://www.jeremyjordan.me/evaluating-image-segmentation-models/
https://github.com/xtudbxk/semantic-segmentation-metrics
往期精彩:
深度学习100问-16:为什么U-Net在医学图像上表现优越?
深度学习100问-15:什么是深监督(Deep Supervision)?
深度学习100问-14:图像语义分割有哪些经典的上采样方法?
深度学习100问-13:深度学习如何制作个人数据集?
深度学习100问-12:深度学习有哪些经典数据集?
深度学习100问-11:什么是学习率衰减?
深度学习100问-10:如何部署一个轻量级的深度学习项目?
深度学习100问-9:为什么EfficientNet号称是最好的分类网络?
深度学习100问-8:什么是Batch Normalization?
深度学习100问-7:dropout有哪些细节问题?
深度学习100问-6:有哪些经典的卷积类型?
深度学习100问-5:如何阅读一份深度学习项目代码?
深度学习100问-4:深度学习应遵循怎样的论文研读路线?
深度学习100问-3:深度学习应掌握哪些Linux开发技术?
深度学习100问-2:深度学习应掌握哪些Git开发技术?
深度学习100问-1:深度学习环境配置有哪些坑?
一个算法工程师的成长之路
长按二维码.关注机器学习实验室