语义分割总结(一)

Semantic Segmentation

Posted by AspenStars on April 30, 2020

语义分割

目的:对一张图片上的每一个像素进行分类

实例分割是语义分割的延伸,要求区别出相同类别的不同个体

语义分割与实例分割

语义分割领域中的困难

  1. 数据问题
    • 分割需要精确的像素级标注,包括每一个目标的轮廓等信息,因此使得制作数据集成本过高;
  2. 计算资源问题
    • 高精度的语义分割模型一般需要更深的网络(ResNet101等),网络越深计算资源需求越大,轻量级的网络精度太低;
    • 需要对每个像素进行预测,因此特征图的分辨率要尽可能高,内存需求大;
  3. 精细分割
    • 目前的方法中对于图像中的大体积的东西能够很好的分类;
    • 对于细小的类别,由于其轮廓太小,从而无法精确的定位轮廓,精度较低(医学图像领域尤为突出);
  4. 上下文信息
    • 分割中上下文信息很重要,设计网络的时候要考虑如何应用上下文信息;
    • 否则会造成一个目标被分成多个part,或者不同类别目标分类成相同类别;

语义分割方法的发展

非深度学习方法

pipline:经典的特征 + forst/boost + CRF的分割

每一个分类器一般只针对单一的类别设计,如果分割类别数很多,会造成计算复杂,训练难度大的问题。

非深度学习方法受特征的限制较大,精度较低。

深度学习方法

自2014年的FCN与Deeplabv1的提出,近几年深度学习语义分割方法进步明显

深度学习方法可以直接预测多类别目标,克服了非深度学习方法的单类别的限制

对于单类别问题,仍然是深度学习方法好,如道路分割等

目前的进展

从目前的发展趋势看,深度学习方法仍是主导方法。

深度学习方法一般都是在分类网络上进行精调,分类网络为了能获取更抽象的特征分层,采取了Conv+pool堆叠的方式,这导致了分辨率降低丢失了很多信息,这对分割任务来说肯定是不好的,因为分割是对每一个像素进行分类,会造成定位精度不高。但同时更高层的特征对于分类又很重要。如何权衡这两者呢?

encoder-decoder方法

与经典的FCN中的skip-connection思想类似,encoder为分类网络,用于提取特征,而decoder则是将encoder的先前丢失的空间信息逐渐恢复,decoder的典型结构有U-Net/segnet/refineNet,该类方法虽然有一定的效果,能恢复部分信息,但毕竟信息已经丢失了,不可能完全恢复。

dialed FCN方法

deeplabv1提出的方法,将vgg的最后的两个pool层步长置为1,这样网络的输出分辨率从1/32变为1/8。可以保留更多的细节信息,同时也丢掉了复杂的decoder结构,但这种方法计算量大。deeplabv3+将这两者结合,效果比较好,但是计算量大。

评价指标

  1. 执行时间:非常依赖硬件设备及后台实现,在实验时不是最重要的,但在上线生产环境时一般要考虑是否满足硬实时的要求,因此是一个度量要求

  2. 内存占用

  3. 精确度:这里指的是逐像素标记的精度测量

    假设共有k个类(从0到k中有一个类别属于背景),$P_{ij}$表示本属于$i$类但是被预测为$j$类的像素个数,$P_{ii}$表示为真正分对类的数量,而$P_{ij}$与$P_{ji}$分别被称为假正样本和假负样本

    • Pixel Accuracy(PA,像素精度) 标记正确的像素占总像素的比例
    \[PA = \frac{\sum^k_{i=0}P_{ii}}{\sum^k_{i=0}\sum^k_{j=0}P_{ij}}\]
    • Mean Pixel Accuracy(MPA,平均像素精度) 计算每个类内被正确分类像素数比例,之后求所有类的平均数
    \[MPA = \frac{1}{k+1}\sum^k_{i=0}\frac{P_{ii}}{\sum^k_{j=0}P_{ij}}\]
    • Mean Intersection over Union(mIoU,平均交并比) 为语义分割的标准度量,其计算两个集合的交集和并集之比,这两个集合分别为ground truth与predicted segmentation在每个类上计算IoU,之后将其求平均。
    \[IoU = \frac{真正样本数量}{真正样本数量+假正样本数量+假负样本数量}\] \[mIoU = \frac{1}{k+1}\sum^k_{i=0}\frac{P_{ii}}{\sum^k_{j=0}P_{ij} + \sum^k_{j=0}P_{ji} - P_{ii}}\]

    其中$k+1$为类别数,$P{ii}$表示TP,$P_{ij}$表示FN,$P_{ji}$表示FP($i$表示真实类别,$j$表示其他类别),最后那个地方减了一个$P_{ii}$是因为前面两项里加了2个$P_{ii}$

    • Frequency weighted Intersection over Union(FWIoU,频权交并) mIoU的一种提升,这种方法根据每个类出现的频率设置权重
    \[FwIoU = \frac{1}{\sum^k_{i=0}\sum^k_{j=0}P_{ij}}\sum^k_{i=0}\frac{P_{ii}}{\sum^k_{j=0}P_{ij} + \sum^k_{j=0}P_{ji} - P_{ii}}\]

下面以一个简单的例子,说明怎么计算mIoU,由于分割也是分类问题,分类问题的指标一般使用混淆矩阵来求解,其实就是矩阵的每一行加每一列,再减去重复的TP

混淆矩阵 预测1 预测2 预测3
实际1 43 5 2
实际2 2 45 3
实际3 0 1 49
  • 类别1:TP=43,FN=7,FP=2,IoU1=43/(43+2+7)=82.69%
  • 类别2:TP=45,FN=5,FP=6,IoU2=45/(45+5+6)=80.36%
  • 类别3:TP=49,FN=1,FP=5,IoU3=49/(49+1+5)=89.09%
  • mIoU=84.05%

