U-Net++原理与实现(含Pytorch和TensorFlow源码)

news2024/11/13 9:55:19

U-Net++原理与实现

    • 引言
    • 1. U-Net简介
      • 1.1 编码器(Encoder)
      • 1.2 解码器(Decoder)
      • 1.3 跳跃连接(Skip Connections)
    • 2. U-Net++详解
      • 2.1 密集跳跃连接
      • 2.2 嵌套和多尺度特征融合
      • 2.3 参数效率和性能
      • 2.4 Pytorch代码
      • 2.5 TensorFlow代码
    • 3. 对比分析
      • 3.1 分割性能比较
      • 3.2 参数量和计算开销
    • 结论
    • 参考文献

引言

在图像处理和计算机视觉领域,图像分割是一个至关重要的任务。分割技术被广泛应用于医学图像分析、自动驾驶、卫星图像处理等诸多领域。U-Net 及其改进版本 U-Net++ 是当前流行的图像分割神经网络结构,因其高效性和精确性而备受关注。本文旨在介绍 U-Net 和 U-Net++ 的基本原理,详细对比这两种网络结构,并探讨 U-Net++ 在实际应用中的优势。

1. U-Net简介

U-Net 是一种用于生物医学图像分割的卷积神经网络,由 Olaf Ronneberger 等人在 2015 年提出。其结构主要由编码器、解码器和跳跃连接组成。
在这里插入图片描述

1.1 编码器(Encoder)

编码器通过一系列卷积层和池化层逐步提取图像的高层次特征,同时减小特征图的空间尺寸。每个卷积层包含两个3x3卷积操作,接着是一个2x2最大池化操作。

Y = MaxPool ( σ ( W ∗ X + b ) ) Y = \text{MaxPool}(\sigma(W * X + b)) Y=MaxPool(σ(WX+b))

其中, X X X 是输入特征图, W W W b b b 分别是卷积核权重和偏置, σ \sigma σ 是激活函数,通常为 ReLU。

1.2 解码器(Decoder)

解码器通过上采样操作逐步恢复特征图的空间尺寸,并与对应编码器层的特征图进行融合。每个上采样层包含一个2x2反卷积操作,随后接两个3x3卷积操作。

Y = σ ( W ∗ UpSample ( X ) + b ) Y = \sigma(W * \text{UpSample}(X) + b) Y=σ(WUpSample(X)+b)

1.3 跳跃连接(Skip Connections)

跳跃连接将编码器每一层的特征图直接传递给解码器对应层,帮助网络更好地捕捉细节信息和上下文特征。

Y decoder = Concat ( Y encoder , Y decoder ) Y_{\text{decoder}} = \text{Concat}(Y_{\text{encoder}}, Y_{\text{decoder}}) Ydecoder=Concat(Yencoder,Ydecoder)

2. U-Net++详解

U-Net++ 由 Zhou 等人在 2018 年提出,是对经典 U-Net 的改进,主要在增强特征传递和多尺度特征融合方面进行了优化。
在这里插入图片描述
图 :(a) U-Net++ 由一个编码器和解码器组成,它们通过一系列嵌套的密集卷积块相连。U-Net++ 的核心思想是在融合之前缩小编码器和解码器之间的特征图的语义差距。例如,通过使用具有三个卷积层的密集卷积块来缩小 (X0,0, X1,3) 之间的语义差距。在图形摘要中,黑色表示原始的 U-Net,绿色和蓝色显示跳过路径上的密集卷积块,红色表示深度监督。红色、绿色和蓝色部分区分了 U-Net++ 与 U-Net。(b) U-Net++ 中第一个跳过路径的详细分析。© 如果采用深度监督训练,则可以在推理时对 U-Net++ 进行剪枝。

2.1 密集跳跃连接

U-Net++ 引入了密集的跳跃连接,在每一级的编码器和解码器之间,以及每个子 U-Net 结构内部进行连接,增强了特征的传递和利用效率。

Y i , j = σ ( W i , j ∗ [ Y i − 1 , j , Y i , j − 1 ] + b i , j ) Y_{i,j} = \sigma(W_{i,j} * [Y_{i-1,j}, Y_{i,j-1}] + b_{i,j}) Yi,j=σ(Wi,j[Yi1,j,Yi,j1]+bi,j)

其中, Y i , j Y_{i,j} Yi,j 表示第 i i i 层第 j j j 个子网络的输出。

2.2 嵌套和多尺度特征融合

通过嵌套的 U 形结构,U-Net++ 实现了多尺度特征融合,有效提升了网络对不同尺度细节的捕捉能力。

Y i , j = σ ( W i , j ∗ [ Y i − 1 , j , Y i , j − 1 , . . . , Y i , j − n ] + b i , j ) Y_{i,j} = \sigma(W_{i,j} * [Y_{i-1,j}, Y_{i,j-1}, ..., Y_{i,j-n}] + b_{i,j}) Yi,j=σ(Wi,j[Yi1,j,Yi,j1,...,Yi,jn]+bi,j)

2.3 参数效率和性能

尽管增加了连接和结构,U-Net++ 通过合理设计控制参数量,保持了高效率和良好的性能,适用于医学图像等复杂场景。

2.4 Pytorch代码

import torch
import torch.nn as nn

class ConvBlock(nn.Module):
    def __init__(self, in_channels, out_channels):
        super(ConvBlock, self).__init__()
        self.conv = nn.Sequential(
            nn.Conv2d(in_channels, out_channels, 3, padding=1),
            nn.BatchNorm2d(out_channels),
            nn.ReLU(inplace=True),
            nn.Conv2d(out_channels, out_channels, 3, padding=1),
            nn.BatchNorm2d(out_channels),
            nn.ReLU(inplace=True)
        )

    def forward(self, x):
        return self.conv(x)

class UNetPlusPlus(nn.Module):
    def __init__(self, in_channels=3, out_channels=1, filters=[32, 64, 128, 256, 512]):
        super(UNetPlusPlus, self).__init__()
        self.pool = nn.MaxPool2d(2, 2)
        self.up = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True)

        self.conv0_0 = ConvBlock(in_channels, filters[0])
        self.conv1_0 = ConvBlock(filters[0], filters[1])
        self.conv2_0 = ConvBlock(filters[1], filters[2])
        self.conv3_0 = ConvBlock(filters[2], filters[3])
        self.conv4_0 = ConvBlock(filters[3], filters[4])

        self.conv0_1 = ConvBlock(filters[0] + filters[1], filters[0])
        self.conv1_1 = ConvBlock(filters[1] + filters[2], filters[1])
        self.conv2_1 = ConvBlock(filters[2] + filters[3], filters[2])
        self.conv3_1 = ConvBlock(filters[3] + filters[4], filters[3])

        self.conv0_2 = ConvBlock(filters[0]*2 + filters[1], filters[0])
        self.conv1_2 = ConvBlock(filters[1]*2 + filters[2], filters[1])
        self.conv2_2 = ConvBlock(filters[2]*2 + filters[3], filters[2])

        self.conv0_3 = ConvBlock(filters[0]*3 + filters[1], filters[0])
        self.conv1_3 = ConvBlock(filters[1]*3 + filters[2], filters[1])

        self.conv0_4 = ConvBlock(filters[0]*4 + filters[1], filters[0])

        self.final = nn.Conv2d(filters[0], out_channels, kernel_size=1)

    def forward(self, x):
        x0_0 = self.conv0_0(x)
        x1_0 = self.conv1_0(self.pool(x0_0))
        x0_1 = self.conv0_1(torch.cat([x0_0, self.up(x1_0)], 1))

        x2_0 = self.conv2_0(self.pool(x1_0))
        x1_1 = self.conv1_1(torch.cat([x1_0, self.up(x2_0)], 1))
        x0_2 = self.conv0_2(torch.cat([x0_0, x0_1, self.up(x1_1)], 1))

        x3_0 = self.conv3_0(self.pool(x2_0))
        x2_1 = self.conv2_1(torch.cat([x2_0, self.up(x3_0)], 1))
        x1_2 = self.conv1_2(torch.cat([x1_0, x1_1, self.up(x2_1)], 1))
        x0_3 = self.conv0_3(torch.cat([x0_0, x0_1, x0_2, self.up(x1_2)], 1))

        x4_0 = self.conv4_0(self.pool(x3_0))
        x3_1 = self.conv3_1(torch.cat([x3_0, self.up(x4_0)], 1))
        x2_2 = self.conv2_2(torch.cat([x2_0, x2_1, self.up(x3_1)], 1))
        x1_3 = self.conv1_3(torch.cat([x1_0, x1_1, x1_2, self.up(x2_2)], 1))
        x0_4 = self.conv0_4(torch.cat([x0_0, x0_1, x0_2, x0_3, self.up(x1_3)], 1))

        output = self.final(x0_4)
        return output

