2024年DC-UNet:重新思考UNet架构和双通道高效CNN医学图像_unet改进(2)

文章探讨了如何通过改进MultiResUnet结构,特别是使用DualChannel块替换残差连接,以提高医学图像分割的性能。DC-UNet通过提供更丰富、有效的空间特征,解决了MultiResUnet在复杂场景下的不足,强调了特征尺度多样性和深度学习在医学图像处理中的重要性。
摘要由CSDN通过智能技术生成

如图2中(b)的降维版本解决了这一问题,在计算3x3和5x5的卷积之前,使用1x1的卷积层来降维。

虽然可以使用1x1的卷积层来降低维度,但是使用更大的卷积核来进行卷积也是相当耗时的,因此Inception模块可以进一步简化为下图所示的结构使用两个3x3的卷积来代替一个5x5的卷积。

另外还使用了多个3x3的卷积来代替7x7的卷积,如下图所示:

整个MulitResUnet的网络结构如下图所示:

DC-UNet

动机:MultiResUNet可以提供比U-Net更好的输出,因为它可以提供不同尺度的特征。然而,对于一些极具挑战性的医学图像情况,MultiResUNet表现不佳,例如物体模糊,背景(部分医疗设备)的干扰。MultiRes块的目标是提供不同尺度的特征来帮助将物体从整个图像中分离出来。因此,我们修改了MultiRes块以提供更有效的功能。

