Attention中文意思为注意力,这个机制放到计算机视觉里,类似于给我们看一张美女帅哥的图片,我们第一眼首先关注的地方是这个人的哪里呢
最早attention机制就应用到计算机视觉中,这里说的机制,其实就是神经网络中一个模块,类似于U-Net加上attention机制的变化。
看出什么变化了吗,其实就是在原始的网络结构增加一些结构模块。
随着NLP领域的发展,也开始应用了atteniton机制,除了这个还有循环神经网络(RNNs)和门控循环单元(GRUs)﹑长短期记忆(LSTMs)﹑序列对序列(Seq2Seq)﹑记忆网络(Memory Networks)等。这些都是Encoder-Decoder的不同框架。
但是attention是可以脱离Encoder-Decoder,被其他模型框架使用的。
在平时最常用的淘宝,得物的照片识别,其实算法都是使用attention这个机制的。
Attention 原理的3步分解:
第一步: query 和 key 进行相矩阵相乘
第二步:将矩阵相乘得到的结果根据不同权重进行归一化
第三步:将结果和 value 再进行一次矩阵相乘
这里步骤中提到的query、key、value其实就是我们的feature maps分别跟1x1的卷积核卷积得到的三个向量。如下图所示。
整体步骤,可以这样理解:
说白了,在attention机制就是一种特征图的权重分布,把有用的特征权重加大,没有的特征权重加小,再用学出来的权重施加在原特征图之上最后进行加权求和。
目前attention已经应用到计算机视觉,自然语言处理等多个领域,这些不同领域的应用,虽然attention的结构不变,但是其中的query、key、value的计算方式是不同的。计算区域也不同(一个卷积核乘积,不是所有的feature maps都做乘积)。
前面attention原理,介绍的是attention的通用版本。这里我只提计算机视觉方面的attention,在计算机视觉中,主要有三种attention,分别为:
其中Spatial Attention Module模块:
首先将通道本身进行降维,分别获取最大池化和均值池化结果,然后拼接成一个特征图,再使用一个卷积层进行学习。
这两种机制,分别学习了通道的重要性和空间的重要性,还可以很容易地嵌入到任何已知的框架中。
CBAM模块详细:
其中Channel Attention模块:
其中Spatial Attention模块:
代码如下:
import torch
import torch.nn as nn
import torchvision
#ratio 为通道数
class ChannelAttention(nn.Moudel):
def __init__(self, channel, ratio=16):
super(ChannelAttentionModule, self).__init__()
self.avg_pool = nn.AdaptiveAvgPool2d(1)
self.max_pool = nn.AdaptiveMaxPool2d(1)
self.shared_MLP = nn.Sequential(
nn.Conv2d(channel, channel // ratio, 1, bias=False),
nn.ReLU(),
nn.Conv2d(channel // ratio, channel, 1, bias=False)
)
self.sigmoid = nn.Sigmoid()
def forward(self, x):
avgout = self.shared_MLP(self.avg_pool(x))
print(avgout.shape)
maxout = self.shared_MLP(self.max_pool(x))
return self.sigmoid(avgout + maxout)
class SpatialAttentionModule(nn.Module):
def __init__(self):
super(SpatialAttentionModule, self).__init__()
self.conv2d = nn.Conv2d(in_channels=2, out_channels=1, kernel_size=7, stride=1, padding=3)
self.sigmoid = nn.Sigmoid()
def forward(self, x):
avgout = torch.mean(x, dim=1, keepdim=True)
maxout, _ = torch.max(x, dim=1, keepdim=True)
out = torch.cat([avgout, maxout], dim=1)
out = self.sigmoid(self.conv2d(out))
return out
class CBAM(nn.Module):
def __init__(self, channel):
super(CBAM, self).__init__()
self.channel_attention = ChannelAttentionModule(channel)
self.spatial_attention = SpatialAttentionModule()
def forward(self, x):
out = self.channel_attention(x) * x
print('outchannels:{}'.format(out.shape))
out = self.spatial_attention(out) * out
return out