import torch
import torch.nn as nn
from torch.nn import functional as F
class CPCAChannelAttention(nn.Module):
def __init__(self, input_channels, internal_neurons):
super(CPCAChannelAttention, self).__init__()
self.fc1 = nn.Conv2d(in_channels=input_channels, out_channels=internal_neurons, kernel_size=1, stride=1,
bias=True)
self.fc2 = nn.Conv2d(in_channels=internal_neurons, out_channels=input_channels, kernel_size=1, stride=1,
bias=True)
self.input_channels = input_channels
def forward(self, inputs):
x1 = F.adaptive_avg_pool2d(inputs, output_size=(1, 1))
x1 = self.fc1(x1)
x1 = F.relu(x1, inplace=True)
x1 = self.fc2(x1)
x1 = torch.sigmoid(x1)
x2 = F.adaptive_max_pool2d(inputs, output_size=(1, 1))
x2 = self.fc1(x2)
x2 = F.relu(x2, inplace=True)
x2 = self.fc2(x2)
x2 = torch.sigmoid(x2)
x = x1 + x2
x = x.view(-1, self.input_channels, 1, 1)
return inputs * x
class CPCA(nn.Module):
def __init__(self, channels, channelAttention_reduce=4):
super().__init__()
self.ca = CPCAChannelAttention(input_channels=channels, internal_neurons=channels // channelAttention_reduce)
self.dconv5_5 = nn.Conv2d(channels, channels, kernel_size=5, padding=2, groups=channels)
self.dconv1_7 = nn.Conv2d(channels, channels, kernel_size=(1, 7), padding=(0, 3), groups=channels)
self.dconv7_1 = nn.Conv2d(channels, channels, kernel_size=(7, 1), padding=(3, 0), groups=channels)
self.dconv1_11 = nn.Conv2d(channels, channels, kernel_size=(1, 11), padding=(0, 5), groups=channels)
self.dconv11_1 = nn.Conv2d(channels, channels, kernel_size=(11, 1), padding=(5, 0), groups=channels)
self.dconv1_21 = nn.Conv2d(channels, channels, kernel_size=(1, 21), padding=(0, 10), groups=channels)
self.dconv21_1 = nn.Conv2d(channels, channels, kernel_size=(21, 1), padding=(10, 0), groups=channels)
self.conv = nn.Conv2d(channels, channels, kernel_size=(1, 1), padding=0)
self.act = nn.GELU()
def forward(self, inputs):
# Global Perceptron
inputs = self.conv(inputs)
inputs = self.act(inputs)
inputs = self.ca(inputs)
x_init = self.dconv5_5(inputs)
x_1 = self.dconv1_7(x_init)
x_1 = self.dconv7_1(x_1)
x_2 = self.dconv1_11(x_init)
x_2 = self.dconv11_1(x_2)
x_3 = self.dconv1_21(x_init)
x_3 = self.dconv21_1(x_3)
x = x_1 + x_2 + x_3 + x_init
spatial_att = self.conv(x)
out = spatial_att * inputs
out = self.conv(out)
return out
elif m is CPCA:
c2 = ch[f]
args = [c2, *args]
class C2CPCA(nn.Module):
#同C2PSA注册
def __init__(self, c1, c2, n=1, e=0.5, attention='cpca'):
super().__init__()
assert c1 == c2,
self.c = int(c1 * e)
self.cv1 = Conv(c1, 2 * self.c, 1, 1)
self.cv2 = Conv(2 * self.c, c1, 1)
if attention == 'psa':
self.m = nn.Sequential(
*(PSABlock(self.c, attn_ratio=0.5, num_heads=self.c // 64) for _ in range(n))
)
elif attention == 'cpca':
self.m = nn.Sequential(
*(CPCAChannelAttention(self.c, internal_neurons=self.c // 2) for _ in range(n))
)
else:
raise ValueError("attention参数只能是 'psa' 或 'cpca'。")
def forward(self, x):
a, b = self.cv1(x).split((self.c, self.c), dim=1)
b = self.m(b)
return self.cv2(torch.cat((a, b), 1))
[2306.05196] 用于医学图像分割的通道先验卷积注意
低对比度和显着器官形状变化等特征经常出现在医学图像中。医学成像中分割性能的提高受到现有注意力机制普遍适应能力不足的限制。该文提出了一种高效的通道先验卷积注意力(CPCA)方法,支持注意力权重在通道和空间维度上的动态分布。通过采用多尺度深度卷积模块,在保留通道先验的同时有效地提取空间关系。CPCA 拥有专注于信息渠道和重要区域的能力。该文基于 CPCA 提出了一种用于医学图像分割的 CPCANet 分割网络。CPCANet 在两个公开可用的数据集上进行了验证。CPCANet 实现了更高的分割性能,同时通过与最先进的算法相比,需要的计算资源更少。