在PyTorch中使用DeepLabv3进行语义分割的迁移学习(上)

简介: 在PyTorch中使用DeepLabv3进行语义分割的迁移学习

当我在使用深度学习进行图像语义分割并想使用PyTorch在DeepLabv3[1]上运行一些实验时,我找不到任何在线教程。并且torchvision不仅没有提供分割数据集,而且也没有关于DeepLabv3类内部结构的详细解释。然而,我是通过自己的研究进行了现有模型的迁移学习,我想分享这个过程,这样可能会对你们有帮助。

在本文中,我将介绍如何使用预先训练的语义分割DeepLabv3模型,通过使用迁移学习在PyTorch中进行道路裂缝检测。同样的过程也可以应用于调整自定义数据集的网络。

介绍

让我们首先简要介绍图像分割。分割任务的主要目标是输出像素级输出蒙版,其中将属于某些类别的区域分配给相同的不同像素值。如果通过为每个类别分配不同的颜色来对这些细分蒙版进行颜色编码以使其可视化,那么你就会得到一个类似于儿童涂色书中的图像。下面显示了一个示例:

640.png

分割在计算机视觉和图像处理领域已经存在很长时间了。其中一些技术是简单的阈值化,基于聚类的方法,例如k均值聚类分割,区域增长方法等。[3]

随着深度学习的最新进展以及卷积神经网络在图像相关任务中比传统方法的成功,这些技术也已应用于图像分割任务。

这些网络架构之一是Google的DeepLabv3。对模型的工作原理进行解释超出了本文的范围。相反,我们将专注于如何对数据集使用经过预训练的DeepLabv3网络。为此,我们将简要讨论转移学习。

迁移学习

当有限的数据可用时,深度学习模型往往会遇到困难。对于大多数实际应用,即使不是不可能,也很难访问大量数据集。标注既繁琐又费时。即使您打算将其外包,您仍然必须花钱。已经做出努力以能够从有限的数据训练模型。这些技术中的一种称为转移学习。

迁移学习涉及使用针对源域和任务进行预训练的网络(希望您可以在其中访问大型数据集),并将其用于您的预期/目标域和任务(与原始任务和域类似) )[4]。下图可以从概念上表示它。

640.png

我们根据自己的要求更改目标细分子网络,然后训练部分网络或整个网络。选择的学习率低于正常训练的学习率。这是因为网络已经对源任务具有良好的权重。我们不想太快地改变权重。有时也可以冻结初始层,因为有人认为这些层提取了一般特征,可以潜在地使用而无需任何更改。

接下来,在继续PyTorch相关部分之前,我将讨论本文中使用的数据集。

使用CrackForest数据集进行裂缝检测

在本教程中,我将使用CrackForest [5] [6]数据集通过分段进行道路裂缝检测。它由具有裂缝作为缺陷的城市道路表面图像组成。图像包含混淆区域,例如阴影,溢油和水渍。这些图像是使用普通的iPhone5相机拍摄的。数据集包含118张图像,并具有对应的裂纹像素级别蒙版,所有蒙版的大小均为320×480。额外的混杂因素以及可用于训练的有限数量的样本使CrackForest成为具有挑战性的数据集[7]。

640.png

PyTorch的数据集

让我们首先为模型构造一个数据集类,该数据集类将用于获取训练样本。为了进行分割,我们将一个地面真相掩码图像作为标签,而不是一个可以热编码的单值数字标签。蒙版具有可用的像素级注释,如图3所示。因此,用于输入和标签的训练张量将是四维的。对于PyTorch,它们是:batch_size x通道x高x宽。

我们现在将定义细分数据集类。类定义如下。

