【Block总结】CPCA,通道优先卷积注意力|即插即用

news2025/2/2 14:49:08

论文信息

标题: Channel Prior Convolutional Attention for Medical Image Segmentation

论文链接: arxiv.org

代码链接: GitHub
在这里插入图片描述

创新点

本文提出了一种新的通道优先卷积注意力(CPCA)机制,旨在解决医学图像分割中存在的低对比度和显著器官形状变化等问题。CPCA通过在通道和空间维度上动态分配注意力权重,增强了模型对信息丰富通道和重要区域的关注能力。
在这里插入图片描述

方法

CPCA方法的核心在于以下几个方面:

  • 动态注意力分配: 在通道和空间维度上支持动态分配注意力权重,使得模型能够自适应地关注不同的特征。

  • 多尺度深度可分离卷积模块: 该模块有效提取空间关系,同时保持通道优先,增强了特征表示能力。

  • CPCANet网络结构: 基于CPCA的医学图像分割网络CPCANet被设计用于实现更高效的分割性能。

CPCA模块详解

通道优先卷积注意力(Channel Prior Convolutional Attention,CPCA)是一种新型的注意力机制,旨在提升深度学习模型在医学图像分割等任务中的性能。CPCA通过动态分配通道和空间维度的注意力权重,增强了模型对重要特征的关注能力。

CPCA结合了通道注意力和空间注意力的机制,具体实现步骤如下:

  1. 通道注意力(Channel Attention):

    • 特征聚合: 通过全局平均池化和全局最大池化操作,生成两个不同的特征表示。
    • 特征处理: 将这两个特征表示分别通过卷积层和激活函数处理,以提取通道之间的关系。
    • 权重生成: 通过Sigmoid函数生成通道注意力权重,用于动态调整每个通道的重要性。
  2. 空间注意力(Spatial Attention):

    • 空间关系捕捉: 使用多尺度深度可分离卷积模块来提取特征图中不同位置之间的关系。
    • 多尺度卷积: 采用不同大小的卷积核来捕获多尺度信息,从而更好地理解特征图的空间结构。
  3. 整体机制:

    • CPCA通过结合通道和空间注意力,动态分配注意力权重,并保持通道优先。这种结合使得网络能够更好地捕捉重要特征,提高特征的表征能力。

效果

在多个公开数据集上进行的实验表明,CPCANet相较于其他最先进的算法在分割性能上表现更佳,同时所需计算资源更少。具体来说,CPCA在处理低对比度和复杂形状变化的医学图像时,显著提高了分割精度。

实验结果

实验结果显示,CPCANet在两个主要数据集(如ACDC和ISIC2016)上均取得了优于现有方法的分割效果。通过对比分析,CPCA方法在多个指标上均表现出色,尤其是在处理复杂背景和形状变化时,展现了其优越性。

总结

本文通过提出通道优先卷积注意力(CPCA)机制,显著提升了医学图像分割的性能。CPCA不仅增强了模型对重要特征的关注能力,还通过动态分配注意力权重,优化了计算资源的使用。未来的研究可以进一步探索CPCA在其他领域的应用潜力,以及与其他深度学习技术的结合。

代码

import torch
import torch.nn.functional
import torch.nn.functional as F
from torch import nn

class Mlp(nn.Module):
    """ Multilayer perceptron."""

    def __init__(self, in_features, hidden_features=None, out_features=None, act_layer=nn.GELU, drop=0.):
        super().__init__()
        out_features = out_features or in_features
        hidden_features = hidden_features or in_features
        self.fc1 = nn.Linear(in_features, hidden_features)
        self.act = act_layer()
        self.fc2 = nn.Linear(hidden_features, out_features)
        self.drop = nn.Dropout(drop)

    def forward(self, x):
        x = self.fc1(x)
        x = self.act(x)
        x = self.drop(x)
        x = self.fc2(x)
        x = self.drop(x)
        return x


def conv_bn(in_channels, out_channels, kernel_size, stride, padding, groups=1):
    result = nn.Sequential()
    result.add_module('conv', nn.Conv2d(in_channels=in_channels, out_channels=out_channels,
                                        kernel_size=kernel_size, stride=stride, padding=padding, groups=groups,
                                        bias=False))
    result.add_module('bn', nn.BatchNorm2d(num_features=out_channels))
    return result


def conv_bn_relu(in_channels, out_channels, kernel_size, stride, padding, groups=1):
    result = conv_bn(in_channels=in_channels, out_channels=out_channels, kernel_size=kernel_size, stride=stride,
                     padding=padding, groups=groups)
    result.add_module('relu', nn.ReLU())
    return result


def fuse_bn(conv_or_fc, bn):
    std = (bn.running_var + bn.eps).sqrt()
    t = bn.weight / std
    t = t.reshape(-1, 1, 1, 1)

    if len(t) == conv_or_fc.weight.size(0):
        return conv_or_fc.weight * t, bn.bias - bn.running_mean * bn.weight / std
    else:
        repeat_times = conv_or_fc.weight.size(0) // len(t)
        repeated = t.repeat_interleave(repeat_times, 0)
        return conv_or_fc.weight * repeated, (bn.bias - bn.running_mean * bn.weight / std).repeat_interleave(
            repeat_times, 0)


