< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

 

地址:https://github.com/yaoppeng/U-Net_v2/tree/master

1. 摘要

    Unetv2的目的是增加注入到低级特征中的语义信息,同时用更精细的细节来精炼高级特征。我们的方法可以无缝集成到任何编码器-解码器网络中。在几个公共医学分割数据集上评估了皮肤损伤分割和息肉分割,实验结果证明该方法的分割精度超过了最先进的方法,同时保持了内存和计算效率。

 

2. 方法

2.1 整体结构

unet v2的整体结构如下图,包含编码器、SDI(semantic and detail infusion)模块和解码器三部分:

编码器输出的M级特征传到SDI以更进一步精炼。

 

2.2 SDI模块

    首先,在第i级特征上应用空间和通道注意力机制,制,以集成局部空间信息和全局channel信息,然后利用1x1卷积将通道降至c(c为超参),得到的结果图表示为fi2,将decoder的每个level的特征图都调整至fi2大小,表示为:

D表示平均池化,I表示恒等映射,U代表双线性插值,之后采用3x3卷积平和每个特征图f3ij,之后采用Hadamard product到所有特征图以用更多语义信息和精细细节增强第i个级别的特征图,表示为:

然后,fi5被发送到第i级解码器进行进一步的分辨率重建和分割。

 

3. 实验

 

 

 

 

 

通道注意力、空间注意力以及SDI模块代码如下:

代码转自https://github.com/yaoppeng/U-Net_v2/blob/master/unet_v2/UNet_v2.py

class ChannelAttention(nn.Module):
   def __init__(self, in_planes, ratio=16):
       super(ChannelAttention, self).__init__()
       self.avg_pool = nn.AdaptiveAvgPool2d(1)
       self.max_pool = nn.AdaptiveMaxPool2d(1)

       self.fc1 = nn.Conv2d(in_planes, in_planes // 16, 1, bias=False)
       self.relu1 = nn.ReLU()
       self.fc2 = nn.Conv2d(in_planes // 16, in_planes, 1, bias=False)

       self.sigmoid = nn.Sigmoid()

   def forward(self, x):
       avg_out = self.fc2(self.relu1(self.fc1(self.avg_pool(x))))
       max_out = self.fc2(self.relu1(self.fc1(self.max_pool(x))))
       out = avg_out + max_out
       return self.sigmoid(out)


class SpatialAttention(nn.Module):
   def __init__(self, kernel_size=7):
       super(SpatialAttention, self).__init__()

       assert kernel_size in (3, 7), 'kernel size must be 3 or 7'
       padding = 3 if kernel_size == 7 else 1

       self.conv1 = nn.Conv2d(2, 1, kernel_size, padding=padding, bias=False)
       self.sigmoid = nn.Sigmoid()

   def forward(self, x):
       avg_out = torch.mean(x, dim=1, keepdim=True)
       max_out, _ = torch.max(x, dim=1, keepdim=True)
       x = torch.cat([avg_out, max_out], dim=1)
       x = self.conv1(x)
       return self.sigmoid(x)

 

class SDI(nn.Module):
   def __init__(self, channel):
       super().__init__()

       self.convs = nn.ModuleList(
           [nn.Conv2d(channel, channel, kernel_size=3, stride=1, padding=1)] * 4)

   def forward(self, xs, anchor):
       ans = torch.ones_like(anchor)
       target_size = anchor.shape[-1]

       for i, x in enumerate(xs):
           if x.shape[-1] > target_size:
               x = F.adaptive_avg_pool2d(x, (target_size, target_size))
           elif x.shape[-1] < target_size:
               x = F.interpolate(x, size=(target_size, target_size),
                                     mode='bilinear', align_corners=True)

           ans = ans * self.convs[i](x)

       return ans

 

 

 
posted on   一点飞鸿  阅读(268)  评论(0编辑  收藏  举报
编辑推荐:
· 理解Rust引用及其生命周期标识(下)
· 从二进制到误差:逐行拆解C语言浮点运算中的4008175468544之谜
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
阅读排行:
· C# 13 中的新增功能实操
· Ollama本地部署大模型总结
· 2025成都.NET开发者Connect圆满结束
· langchain0.3教程:从0到1打造一个智能聊天机器人
· 用一种新的分类方法梳理设计模式的脉络
点击右上角即可分享
微信分享提示