unet模型及代码解析

article/2025/8/24 7:54:37

什么是unet

一个U型网络结构,2015年在图像分割领域大放异彩,unet被大量应用在分割领域。它是在FCN的基础上构建,它的U型结构解决了FCN无法上下文的信息和位置信息的弊端

Unet网络结构

主干结构解析

左边为特征提取网络(编码器),右边为特征融合网络(解码器)

高分辨率—编码—低分辨率—解码—高分辨率

特征提取网络

高分辨率—编码—低分辨率

前半部分是编码, 它的作用是特征提取(获取局部特征,并做图片级分类),得到抽象语义特征

由两个3x3的卷积层(RELU)再加上一个2x2的maxpooling层组成一个下采样的模块,一共经过4次这样的操作

特征融合网络

低分辨率—解码—高分辨率

利用前面编码的抽象特征来恢复到原图尺寸的过程, 最终得到分割结果(掩码图片)

由一层反卷积+特征拼接concat+两个3x3的卷积层(ReLU)反复构成,一共经过4次这样的操作,与特征提取网络刚好相对应,最后接一层1*1卷积,降维处理,即将通道数降低至特定的数量,得到目标图,具体内容可以参考这篇文章 一文读懂卷积神经网络中的1x1卷积核

FCN与UNet特征融合操作对比解析

FCN是通过特征图对应像素值的相加来融合特征的

torch代码:

concat1 = out1+out2
# 其中out1与out2都是torch中的tensor格式

unet是通过同维度矩阵拼接来融合特征的

torch代码:

concat2 = torch.cat([convt1,conv4],dim=1)
# dim = 1 意味着在第1维度方向(第1维也就是列为4的方向)进行叠加
# 对于更高维的数据,也就是在dim = x 时,即x所对应维度方向进行叠加

UNet主要创新点

  • 采取将低级特征图与后面的高级特征图进行融合操作

  • 完全对称的U型结构使得前后特征融合更为彻底,使得高分辨率信息与低分辨率信息在目标图片中增加

  • 结合了下采样时的低分辨率信息(提供物体类别识别依据)和上采样时的高分辨率信息(提供精准分割定位依据),此外还通过融合操作(跳跃结构)填补底层信息以提高分割精度.(分辨率就是图片的尺寸)

对高层语义特征与底层空间信息的理解

越底层的特征蕴含的空间信息(分割定位特征)更多,语义特征(就是类别判断特征,像素点可以分到哪一个类别中去)更少,越高级的特征蕴含的空间信息更少,语义特征更多

  • 底层特征图片更偏向于组成图像的基本单元,如点,线,边缘轮廓
  • 高层抽象的特征就更抽象,更近似于表示的是图像的语义信息

    注:图片来源于神经网络可视化论文《Visualizing and Understanding Convolutional Networks》

UNet与FCN的比较

1.编解码结构
  • 它们的结构都用了一个比较经典的思路,也就是编码和解码(encoder-decoder)结构,该结构早在2006年就被Hinton提出来发表在了nature上。当时这个encoder-decoder结构提出的主要作用并不是分割,而是压缩图像和去噪声。输入是一幅图,经过下采样的编码,得到一串比原先图像更小的特征,相当于压缩,然后再经过一个解码,理想状况就是能还原到原来的图像。这样的话我们存一幅图的时候就只需要存一个特征和一个解码器即可。同理,这个思路也可以用在原图像去噪,做法就是在训练的阶段在原图人为地加上噪声,然后放到这个编码解码器中,目标是可以还原得到原图。在UNet与FCN的目标任务中,是得到一张Mask掩码图,实现端到端(由图得到图),这与Hinton提出的编解码操作不谋而合。

  • 和FCN相比,U-Net的第一个特点是完全对称,也就是左边和右边是很类似的,而FCN的解码器部分相对简单,只用了一个反卷积的操作,之后并没有跟上卷积结构。

2.全卷积结构
  • UNet和FCN一样, 是全卷积形式, 没有全连接层(即没有固定图的尺寸)——全连接层输入是提前固定好的,所以容易适应很多输入尺寸大小
3.跳跃结构,即特征融合操作
  • UNet相比FCN,跳跃结构更多,更彻底,每一层下采样都与后面每一次上采样对应,一个经验的解释(大量实验)就是跳级连接能够保证特征更加精细
  • UNet是拼接操作,而FCN是加操作

模型torch代码解析

