【交互式分割】Reviving Iterative training with Mask Guidance for Interactive Segmentation

交互式分割系列文章目录

  • 交互式分割【2022ICIP】Reviving Iterative training with Mask Guidance for Interactive Segmentation
  • 交互式分割【2023ICCV】 SimpleClick:Interactive Image Segmentation with Simple Vision Transformers(编辑中)


一、文献阅读

1.1摘要

  • 问题:最近基于点击的交互式分割已经证明通过不同的推理优化策略可以达到最先进的结果。这些方法的计算量比前馈模型的消耗还要大,因为它们在推理期间运行向后的梯度,此外在流行的移动框架中不知向后传递,这使得在嵌入式设备上不住这样的方法变得复杂。
  • 方法:在本文中,我们研究了交互式分割的设计选择,并发现无需任何额外的优化方案即可获得最先进的结果。我们提出了一个简单的基于点击的交互式分割,并采用前面的步骤分割掩模前馈模型,它不仅可以分割一个全新的对象,还可以纠正现有的掩模。
  • 结果:我们分析了不同数据集上训练模型的性能,并观察到训练数据集的选择对交互式分割的质量有很大影响。我们发现在COCO和LVIS的组合上训练的模型具有多样化和高质量的注释,优于所有现有的模型
    在这里插入图片描述
  • 除了分割新对象外,所提出的方法还允许校正例如由其他实例或语义分割产生的掩模。用户可以通过正和负点击来修复错误区域。

1.2 引言

  • 交互式分割简介:标准的语义分割和实例分割是单次过程中获得分割结果,与他们不同的是,交互式分割算法允许用户在多次迭代中使用交互式输入来操纵预测:用户可以选择感兴趣的对象并纠正预测错误。此外,这些算法能够分割以前看不见的类的对象。

  • 交互式分割的应用场景

    • 通常基于深度学习的语义和实例分割算法的训练需要大量的注释数据,使用分割掩码注释数据非常耗时,因此成本很高,但交互式分割可以显著简化和加快这一过程。
    • 另一个应用是移动的照片编辑,其中交互式分割允许轻松选择对象
  • 相关工作进展: 基于点击的交互式分割的最新工作集中在推理时间优化,令人惊讶的是,我们发现通过标准随机点采样程序训练的交互式点分割基线模型可以在没有明确的细化技术和其他具体修改的情况下实现最先进的结果。

  • 本文创新(创新点+具体实现方法+实验结果):我们的方法扩展了基于点击的交互式分割,允许修改现有的实例分割掩模交互式。我们恢复了一个迭代训练过程,并使网络知道上一步的掩模,这一步骤不仅可以提高模型的鲁棒性还可以防止添加新点击时准确性下降。我们的实验表明使用不同的大型数据集和精细的掩码进行训练在模型性能上起着至关重要的作用,据我们所知,COCO和LVIS结合的数据集是最适合交互式分割模型的训练数据集。

  • 本文的贡献

    • 我们使用前馈模型获得了最先进的结果
    • 我们扩展了我们的模型以支持交互式修改现有的实例分割掩码
    • 我们在COCO和LVIS组合的数据集上训练了我们所提出的模型。

1.3 方法

1.3.1 修改网络体系结构

对于网络架构,交互式分割与实例或语义分割非常相似:在所有这些任务中,网络接受输入图像并生成与该图像对其的分割掩码。关键的区别在于额外的用户输入应该在网络中以某种方式编码和处理。因此没有必要重新发明分段架构,相反我们可以依靠最先进的分段网络专注于开发交互式特定部件。我们采用两个语义分割架构作为骨干。我们的第一个主干DeeplLabV3是一个经过充分研究的分割架构。在许多与分割相关的任务中被证明是有效的。第二个主干是HRNet+OCR,这是一个相对较新的有前途的架构,专门设计用于生产高分辨率输出。根据表一,基于HRNet的模型优于基于DeepLabV3的模型。

  • 表一注释:网络架构选择的消融研究。分别在没有和有f-BRS-B[2]的情况下获得每个单元中的第一/第二结果。所有模型都在SBD上训练。“DT”代表距离变换编码。“disk”表示磁盘编码;我们使用半径为3和5像素的磁盘。
  • 在这里插入图片描述
