当前位置: 首页 > news >正文

【代码分析】Unet-Pytorch

1:unet_parts.py

主要包含:

【1】double conv,双层卷积

【2】down,下采样

【3】up,上采样

【4】out conv,输出卷积

""" Parts of the U-Net model """import torch
import torch.nn as nn
import torch.nn.functional as Fclass DoubleConv(nn.Module):"""(convolution => [BN] => ReLU) * 2"""def __init__(self, in_channels, out_channels, mid_channels=None):super().__init__()if not mid_channels:mid_channels = out_channelsself.double_conv = nn.Sequential(nn.Conv2d(in_channels, mid_channels, kernel_size=3, padding=1, bias=False),nn.BatchNorm2d(mid_channels),nn.ReLU(inplace=True),nn.Conv2d(mid_channels, out_channels, kernel_size=3, padding=1, bias=False),nn.BatchNorm2d(out_channels),nn.ReLU(inplace=True))def forward(self, x):return self.double_conv(x)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)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)self.conv = DoubleConv(in_channels, out_channels, in_channels // 2)else:# // 是整除运算self.up = nn.ConvTranspose2d(in_channels, 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 = x2.size()[2] - x1.size()[2]diffX = x2.size()[3] - x1.size()[3]x1 = F.pad(x1, [diffX // 2, diffX - diffX // 2,diffY // 2, diffY - diffY // 2])# if you have padding issues, see# https://github.com/HaiyongJiang/U-Net-Pytorch-Unstructured-Buggy/commit/0e854509c2cea854e247a9c615f175f76fbb2e3a# https://github.com/xiaopeng-liao/Pytorch-UNet/commit/8ebac70e633bac59fc22bb5195e513d5832fb3bdx = torch.cat([x2, x1], dim=1)return self.conv(x)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】double conv

=》卷积。卷积核是3*3,填充是1

=》批归一化。

=》ReLU。激活函数

=》卷积。卷积核是3*3,填充是1

=》批归一化。

=》ReLU。激活函数

【2】down

=》最大池化。池化核是2*2

=》double conv。

【3】up

=》上采样。可选择upsample + double conv 和 transpose + double conv

=》计算尺寸差异。

=》填充x1。使得x1和x2对齐

=》拼接x2和x1。按照dim=1,也就是channel通道拼接

=》double conv。

【4】out conv

=》卷积。卷积核是1*1

2:unet_model.py

主要包含:UNet完整架构

""" Full assembly of the parts to form the complete network """from .unet_parts import *class UNet(nn.Module):def __init__(self, n_channels, n_classes, bilinear=False):super(UNet, self).__init__()self.n_channels = n_channelsself.n_classes = n_classesself.bilinear = bilinearself.inc = (DoubleConv(n_channels, 64))self.down1 = (Down(64, 128))self.down2 = (Down(128, 256))self.down3 = (Down(256, 512))factor = 2 if bilinear else 1self.down4 = (Down(512, 1024 // factor))self.up1 = (Up(1024, 512 // factor, bilinear))self.up2 = (Up(512, 256 // factor, bilinear))self.up3 = (Up(256, 128 // factor, 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 logitsdef use_checkpointing(self):self.inc = torch.utils.checkpoint(self.inc)self.down1 = torch.utils.checkpoint(self.down1)self.down2 = torch.utils.checkpoint(self.down2)self.down3 = torch.utils.checkpoint(self.down3)self.down4 = torch.utils.checkpoint(self.down4)self.up1 = torch.utils.checkpoint(self.up1)self.up2 = torch.utils.checkpoint(self.up2)self.up3 = torch.utils.checkpoint(self.up3)self.up4 = torch.utils.checkpoint(self.up4)self.outc = torch.utils.checkpoint(self.outc)

其中,use_checkpointing的作用是丢弃中间计算结果,加快训练速度。

上面的代码可以结合下图分析

前向传播过程:

        x1 = self.inc(x)

通过double conv双层卷积,输入通道为图像自身的,输出通道为64

        x2 = self.down1(x1)

通过down下采样,输入通道为64,输出通道为128

        x3 = self.down2(x2)

通过down下采样,输入通道为128,输出通道为256

        x4 = self.down3(x3)

通过down下采样,输入通道为256,输出通道为512

        x5 = self.down4(x4)

通过down下采样,输入通道为512,输出通道为1024(非bilinear,后续上采样也是如此)

        x = self.up1(x5, x4)

通过up上采样,输入通道为1024,输出通道为512

这个地方concat的对象是x4,也就是下采样输出通道为512的时候的特征

        x = self.up2(x, x3)

通过up上采样,输入通道为512,输出通道为256

这个地方concat的对象是x,也就是原图(后续也是原图)

其实这里和原作者的跳跃连接有点不太一样,代码库的作者直接省事用了原图进行拼接

        x = self.up3(x, x2)

通过up上采样,输入通道为256,输出通道为128

        x = self.up4(x, x1)

通过up上采样,输入通道为128,输出通道为64

        logits = self.outc(x)

通过out conv输出卷积,输入通道为64,输出通道为2,也就是分割为背景和物体2个类别的像素

3:完整代码

可以在github上通过git clone下载

milesial/Pytorch-UNet: PyTorch implementation of the U-Net for image semantic segmentation with high quality images (github.com)

http://www.lryc.cn/news/513925.html

相关文章:

  • 【LLM入门系列】01 深度学习入门介绍
  • 安卓系统主板_迷你安卓主板定制开发_联发科MTK安卓主板方案
  • 关键点检测——HRNet原理详解篇
  • 25考研总结
  • 网络安全态势感知
  • 在K8S中,节点状态notReady如何排查?
  • 深度学习在光学成像中是如何发挥作用的?
  • 树莓派linux内核源码编译
  • 本地小主机安装HomeAssistant开源智能家居平台打造个人AI管家
  • SpringBoot返回文件让前端下载的几种方式
  • 人工智能及深度学习的一些题目
  • 15-利用dubbo远程服务调用
  • 【Rust自学】8.5. HashMap Pt.1:HashMap的定义、创建、合并与访问
  • 未来网络技术的新征程:5G、物联网与边缘计算(10/10)
  • LLM(十二)| DeepSeek-V3 技术报告深度解读——开源模型的巅峰之作
  • Uniapp在浏览器拉起导航
  • 公平联邦学习——多目标优化
  • 奇怪的Python:为何字符串要设置成不可变的?
  • Vue-Router之嵌套路由
  • MyBatis使用的设计模式
  • arm rk3588 升级glibc2.31到2.33
  • 【Linux系列】sed命令的深入解析:如何使用sed删除文件内容
  • C++ 设计模式:桥接模式(Bridge Pattern)
  • MATLAB中whitespacePattern函数用法
  • Django多字段认证的实现
  • 【AndroidAPP】权限被拒绝:[android.permission.READ_EXTERNAL_STORAGE],USB设备访问权限系统报错
  • SQL进阶技巧:如何分析连续签到领金币数问题?
  • 1、ELK的架构和安装
  • Vue2/Vue3使用DataV
  • 汇编环境搭建