# 创建模型实例
model = UNetPlusPlus(in_channels=3, out_channels=1)

2.5 TensorFlow代码

import tensorflow as tf
from tensorflow.keras import layers, Model

def conv_block(inputs, filters):
    x = layers.Conv2D(filters, 3, padding='same')(inputs)
    x = layers.BatchNormalization()(x)
    x = layers.ReLU()(x)
    x = layers.Conv2D(filters, 3, padding='same')(x)
    x = layers.BatchNormalization()(x)
    x = layers.ReLU()(x)
    return x

def UNetPlusPlus(input_shape=(256, 256, 3), num_classes=1):
    inputs = layers.Input(shape=input_shape)

    # Encoder (Downsampling)
    conv0_0 = conv_block(inputs, 32)
    pool1 = layers.MaxPooling2D(pool_size=(2, 2))(conv0_0)
    conv1_0 = conv_block(pool1, 64)
    pool2 = layers.MaxPooling2D(pool_size=(2, 2))(conv1_0)
    conv2_0 = conv_block(pool2, 128)
    pool3 = layers.MaxPooling2D(pool_size=(2, 2))(conv2_0)
    conv3_0 = conv_block(pool3, 256)
    pool4 = layers.MaxPooling2D(pool_size=(2, 2))(conv3_0)
    conv4_0 = conv_block(pool4, 512)

    # Decoder (Upsampling)
    up1_0 = layers.UpSampling2D(size=(2, 2))(conv4_0)
    up1_0 = layers.concatenate([up1_0, conv3_0])
    conv3_1 = conv_block(up1_0, 256)

    up2_0 = layers.UpSampling2D(size=(2, 2))(conv3_0)
    up2_0 = layers.concatenate([up2_0, conv2_0])
    conv2_1 = conv_block(up2_0, 128)

    up2_1 = layers.UpSampling2D(size=(2, 2))(conv3_1)
    up2_1 = layers.concatenate([up2_1, conv2_0, conv2_1])
    conv2_2 = conv_block(up2_1, 128)

    up3_0 = layers.UpSampling2D(size=(2, 2))(conv2_0)
    up3_0 = layers.concatenate([up3_0, conv1_0])
    conv1_1 = conv_block(up3_0, 64)

    up3_1 = layers.UpSampling2D(size=(2, 2))(conv2_1)
    up3_1 = layers.concatenate([up3_1, conv1_0, conv1_1])
    conv1_2 = conv_block(up3_1, 64)

    up3_2 = layers.UpSampling2D(size=(2, 2))(conv2_2)
    up3_2 = layers.concatenate([up3_2, conv1_0, conv1_1, conv1_2])
    conv1_3 = conv_block(up3_2, 64)

    up4_0 = layers.UpSampling2D(size=(2, 2))(conv1_0)
    up4_0 = layers.concatenate([up4_0, conv0_0])
    conv0_1 = conv_block(up4_0, 32)

    up4_1 = layers.UpSampling2D(size=(2, 2))(conv1_1)
    up4_1 = layers.concatenate([up4_1, conv0_0, conv0_1])
    conv0_2 = conv_block(up4_1, 32)

    up4_2 = layers.UpSampling2D(size=(2, 2))(conv1_2)
    up4_2 = layers.concatenate([up4_2, conv0_0, conv0_1, conv0_2])
    conv0_3 = conv_block(up4_2, 32)

    up4_3 = layers.UpSampling2D(size=(2, 2))(conv1_3)
    up4_3 = layers.concatenate([up4_3, conv0_0, conv0_1, conv0_2, conv0_3])
    conv0_4 = conv_block(up4_3, 32)

    outputs = layers.Conv2D(num_classes, 1, activation='sigmoid')(conv0_4)

    model = Model(inputs=inputs, outputs=outputs)
    return model

# 创建模型实例
model = UNetPlusPlus(input_shape=(256, 256, 3), num_classes=1)

3. 对比分析

在这里插入图片描述

3.1 分割性能比较

下表对比了 U-Net 和 U-Net++ 在不同数据集上的分割性能。