Clicks encoding:

click可以由它们在图像中的坐标表示。通过距离变换对click进行编码可以说是基于点击的交互式分割中最常用的方法,相反的,click同样可以由高斯函数或固定半径的圆盘表示。如表一所示,与距离变换编码相比,圆盘编码确保了更好的结果。

Feeding encoded click to a backbone

用于语义分割的主干通常在ImageNet上预先训练,并接受RGB图像作为输入。处理其他模态(如编码用户click)的输入的标准方式,是增加预训练模型的第一层卷积层的权重,使它接受N信道输入。在下文中,我们将这种网络修改表示为ConvIE。或者我们可以运用卷积块,并将其输出逐元素地与第一骨干卷积层的输出相加,该修改被称为Conv1S.我们还实现了距离图融合(DMF),它将与附加用户输入链接的图像转换为3通道输入。

图2显示了将点击馈送到主干的不同方式,我们的实验表明Conv1S是测试方法中最有效的一种。
在这里插入图片描述

1.3.2 迭代抽样策略

最新的基于点击的交互式分割通过随机抽样策略在训练过程中模拟用户点击,忽略点击之间的任何关系。实际上,这些点击并不是独立的,因为每一次新的点击都被放置在预测错误区域中。

Magadevan等人提出了另一种迭代采样策略,我们采用这种采样策略但引入两个修改。首先,我们不是从错误标记区域的中心采样点,而是从面积小4倍的错误标记区域采样点。其次,我们在训练过程中不保存模拟的点击,并为每个批次模拟用户点击,我们将采样迭代的最大数量限制为Niters,以便每个批次可以均匀的从0到Niters迭代。

我们结合随机和迭代采样策略来训练我们的迭代模型,更准确的说,我们模拟用户点击与随机抽样策略,并添加从0到Niters迭代模拟点击。

1.3.3 归一化焦点损失(Normalized Focal Loss)

二进制交叉熵(BCE)损失是交互式分割中的常见选择。然而,它平等地对待几乎正确分割的区域和错误区域。焦点丢失旨在缓解这个问题,但它的梯度会随着时间的推移而减弱,从而减缓了训练过程。Sofiiuk等人提出了归一化的焦点损失,其梯度保持等于BCE的梯度。我们的实证研究表明,归一化的焦点损失提供了更快的收敛速度和更好的准确性相比,BCE,所以我们使用归一化的焦点损失的训练。


二、代码

2.1 主体结构

  • 获取参数
  • 模型加载
  • 初始化实验设置
  • 开始训练
    在这里插入图片描述
def main():
    args = parse_args()
    if args.temp_model_path:
        model_script = load_module(args.temp_model_path)
    else:
        model_script = load_module(args.model_path)

    model_base_name = getattr(model_script, 'MODEL_NAME', None)

    args.distributed = 'WORLD_SIZE' in os.environ
    cfg = init_experiment(args, model_base_name)

    torch.backends.cudnn.benchmark = True
    torch.multiprocessing.set_sharing_strategy('file_system')

    model_script.main(cfg)

2.2 加载模型脚本

def main(cfg):
	#先初始化model
    model, model_cfg = init_model(cfg)
   #再进行训练
    train(model, cfg, model_cfg)

2.2.1 模型初始化

