Cityscapes踩坑记录


Cityscapes是做像素级分割一个很常用的数据集,我因为需要确认论文的代码复现效果下载了这个数据集。这个数据集看上去好像就是个输入图像和标签的pair,实际上坑很多,下面简单总结下吧。

在阅读之前,希望你已经看过了这篇帖子:https://blog.csdn.net/zz2230633069/article/details/84591532,因为对于数据集的文件组织结构下面将不会涉及。然后希望你也能知道除了官网(https://www.cityscapes-dataset.com/)下载的数据集外,还有一个Github工具包(https://github.com/mcordts/cityscapesScripts)最好也下载下来,这其中包含了preparation文件夹下可以帮助你生成*_labelTrainId.png的19类别标注的脚本。

 

下面是正文:

1. 数据集没有测试集,只有验证集。想得到测试结果需要提交模型在线测试。

2. 这个数据集直接下载下来的话,输入就是leftImage8bit里面的文件,然后需要注意的是其对应的标注是有几类的,包括彩色的*_color.png和按照类别标注的*_labelIds.png等等。这个*_labelIds.png实际上是完整的34类标注,像素按照类别被标成-1~33中的数字(不过我用opencv读进来发现标注是从1~33的,-1当然没有但0不知道为何也消失了,这一问题在读取labelTrainId时没有出现),便于训练时直接使用交叉熵损失函数。在那个github工具包中有提供将1-34对应转换成*_color.png的脚本,可在可视化时使用。

3. 在github工具包的helper/labels.py下面有类别和id信息的一一对应,可以看到很多论文中使用的其实是19类的trainId,所以我们还需要通过工具包中preparation文件夹中的脚本额外生成*_labelTrainIds.png

 

 4. 特别提醒下,因为原图2048*1024实在太大,一般读取都会做resize,在resize输入时可以就用默认的双线性插值,但在resize标签的时候记得得用最近邻插值,要不然会多出一些其他数字的。

5. trainId生成后,需要注意的是无关的类别都被标注成了255,所有使用交叉熵损失函数时记得加上ignore_index=255

6. 关于mIoU的计算,工具包中提供了34类的训练模型的计算,我因为需要复现的是19类的所以自己写了一个,就是直接算交集并集然后除一下嘛,结果测出来结果差的要命。上网搜了一圈扒了开源代码的一个类下来:

import numpy as np


class Evaluator(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 Pixel_Accuracy_Class(self):
        Acc = np.diag(self.confusion_matrix) / self.confusion_matrix.sum(axis=1)
        Acc = np.nanmean(Acc)
        return Acc

    def Mean_Intersection_over_Union(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

    def Frequency_Weighted_Intersection_over_Union(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

    def _generate_matrix(self, gt_image, pre_image):
        mask = (gt_image >= 0) & (gt_image < self.num_class)
        label = self.num_class * gt_image[mask].astype('int') + 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)

这个是通过混淆矩阵计算的,然后通过add_batch加入新的预测、GT对后就可以调用Mean_Intersection_over_Union()函数获取新的mIoU

7. 我在512*256的输入下,不做任何增广、crop等等操作,使用deeplab v3+、adam和学习率0.99指数下降,训练大概200个epoch只能到0.47的mIoU,不知道是不是有什么地方搞错了。使用开源的deeplab v3+在512*512的crop上直接跑大概能有0.65,虽说输入大小不一样lr什么的策略也都不一样,但相比之下还是差太多了点。

 

供大家参考。

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM