Pytorch实战系列(一)——CNN之UNet代码解析

article/2025/8/24 3:16:21

目录

1.UNet整体结构理解

1.1 UNet结构拆解

1.1.1 卷积层主体:两次卷积操作

1.1.2 左部分每一层:下采样+卷积层

1.1.3 右部分每一层:上采样+中部分跳跃连接+卷积层

1.1.4 输入层和输出层

1.2 UNet结构融合

2.UNet Pytorch代码理解

2.1 UNet基本组件编码

2.1.1 卷积层编码

2.1.2 左部分层编码(下采样+卷积层)

2.1.3 右部分层编码(上采样+跳跃连接+卷积层)

2.1.4 输出层编码(输出结果采用1*1卷积)

2.2 UNet整体网络编码


1.UNet整体结构理解

        关于UNet的介绍网上有很多,它在语义分割上的传奇地位是任何深度学习初学者在接触CNN时都一定会知晓的。因而在此就不再赘述一些网络特点优势等等等等,我们直接来理解网络的组成和结构就好了。

        先放上UNet用得烂了但也被称作“存在一大批魔改”的结构图:

        在这里,我们可以把UNet拆解成三个部分进行理解:左、右、中三部分。

  • 左:特征提取模块,主要操作是进行下采样(池化)
  • 右:特征融合模块,主要操作是进行上采样
  • 中:跳跃连接模块,主要操作是将左右相同层两个模块的特征连接起来

        上述就是整个UNet结构的主要理解,理解完成之后,我们将各个模块进行编码上的拆解,之后再融合起来,组成整个UNet的结构。

1.1 UNet结构拆解

1.1.1 卷积层主体:两次卷积操作

        单看每一个卷积层,实际上就是每一个卷积层内做两次卷积操作,两次的卷积操作都是做kernel_size=3,stride=1的3*3卷积,结构图所示的网络没有做填补即padding=0,实际上我们为了保持图像尺寸大小不变通常会将padding设为1。

        在卷积层内,卷积之后得到的特征图进行BatchNorm操作,再进入激活函数ReLU即可。所以这就是我们第一个需要编码的小模块。

1.1.2 左部分每一层:下采样+卷积层

        这部分就比较简单了,除了最后一层之外,所有都需要进行下采样,所以结合1.1.1中的卷积层,每一层做一次kerner_size=2的下采样+卷积层(两次卷积操作)即可。

1.1.3 右部分每一层:上采样+中部分跳跃连接+卷积层

        这里需要结合中部分和右部分的网络结构来看,对于右部分每一层最终得到的特征图而言,其应该是下一层上采样之后,结合左部分相同层特征图的跳跃连接,再经过卷积层(两次卷积操作)得到的。所以对应操作应该是先做一次scale_factor=2的上采样,并将之前相同层数得到的下采样结果做一个cat连接,再经过卷积层。

1.1.4 输入层和输出层

        由于输入层无需下采样且输出层无需上采样,所以输入层和输出层都只需要经过一层卷积层(两次卷积操作)即可。

1.2 UNet结构融合

        所以综合来看,整个UNet模型应该是:

输入层+左部分四层+右部分四层+输出层

输入层:一个卷积层

左部分四层:一次下采样+一个卷积层

右部分四层:一次上采样+一个卷积层

输出层:一个卷积层

        左边输入层的in_channels是你所用图片的层数,右边输出层的out_channels是你所需要做分割的类别个数。其他的所有参数参照上面的UNet结构图即可。

2.UNet Pytorch代码理解

2.1 UNet基本组件编码

2.1.1 卷积层编码

class DoubleConv(nn.Module):"""(convolution => [BN] => ReLU) * 2"""def __init__(self, in_channels, out_channels):super().__init__()self.double_conv = nn.Sequential(nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1),nn.BatchNorm2d(out_channels),nn.ReLU(inplace=True),nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1),nn.BatchNorm2d(out_channels),nn.ReLU(inplace=True))def forward(self, x):return self.double_conv(x)

        可以看到整个卷积层的主体部分就是(Conv2d->BatchNorm2d->ReLU),没什么好说的。

        卷积层类命名为DoubleConv,意为做两次卷积。

