【语义分割系列:六】Unet++ 论文阅读翻译笔记 医学图像 pytorch实现

本文介绍了Unet++的改进之处,包括重新设计的跳跃路径、深层监督和损失函数。在医学图像语义分割任务中,Unet++通过在跳跃路径上添加卷积层缩小编码器和解码器特征图之间的语义差距,采用密集的跳跃连接优化梯度流,并利用深层监督实现模型剪枝。实验结果显示,Unet++在保持高精度的同时,能够有效减少推理时间。
摘要由CSDN通过智能技术生成

UNet++

2018 CVPR

周纵苇,发表论文时是一个在读二年级的博士,在亚利桑那州立大学念生物信息学。

UNet++: A Nested U-Net Architecture for Medical Image Segmentation

研习U-Net++

1、Introduce

UNet++与U-Net的区别:

  • Re-designed skip pathways
  • Deep supervision

2、Network

title

  • (a)黑色表示原始的Unet,绿色和蓝色表示skip pathways 上密集的卷积块,红色表示deep supervision
  • (b) UNet++的第一个skip pathway 的详细分析。
  • (c) 如果经过deep supervision训练,UNet++可以在推理时进行修剪。

Re-designed skip pathways

title

在U-Net中,编码器的特征图在解码器中直接接收;然而,在UNet++中,它们经历了一个密集的卷积块,其卷积层数依赖于金字塔级。

  • title :denote the output of node title
  • i indexes the down-sampling layer along the encoder
  • j indexes the convolution layer of the dense block along the skip pathway

title

  • title is a convolution operation followed by an activation function

  • title denotes an up-sampling laye

  • title denotes the concatenation laye

  • nodes at level j = 0 :一个输入,来自上一层encoder

  • nodes at level j = 1 : 两个输入,其中 1 个输入为同一 skip pathway 前1个节点的输出, 1 个为 lower skip pathway 的 up-sampled 输出

  • nodes at level j > 1 : j+1 个输入,其中 j 个输入为同一 skip pathway 前 j 个节点的输出, 1 个为 lower skip pathway 的 up-sampled 输出

title

Deep supervisio

enabling the model to operate in two mode:

  • accurate mode
    the outputs from all segmentation branches are averaged
  • fast mode
    the final segmentation map is selected from only one of the segmentation branches , the choice of which determines the extent of model pruning and speed gain

Fig. 1c shows how the choice of segmentation branch in fast mode results in architectures of varying complexit

  • 8
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
以下是基于Pytorch实现医学图像语义分割Unet++的代码: ```python import torch import torch.nn as nn from torchvision import models class ConvBlock(nn.Module): def __init__(self, in_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=True, bn=True): super(ConvBlock, self).__init__() self.conv = nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding, bias=bias) self.bn = nn.BatchNorm2d(out_channels) if bn else None self.relu = nn.ReLU(inplace=True) def forward(self, x): x = self.conv(x) if self.bn is not None: x = self.bn(x) x = self.relu(x) return x class UpConv(nn.Module): def __init__(self, in_channels, out_channels, upscale_factor, mode='transpose', align_corners=True): super(UpConv, self).__init__() self.upscale_factor = upscale_factor self.align_corners = align_corners if mode == 'transpose': self.conv = nn.ConvTranspose2d(in_channels, out_channels, kernel_size=2*self.upscale_factor, stride=self.upscale_factor, padding=self.upscale_factor//2, output_padding=self.upscale_factor%2, bias=True) else: self.conv = nn.Sequential( nn.Upsample(scale_factor=self.upscale_factor, mode=mode, align_corners=self.align_corners), nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=True) ) def forward(self, x): return self.conv(x) class NestedUNet(nn.Module): def __init__(self, in_channels=1, out_channels=2, init_features=32): super(NestedUNet, self).__init__() self.down1 = nn.Sequential( ConvBlock(in_channels, init_features, bn=False), ConvBlock(init_features, init_features*2) ) self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True) self.down2 = nn.Sequential( ConvBlock(init_features*2, init_features*2*2), ConvBlock(init_features*2*2, init_features*2*2*2) ) self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True) self.down3 = nn.Sequential( ConvBlock(init_features*2*2*2, init_features*2*2*2*2), ConvBlock(init_features*2*2*2*2, init_features*2*2*2*2*2) ) self.pool3 = nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True) self.down4 = nn.Sequential( ConvBlock(init_features*2*2*2*2, init_features*2*2*2*2*2), ConvBlock(init_features*2*2*2*2*2, init_features*2*2*2*2*2*2) ) self.pool4 = nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True) self.bottom = nn.Sequential( ConvBlock(init_features*2*2*2*2*2, init_features*2*2*2*2*2*2), ConvBlock(init_features*2*2*2*2*2*2, init_features*2*2*2*2*2*2), UpConv(init_features*2*2*2*2*2*2, init_features*2*2*2*2*2, upscale_factor=2) ) self.up4 = nn.Sequential( ConvBlock(init_features*2*2*2*2*2, init_features*2*2*2*2*2), ConvBlock(init_features*2*2*2*2*2, init_features*2*2*2*2), UpConv(init_features*2*2*2*2, init_features*2*2, upscale_factor=2) ) self.up3 = nn.Sequential( ConvBlock(init_features*2*2*2*2, init_features*2*2), ConvBlock(init_features*2*2, init_features*2), UpConv(init_features*2, init_features, upscale_factor=2) ) self.up2 = nn.Sequential( ConvBlock(init_features*2*2, init_features), ConvBlock(init_features, init_features), UpConv(init_features, init_features//2, upscale_factor=2) ) self.up1 = nn.Sequential( ConvBlock(init_features, init_features//2), ConvBlock(init_features//2, out_channels) ) def forward(self, x): x1 = self.down1(x) x2 = self.pool1(x1) x2 = self.down2(x2) x3 = self.pool2(x2) x3 = self.down3(x3) x4 = self.pool3(x3) x4 = self.down4(x4) btm = self.pool4(x4) btm = self.bottom(btm) x4 = torch.cat([btm, x4], dim=1) x4 = self.up4(x4) x3 = torch.cat([x4, x3], dim=1) x3 = self.up3(x3) x2 = torch.cat([x3, x2], dim=1) x2 = self.up2(x2) x1 = torch.cat([x2, x1], dim=1) x1 = self.up1(x1) return x1 ``` 这段代码实现了一个基于PytorchNestedUNet模型,包含四个下采样/池化层和四个上采样/卷积层。其中,第一个下采样/池化层的输出被送入第二个下采样/池化层,以此类推。最后的bottom层会将最后一层下采样/池化层的输出送入上采样/卷积层,以生成最终的分割结果。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值