class ChannelAttention(nn.Module):

    def __init__(self, input_channels, internal_neurons):
        super(ChannelAttention, 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))
        # print('x:', x.shape)
        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))
        # print('x:', x.shape)
        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 x


class RepBlock(nn.Module):

    def __init__(self, in_channels, out_channels,
                 channelAttention_reduce=4):
        super().__init__()

        self.C = in_channels
        self.O = out_channels

        assert in_channels == out_channels
        self.ca = ChannelAttention(input_channels=in_channels, internal_neurons=in_channels // channelAttention_reduce)
        self.dconv5_5 = nn.Conv2d(in_channels, in_channels, kernel_size=5, padding=2, groups=in_channels)
        self.dconv1_7 = nn.Conv2d(in_channels, in_channels, kernel_size=(1, 7), padding=(0, 3), groups=in_channels)
        self.dconv7_1 = nn.Conv2d(in_channels, in_channels, kernel_size=(7, 1), padding=(3, 0), groups=in_channels)
        self.dconv1_11 = nn.Conv2d(in_channels, in_channels, kernel_size=(1, 11), padding=(0, 5), groups=in_channels)
        self.dconv11_1 = nn.Conv2d(in_channels, in_channels, kernel_size=(11, 1), padding=(5, 0), groups=in_channels)
        self.dconv1_21 = nn.Conv2d(in_channels, in_channels, kernel_size=(1, 21), padding=(0, 10), groups=in_channels)
        self.dconv21_1 = nn.Conv2d(in_channels, in_channels, kernel_size=(21, 1), padding=(10, 0), groups=in_channels)
        self.conv = nn.Conv2d(in_channels, in_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)

        channel_att_vec = self.ca(inputs)
        inputs = channel_att_vec * 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


if __name__ == "__main__":
    dim=64
    # 如果GPU可用,将模块移动到 GPU
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    # 输入张量 (batch_size, height, width,channels)
    x = torch.randn(2,dim,40,40).to(device)
    # 初始化 CPCA模块
    block = RepBlock(dim,dim)
    print(block)
    block = block.to(device)
    # 前向传播
    output = block(x)
    print("输入:", x.shape)
    print("输出:", output.shape)

输出结果:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2290815.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

信息学奥赛一本通 1607:【 例 2】任务安排 2 | 洛谷 P10979 任务安排 2

【题目链接】 ybt 1607:【 例 2】任务安排 2 洛谷 P10979 任务安排 2 注:ybt1607中n最大达到 1 0 4 10^4 104,洛谷P10979中n最大达到 3 ∗ 1 0 5 3*10^5 3∗105,本题解统一认为n最大达到 3 ∗ 1 0 5 3*10^5 3∗105。 【题目考点…

OFDM系统仿真

1️⃣ OFDM的原理 1.1 介绍 OFDM是一种多载波调制技术,将输入数据分配到多个子载波上,每个子载波上可以独立使用 QAM、PSK 等传统调制技术进行调制。这些子载波之间互相正交,从而可以有效利用频谱并减少干扰。 1.2 OFDM的核心 多载波调制…

【Go语言圣经】第四节:复合数据类型

第四章:复合数据类型 本节主要讨论四种类型——数组、slice、map和结构体。 数组和结构体都是有固定内存大小的数据结构。相比之下,slice 和 map 则是动态的数据结构,它们可以根据需要动态增长。 4.1 数组 数组是一个定长的由特定类型元素…

完美还是完成?把握好度,辨证看待

完美还是完成? 如果说之前这个答案有争议,那么现在,答案毋庸置疑 ■为什么完美大于完成 ●时间成本: 做事不仅要考虑结果,还要考虑时间和精力,要说十年磨一剑的确质量更好,但是现实没有那么多…

Many Whelps! Handle It! (10 player) Many Whelps! Handle It! (25 player)

http://db.nfuwow.com/80/?achievement4403 http://db.nfuwow.com/80/?achievement4406 最少扣你50DKP! 第二阶段 当奥妮克希亚升空后,在10秒内引出50只奥妮克希亚雏龙,随后击败奥妮克希亚。 World of Warcraft [CLASSIC][80猎人][Grandel][最少扣你5…

【React】PureComponent 和 Component 的区别

前言 在 React 中,PureComponent 和 Component 都是用于创建组件的基类,但它们有一个主要的区别:PureComponent 会给类组件默认加一个shouldComponentUpdate周期函数。在此周期函数中,它对props 和 state (新老的属性/状态)会做一…

MongoDb user自定义 role 添加 action(collStats, EstimateDocumentCount)

使用 mongosh cd mongsh_bin_path mongosh “mongodb://user:passip:port/db”这样就直接进入了对应的db 直接输入: 这样 role “read_only_role" 就获得了3个 action, 分别是 查询,列举集合,集合元数据查询 P.S: 如果没有 …

蓝桥杯刷题DAY2:二维前缀和 一维前缀和 差分数组

闪耀的灯光 📌 题目描述 蓝桥公园是一个适合夜间散步的好地方,公园可以被视为由 n m 个矩形区域构成。每个区域都有一盏灯,初始亮度为 a[i][j]。 小蓝可以选择一个大的矩形区域,并按下开关一次,这将使得该区域内每盏…

C++初阶 -- 手撕string类(模拟实现string类)

目录 一、string类的成员变量 二、构造函数 2.1 无参版本 2.2 有参版本 2.3 缺省值版本 三、析构函数 四、拷贝构造函数 五、c_str函数 六、operator重载 七、size函数 八、迭代器iterator 8.1 正常版本 8.2 const版本 九、operator[] 9.1 正常版本 9.2 const版…

【Unity3D】实现2D角色/怪物死亡消散粒子效果

核心:这是一个Unity粒子系统自带的一种功能,可将粒子生成控制在一个Texture图片网格范围内,并且粒子颜色会自动采样图片的像素点颜色,之后则是粒子编辑出消散效果。 Particle System1物体(爆发式随机速度扩散10000个粒…

85.[1] 攻防世界 WEB easyphp

进入靶场 属于代码审计 <?php // 高亮显示当前 PHP 文件的源代码&#xff0c;常用于调试或展示代码 highlight_file(__FILE__);// 初始化两个标志变量&#xff0c;用于后续条件判断 $key1 0; $key2 0;// 从 GET 请求中获取参数 a 和 b $a $_GET[a]; $b $_GET[b];// 检…

pytorch图神经网络处理图结构数据

人工智能例子汇总&#xff1a;AI常见的算法和例子-CSDN博客 图神经网络&#xff08;Graph Neural Networks&#xff0c;GNNs&#xff09;是一类能够处理图结构数据的深度学习模型。图结构数据由节点&#xff08;vertices&#xff09;和边&#xff08;edges&#xff09;组成&a…

海外问卷调查,最常用到的渠道查有什么特殊之处

市场调研&#xff0c;包含市场调查和市场研究两个步骤&#xff0c;是企业和机构根据经营方向而做出的决策问题&#xff0c;最终通过海外问卷调查中的渠道查&#xff0c;来系统地设计、收集、记录、整理、分析、研究市场反馈的工作流程。 市场调研的工作流程包括&#xff1a;确…

【Uniapp-Vue3】解决uni-popup弹窗在安全区显示透明问题

我们在使用uni-popup时&#xff0c;如果想要给弹出内容添加一个背景颜色&#xff0c;我们会发现在安全区域是不显示该背景颜色的。 首先根据如下的目录结构找到uni-popup.vue文件 在该文件中找到bottom配置&#xff0c;将红箭头所指代码注释掉 下面的安全区域就没有了&#xff…

项目练习:重写若依后端报错cannot be cast to com.xxx.model.LoginUser

文章目录 一、情景说明二、解决办法 一、情景说明 在重写若依后端服务的过程中 使用了Redis存放LoginUser对象数据 那么&#xff0c;有存就有取 在取值的时候&#xff0c;报错 二、解决办法 方法1、在TokenService中修改如下 getLoginUser 方法中&#xff1a;LoginUser u…

核心集:DeepCore: A Comprehensive Library for CoresetSelection in Deep Learning

目录 一、TL&#xff1b;DR 二、为什么研究核心集&#xff1f; 三、问题定义和如何做 3.1 问题定义 3.2 业界方法 3.2.1 基于几何的方法 3.2.2 基于不确定性的方法 3.2.3 基于误差/损失的方法 3.2.5 GraNd 和 EL2N 分数 3.2.6 重要性采样 3.2.7 基于决策边界的办法 …

Hot100之矩阵

73矩阵置零 题目 思路解析 收集0位置所在的行和列 然后该行全部初始化为0 该列全部初始化为0 代码 class Solution {public void setZeroes(int[][] matrix) {int m matrix.length;int n matrix[0].length;List<Integer> list1 new ArrayList<>();List<…

可视化相机pose colmap形式的相机内参外参

目录 内参外参转换 可视化相机pose colmap形式的相机内参外参 内参外参转换 def visualize_cameras(cameras, images):fig plt.figure()ax fig.add_subplot(111, projection3d)for image_id, image_data in images.items():qvec image_data[qvec]tvec image_data[tvec]#…

数据库内存与Buffer Pool

数据库内存与Buffer Pool 文章目录 数据库内存与Buffer Pool一&#xff1a;MySQL内存结构1&#xff1a;MySQL工作组件2&#xff1a;工作线程的本地内存3&#xff1a;共享内存区域4&#xff1a;存储引擎缓冲区 二&#xff1a;InnoDB的核心&#xff1a;Buffer Pool1&#xff1a;数…

程序员学英文之At the Airport Customs

Dialogue-1 Making Airline Reservation预定机票 My cousin works for Xiamen Airlines. 我表哥在厦航上班。I’d like to book an air ticket. 我想预定一张机票。Don’t judge a book by its cover. 不要以貌取人。I’d like to book / re-serve a table for 10. 我想预定一…