import torch.nn as nn
import torch.nn.functional as F
import torch.utils.data
import torch"""构造下采样模块--右边特征融合基础模块    
"""class conv_block(nn.Module):"""Convolution Block"""def __init__(self, in_ch, out_ch):super(conv_block, self).__init__()self.conv = nn.Sequential(nn.Conv2d(in_ch, out_ch, kernel_size=3, stride=1, padding=1, bias=True),# 在卷积神经网络的卷积层之后总会添加BatchNorm2d进行数据的归一化处理,这使得数据在进行Relu之前不会因为数据过大而导致网络性能的不稳定nn.BatchNorm2d(out_ch),nn.ReLU(inplace=True),nn.Conv2d(out_ch, out_ch, kernel_size=3, stride=1, padding=1, bias=True),nn.BatchNorm2d(out_ch),nn.ReLU(inplace=True))def forward(self, x):x = self.conv(x)return x"""构造上采样模块--左边特征提取基础模块    
"""
class up_conv(nn.Module):"""Up Convolution Block"""def __init__(self, in_ch, out_ch):super(up_conv, self).__init__()self.up = nn.Sequential(nn.Upsample(scale_factor=2),nn.Conv2d(in_ch, out_ch, kernel_size=3, stride=1, padding=1, bias=True),nn.BatchNorm2d(out_ch),nn.ReLU(inplace=True))def forward(self, x):x = self.up(x)return x"""模型主架构
"""class U_Net(nn.Module):"""UNet - Basic ImplementationPaper : https://arxiv.org/abs/1505.04597"""# 输入是3个通道的RGB图,输出是0或1——因为我的任务是2分类任务def __init__(self, in_ch=3, out_ch=2):super(U_Net, self).__init__()# 卷积参数设置n1 = 64filters = [n1, n1 * 2, n1 * 4, n1 * 8, n1 * 16]# 最大池化层self.Maxpool1 = nn.MaxPool2d(kernel_size=2, stride=2)self.Maxpool2 = nn.MaxPool2d(kernel_size=2, stride=2)self.Maxpool3 = nn.MaxPool2d(kernel_size=2, stride=2)self.Maxpool4 = nn.MaxPool2d(kernel_size=2, stride=2)# 左边特征提取卷积层self.Conv1 = conv_block(in_ch, filters[0])self.Conv2 = conv_block(filters[0], filters[1])self.Conv3 = conv_block(filters[1], filters[2])self.Conv4 = conv_block(filters[2], filters[3])self.Conv5 = conv_block(filters[3], filters[4])# 右边特征融合反卷积层self.Up5 = up_conv(filters[4], filters[3])self.Up_conv5 = conv_block(filters[4], filters[3])self.Up4 = up_conv(filters[3], filters[2])self.Up_conv4 = conv_block(filters[3], filters[2])self.Up3 = up_conv(filters[2], filters[1])self.Up_conv3 = conv_block(filters[2], filters[1])self.Up2 = up_conv(filters[1], filters[0])self.Up_conv2 = conv_block(filters[1], filters[0])self.Conv = nn.Conv2d(filters[0], out_ch, kernel_size=1, stride=1, padding=0)# 前向计算,输出一张与原图相同尺寸的图片矩阵def forward(self, x):e1 = self.Conv1(x)e2 = self.Maxpool1(e1)e2 = self.Conv2(e2)e3 = self.Maxpool2(e2)e3 = self.Conv3(e3)e4 = self.Maxpool3(e3)e4 = self.Conv4(e4)e5 = self.Maxpool4(e4)e5 = self.Conv5(e5)d5 = self.Up5(e5)d5 = torch.cat((e4, d5), dim=1)  # 将e4特征图与d5特征图横向拼接d5 = self.Up_conv5(d5)d4 = self.Up4(d5)d4 = torch.cat((e3, d4), dim=1)  # 将e3特征图与d4特征图横向拼接d4 = self.Up_conv4(d4)d3 = self.Up3(d4)d3 = torch.cat((e2, d3), dim=1)  # 将e2特征图与d3特征图横向拼接d3 = self.Up_conv3(d3)d2 = self.Up2(d3)d2 = torch.cat((e1, d2), dim=1)  # 将e1特征图与d1特征图横向拼接d2 = self.Up_conv2(d2)out = self.Conv(d2)return out

参考文章:

https://blog.csdn.net/weixin_40519315/article/details/104408388


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

相关文章

深度学习论文精读[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深度学习…

憨批的语义分割重制版6——Pytorch 搭建自己的Unet语义分割平台

憨批的语义分割重制版6——Pytorch 搭建自己的Unet语义分割平台 注意事项学习前言什么是Unet模型代码下载Unet实现思路一、预测部分1、主干网络介绍2、加强特征提取结构3、利用特征获得预测结果 二、训练部分1、训练文件详解2、LOSS解析 训练自己的Unet模型一、数据集的准备二、…

UNet详解(附图文和代码实现)

卷积神经网络被大规模的应用在分类任务中,输出的结果是整个图像的类标签。但是UNet是像素级分类,输出的则是每个像素点的类别,且不同类别的像素会显示不同颜色,UNet常常用在生物医学图像上,而该任务中图片数据往往较少…

条纹进度条

最开始学习qml的时候,想实现一个条纹进度条,当时还不熟悉动画,做不出来,只做了个静止的。qml学习和使用了快1年之际,把这个遗憾弥补下。 先上效果图,颜色取自Bootflat。 以下是源码,先上Stripe…

数据批量插入与逐条插入分析

简述 今天抽空做了一下使用Jdbc对数据操作的实际性能。在平时开发过程中我们经常会使用Hibernate来操作数据库,所以我们很少会去使用批量插入数据。一般都是通过hibernate的insert、addSave等方法来一条条地插入数据。所以很少去考虑这个问题。下面是针对Jdbc进行的…

css滚动条

此部分针对webkit内核的浏览器,使用伪类来改变滚动条的默认样式,详情如下: 滚动条组成部分 1. ::-webkit-scrollbar 滚动条整体部分2. ::-webkit-scrollbar-thumb 滚动条里面的小方块,能向上向下移动(或向左向右移动…

计算机组成原理(五)-一条指令是怎么被执行的

什么是指令: 程序代码的本质就是一条一条的指令,我们需要通过编码的方式让CPU知道我们需要它干什么,最后由译码器翻译成一条条的机器指令。机器指令主要有两部分组成:操作码、地址码。地址码直接给出操作数和操作数的地址&#x…

CSS 斜条纹进度条动画

这是第一版进度条 ,用css写的.但是后续因为数据不同,要显示不同的颜色和数据,所以又改了一版,直接用的el-progress.自定义的样式.对于新手小白来说比较友好.先上这一版代码. <div class"state"><span>开机时间</span><!-- 进度条 --><div…

Acrobat DC 更改背景颜色会有一条条白色横纹

解决方法如下&#xff1a; 编辑->首选项->页面显示->取消 使用2D图形加速

turtle模块还能这样玩?(一条条金龙鱼、雨景)

文章目录 一条条金龙鱼雨景 Python的turtle模块不仅可以用来绘制一些基本的图形&#xff0c;还有与图片结合&#xff0c;做出一些特殊的效果&#xff0c;还可以用来做二维小游戏。本篇是介绍用turtle模块做出的一幅动态的鱼儿游过的画面和动态的雨景图 一条条金龙鱼 1、先看一…

2.Python # 代码注释

2. # 代码注释 文章目录 2. # 代码注释1. 什么是代码注释2. 注释语法3. 注释位置1. 注释在代码的上一行2. 注释在代码的末端 4. 课堂练习 1. 什么是代码注释 代码注释即对代码进行批注说明。 相当于给一个英文单词批注中文释义。 【温馨提示】注释是给程序员自己看的&#xf…

python:导入第三方库greenlet,gevent方法

greenlet&#xff0c;gevent greenlet&#xff0c;gevent是python支持的第三方库&#xff0c;它们可以帮助我们完成协程的使用&#xff0c;其中greenlet是手动调换方式&#xff08;switch方法&#xff09;&#xff0c;gevent是自动调换方式&#xff08;遇到IO操作&#xff09;…

python gevent使用

对大部分语言来说&#xff0c;经常用到并发来处理一些情况。比如必须要多次查询数据库&#xff0c;多次请求API&#xff0c;python内置的gevent就很简单好用。传参&#xff0c;获取返回值&#xff0c;捕获协程的错误都很方便。 直接上例子&#xff1a; import gevent as gevent…

指定Geany使用的Python版本

本文介绍&#xff1a; 在win7下配置Geany,使其使用 Python 3 因为电脑上安装了不同版本的Python&#xff0c;需要根据实际情况来进行版本切换。 第一步&#xff1a;首先点击"生成"按钮的三角箭头&#xff0c;再点击"设置生成命令" 第二步&#xff1a;在弹出…

ModuleNotFountError:No module named ‘gensim‘(在python代码中导入gensim模块)

运行窗口&#xff1a; conda install 模块 pip install 模块 第一个命令应该由于网速太慢没有下载完全&#xff0c;第二个命令我手动输入n退出了。 网速慢&#xff0c;可以使用如下命令&#xff1a; pip install -i https://pypi.douban.com/simple gensim pip install -i…

Python学习笔记--图例 legend

Python学习笔记--图例 legend 参靠视频:《Python数据可视化分析 matplotlib教程》链接&#xff1a;https://www.bilibili.com/video/av6989413/?p6 所用的库及环境: IDE:Pycharm Python环境&#xff1a;python3.7 Matplotlib: Matplotlib 1.11 Numpy&#xff1a; Numpy1.1…

【pybind11笔记】eigen与numpy数据交互

系列文章 【pybind11笔记】eigen与numpy数据交互 【pybind11笔记】python调用c函数 【pybind11笔记】python调用c结构体 【pybind11笔记】python调用c类 文件结构 为了方便演示&#xff0c;我们使用cmake构建该样例&#xff0c;文件结构如下&#xff1a; pybind11与eigen…

python学习笔记:问题一,Geany编辑器无法使用中文注释

python学习笔记&#xff1a; 问题一&#xff1a; Geany编辑器无法使用中文注释 Geany编译python时运行弹出SyntaxError: (unicode error) ‘utf-8’ codec can’t提升&#xff0c;文本编辑器Geany无法使用中文注释&#xff0c;可以设置一下文本编码格式就好了设置方法为&…