2.1.2 左部分层编码(下采样+卷积层)

class Down(nn.Module):"""Downscaling with maxpool then double conv"""def __init__(self, in_channels, out_channels):super().__init__()self.maxpool_conv = nn.Sequential(nn.MaxPool2d(2),DoubleConv(in_channels, out_channels))def forward(self, x):return self.maxpool_conv(x)

        基于2.1.1的卷积层,左部分层的编码也非常简单,直接就是(MaxPool2d->DoubleConv)。

        左部分层类命名为Down,意为下采样,但下采样在编码的时候也做了两次卷积。

2.1.3 右部分层编码(上采样+跳跃连接+卷积层)

class Up(nn.Module):"""Upscaling then double conv"""def __init__(self, in_channels, out_channels, bilinear=True):super().__init__()# if bilinear, use the normal convolutions to reduce the number of channelsif bilinear:self.up = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True)else:self.up = nn.ConvTranspose2d(in_channels // 2, in_channels // 2, kernel_size=2, stride=2)# //为整数除法self.conv = DoubleConv(in_channels, out_channels)def forward(self, x1, x2):x1 = self.up(x1)# input is CHWdiffY = torch.tensor([x2.size()[2] - x1.size()[2]])diffX = torch.tensor([x2.size()[3] - x1.size()[3]])x1 = F.pad(x1, [diffX // 2, diffX - diffX // 2,diffY // 2, diffY - diffY // 2])x = torch.cat([x2, x1], dim=1)return self.conv(x)

        这一层理解起来会稍微复杂一点,但总体结构是不变的,还是上采样+跳跃连接+卷积层

        首先是bilinear的理解,从代码上可以看出来,用与不用bilinear会导致不同策略的上采样。使用bilinear会采用Upsample的上采样,其算法为插值上采样,不需要训练参数,速度比较快;不使用bilinear则会采用ConvTranspose2d的上采样,其算法是逆卷积化,需要训练参数,所以速度会比较慢,但上采样的数据会比较好。具体Upsample和ConvTranspose2d的参数可以查阅Pytorch官网或者网上的说明。

        其次是卷积操作conv,直接调用DoubleConv即可,不再赘述。

        最后看forward前向传播的操作里,可以看到在前向传播过程中,是先做了up操作,然后再做cat操作,最后return了conv即做了卷积操作。所以这也符合我们上面的说法。

        input是tensor即CHW,(channels,height,width),但是初看x1.size()[2]真的很奇怪,这不对吧。后来查了查,发现是(batchsize, channel, height, width),所以x2.size()[2]-x1.size()[2]是张量x2和张量x1的行差,x2.size()[3]-x1.size()[3]是张量x2和张量x1的列差。

        查阅了一下函数,F.pad函数用于扩充,参数如下:

torch.nn.functional.pad(input, pad, mode='constant', value=0)

        具体的扩充法则比较复杂,input就是需要扩充的tensor张量,pad是扩充参数(形状大小),mode是扩充模式,value是扩充值。

        详细的扩充法则可以查阅PyTorch碎片:F.pad的图文透彻理解_柚有所思的博客-CSDN博客。

        于是diffY和diffX分别是同层左部分特征图与右部分上采样后特征图的列差与行差,F.pad函数则是在右部分上采样后的特征图上补足与同层左部分特征图的行列,使之左右部分特征图有相同的尺寸

        最后再采用torch.cat函数将同层左部分特征图与右部分上采样后特征图在dim=1即行维度上进行拼接,这就完成了跳跃连接。

2.1.4 输出层编码(输出结果采用1*1卷积)

class OutConv(nn.Module):def __init__(self, in_channels, out_channels):super(OutConv, self).__init__()self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=1)def forward(self, x):return self.conv(x)

        最后输出层则是需要直接进行一个卷积层(两次卷积)操作,其两次卷积均采用1*1的卷积核得到最终的输出结果(语义分割类别)。

2.2 UNet整体网络编码

        完成2.1四个基本组件的编码后,即可得到以下UNet整体的网络编码:其通道数与其他参数如UNet的结构图所示,其前向传播forward的组成结构严格按照1.2的顺序