改进:之前使用的

  • 19
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的UNET网络双解码器模型的代码和注释。这个模型使用了PyTorch框架。 ``` import torch import torch.nn as nn import torch.nn.functional as F class DoubleDecoderUNet(nn.Module): def __init__(self, in_channels, out_channels): super(DoubleDecoderUNet, self).__init__() self.in_channels = in_channels self.out_channels = out_channels # 编码器 self.conv1 = nn.Conv2d(in_channels, 64, kernel_size=3, stride=1, padding=1, bias=True) self.bn1 = nn.BatchNorm2d(64) self.relu1 = nn.ReLU(inplace=True) self.conv2 = nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1, bias=True) self.bn2 = nn.BatchNorm2d(128) self.relu2 = nn.ReLU(inplace=True) self.conv3 = nn.Conv2d(128, 256, kernel_size=3, stride=1, padding=1, bias=True) self.bn3 = nn.BatchNorm2d(256) self.relu3 = nn.ReLU(inplace=True) self.conv4 = nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=1, bias=True) self.bn4 = nn.BatchNorm2d(512) self.relu4 = nn.ReLU(inplace=True) self.conv5 = nn.Conv2d(512, 1024, kernel_size=3, stride=1, padding=1, bias=True) self.bn5 = nn.BatchNorm2d(1024) self.relu5 = nn.ReLU(inplace=True) # 解码器1 self.upconv6 = nn.ConvTranspose2d(1024, 512, kernel_size=2, stride=2, padding=0, bias=True) self.conv6 = nn.Conv2d(1024, 512, kernel_size=3, stride=1, padding=1, bias=True) self.bn6 = nn.BatchNorm2d(512) self.relu6 = nn.ReLU(inplace=True) self.upconv7 = nn.ConvTranspose2d(512, 256, kernel_size=2, stride=2, padding=0, bias=True) self.conv7 = nn.Conv2d(512, 256, kernel_size=3, stride=1, padding=1, bias=True) self.bn7 = nn.BatchNorm2d(256) self.relu7 = nn.ReLU(inplace=True) self.upconv8 = nn.ConvTranspose2d(256, 128, kernel_size=2, stride=2, padding=0, bias=True) self.conv8 = nn.Conv2d(256, 128, kernel_size=3, stride=1, padding=1, bias=True) self.bn8 = nn.BatchNorm2d(128) self.relu8 = nn.ReLU(inplace=True) self.upconv9 = nn.ConvTranspose2d(128, 64, kernel_size=2, stride=2, padding=0, bias=True) self.conv9 = nn.Conv2d(128, 64, kernel_size=3, stride=1, padding=1, bias=True) self.bn9 = nn.BatchNorm2d(64) self.relu9 = nn.ReLU(inplace=True) self.conv10 = nn.Conv2d(64, out_channels, kernel_size=1, stride=1, padding=0, bias=True) # 解码器2 self.upconv11 = nn.ConvTranspose2d(1024, 512, kernel_size=2, stride=2, padding=0, bias=True) self.conv11 = nn.Conv2d(1024, 512, kernel_size=3, stride=1, padding=1, bias=True) self.bn11 = nn.BatchNorm2d(512) self.relu11 = nn.ReLU(inplace=True) self.upconv12 = nn.ConvTranspose2d(512, 256, kernel_size=2, stride=2, padding=0, bias=True) self.conv12 = nn.Conv2d(512, 256, kernel_size=3, stride=1, padding=1, bias=True) self.bn12 = nn.BatchNorm2d(256) self.relu12 = nn.ReLU(inplace=True) self.upconv13 = nn.ConvTranspose2d(256, 128, kernel_size=2, stride=2, padding=0, bias=True) self.conv13 = nn.Conv2d(256, 128, kernel_size=3, stride=1, padding=1, bias=True) self.bn13 = nn.BatchNorm2d(128) self.relu13 = nn.ReLU(inplace=True) self.upconv14 = nn.ConvTranspose2d(128, 64, kernel_size=2, stride=2, padding=0, bias=True) self.conv14 = nn.Conv2d(128, 64, kernel_size=3, stride=1, padding=1, bias=True) self.bn14 = nn.BatchNorm2d(64) self.relu14 = nn.ReLU(inplace=True) self.conv15 = nn.Conv2d(64, out_channels, kernel_size=1, stride=1, padding=0, bias=True) def forward(self, x): # 编码器 x1 = self.relu1(self.bn1(self.conv1(x))) x2 = self.relu2(self.bn2(self.conv2(x1))) x3 = self.relu3(self.bn3(self.conv3(x2))) x4 = self.relu4(self.bn4(self.conv4(x3))) x5 = self.relu5(self.bn5(self.conv5(x4))) # 解码器1 y6 = torch.cat([self.upconv6(x5), x4], 1) y6 = self.relu6(self.bn6(self.conv6(y6))) y7 = torch.cat([self.upconv7(y6), x3], 1) y7 = self.relu7(self.bn7(self.conv7(y7))) y8 = torch.cat([self.upconv8(y7), x2], 1) y8 = self.relu8(self.bn8(self.conv8(y8))) y9 = torch.cat([self.upconv9(y8), x1], 1) y9 = self.relu9(self.bn9(self.conv9(y9))) y10 = self.conv10(y9) # 解码器2 z11 = torch.cat([self.upconv11(x5), x4], 1) z11 = self.relu11(self.bn11(self.conv11(z11))) z12 = torch.cat([self.upconv12(z11), x3], 1) z12 = self.relu12(self.bn12(self.conv12(z12))) z13 = torch.cat([self.upconv13(z12), x2], 1) z13 = self.relu13(self.bn13(self.conv13(z13))) z14 = torch.cat([self.upconv14(z13), x1], 1) z14 = self.relu14(self.bn14(self.conv14(z14))) z15 = self.conv15(z14) # 返回两个输出 return y10, z15 ``` 在上面的代码中,我们定义了一个名为`DoubleDecoderUNet`的类,它继承自`nn.Module`。该类包含了UNET网络的编码器和两个解码器。 在`__init__`函数中,我们定义了UNET网络的各个层。编码器部分包括5个卷积层,每个卷积层后面都有一个BatchNorm层和ReLU激活函数。第一个卷积层的输入通道数等于原始图像的通道数。第五个卷积层的输出通道数为1024。解码器部分包括4个反卷积层和4个卷积层。解码器1的输出是一个大小与原始输入相同的特征图,并且输出通道数等于需要预测的类别数。解码器2的输出与解码器1相同。 在`forward`函数中,我们定义了UNET网络的前向传播过程。输入数据首先通过编码器,得到5个特征图。解码器1从第5个特征图开始反卷积,并与编码器的第4、3、2、1个特征图进行合并和卷积。解码器1的输出是一个预测图。类似地,解码器2从第5个特征图开始反卷积,并与编码器的第4、3、2、1个特征图进行合并和卷积。解码器2的输出也是一个预测图。 最后,该模型返回两个输出,分别是解码器1和解码器2的输出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值