def init_model(cfg):
    model_cfg = edict()
    #1、设置裁剪参数
    model_cfg.crop_size = (320, 480)
    #2、设置最大点数
    model_cfg.num_max_points = 24

    #=================================3、初始化model==================================
    model = HRNetModel(width=18, ocr_width=64, with_aux_output=True, use_leaky_relu=True,
                       use_rgb_conv=False, use_disks=True, norm_radius=5,
                       with_prev_mask=True)

    #4、将模型加载到GPU上
    model.to(cfg.device)
    #5、对model的每个参数进行初始化
    model.apply(initializer.XavierGluon(rnd_type='gaussian', magnitude=2.0))
    #6、对model的feature_extractor加载预训练权重
    model.feature_extractor.load_pretrained_weights(cfg.IMAGENET_PRETRAINED_MODELS.HRNETV2_W18)

    return model, model_cfg
HRNetModel结构

在这里插入图片描述

(1)prepare_input
对含有mask的image进行切片,假定image的形状为N,C,H,W。此时对C维度进行切片,C维度中前三个维度被切为新的image,而剩下的维度被切割为prev_mask。

(2)get_coord_features
1、使用DistMaps函数生成clik的距离图,得到距离图特征
2、将距离图特征与prev_mask在通道维度上进行拼接

生成距离图:
距离图是一种图像表示,其中每个像素的值表示该像素到图像中某个特定集合(如一组点、线条或形状)的最短距离。
假设你有一个二维图像,其中有若干个标记点,你想要生成一个距离图来表示每个像素点到这些标记点的欧几里得距离。在这个距离图中,每个像素点的值就是它到最近标记点的距离。如果你查看整个距离图,会发现某些像素点的值特别小,这些就是最小值,它们通常位于或非常接近标记点的位置。
在实际的图像处理算法中,通过查找距离图中的最小值,可以快速定位到图像中的重要特征或对象的边界。

(3)maps_transform

  • 结构:Conv2d+LeakyRelu+Conv2d+ScaleLayer

(4)backbone_forward

  • 创建feature_extractor:创建一个 HighResolutionNet 实例作为特征提取器
  • 应用学习率乘数到特征提取器的参数上,这通常用于调整骨干网络的学习率。
  • backbone_forward:
    • 输入是image 和 上述步骤得到的距离图。
    • 按照上面Fig2中的结构3来处理img和距离图
  • 得到out和out_aux

(5)interpolate
将得到的out和out_aux进行双线性插值,插值到和原始输入图像的大小一致。

2.2.2 分割模型训练

获取训练、验证数据集

在这里插入图片描述

(1)CocoLvisDataset
1、获取index:

  • self.dataset_samples用来存储所有的数据id(或是数据路径也可)
  • 其他的数据集读取通过重新定义def _ _ len_ _(self)的方式来获取随机index以读取特定数据,而本代码通过len(self.dataset_samples)的方式生成随机index
  • 因此如果需要重写数据集,要记得重写self.dataset_samples变量

2、获得sample

  • 读取方式都大同小异,这里不作详细说明
  • 得到的sample格式是:image, mask, instances_info

(2)DSample

  • 数据增强
    具体流程可见下面代码的注释,每一步流程的具体实施方案见源代码,不作赘述,这里只帮助大家梳理整个代码脉络。
    • attention:针对数据增强模块,在我跑自己的数据集的时候,因为数据分布的原因,会导致代码陷入死循环,因此需要根据自己的数据集调整self.augmentator。
       def augment_sample(self, sample) -> DSample:
        if self.augmentator is None:
            return sample

        #valid_augmentation==>用来判断增强是否有效,若无效则继续增强
        valid_augmentation = False
        while not valid_augmentation:
            #使用预先定义好的数据增强其进行数据增强
            sample.augment(self.augmentator)
            """keep_background_prob为样本保留的概率,若概率小于0则keep_sample始终为false
            若概率不小于0,则keep_sample被随机赋予ture(随机生成的数<给定的keep_background_prob分数) or false"""
            keep_sample = (self.keep_background_prob < 0.0 or
                           random.random() < self.keep_background_prob)
            """在第一步的数据增强中,代码会移除目标较小的sample,这时就会导致leb(sample)<0
            此时代码会查询keep_sample是否为true,若是则继续下一步,若不是则重复进行数据增强操作,直至得到的sample合规
            这里keep_background_prob选为0.05时,大概率是要继续重新增强的。
            因此部分数据集会卡在这个循环里出不来,需要自己手动调整数据增强器"""
            valid_augmentation = len(sample) > 0 or keep_sample

  • 移除小目标
    这里会再移除一遍小目标,使用的移除方法和第一步数据增强使用的方法一致,区别在于目标面积阈值的不同。
    在数据增强部分,小目标的面积阈值为1,而这里的阈值为1000。
    可以看出,原始代码在实际执行的时候,只会在数据增强部分移除小目标,而不会再在后面进行进一步的移除。这里添加新的移除步骤是为了方便后续使用者根据实际需求定制合适的参数。