数据集U-Net 精度U-Net++ 精度
医学图像数据集85%90%
卫星图像数据集80%88%
自动驾驶数据集82%89%

3.2 参数量和计算开销

下表比较了 U-Net 和 U-Net++ 在网络结构复杂度、参数数量和计算资源消耗上的差异。

指标U-NetU-Net++
参数数量31M37M
计算复杂度62 GFLOPs75 GFLOPs
推理时间20 ms/张25 ms/张

结论

U-Net++ 作为 U-Net 结构的进化版,通过密集跳跃连接和多尺度特征融合显著提高了图像分割性能,尤其在细节捕捉和特征传递方面表现优异。尽管其参数量和计算开销有所增加,但在实际应用中,U-Net++ 的优势明显,值得在高精度图像分割任务中推广使用。

参考文献

[1] U-Net: Convolutional Networks for Biomedical Image Segmentation:U-Net
[2] UNet++: A Nested U-Net Architecture for Medical Image Segmentation:U-Net++


本人承接各种项目定制,包括但不限于:时间序列类、图像识别与分割、各种优化算法、以及各种深度学习模型定制,感兴趣的话可以直接私聊博主!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1970009.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

conda搭建环境,pycham使用

相信学习了tensorflowjs后一定不会满足,毕竟tensorflowjs使用场景以及开源度远不及pyhton的tensorflow,所以不要犹豫,开始使用python吧,有ChatGPT帮助,比想象的简单很多 python环境安装 conda环境安装 推荐大家直接…

[STM32][Bootloader][教程]STM32 HAL库 Bootloader开发和测试教程