class UNet(nn.Module):def __init__(self, n_channels, n_classes, bilinear=True):super(UNet, self).__init__()self.n_channels = n_channels # 输入通道数self.n_classes = n_classes # 输出类别数self.bilinear = bilinear # 上采样方式self.inc = DoubleConv(n_channels, 64) # 输入层self.down1 = Down(64, 128)self.down2 = Down(128, 256)self.down3 = Down(256, 512)self.down4 = Down(512, 512)self.up1 = Up(1024, 256, bilinear)self.up2 = Up(512, 128, bilinear)self.up3 = Up(256, 64, bilinear)self.up4 = Up(128, 64, bilinear)self.outc = OutConv(64, n_classes) # 输出层def forward(self, x):x1 = self.inc(x) # 一开始输入x2 = self.down1(x1) # 四层左部分x3 = self.down2(x2)x4 = self.down3(x3)x5 = self.down4(x4)x = self.up1(x5, x4) # 四层右部分x = self.up2(x, x3)x = self.up3(x, x2)x = self.up4(x, x1)logits = self.outc(x) # 最终输出return logits

我的GitHub主页:JeasunLok · GitHub 

具体训练测试代码在:GitHub - JeasunLok/1_UNet-Pytorch-for-DL-course: The first CNN-Net for segmentations UNet in DL course


http://chatgpt.dhexx.cn/article/dh5ueWkr.shtml

相关文章

快速理解Unet的网络结构

Unet 前言FCNUnet 前言 U-Net和FCN非常的相似,U-Net比FCN稍晚提出来,但都发表在2015年,和FCN相比,U-Net的第一个特点是完全对称,也就是左边和右边是很类似的,而FCN的decoder相对简单,只用了一个…

Unet网络解析

1 Unet网络概述 论文名称:U-Net: Convolutional Networks for Biomedical Image Segmentation 发表会议及时间 :MICCA ( 国际医学图像计算和 计算机辅 助干预会 议 ) 2 0 1 5 Unet提出的初衷是为了解决医学图像分割的问题。 Unet网络非常的简单&…

分割网络模型(FCN、Unet、Unet++、SegNet、RefineNet)

1、FCN https://blog.csdn.net/bestrivern/article/details/89523329《Fully Convolutional Networks for Semantic Segmentation》https://arxiv.org/abs/1411.4038 FCN是不含全连接层的全卷积网络,对图像进行像素级的分类,解决了图像的语义分割问题&a…

UNet网络解读

UNet解读 UNet论文UNet的简介代码解读DoubleConv模块Down模块Up模块OutConv模块 整个UNet参考资料 UNet论文 UNet论文地址 UNet的简介 UNet是一个对称的网络结构,左侧为下采样,右侧为上采样;下采样为encoder,上采样为decoder;四…

UNet网络

UNet 本博客主要对UNet网络进行讲解,以下为文章目录: UNet 原论文讲解网络结构数据集介绍评价指标损失计算代码 本文参考资料如下: UNet原论文 https://arxiv.org/pdf/1505.04597.pdfU-Net网络结构讲解(语义分割) https://www.bilibili.c…

U-Net网络详解

U-Net: Convolutional Networks for Biomedical Image Segmentation 原文地址:https://zhuanlan.zhihu.com/p/43927696 前言 U-Net是比较早的使用全卷积网络进行语义分割的算法之一,论文中使用包含压缩路径和扩展路径的对称U形结构在当时非常具有创新…

U-Net网络

U-Net普遍应用在生物医学影像领域,其在架构设计和其他利用卷积神经网络基于像素的图像分割方面更成功,它甚至对有限数据集的图像更有效。U-Net的命名源自它的结构,它的网络结构可视化的结果很像一个字母U。 U-NET网络性能机制 U-Net 融合了 …

【Unet系列】Unet Unet++

文章目录 U-net概述细节部分1、结构的解析2、一些小点 result Unet概述细节部分resultsummary U-net U-Net是一篇基本结构非常好的论文,主要是针对生物医学图片的分割,而且,在今后的许多对医学图像的分割网络中,很大一部分会采取…

图像分割UNet系列------UNet详解