"""Author: Manpreet Singh MinhasContact: msminhas at uwaterloo ca"""frompathlibimportPathfromtypingimportAny, Callable, OptionalimportnumpyasnpfromPILimportImagefromtorchvision.datasets.visionimportVisionDatasetclassSegmentationDataset(VisionDataset):
"""A PyTorch dataset for image segmentation task.The dataset is compatible with torchvision transforms.The transforms passed would be applied to both the Images and Masks."""def__init__(self,
root: str,
image_folder: str,
mask_folder: str,
transforms: Optional[Callable] =None,
seed: int=None,
fraction: float=None,
subset: str=None,
image_color_mode: str="rgb",
mask_color_mode: str="grayscale") ->None:
"""Args:root (str): Root directory path.image_folder (str): Name of the folder that contains the images in the root directory.mask_folder (str): Name of the folder that contains the masks in the root directory.transforms (Optional[Callable], optional): A function/transform that takes ina sample and returns a transformed version.E.g, ``transforms.ToTensor`` for images. Defaults to None.seed (int, optional): Specify a seed for the train and test split for reproducible results. Defaults to None.fraction (float, optional): A float value from 0 to 1 which specifies the validation split fraction. Defaults to None.subset (str, optional): 'Train' or 'Test' to select the appropriate set. Defaults to None.image_color_mode (str, optional): 'rgb' or 'grayscale'. Defaults to 'rgb'.mask_color_mode (str, optional): 'rgb' or 'grayscale'. Defaults to 'grayscale'.Raises:OSError: If image folder doesn't exist in root.OSError: If mask folder doesn't exist in root.ValueError: If subset is not either 'Train' or 'Test'ValueError: If image_color_mode and mask_color_mode are either 'rgb' or 'grayscale'"""super().__init__(root, transforms)
image_folder_path=Path(self.root) /image_foldermask_folder_path=Path(self.root) /mask_folderifnotimage_folder_path.exists():
raiseOSError(f"{image_folder_path} does not exist.")
ifnotmask_folder_path.exists():
raiseOSError(f"{mask_folder_path} does not exist.")
ifimage_color_modenotin ["rgb", "grayscale"]:
raiseValueError(
f"{image_color_mode} is an invalid choice. Please enter from rgb grayscale."          )
ifmask_color_modenotin ["rgb", "grayscale"]:
raiseValueError(
f"{mask_color_mode} is an invalid choice. Please enter from rgb grayscale."          )
self.image_color_mode=image_color_modeself.mask_color_mode=mask_color_modeifnotfraction:
self.image_names=sorted(image_folder_path.glob("*"))
self.mask_names=sorted(mask_folder_path.glob("*"))
else:
ifsubsetnotin ["Train", "Test"]:
raise (ValueError(
f"{subset} is not a valid input. Acceptable values are Train and Test."              ))
self.fraction=fractionself.image_list=np.array(sorted(image_folder_path.glob("*")))
self.mask_list=np.array(sorted(mask_folder_path.glob("*")))
ifseed:
np.random.seed(seed)
indices=np.arange(len(self.image_list))
np.random.shuffle(indices)
self.image_list=self.image_list[indices]
self.mask_list=self.mask_list[indices]
ifsubset=="Train":
self.image_names=self.image_list[:int(
np.ceil(len(self.image_list) * (1-self.fraction)))]
self.mask_names=self.mask_list[:int(
np.ceil(len(self.mask_list) * (1-self.fraction)))]
else:
self.image_names=self.image_list[
int(np.ceil(len(self.image_list) * (1-self.fraction))):]
self.mask_names=self.mask_list[
int(np.ceil(len(self.mask_list) * (1-self.fraction))):]
def__len__(self) ->int:
returnlen(self.image_names)
def__getitem__(self, index: int) ->Any:
image_path=self.image_names[index]
mask_path=self.mask_names[index]
withopen(image_path, "rb") asimage_file, open(mask_path,
"rb") asmask_file:
image=Image.open(image_file)
ifself.image_color_mode=="rgb":
image=image.convert("RGB")
elifself.image_color_mode=="grayscale":
image=image.convert("L")
mask=Image.open(mask_file)
ifself.mask_color_mode=="rgb":
mask=mask.convert("RGB")
elifself.mask_color_mode=="grayscale":
mask=mask.convert("L")
sample= {"image": image, "mask": mask}
ifself.transforms:
sample["image"] =self.transforms(sample["image"])
sample["mask"] =self.transforms(sample["mask"])
returnsample

我们使用torchvision中的VisionDataset类作为Segmentation数据集的基类。以下三种方法需要重载。

init:此方法是数据集对象将初始化的位置。通常,您需要构建图像文件路径和相应的标签,它们是用于分割的遮罩文件路径。然后,在lengetitem方法中使用这些路径。getitem:每当您使用object [index]访问任何元素时,都会调用此方法。因此,我们需要在此处编写图像和蒙版加载逻辑。因此,实质上,您可以使用此方法中的数据集对象从数据集中获得一个训练样本。len:每当使用len(obj)时,都会调用此方法。此方法仅返回目录中训练样本的数量。

为PyTorch创建自定义数据集时,请记住使用PIL库。这使您可以直接使用Torchvision转换,而不必定义自己的转换。

在此类的第一个版本中,我使用OpenCV来加载图像!该库不仅非常繁重,而且与Torchvision转换不兼容。我必须编写自己的自定义转换并自己处理尺寸更改。

我添加了其他功能,使您可以将数据集保留在一个目录中,而不是将Train和Val拆分到单独的文件夹中,因为我使用的许多数据集都不采用这种格式,并且我不想重组我的数据集 文件夹结构每次。

现在我们已经定义了数据集类,下一步是从此创建一个PyTorch数据加载器。数据加载器使您可以使用多线程处理来创建一批数据样本和标签。这使得数据加载过程更加快捷和高效。为此,可以使用torch.utils.data下可用的DataLoader类。创建过程本身很简单。通过将数据集对象传递给它来创建一个DataLoader对象。支持的参数如下所示。

DataLoader(dataset, batch_size=1, shuffle=False, sampler=None,
batch_sampler=None, num_workers=0, collate_fn=None,
pin_memory=False, drop_last=False, timeout=0,
worker_init_fn=None, *, prefetch_factor=2,
persistent_workers=False)

