主动学习实现领域自适应语义分割

140 阅读9分钟

本文所涉及所有资源均在传知代码平台可获取。

一、概述

本文讲解并复现一篇CVPR论文 “Towards Fewer Annotations: Active Learning via Region Impurity and Prediction Uncertainty for Domain Adaptive Semantic Segmentation”,该论文基于主动学习实现像素级分割–语义分割,并实现迁移学习–将两个虚拟生成的数据集进行训练,并迁移到真实世界数据集

二、论文地址

Towards Fewer Annotations: Active Learning via Region Impurity and Prediction Uncertainty for Domain Adaptive Semantic Segmentation

三、研究背景

自训练极大地促进了领域自适应语义分割,在无标签目标数据上迭代生成伪标签并重新训练网络。到目前为止,由于数据集移位,考虑将注释从在给定域(合成数据集)上训练的模型迁移到不同域(真实世界数据集)的工作很少。然而,它在实践中经常发生,但并没有得到完美解决。一般来说,伪标签是有噪声的,而自我训练会着重于高频率的类,而牺牲了在罕见类或小物体上的性能,从而导致不期望的偏差。

在此,让我们简要介绍一下主动学习的目标。主动学习(Active learning)旨在在尽可能减少标记工作量的同时,最大化模型性能。常见的策略包括不确定性抽样和代表性抽样。然而,迄今为止,由于数据集的偏移,训练于特定领域(如合成数据集)的模型在迁移到不同领域(如真实世界数据集)时,面临的挑战很少被解决,但这种情况在实际应用中经常发生,但却尚未得到充分的解决。在本项工作中,有效地解决了这一问题。更多关于主动学习工作流程和原理的知识,请参考该文章

四、主要贡献

● 对之前关于语义分割的主动域适应方法的性能进行了基准测试,发现使用基于图像或基于点的选择策略的方法是无效的;

● 提出了一种基于区域的自适应语义分割策略,称为RIPU。它利用了区域杂质和预测不确定性识别空间邻接性不同、预测输出不确定的图像区域;

● 实验表明,使用标准的分割模型,即DeepLab-v2和DeepLab-v3+,该方法在两个代表性的域适应基准上带来了显著的性能提升,即 GTAV → Cityscapes, SYNTHIA → Cityscapes;

五、模型结构和代码

下图为模型整体结构图;我们将整个模型运行分为3部分讲解:图像区域生成,主动学习过程,损失函数计算;接下来我们将分别进行详细介绍;

1. 区域生成

传统的基于区域的主动学习语义分割方法只是将图像分割成互不重叠的矩形或采用超像素算法。作者认为这些固定的区域不灵活或不适合基于区域的选择策略。主要原因是相邻区域的模型预测也需要考虑;本文将像素的k平方邻域视为一个区域,具体来说,将大小为(2k + 1, 2k + 1)的规则形状的正方形视为以每个像素为中心的区域。下图是对传统和本文提出的区域生成方法的对比:

以下是区域选取算法的核心代码:

计算当前样本中需要选择的活跃区域数量

active_regions = math.ceil(num_pixel_cur * active_ratio / per_region_pixels)
            # 选择指定数量的活跃区域
            for pixel in range(active_regions):
                values, indices_h = torch.max(score, dim=0)
                _, indices_w = torch.max(values, dim=0)
                w = indices_w.item()
                h = indices_h[w].item()

                active_start_w = w - active_radius if w - active_radius >= 0 else 0
                active_start_h = h - active_radius if h - active_radius >= 0 else 0
                active_end_w = w + active_radius + 1
                active_end_h = h + active_radius + 1

                mask_start_w = w - mask_radius if w - mask_radius >= 0 else 0
                mask_start_h = h - mask_radius if h - mask_radius >= 0 else 0
                mask_end_w = w + mask_radius + 1
                mask_end_h = h + mask_radius + 1

2. 主动学习过程

在实际应用中,语义分割常常面临类别不平衡问题,因为某些类别的出现频率较低。这导致少数类别的性能在训练过程中可能显著下降,因为训练样本不足。为了解决这个问题,可以在训练过程中采用类重新平衡或增强的方法。主动学习通过在数据收集阶段迭代地选择一批样本进行标注,可以隐式地帮助解决这种类别不平衡的问题。给定预定义的图像区域,本文描述了采集策略,并实现了两种不同的标注机制,即基于区域的标注 Region-based (RA)和基于像素的标注 Pixel-based (PA)。

● Region-based Annotating:RA标注所选区域中的每个像素;

● Pixel-based Annotating:PA通过选择区域内的中心像素,更注重标记效率;

下图是两种传统策略和Region-based策略的对比:

以下我们将以Region-based策略为例,讲解部分核心代码:

计算当前样本中需要选择的活跃区域数量

active_regions = math.ceil(num_pixel_cur * active_ratio / per_region_pixels)

选择指定数量的活跃区域

for pixel in range(active_regions):
     values, indices_h = torch.max(score, dim=0)
     _, indices_w = torch.max(values, dim=0)
     w = indices_w.item()
     h = indices_h[w].item()

active_start_w = w - active_radius if w - active_radius >= 0 else 0
active_start_h = h - active_radius if h - active_radius >= 0 else 0
active_end_w = w + active_radius + 1
active_end_h = h + active_radius + 1

mask_start_w = w - mask_radius if w - mask_radius >= 0 else 0
mask_start_h = h - mask_radius if h - mask_radius >= 0 else 0
mask_end_w = w + mask_radius + 1
mask_end_h = h + mask_radius + 1