图像分割unet系列------UNet详解 1、UNet网络结构2、UNet网络结构高性能的原因分析3、医学图像使用UNet网络结构 UNet最早发表在2015的MICCAI上,到2020年中旬的引用量已经超过了9700多次,估计现在都过万了,从这方面看足以见得其影响力。当然&…

UNet、UNet++、UNet3+系列

一、unet 简介 继承FCN的思想,继续进行改进。但是相对于FCN,有几个改变的地方,U-Net是完全对称的,且对解码器(应该自Hinton提出编码器、解码器的概念来,即将图像->高语义feature map的过程看成编码器&…

unet网络详解

Unet 参考文献:U-Net: Convolutional Networks for Biomedical Image Segmentation作者:Olaf Ronneberger, Philipp Fischer, and Thomas Brox 什么是Unet模型 Unet是一个优秀的语义分割模型,其主要执行过程与其它语义分割模型类似。与CNN…

Unet相关介绍

老师的bloghttps://zhuanlan.zhihu.com/p/370931792。写的比我这个好,233 Unet是在Fcn基础上提出的一种应用于医学影响的分割网络。医学影像的特点是1、数据集小。2、单张图片大。 由于以上医疗影像的特点,我们无法直接用Fcn进行分割学习。一个德国团队…

UNET详解和UNET++介绍(零基础)

一背景介绍 背景介绍: 自2015年以来,在生物医学图像分割领域,U-Net得到了广泛的应用,目前已达到四千多次引用。至今,U-Net已经有了很多变体。目前已有许多新的卷积神经网络设计方式,但很多仍延续了U-Net的核…

UNet - unet网络

目录 1. u-net介绍 2. u-net网络结构 3. u-net 网络搭建 3.1 DoubleConv 3.2 Down 下采样 3.3 Up 上采样 3.4 网络输出 3.5 UNet 网络 UNet 网络 forward 前向传播 3.6 网络的参数 4. 完整代码 1. u-net介绍 Unet网络是医学图像分割领域常用的分割网络&#xff0…

UNet 浅析

文章目录 1. UNet 简介2. UNet 详解3. 代码实例 - 医学图像分割 (ISBI数据集)【参考】 1. UNet 简介 UNet 属于 FCN 的一种变体,它可以说是最常用、最简单的一种分割模型,它简单、高效、易懂、容易构建,且可以从小数据集中训练。2015 年&…

unet 网络结构

unet 是15年提出的用于解决医学图像分割问题。unet有两部分组成。左边部分可以看出是特征提取网络,用于提取图像的抽象特征。右边可以看作是特征融合操作。与传统的FCN相比,unet使用是使用特征拼接实现特征的融合。unet 通过特征融合操作,实现了浅层的低分辨率(越底层的信息…

unet模型及代码解析

什么是unet 一个U型网络结构,2015年在图像分割领域大放异彩,unet被大量应用在分割领域。它是在FCN的基础上构建,它的U型结构解决了FCN无法上下文的信息和位置信息的弊端 Unet网络结构 主干结构解析 左边为特征提取网络(编码器&…

深度学习论文精读[6]:UNet++

UNet的编解码结构一经提出以来,大有统一深度学习图像分割之势,后续基于UNet的改进方案也经久不衰,一些研究者也在从网络结构本身来思考UNet的有效性。比如说编解码网络应该取几层,跳跃连接是否能够有更多的变化以及什么样的结构训…

【Unet系列】(三)Unet++网络

一、UNet整体网络结构 Unet主要是探索encoder和decoder需要多大的问题,以此为基础,提出了融合不同尺寸Unet结构的网络。创新点就是把不同尺寸的Uent结构融入到了一个网络里。 二、结构的好处 (1)不管哪个深度的特征有效&#…

深度学习零基础学习之路——第四章 UNet-Family中Unet、Unet++和Unet3+的简介

Python深度学习入门 第一章 Python深度学习入门之环境软件配置 第二章 Python深度学习入门之数据处理Dataset的使用 第三章 数据可视化TensorBoard和TochVision的使用 第四章 UNet-Family中Unet、Unet和Unet3的简介 第五章 个人数据集的制作 Unet-Family的学习 Python深度学习…