Augmentation Matters:一种简单而有效的半监督语义分割方法(CVPR2023)

Augmentation Matters: A Simple-yet-Effective Approach to Semi-supervised Semantic Segmentation

摘要

最近关于半监督语义分割(SSS)的研究进展迅速。尽管它们的性能很有希望,但目前最先进的方法往往以引入更多的网络组件和额外的训练程序为代价,进行越来越复杂的设计。
本文方法

  1. 遵循标准的教师-学生框架,并提出了AugSeg,这是一种简单而干净的方法,主要关注数据扰动,以提高SSS性能。
  2. 应该调整各种数据增强,以更好地适应半监督的场景,而不是直接应用监督学习中的这些技术
  3. 本文采用了一种简化的基于强度的增强方法,该方法从连续空间中选择随机数目的数据变换,并对失真强度进行均匀采样。
  4. 基于模型对不同未标记样本的估计置信度,随机注入标记信息,以自适应的方式增强未标记样本。
    在这里插入图片描述
    在这里插入图片描述

本文方法

在这里插入图片描述

  1. 标准的师生框架
  2. AugSeg通过分别最小化相应的监督损失Lx和无监督一致性损失Lu
  3. 在标记数据(x,y)和未标记数据u上训练由θs参数化的学生模型,由θt参数化的教师模型通过θs的指数移动平均(EMA)进行更新,并在未标记数据上生成伪标签pt。
  4. AugSeg的核心是对输入的未标记样本应用各种增强技术,包括弱几何增强Ag、基于随机强度的增强Ar和自适应标签辅助增强Aa。
  5. 红线和蓝线分别表示标记数据和未标记数据的正向路径。虚线表示“停止坡度”
    在这里插入图片描述

Random Intensity-based Augmentations

在这里插入图片描述
基于随机强度的增强:
在连续空间而不是有限离散空间中均匀地采样失真度
从扩充池中采样随机数目的扩充,以最大值k为界,而不是使用固定数
在增强池中删除基于强度的强转换,如反转操作。我们的池是从RandomAug中的池直接简化而来的,如表2所示。

基于随机强度的增强可以享受更好的数据多样性,并更多地适应semisuspervisored任务。
高度随机设计不会显著损害数据分布。因此,我们可以摆脱额外的特定于分发的修订和额外的过滤策略。

Adaptive Label-aided CutMix

与CutMix相关的或复制粘贴增强在监督和半监督分割任务中显示了其有效性。SSS中的最新研究在小批量内的未标记样本之间应用随机复制粘贴,并相应地修改其伪标签,然而,高度依赖伪标签可能不可避免地导致确认偏差,特别是对于一些难以训练的样本,或者在早期训练阶段。

因此,我们倾向于利用有信心的标记样本来增加未标记的数据,从而可以充分利用标记的信息。然而,将有信心的标记信息与未标记数据混合自然是有益的,但可能会充分利用未标记数据。这只是因为未标记数据的一些区域被标记样本的区域覆盖,并且在训练过程中从未使用过
在这里插入图片描述

设计了一种自适应标签辅助增强,可以充分利用标记数据,以特定于实例和置信度自适应的方式帮助对未标记样本进行训练。具体而言,我们首先估计置信度得分ρi,表示当前模型对第i个未标记实例的预测的置信度
在这里插入图片描述

实验结果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
当然,我会提供一个代码框架,并且根据您的数据集和模型选择进行适当的调整。下面是一个简单深度学习半监督语义分割的代码框架: ```python import torch import torch.nn as nn import torch.optim as optim import torchvision.transforms as transforms from torch.utils.data import Dataset, DataLoader from skimage.io import imread from skimage.transform import resize # Define hyperparameters num_epochs = 50 batch_size = 4 learning_rate = 0.001 img_height = 256 img_width = 256 num_classes = 2 # Define transforms for data augmentation transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.5), (0.5)) ]) # Define dataset class class SegmentationDataset(Dataset): def __init__(self, image_dir, mask_dir=None): self.image_dir = image_dir self.mask_dir = mask_dir self.image_files = sorted(os.listdir(image_dir)) def __getitem__(self, idx): img = imread(self.image_dir + self.image_files[idx]) img = resize(img, (img_height, img_width)) if self.mask_dir: mask = imread(self.mask_dir + self.image_files[idx], as_gray=True) mask = resize(mask, (img_height, img_width)) mask = (mask > 0).astype(float) mask = torch.from_numpy(mask).float() return transform(img), mask return transform(img) def __len__(self): return len(self.image_files) # Define model class class SegmentationModel(nn.Module): def __init__(self): super(SegmentationModel, self).__init__() self.conv1 = nn.Conv2d(3, 16, 3, padding=1) self.bn1 = nn.BatchNorm2d(16) self.relu1 = nn.ReLU(inplace=True) self.conv2 = nn.Conv2d(16, 32, 3, padding=1) self.bn2 = nn.BatchNorm2d(32) self.relu2 = nn.ReLU(inplace=True) self.conv3 = nn.Conv2d(32, num_classes, 1) def forward(self, x): x = self.conv1(x) x = self.bn1(x) x = self.relu1(x) x = self.conv2(x) x = self.bn2(x) x = self.relu2(x) x = self.conv3(x) return x # Define training function def train_model(model, dataloader, criterion, optimizer, device): model.train() for i, (inputs, targets) in enumerate(dataloader): inputs = inputs.to(device) targets = targets.to(device) optimizer.zero_grad() outputs = model(inputs) loss = criterion(outputs, targets) loss.backward() optimizer.step() # Define testing function def test_model(model, dataloader, criterion, device): model.eval() total_loss = 0 with torch.no_grad(): for inputs, targets in dataloader: inputs = inputs.to(device) targets = targets.to(device) outputs = model(inputs) loss = criterion(outputs, targets) total_loss += loss.item() return total_loss / len(dataloader) # Define main function def main(): # Define data paths image_dir = 'path/to/image/folder/' mask_dir = 'path/to/mask/folder/' # Split data into train and test sets dataset = SegmentationDataset(image_dir, mask_dir) train_size = int(0.8 * len(dataset)) test_size = len(dataset) - train_size train_dataset, test_dataset = torch.utils.data.random_split(dataset, [train_size, test_size]) # Define dataloaders for training and testing train_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True) test_dataloader = DataLoader(test_dataset, batch_size=batch_size, shuffle=True) # Instantiate model, criterion, and optimizer model = SegmentationModel() criterion = nn.BCEWithLogitsLoss() optimizer = optim.Adam(model.parameters(), lr=learning_rate) # Move model and criterion to GPU if available device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') model.to(device) criterion.to(device) # Train the model for epoch in range(num_epochs): train_model(model, train_dataloader, criterion, optimizer, device) test_loss = test_model(model, test_dataloader, criterion, device) print(f'Epoch [{epoch+1}/{num_epochs}], Test Loss: {test_loss:.4f}') if __name__ == '__main__': main() ``` 请注意,这只是一个框架,您需要根据您的数据集和模型调整超参数和网络结构。另外,请不要将此代码或其派生代码用于商业或不当用途。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小杨小杨1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值