(即插即用模块-Attention部分) 二十、(2021) GAA 门控轴向注意力

ops/2024/12/1 4:17:46/

在这里插入图片描述

文章目录

  • 1、Gated Axial-Attention
  • 2、代码实现

paper:Medical Transformer: Gated Axial-Attention for Medical Image Segmentation

Code:https://github.com/jeya-maria-jose/Medical-Transformer


1、Gated Axial-Attention

论文首先分析了 ViTs 在训练小规模数据集时的弊端以及指出了 ViTs 的计算复杂度偏高。为此,论文提出了一种门控轴向注意力(Gated Axial-Attention),其通过在自注意力模块中引入额外的门控机制来扩展现有的体系结构。在分析了位置偏差难以学习、相对位置编码不够准确等问题后,通过将可控制的影响位置偏差施加在编码的非本地上下文来实现改进。Gated Axial-Attention的 核心思想是Gate门控机制,通过引入 Gate 控制机制来控制位置编码对 Self-Attention 的影响程度。

对于一个输入特征 X,Gated Axial-Attention的实现过程:

  1. 输入特征图: 将输入图像提取特征图,并进行通道维度上的线性变换,得到 Query、Key 和 Value 向量。

  2. Axial-Attention

    在高度方向上进行 1D Self-Attention,计算像素之间的依赖关系。

    在宽度方向上进行 1D Self-Attention,计算像素之间的依赖关系。

  3. Positional Encoding:计算相对位置编码,将像素位置信息融入到 Query、Key 和 Value 向量中。

  4. Gate 控制机制:通过可学习的 Gate 参数,控制相对位置编码对 Self-Attention 的影响程度。

  5. 输出特征图: 将经过 Self-Attention 和 Gate 控制的特征图进行线性变换,得到最终输出特征图。


Gated Axial-Attention 结构图:
在这里插入图片描述


2、代码实现

import torch
import torch.nn as nn
import torch.nn.functional as F
import mathdef conv1x1(in_planes, out_planes, stride=1):"""1x1 卷积"""return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False)class qkv_transform(nn.Conv1d):"""Conv1d for qkv_transform"""class AxialAttention(nn.Module):def __init__(self, in_planes, out_planes, groups=8, kernel_size=56,stride=1, bias=False, width=False):assert (in_planes % groups == 0) and (out_planes % groups == 0)super(AxialAttention, self).__init__()self.in_planes = in_planesself.out_planes = out_planesself.groups = groupsself.group_planes = out_planes // groupsself.kernel_size = kernel_sizeself.stride = strideself.bias = biasself.width = width# Multi-head self attentionself.qkv_transform = qkv_transform(in_planes, out_planes * 2, kernel_size=1, stride=1,padding=0, bias=False)self.bn_qkv = nn.BatchNorm1d(out_planes * 2)self.bn_similarity = nn.BatchNorm2d(groups * 3)self.bn_output = nn.BatchNorm1d(out_planes * 2)# Position embeddingself.relative = nn.Parameter(torch.randn(self.group_planes * 2, kernel_size * 2 - 1), requires_grad=True)query_index = torch.arange(kernel_size).unsqueeze(0)key_index = torch.arange(kernel_size).unsqueeze(1)relative_index = key_index - query_index + kernel_size - 1self.register_buffer('flatten_index', relative_index.view(-1))if stride > 1:self.pooling = nn.AvgPool2d(stride, stride=stride)self.reset_parameters()def forward(self, x):# pdb.set_trace()if self.width:x = x.permute(0, 2, 1, 3)else:x = x.permute(0, 3, 1, 2)  # N, W, C, HN, W, C, H = x.shapex = x.contiguous().view(N * W, C, H)# Transformationsqkv = self.bn_qkv(self.qkv_transform(x))q, k, v = torch.split(qkv.reshape(N * W, self.groups, self.group_planes * 2, H),[self.group_planes // 2, self.group_planes // 2, self.group_planes], dim=2)# Calculate position embeddingall_embeddings = torch.index_select(self.relative, 1, self.flatten_index).view(self.group_planes * 2,self.kernel_size,self.kernel_size)q_embedding, k_embedding, v_embedding = torch.split(all_embeddings,[self.group_planes // 2, self.group_planes // 2,self.group_planes], dim=0)qr = torch.einsum('bgci,cij->bgij', q, q_embedding)kr = torch.einsum('bgci,cij->bgij', k, k_embedding).transpose(2, 3)qk = torch.einsum('bgci, bgcj->bgij', q, k)stacked_similarity = torch.cat([qk, qr, kr], dim=1)stacked_similarity = self.bn_similarity(stacked_similarity).view(N * W, 3, self.groups, H, H).sum(dim=1)# stacked_similarity = self.bn_qr(qr) + self.bn_kr(kr) + self.bn_qk(qk)# (N, groups, H, H, W)similarity = F.softmax(stacked_similarity, dim=3)sv = torch.einsum('bgij,bgcj->bgci', similarity, v)sve = torch.einsum('bgij,cij->bgci', similarity, v_embedding)stacked_output = torch.cat([sv, sve], dim=-1).view(N * W, self.out_planes * 2, H)output = self.bn_output(stacked_output).view(N, W, self.out_planes, 2, H).sum(dim=-2)if self.width:output = output.permute(0, 2, 1, 3)else:output = output.permute(0, 2, 3, 1)if self.stride > 1:output = self.pooling(output)return outputdef reset_parameters(self):self.qkv_transform.weight.data.normal_(0, math.sqrt(1. / self.in_planes))# nn.init.uniform_(self.relative, -0.1, 0.1)nn.init.normal_(self.relative, 0., math.sqrt(1. / self.group_planes))if __name__ == '__main__':x = torch.randn(4, 512, 7, 7).cuda()# kernel_size 要跟 h,w 相同model = AxialAttention(512, 512, kernel_size=7).cuda()out = model(x)print(out.shape)