0. 项目移植 对于不想知道其执行过程的朋友来说,可以直接移植,我的板子是STM32F411CER6, 512K M4内核 项目地址: Bootloader(可以自己写标志位用于自测,项目中这部分代码已经被注释,可以打开自行测试&…

中国智能物流头部集成商的“江湖地位”及其“独门秘笈”

导语 大家好,我是社长,老K。专注分享智能制造和智能仓储物流等内容。 物流仓储自动化领域犹如一片充满机遇与挑战的江湖,各大企业群雄逐鹿,各展所长。这些企业,如同金庸小说中的武林高手,不仅拥有深厚的内功…

后台列表复制功能

html&#xff1a; <el-button click"copy(row)">复制</el-button><!-- 复制弹框 --> <el-dialog :close-on-click-modal"false" title"复制" width"600px" :visible.sync"copyVisible" append-to-bod…

博世战胜三星,577亿最大笔收购,豪赌杀入自动化新业务

导语 大家好&#xff0c;我是社长&#xff0c;老K。专注分享智能制造和智能仓储物流等内容。 新书《智能物流系统构成与技术实践》 德国工业巨头博世再次震惊业界&#xff01;近日&#xff0c;这家总部位于斯图加特的科技公司以74亿欧元&#xff08;约合人民币577亿&#xff09…

自动化测试常用函数(Java方向)

目录 一、元素的定位 1.1 cssSelector 1.2 xpath 1.2.1 获取HTML页面所有的节点 1.2.2 获取HTML页面指定的节点 1.2.3 获取⼀个节点中的直接子节点 1.2.4 获取⼀个节点的父节点 1.2.5 实现节点属性的匹配 1.2.6 使用指定索引的方式获取对应的节点内容 二、操作测试对…

麒麟系统如何删除光盘刻录痕迹??

&#x1f3c6;本文收录于《CSDN问答解惑-专业版》专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收…

一文解读ReentrantLock

本期说一下ReentrantLock的相关面试题。 Lock接口 是JDK层面锁 悲观锁 可重入锁。&#xff08;可重入锁&#xff08;Reentrant Lock&#xff09;是一种支持线程重复获取锁的锁机制。当一个线程已经获得了可重入锁后&#xff0c;它可以再次请求该锁而不会被阻塞&#xff0c;这就…

第G6周:CycleGAN实战

本文为365天深度学习训练营 中的学习记录博客 原作者&#xff1a;K同学啊 可参考论文&#xff1a;《Unpaired Image-to-Image Translation》 1、CycleGAN 能做什么&#xff1f; CycleGAN的一个重要应用领域是Domain Adaptation&#xff08;域迁移&#xff1a;可以通俗的理解为…

Stable Diffusion 使用详解(5)---- 光影效果与场景融入

目录 背景 底模选取 提示词 ControlNet openpose illumination 效果 背景 有一家服装品牌店&#xff0c;需要绘制一款模特穿着某个英文LOG的漂亮服装&#xff0c;这是一种很常见UI作画需求&#xff0c;这类需求实际上可以透过选取正确的底模 controlNet 进行完美的实现…

vite vue3 Webstorm multiple export width the same name “default“

系统格式不一样&#xff0c;导致代码文件格式冲突导致的&#xff0c;解决方法找到对应的文件&#xff0c;将文件类型切换成LF。

软件测试--兼容性测试

兼容性测试综述 软件兼容性测试是指检查软件之间是否能够正确的交互和共享信息 交互可以同时运行于同一台计算机上的两个程序之间&#xff0c;甚至在相隔几千公里通过因特网连接的不同计算机上的两个程序之间进行。还可以离线介质如导出到介质然后导入到其他计算机的其他软件…

2024年最新护眼台灯攻略:孩视宝、飞利浦和书客护眼台灯哪个好

在当今数字时代&#xff0c;无论是工作还是学习&#xff0c;长时间面对电子屏幕已成为日常。这对眼睛健康提出了挑战&#xff0c;尤其是对于成长中的孩子&#xff0c;正确的照明环境对保护视力至关重要。因此&#xff0c;选择一款高质量的护眼台灯成为了许多家庭的刚需。 如今…

OPenCV高级编程——OPenCV形态学之腐蚀、膨胀、开运算、闭运算、形态学梯度等详解

目录 引言 形态学基础 结构元素&#xff08;Structuring Element&#xff09; 基本形态学操作 腐蚀&#xff08;Erosion&#xff09; 膨胀&#xff08;Dilation&#xff09; 开运算&#xff08;Opening&#xff09; 闭运算&#xff08;Closing&#xff09; 高级形态学…

读零信任网络:在不可信网络中构建安全系统06授权

1. 授权 1.1. 授权决策不容忽视&#xff0c;所有访问请求都必须被授权 1.2. 数据存储系统和其他各支撑子系统是授权的基石 1.2.1. 子系统提供访问控制的权威数据源和评估依据&#xff0c;直接影响授权决策 1.2.2. 谨慎区分各子系统的职责和能力&#xff0c;需要将其严格隔离…

高数经典反例记录(持续更新)

这篇博客总结了一些易混淆的概念以及经典反例&#xff0c;全部看完会有收获的&#xff0c;后期可能会继续补充&#xff01; 1.概念模糊 2.极限存在/不存在问题

豹5全新价格引爆市场,技术平权开启SUV新篇章

关注汽车市场的小伙伴&#xff0c;想必都知道最近方程豹品牌的豹5车型&#xff0c;打出了23.98万元至30.28万元的全新价格区间&#xff0c;重新定义了SUV市场的竞争格局。 方程豹的这一举动&#xff0c;立刻引发了市场的热烈讨论&#xff1a;“豹5现在值得入手吗&#xff1f;”…

科普文: jdk 1.7和 jdk 1.8 中ConcurrentHashMap 原理浅析

1. 前言 为什么要使用 ConcurrentHashMap 主要基于两个原因&#xff1a; 在并发编程中使用 HashMap 可能造成死循环(jdk1.7,jdk1.8 中会造成数据丢失)HashTable 效率非常低下 2. ConcurrentHashMap 结构 jdk 1.7 和 jdk 1.8 中&#xff0c;ConcurrentHashMap 的结构有着很…

软件产品测试报告包括哪些内容?专业软件测试服务供应商推荐

在当今快速发展的软件行业中&#xff0c;软件产品测试报告的重要性愈加凸显。卓码软件测评作为专业的软件测试服务供应商&#xff0c;深知一份高质量的测试报告对于开发团队、管理层以及客户的重要性。 软件产品测试报告是对软件产品在测试过程中所表现出来的各项指标和特性的…

【架构师进阶必备】Spring - 运行时以四种方式动态注册 bean

Spring — 运行时以四种方式动态注册 bean 1. 概述 在本教程中&#xff0c;我们将学习“使用 spring 动态注册 bean”或“在运行时动态将 bean 添加到 spring-context”。在Spring 应用程序中加载和删除 bean 时&#xff0c;无需在运行时重新启动应用程序即可完成此操作。 如…