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什么的策略也都不一样,但相比之下还是差太多了点。
供大家参考。