(3)MultiPointSampler

  • 对象采样,确定当前样本中哪些对象和区域将被用于点采样
  • 点采样,根据上一步确定的掩码来生成一组点
  • 获取当前选定的掩码
开始训练

在这里插入图片描述

(1)训练参数初始化

#1、定义loss
    loss_cfg = edict()
    loss_cfg.instance_loss = NormalizedFocalLossSigmoid(alpha=0.5, gamma=2)
    loss_cfg.instance_loss_weight = 1.0
    loss_cfg.instance_aux_loss = SigmoidBinaryCrossEntropyLoss()
    loss_cfg.instance_aux_loss_weight = 0.4

#2、优化参数数值设置
    optimizer_params = {
        'lr': 5e-4, 'betas': (0.9, 0.999), 'eps': 1e-8
    }

#3、学习率调整器:当训练到200epoch和220epoch时,学习率缩小十倍
    lr_scheduler = partial(torch.optim.lr_scheduler.MultiStepLR,
                           milestones=[200, 220], gamma=0.1)
#4、其余参数设置
	self.max_interactive_points = max_interactive_points #可交互的最大点数:24
	self.tb_dump_period = tb_dump_period #多久记录一次数据:25
	self.max_num_next_clicks = max_num_next_clicks #下次最大点击数:3
	self.train_metrics = [AdaptiveIoU()] #评估指标
	checkpoint_interval=[(0, 5), (200, 1) #checkpoint的保存频率,指的是从0开始,每五个保存一次。从200epoch开始,每个都保存
	self.image_dump_interval = image_dump_interval #训练多少轮保存一次图像
	self.optim = get_optimizer(model, optimizer, optimizer_params) #创建adam优化器实例
	model = self._load_weights(model) #加载预训练权重

AdaptiveIoU 的核心思想是在训练过程中自适应地调整IoU阈值,以便更精确地评估模型性能。通过计算预测和真实掩膜之间的IoU,并根据IoU阈值的EMA来更新这个阈值,可以在不同批次和轮次之间平滑IoU阈值的变化。这种方法特别适用于那些需要精确目标检测或分割的任务

(2)batch_forward

流程:
1、先进行点击模拟,得到几轮点击矫正后的预测mask和预测矫正点
2、再将得到的预测mask与预测矫正点和image一起馈送到model中,得到新的预测结果
3、比较新预测结果与真实标记结果差异,计算loss

        #验证状态下禁止梯度更新,训练状态下进行梯度更新
        with torch.set_grad_enabled(not validation):
            #解压数据
            batch_data = {k: v.to(self.device) for k, v in batch_data.items()}
            image, gt_mask, points = batch_data['images'], batch_data['instances'], batch_data['points']
            orig_image, orig_gt_mask, orig_points = image.clone(), gt_mask.clone(), points.clone()

            #创建全0张量
            prev_output = torch.zeros_like(image, dtype=torch.float32)[:, :1, :, :]

            #定义last_clicl_index
            last_click_indx = None

            #禁止参数更新,进行交互式点击模拟
            with torch.no_grad():
                #在0~3之间随机选取,模拟现实情况下的迭代次数
                num_iters = random.randint(0, self.max_num_next_clicks)
				
                for click_indx in range(num_iters):
                    last_click_indx = click_indx

                    #训练模式时,将model设为eval()格式,禁止 Dropout 和 Batch Normalization 等特定层的训练行为
                    if not validation:
                        self.net.eval()

                    #原始代码中,click_models为none,因此验证模型为self.net,即上述的HRNetModel
                    if self.click_models is None or click_indx >= len(self.click_models):
                        eval_model = self.net
                    else:
                        eval_model = self.click_models[click_indx]

                    #若包含上一次的分割结果prev_output,则将prev_output和img在通道维度上进行拼接
                    net_input = torch.cat((image, prev_output), dim=1) if self.net.with_prev_mask else image
                    prev_output = torch.sigmoid(eval_model(net_input, points)['instances'])

                    #根据预测结果和真实的标注信息寻找下一次的click位置
                    points = get_next_points(prev_output, orig_gt_mask, points, click_indx + 1)

                    #训练模式下改为train()
                    if not validation:
                        self.net.train()

                #模型正则化的变种,用于随机丢弃掩模,提升模型的泛化能力
                if self.net.with_prev_mask and self.prev_mask_drop_prob > 0 and last_click_indx is not None:
                    zero_mask = np.random.random(size=prev_output.size(0)) < self.prev_mask_drop_prob
                    prev_output[zero_mask] = torch.zeros_like(prev_output[zero_mask])

            batch_data['points'] = points
			
			#将交互式模拟后的预测结果与imag相拼接,和points一起输入进model中,进行前向传播
            net_input = torch.cat((image, prev_output), dim=1) if self.net.with_prev_mask else image
            output = self.net(net_input, points)

            loss = 0.0
            loss = self.add_loss('instance_loss', loss, losses_logging, validation,
                                 lambda: (output['instances'], batch_data['instances']))
            loss = self.add_loss('instance_aux_loss', loss, losses_logging, validation,
                                 lambda: (output['instances_aux'], batch_data['instances']))

            if self.is_master:
                with torch.no_grad():
                    for m in metrics:
                        m.update(*(output.get(x) for x in m.pred_outputs),
                                 *(batch_data[x] for x in m.gt_outputs))
        return loss, losses_logging, batch_data, output

(3)training

    def training(self, epoch):
        #初始化日志记录器
        if self.sw is None and self.is_master:
            self.sw = SummaryWriterAvg(log_dir=str(self.cfg.LOGS_PATH),
                                       flush_secs=10, dump_period=self.tb_dump_period)

        #分布式训练设置
        if self.cfg.distributed:
            self.train_data.sampler.set_epoch(epoch)

        #初始化训练进度
        log_prefix = 'Train' + self.task_prefix.capitalize()
        tbar = tqdm(self.train_data, file=self.tqdm_out, ncols=100)\
            if self.is_master else self.train_data

        #重置度量指标
        for metric in self.train_metrics:
            metric.reset_epoch_stats()

        self.net.train()
        train_loss = 0.0
        for i, batch_data in enumerate(tbar):
            global_step = epoch * len(self.train_data) + i

            #进行单批次的训练,得到新的loss
            loss, losses_logging, splitted_batch_data, outputs = \
                self.batch_forward(batch_data)

            #执行反向传播和优化器步骤来更新模型参数
            self.optim.zero_grad()
            loss.backward()
            self.optim.step()

            ....................

        #学习率调整
        if hasattr(self, 'lr_scheduler'):
            self.lr_scheduler.step()

2.3初始化实验设置

init_experiment 函数负责准备和配置深度学习模型训练所需的环境和参数。它涵盖了从解析命令行参数、加载和更新配置、设置分布式训练环境、创建实验目录、复制模型脚本、设置设备和日志记录等一系列步骤。通过这个函数,可以确保训练流程的一致性和可复现性。

三、代码运行记录

3.1 Readme翻译

这个代码提供了使用官方pytorch实现的一下论文中最先进的基于点击的交互式分割模型的训练和测试源代码

3.1.1设置环境

pip3 install -r requirements.txt
您也可以使用我们的Dockerfile构建一个配置过环境的容器
如果您想运行训练或测试,您必须在config.yml中配置数据集的路径。

3.1.2交互式分割演示(demo运行)

python3 demo.py --checkpoint=hrnet18_cocolvis_itermask_3p
如果内存不多,可以减少limit-longest-size(默认=800)
python3 demo.py --checkpoint=/home/demo/fBRS/weights/hrnet18_cocolvis_itermask_3p --limit-longest-size=400
还可以仅使用cpu模式尝试演示
python3 demo.py --checkpoint=hrnet18_cocolvis_itermask_3p --cpu

3.1.3使用外部分割掩码初始化ITER-M模型

根据我们的论文,ITER-M模型将图像、编码的用户输入和前一步的掩码作为它们的输入。此外,用户可以在放置任何点击之前用外部掩码初始化模型,并使用相同的界面纠正这个掩码。结果表明,我们的模型成功处理了这种情况,并使得更改掩码成为可能。要使用外部掩码初始化任何ITER-M模型,请使用菜单栏中的“加载掩码”按钮。

3.1.4数据集

我们在 SBD 和 COCO+LVIS 上训练所有模型,并在 GrabCut、Berkeley、DAVIS、SBD 和 PascalVOC 上对其进行评估。我们还提供了用于消融研究的其他数据集的链接
在这里插入图片描述
不要忘记在下载和解压缩后更改config.yml数据集的路径。
(*) 为了准备COCO+LVIS数据集,您需要先下载原始的LVIS v1.0版本,然后下载并解压我们通过组合COCO和LVIS数据集得到的预处理注释,将这些注释解压到包含LVIS v1.0的文件夹中。

3.1.5测试
  • 3.1.5.1预训练模型
  • 3.1.5.2验证

我们提供了一个脚本来测试所有在GrabCut、Berkeley、DAVIS、Pascal VOC和SBD上展示的模型的所有可能配置。要测试一个模型,您应该下载其权重并放入指定文件夹中(您可以在config.yml中更改此路径,参见相关变量)。要测试我们的任何模型,只需指定对应检查点的路径。我们的脚本会自动检测加载模型的架构。

  • 以下命令在所有测试数据集上运行NoC评估(使用’-h’可以显示其他选项):
    python3 scripts/evaluate_model.py <brs-mode> --checkpoint=<checkpoint-name>
  • 此命令在所有数据集上以NoBRS模式评估HRNetV2-W18-C+OCR ITER-M模型。
    python3 scripts/evaluate_model.py NoBRS --checkpoint=hrnet18_cocolvis_itermask_3p
  • 此命令在所有数据集上以f-BRS-B模式评估HRNet-W18-C-Small-v2+OCR ITER-M模型。
    python3 scripts/evaluate_model.py f-BRS-B --checkpoint=hrnet18s_cocolvis_itermask_3p
  • 此命令在GrabCut和Berkeley数据集上以NoBRS模式评估HRNetV2-W18-C+OCR ITER-M模型。
    python3 scripts/evaluate_model.py NoBRS --checkpoint=hrnet18_cocolvis_itermask_3p --datasets=GrabCut,Berkeley
3.1.6训练

我们提供了在SDB数据集上训练我们模型的脚本,你可以使用以下命令开始训练:

  • resnet-34非迭代基线模型
    python3 train.py models/noniterative_baselines/r34_dh128_cocolvis.py --gpus=0 --workers=4 --exp-name=first-try
  • HRNet-W18-C-Small-v2+OCR ITER-M模型
    python3 train.py models/iter_mask/hrnet18s_cocolvis_itermask_3p.py --gpus=0 --workers=4 --exp-name=first-try
  • HRNetV2-W18-C+OCR ITER-M 模型
    python3 train.py models/iter_mask/hrnet18_cocolvis_itermask_3p.py --gpus=0,1 --workers=6 --exp-name=first-try
  • HRNetV2-W32-C+OCR ITER-M 模型
    python3 train.py models/iter_mask/hrnet32_cocolvis_itermask_3p.py --gpus=0,1,2,3 --workers=12 --exp-name=first-try
    对于每次实验,都会在 ./experiments 文件夹中创建一个单独的文件夹,其中包含Tensorboard日志、文本日志、可视化和检查点。你可以在 config.yml 中指定另一个路径(参见 EXPS_PATH 变量)。
    请注意,我们在1个GPU上训练了ResNet-34和HRNet-18s,在2个GPU上训练了HRNet-18,在4个GPU上训练了HRNet-32(我们使用Nvidia Tesla P40进行训练)。要在不同的GPU上训练,你应该使用命令行参数 --batch-size 调整批量大小,或者在模型脚本中更改默认值。
    我们使用了官方仓库中的预训练HRNetV2模型。如果你想使用这些模型训练交互式分割,你需要下载权重并在 config.yml 中指定它们的路径。

3.2bug解决记录

3.2.1demo运行bug

  • bug1
Traceback (most recent call last):
  File "demo.py", line 7, in <module>
    from isegm.inference import utils
  File "E:\xinjiguanzhu\Interactive segmentation\model\ritm_interactive_segmentation-master\isegm\inference\utils.py", line 7, in <module>
    from isegm.data.datasets import GrabCutDataset, BerkeleyDataset, DavisDataset, SBDEvaluationDataset, PascalVocDataset
  File "E:\xinjiguanzhu\Interactive segmentation\model\ritm_interactive_segmentation-master\isegm\data\datasets\__init__.py", line 1, in <module>
    from isegm.data.compose import ComposeDataset, ProportionalComposeDataset
  File "E:\xinjiguanzhu\Interactive segmentation\model\ritm_interactive_segmentation-master\isegm\data\compose.py", line 3, in <module>
    from .base import ISDataset
  File "E:\xinjiguanzhu\Interactive segmentation\model\ritm_interactive_segmentation-master\isegm\data\base.py", line 5, in <module>
    from torchvision import transforms
  File "C:\Users\user\.conda\envs\torch1.8\lib\site-packages\torchvision\__init__.py", line 7, in <module>
    from torchvision import datasets
  File "C:\Users\user\.conda\envs\torch1.8\lib\site-packages\torchvision\datasets\__init__.py", line 1, in <module>
    from .lsun import LSUN, LSUNClass
  File "C:\Users\user\.conda\envs\torch1.8\lib\site-packages\torchvision\datasets\lsun.py", line 2, in <module>
    from PIL import Image
  File "C:\Users\user\.conda\envs\torch1.8\lib\site-packages\PIL\Image.py", line 100, in <module>
    from . import _imaging as core
ImportError: DLL load failed: 找不到指定的模块。

解决方案:更新pillow

  • bug2:AttributeError: module ‘cv2’ has no attribute ‘gapi_wip_gst_GStreamerPipeline’
    解决方案:opencv-contrib-python与opencv-python只留一个就可以了
  • bug3: AttributeError: module ‘cv2’ has no attribute ‘INTER_LINEAR’
    解决方案:opencv-python-headless版本太高,降低版本至4.2.0.34

3.2.2训练bug

  • bug1:模型卡在数据读取部分,无法往下继续执行
    • 解决方案见本文4.2.2中的(2)DSample模块,由于数据分布的原因,导致在继续数据增强时,模型陷入死循环。

3.3demo运行结果

在这里插入图片描述
如图,需要分割的是被云朵围绕的山峰,可以发现山峰被完整分割下来。

  • 13
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值