常用数据集

忽视标签(ignore label)

忽视标签从字面上理解,就是该标签不用于计算损失,也不用于计算精度。以一个三个类别的例子为例。

该例子,包含3个目标类别,1个背景类别,1个忽视类别。

标签可以设置为:0,1,2,3,4

其中,0代表背景,1-4代表目标类别 如果忽视标签为4,则可以直接设置类别数为4(背景 + 目标),如果忽视标签为1-3,需要单独进行处理,比如deeplabv3+中是这样处理的

self.void_classes = [3, -1]
self.valid_classes = [0, 1, 2, 4]
self.class_names = ['unlabelled', 'c1','c2','c4']

self.ignore_index = 255
self.class_map = dict(zip(self.valid_classes, range(self.NUM_CLASSES)))

def encode_segmap(self, mask):
    # Put all void classes to zero
    for _voidc in self.void_classes:
        mask[mask == _voidc] = self.ignore_index
    for _validc in self.valid_classes:
        mask[mask == _validc] = self.class_map[_validc]
    return mask

Pascal VOC系列

M. Everingham, L. J. V. Gool, et al. The pascal visual object classes VOC challenge.// IJCV 2010. B. Hariharan, P. Arbelaez, et al. Semantic contours from inverse detectors. //ICCV2011.

可以用于:目标检测、语义分割等

原始VOC2012数据集:1464训练集,1449验证集,1456测试集。经过加强的数据集,包含10582训练集,1449验证集,1456测试集。目前论文结果均使用后者进行训练。该数据集特点包括:

  • 数据集包含21类别目标,20类目标+1类背景,分辨率大小不完全相同,为此训练过程为了能处理batch图像,因此需要将图像固定到某一大小,deeplab里面使用321大小。
  • 该数据集中,label处理时发现并没有忽视标签,均在0-21之间,因此不需要设置忽视标签。在deeplab版本里作者将ignore_index设为255,标签里面本来就没有255,设不设置没关系.
  • 每幅图像包含的目标类别很少,但每个目标的轮廓还是比较复杂,因此,该数据集的分割精度没有想象中那么高。

CamVid

Brostow, G.J., Shotton, et al. Segmentation and recognition using structure from motion point clouds. //ECCV 2008 Vijay Badrinarayanan, Alex Kendall et al. SegNet: A Deep Convolutional Encoder-Decoder Architecture for Image Segmentation.//TPAMI 2017.

训练集367,验证集101,测试集233。三个均有标注文件

  • 图像数量太少,因此很少有人跑这个数据集,只有少数轻量级分割网络会跑,如ENet/Segnet/LinkNet/Bisenet等,现在能看到的最好精度也就60多mIOU。
  • 原始数据集分辨率为960×720,而Segnet将其处理为480*360,后者也是使用得多,可能是因为Segnet将其处理后的文件夹上传的原因吧。
  • 该数据集也存在忽视标签,Segnet作者将其统一设置为11,类别数为11,标注为0-10,因此计算softmax损失时,需要设置ignore_index=11,或者在处理标签图片时,将mask[index==11] = -1,这样处理后不计算忽视标签的损失。
  • 由于图像分辨率为480*360,且有11类目标,造成细小目标偏多,如行人,交通灯等。

Cityscapes

M. Cordts, M. Omran, et al. The Cityscapes Dataset for Semantic Urban Scene Understanding.//CVPR 2016.

适用于汽车自动驾驶的训练数据集,包括19种都市街道场景:road、side-walk、building、wal、fence、pole、traficlight、trafic sign、vegetation、terain、sky、person、rider、car、truck、bus、train、motorcycle 和 bicycle。

训练集2975,验证集500,测试集1525。训练集与验证集包括Fine annotations以及额外的19998个coarse annotations,可以于训练集一起训练。测试集标注没有公开。数据集主要特点包括:

  • 标签包括:’name’/’id’/’trainId’/’category’/’catId’/’hasInstances’/’ignoreInEval’/’color ‘等,’id’是原始的标注id,而’trainId’是用于训练的Id,’ignoreInEval’为忽视对象。
  • 原始的标注包括35类,其中有16类为在评测中忽视的类别,因此训练时候只有19类,因此标签可以设置为0-18,验证的时候也可以使用0-18。如果要测试,则需要将0-18反变化回原始标签
  • 原始标注文件包括:color.png/instanceIds.png/labelIds.png/polygons.json四个文件,其中,labelIds.png文件为原始标注,因此需要将该文件转换为trainIds,可以参考labels.py和preparation,转换后忽视标签为255,而其他标签为0-18,这样训练过程使用19类目标,忽视255。在处理过程中,可以将mask[index==255] = -1,这样损失函数不会计算。或者计算softmax损失的时候设置ignore_index=255。
  • 图像分辨率较大,1024*2048,如果使用原图训练,计算量太大,一般会crop一定的大小,但也不能太小,太小效果很差,猜想:这也是这个数据集精度很难提升的一个原因。 从提交的评测结果可以看出,基本都是深度学习方法(没有全部过一遍)。传统算法在这种环境复杂的交通场景做分割难度还是太大了。
  • 每幅图像涵盖的目标类别较多,同时,存在很多细小目标,使得分割难度进一步增大。

Microsoft COCO

一共有80个类别。这个数据集主要用于实例级别的分割(Instance-level Segmentation)以及图片描述(Image Caption)。

参考资料

  1. 点点点 - 语义分割-从入门到放弃
  2. Kwong - 语义分割
  3. Yanpeng Sun - 语义分割入门的一点总结