下面解释了几个有用的参数:

数据集(Dataset):要从中加载数据的数据集。

batch_size(整数,可选):每个批次要加载多少样本(默认值:1)

shuffle(布尔型,可选):设置为True可使数据在每个时期都重新随机播放。(默认值:False)

num_workers(int,可选):要用于数据加载的子进程数。0表示将在主进程中加载数据。(默认值:0)提示:您可以将此值设置为等于系统处理器中的内核数,以作为最佳值。设置较高的值可能会导致性能下降。

此外,我编写了两个帮助程序函数,这些函数可以根据您的数据目录结构为您提供数据加载器,并且可以在datahandler.py文件中使用它们。

get_dataloader_sep_folder:从两个单独的Train和Test文件夹中创建Train和Test数据加载器。目录结构应如下所示。

data_dir--Train------Image---------Image1---------ImageN------Mask---------Mask1---------MaskN--Train------Image---------Image1---------ImageN------Mask---------Mask1---------MaskN

get_dataloader_single_folder:从单个文件夹创建。结构应如下

--data_dir------Image---------Image1---------ImageN------Mask---------Mask1---------MaskN

接下来,我们讨论本教程的关键所在,即如何根据我们的数据需求加载预训练的模型并更改分割头。

目录
相关文章
|
1月前
|
PyTorch Linux 算法框架/工具
pytorch学习一:Anaconda下载、安装、配置环境变量。anaconda创建多版本python环境。安装 pytorch。
这篇文章是关于如何使用Anaconda进行Python环境管理,包括下载、安装、配置环境变量、创建多版本Python环境、安装PyTorch以及使用Jupyter Notebook的详细指南。
268 1
pytorch学习一:Anaconda下载、安装、配置环境变量。anaconda创建多版本python环境。安装 pytorch。
|
5月前
|
机器学习/深度学习 自然语言处理 算法
【从零开始学习深度学习】49.Pytorch_NLP项目实战:文本情感分类---使用循环神经网络RNN
【从零开始学习深度学习】49.Pytorch_NLP项目实战:文本情感分类---使用循环神经网络RNN
|
1月前
|
机器学习/深度学习 缓存 PyTorch
pytorch学习一(扩展篇):miniconda下载、安装、配置环境变量。miniconda创建多版本python环境。整理常用命令(亲测ok)
这篇文章是关于如何下载、安装和配置Miniconda,以及如何使用Miniconda创建和管理Python环境的详细指南。
402 0
pytorch学习一(扩展篇):miniconda下载、安装、配置环境变量。miniconda创建多版本python环境。整理常用命令(亲测ok)
|
3月前
|
存储 PyTorch API
Pytorch入门—Tensors张量的学习
Pytorch入门—Tensors张量的学习
29 0
|
5月前
|
机器学习/深度学习 PyTorch 算法框架/工具
【从零开始学习深度学习】47. Pytorch图片样式迁移实战:将一张图片样式迁移至另一张图片,创作自己喜欢风格的图片【含完整源码】
【从零开始学习深度学习】47. Pytorch图片样式迁移实战:将一张图片样式迁移至另一张图片,创作自己喜欢风格的图片【含完整源码】
|
5月前
|
机器学习/深度学习 资源调度 PyTorch
【从零开始学习深度学习】15. Pytorch实战Kaggle比赛:房价预测案例【含数据集与源码】
【从零开始学习深度学习】15. Pytorch实战Kaggle比赛:房价预测案例【含数据集与源码】
|
5月前
|
机器学习/深度学习 算法 PyTorch
【从零开始学习深度学习】50.Pytorch_NLP项目实战:卷积神经网络textCNN在文本情感分类的运用
【从零开始学习深度学习】50.Pytorch_NLP项目实战:卷积神经网络textCNN在文本情感分类的运用
|
5月前
|
机器学习/深度学习 自然语言处理 PyTorch
【从零开始学习深度学习】48.Pytorch_NLP实战案例:如何使用预训练的词向量模型求近义词和类比词
【从零开始学习深度学习】48.Pytorch_NLP实战案例:如何使用预训练的词向量模型求近义词和类比词
|
5月前
|
机器学习/深度学习 算法 PyTorch
【从零开始学习深度学习】45. Pytorch迁移学习微调方法实战:使用微调技术进行2分类图片热狗识别模型训练【含源码与数据集】
【从零开始学习深度学习】45. Pytorch迁移学习微调方法实战:使用微调技术进行2分类图片热狗识别模型训练【含源码与数据集】
|
1月前
|
算法 PyTorch 算法框架/工具
Pytorch学习笔记(九):Pytorch模型的FLOPs、模型参数量等信息输出(torchstat、thop、ptflops、torchsummary)
本文介绍了如何使用torchstat、thop、ptflops和torchsummary等工具来计算Pytorch模型的FLOPs、模型参数量等信息。
223 2
下一篇
无影云桌面