本文只是对论文中的即插即用模块做了整合,对论文中的一些地方难免有遗漏之处,如果想对这些模块有更详细的了解,还是要去读一下原论文,肯定会有更多收获。


http://www.ppmy.cn/ops/138103.html

相关文章

Applied Intelligence投稿

一、关于手稿格式: 1、该期刊是一个二区的,模板使用Springer nature格式, 期刊投稿要求,详细期刊投稿指南,大部分按Soringernature模板即可,图片表格声明参考文献命名要求需注意。 2、参考文献&#xff…

SQL Server 实战 - 多种连接

目录 背景 一、多种连接 1. 复合连接条件 2. 跨数据库连接 3. 隐连接 4. 自连接 5. 多表外连接 6. UNION ALL 二、一个对比例子 背景 本专栏文章以 SAP 实施顾问在实施项目中需要掌握的 sql 语句为偏向进行选题: 用例:SAP B1 的数据库工具&am…

案例分析:嵌入式边缘计算机ARMxy在工商储能柜新能源应用

可再生能源的快速发展和电力市场的改革深化,工商储能技术正逐渐成为企业能源管理和成本优化的重要工具。特别是在一些大型商业和工业场所,储能系统不仅可以平滑负荷曲线,减少电费支出,还能提高电网的稳定性。然而,为了…

前端网络请求:从 XMLHttpRequest 到 Axios

​🌈个人主页:前端青山 🔥系列专栏:Vue篇 🔖人终将被年少不可得之物困其一生 依旧青山,本期给大家带来Vue篇专栏内容:前端网络请求:从 XMLHttpRequest 到 Axios 前言 在网络应用中,前后端的数据…

[windows] [C++] 由变量命名引起的血案

今天在开发过程中遇到了一个由于变量命名引起的诡异问题,定位了好久,才发现原因,在此记录一下: 最初的代码是: static bool LoadTestDlls() {// 获取可执行文件路径WCHAR exePath[MAX_PATH];if (GetModuleFileNameW(…

Android.mk的变量有哪些

Android.mk 文件是 Android 构建系统中用于定义模块和依赖关系的 Makefile 文件。它使用一系列变量来指定源文件、库、编译选项等。以下是一些常用的 Android.mk 变量及其用途: 常用变量 模块名称 LOCAL_MODULE: 模块的名称,必须唯一。 LOCAL_MODULE : …

【NLP 1、人工智能与NLP简介】

人人都不看好你,可偏偏你最争气 —— 24.11.26 一、AI和NLP的基本介绍 1.人工智能发展流程 弱人工智能 ——> 强人工智能 ——> 超人工智能 ① 弱人工智能 人工智能算法只能在限定领域解决特定的问题 eg:特定场景下的文本分类、垂直领域下的对…

远离网上的广告和无用信息,自己动手搭建Tipask问答网站

文章目录 前言1.Tipask网站搭建1.1 Tipask网站下载和安装1.2 Tipask网页测试1.3 cpolar的安装和注册 2. 本地网页发布2.1 Cpolar临时数据隧道2.2 Cpolar稳定隧道(云端设置)2.3 Cpolar稳定隧道(本地设置) 3. 公网访问测试4. 结语 前…