在接下来的文章中,我们介绍一种有效的获取函数,联合捕获区域不纯度(Region Impurity)和预测不确定性(Prediction Uncertainty),提取空间邻接多样性和预测输出不确定性的区域。

- Region Impurity

给定一个目标图像,我们首先将其传递给网络,然后得到softmax输出。通过最大概率输出可以直接推导出目标伪标签。我们将一个区域划分为C个子集。目前,我们可以收集一个区域的类别统计信息。如果一个区域中有很多类别,我们认为它在标记后有助于训练网络。也就是选择区域内类别最多的区域进行再训练;- Prediction Uncertainty

由于预测结果携带语义关系信息,为了衡量不确定性,我们使用每个像素的预测熵作为预测的不确定性;在基于像素的标注(PA)中,每个像素的不确定性就是熵的值;在基于区域的标注(RA)中,用区域内所有像素熵的平均值来评估其预测不确定性。总而言之,也就是选取预测不确定性最大的数据进行再训练;最后,将两种获取函数进行融合形成最终的获取函数;

# 将区域不纯度和预测不确定性相乘获得得分
score = region_impurity * prediction_uncertainty
return score.squeeze(dim=0).squeeze(dim=0), region_impurity.squeeze(dim=0).squeeze(
            dim=0), prediction_uncertainty.squeeze(dim=0).squeeze(dim=0)

3. Loss函数计算

  1. 来自源域和目标域的所有标记数据都用于通过优化标准监督损失来微调网络:使用分类交叉熵损失;

  2. 同时,加强源图像中某个像素与其邻近像素之间的预测一致性,从而使模型的预测更加平滑,避免对源数据的过拟合:使用区域内所有像素的均值预测;

  3. 此外,在训练的早期阶段,目标图像的较低输出概率实际上显示了特定的缺席类,称为负伪标签。例如,我们很难判断一个预测值为 [0.49,0.50,0.01] 的像素属于哪个类别,但我们可以清楚地知道它不属于得分为0.01的类别。因此,我们赋予负伪标签,因为τ是负阈值,在这项工作中使τ = 0.05,称为负学习损失;

# 源域监督损失
loss = torch.Tensor([0]).cuda()
loss_sup = sup_criterion(src_out, src_label)
meters.update(loss_sup=loss_sup.item())
loss += loss_sup

# 目标域活动监督损失
if torch.sum((tgt_mask != 255)) != 0:  # 目标域有标记像素
    loss_sup_tgt = sup_criterion(tgt_out, tgt_mask)
    meters.update(loss_sup_tgt=loss_sup_tgt.item())
    loss += loss_sup_tgt

# 源一致性正则化损失
if cfg.SOLVER.CONSISTENT_LOSS > 0:
    consistent_loss = local_consistent_loss(src_out, src_label) * cfg.SOLVER.CONSISTENT_LOSS
    meters.update(cr_loss=consistent_loss.item())
    loss += consistent_loss

# 目标负伪损失
if cfg.SOLVER.NEGATIVE_LOSS > 0:
    negative_learning_loss = negative_criterion(predict) * cfg.SOLVER.NEGATIVE_LOSS
    meters.update(nl_loss=negative_learning_loss.item())
    loss += negative_learning_loss

六、数据集介绍

● GTAV:GTAV包含24966张图像,它与cityscape数据集共享19个类;下载链接

● SYNTHIA:SYNTHIA包含9400张图片,共有16个类;下载链接

● CityScapes:包含高质量的城市场景图像。分为2975张训练图像和500张验证图像;下载链接

七、性能效果展示

1. GTAV->Cityscapes:我们可以看到,在GTAV数据迁移到Cityscapes任务中,该模型展示了优越的性能;

2.SYNTHIA->Cityscapes:同样的,在SYNTHIA数据迁移到Cityscapes任务中,该模型也展现了出色的效果;

  1. 对于结果可视化的展示,证明了该模型在语义分割任务中确实可以出色地对照片中所有类别精确地进行分割;

八、复现过程

1. 下载所需库:

pip install -r requirements.txt

2. 下载数据集:

The Cityscapes Dataset,The GTAV Dataset, andThe SYNTHIA Dataset

并放在对应文件夹路径内:

ln -s /path_to_cityscapes_dataset datasets/cityscapes
ln -s /path_to_gtav_dataset datasets/gtav
ln -s /path_to_synthia_dataset datasets/synthia

3.运行生成GTAV/SYNTHIA数据集的标签静态文件:

python datasets/generate_gtav_label_info.py -d datasets/gtav -o datasets/gtav/
python datasets/generate_synthia_label_info.py -d datasets/synthia -o datasets/synthia/

数据文件夹的结构应如下:

├── datasets/
│   ├── cityscapes/     
|   |   ├── gtFine/
|   |   ├── leftImg8bit/
│   ├── gtav/
|   |   ├── images/
|   |   ├── labels/
|   |   ├── gtav_label_info.p
│   └──	synthia
|   |   ├── RAND_CITYSCAPES/
|   |   ├── synthia_label_info.p
│   └──

4. 开始训练

使用单个GPU开始训练模型:

# training for GTAV to Cityscapes
sh gtav_to_cityscapes.sh

# training for SYNTHIA to Cityscapes
sh synthia_to_cityscapes.sh

5. 进行测试

python test.py -cfg configs/gtav/deeplabv3plus_r101_RA.yaml resume checkpint/v3plus_gtav_ra_5.0_precent/model_last.pth OUTPUT_DIR checkpint/v3plus_gtav_ra_5.0_precent

九、运行过程

1. 开始训练

2. 主动学习

训练固定轮数后继续提取数据

3. 语义分割结果

感觉不错,点击我,立即使用