【深度学习】总目录

SE论文:《Squeeze-and-Excitation Networks》将重点放在了通道(channel)关系上,并提出了一种新的结构单元SE block。将SE block堆叠在一起,就形成了SENet。SE块略微增加计算成本但显著地提升了性能,并且即插即用。SENet获得了最后一届ImageNet 2017竞赛分类任务的冠军。

CBAM论文:《Convolutional Block Attention Module》论文(2018年)提出了一种轻量的注意力模块CBAM,可以在通道和空间维度上进行 Attention 。

1 SE模块

  卷积神经网络建立在卷积运算的基础上,通过融合局部感受野内的空间信息和通道信息来提取信息特征。为了提高网络的表示能力,许多现有的工作通过在空间维度上对网络的性能进行了提升,比如Inception模块中嵌入多尺度处理来提高准确度,Spatial Transformer Networks(STN)结合空间注意力机制。本文与这些方法相反,专注于通道,并提出了一种新颖的架构单元“Squeeze-and-Excitation”(SE)模块,通过显式地建模通道之间的相互依赖关系,自适应地重新校准通道式的特征响应。具体来说,就是通过学习的方式来自动获取每个通道的重要程度,然后依照这个重要程度去提升有用的特征并抑制对当前任务用处不大的特征。

Squeeze-and-Excitation Module

给定一个输入x,其特征通道数为c1,通过一系列卷积等一般变换后得到一个特征通道数为c2的特征。接下来通过SE模块的三个操作来重标定前面得到的特征:

1)Squeeze(压缩)。沿着空间维度压缩特征,将每个通道的二维的特征变成一个实数,可以理解为对每个 channel 的特征信息的进行融合,这个实数某种程度上具有全局的感受野,并且输出的维度和输入的特征通道数相匹配。它表征着在特征通道上响应的全局分布,而且使得靠近输入的层也可以获得全局的感受野,这一点在很多任务中都是非常有用。采用全局平局池化来实现,输出维度为1x1xC。

2)Excitation(激励)。得到Squeeze的1x1xC全局特征后,通过全连接层对每个通道的重要性进行预测。它是一个类似于循环神经网络中门的机制。通过参数来为每个特征通道生成权重,其中参数被学习用来显式地建模特征通道间的相关性。
为了减少通道个数从而降低计算量,设置了缩放参数SERatio。 第一个全连接层有C*SERatio个神经元,输入为1×1×C,输出1×1×C×SERadio,起到降维作用。 第二个全连接层有C个神经元,输入为1×1×C×SERadio,输出为1×1×C。

3)Scale(缩放)。将Excitation的输出的权重看做是经过特征选择后的每个特征通道的重要性,然后通过乘法逐通道加权到先前的特征上,完成在通道维度上的对原始特征的重标定。

SE模块的代码实现(pytorch)

from torch import nn
class SELayer(nn.Module):
def __init__(self, channel, reduction=16):
super(SELayer, self).__init__()
self.avg_pool = nn.AdaptiveAvgPool2d(1)
self.fc = nn.Sequential(
nn.Linear(channel, channel // reduction, bias=False),
nn.ReLU(inplace=True),
nn.Linear(channel // reduction, channel, bias=False),
nn.Sigmoid()
) def forward(self, x):
b, c, _, _ = x.size()
y = self.avg_pool(x).view(b, c)
y = self.fc(y).view(b, c, 1, 1)
return x * y.expand_as(x)

2 CBAM模块

CBAM(Convolutional Block Attention Module)是一种轻量的注意力模块,给定一个中间特征图,我们的模块会沿着两个独立的维度(通道和空间)依次推断注意力图,然后将注意力图乘以输入特征图以进行自适应特征修饰。 由于CBAM是轻量级的通用模块,因此可以以可忽略的开销将其无缝集成到任何CNN架构中,并且可以与基础CNN一起进行端到端训练。 论文在 ResNet 和 MobileNet 等经典结构上添加了 CBAM 模块并进行对比分析,同时也进行了可视化,发现 CBAM 更关注识别目标物体,这也使得 CBAM 具有更好的解释性。

2.1 Channel Attention Module(CAM)

通道上的Attention模块以及具体计算如下图所示:

将输入的特征图F(H×W×C)分别经过global max pooling(全局最大池化)和global average pooling(全局平均池化),得到两个1×1×C的特征图,接着,再将它们分别送入一个两层的神经网络(MLP),第一层神经元个数为 C/r(r为减少率),激活函数为 Relu,第二层神经元个数为 C,这个两层的神经网络是共享的。而后,将MLP输出的特征进行基于element-wise的加和操作,再经过sigmoid激活操作,生成最终的channel attention feature,即M_c。最后,将M_c和输入特征图F做element-wise乘法操作,生成Spatial attention模块需要的输入特征。

实验:AvgPool & MaxPool

在channel attention中,表1对于pooling的使用进行了实验对比,发现avg & max的并行池化的效果要更好。这里也有可能是池化丢失的信息太多,avg&max的并行连接方式比单一的池化丢失的信息更少,所以效果会更好一点。

2.2 Spatial Attention Module(SAM)

空间上的Attention模块以及具体计算如下图所示:

将Channel attention模块输出的特征图F’作为本模块的输入特征图。首先做一个基于channel的global max pooling 和global average pooling,得到两个H×W×1 的特征图,然后将这2个特征图基于channel做concat操作(通道拼接)。然后经过一个7×7卷积(7×7比3×3效果要好)操作,降维为1个channel,即H×W×1。再经过sigmoid生成spatial attention feature,即M_s。最后将该feature和该模块的输入feature做乘法,得到最终生成的特征。

实验:Comparison of different spatial attention methods

使用channel-pooling(沿着通道维度进行平均和最大池化)的同时,使用大kernel size=7效果最好。

2.3 CAM和SAM的组合形式

通道注意力和空间注意力这两个模块能够以并行或者串行顺序的方式组合在一块儿,关于通道和空间上的串行顺序和并行作者进行了实验对比,发现先通道再空间的结果会稍微好一点。具体实验结果如下:

从表中可以看出,在ResNet50的基准架构上,两个attetnion子模块的连接顺序里面的确是channel + spatial的要更好一些,也要好于标准的SENet的通道attention。

3 Grad-CAM可视化

论文:Grad-CAM: Visual Explanations from Deep Networks via Gradient-based Localization
博客:Grad-CAM简介

利用 Grad-CAM 对不一样的网络进行可视化后,能够发现,引入 CBAM 后,特征覆盖到了待识别物体的更多部位,而且最终判别物体的几率也更高,这代表注意力机制的确让网络学会了关注重点信息。

3.1 分类网络使用grad-cam

代码:https://github.com/jacobgil/pytorch-grad-cam

首先安装库 pip install grad-cam,然后运行以下文件

import os
import numpy as np
import torch
from PIL import Image
import matplotlib.pyplot as plt
from pytorch_grad_cam.utils.model_targets import ClassifierOutputTarget
from torchvision import models
from torchvision import transforms
from pytorch_grad_cam import GradCAMPlusPlus, GradCAM, XGradCAM
from pytorch_grad_cam.utils.image import show_cam_on_image def main():
model = models.mobilenet_v3_large(pretrained=True)
print(model)
target_layers = [model.features[-1]] # model = models.vgg16(pretrained=True)
# target_layers = [model.features] # model = models.resnet34(pretrained=True)
# target_layers = [model.layer4] # model = models.regnet_y_800mf(pretrained=True)
# target_layers = [model.trunk_output] # model = models.efficientnet_b0(pretrained=True)
# target_layers = [model.features] data_transform = transforms.Compose([transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])
# load image
img_path = "both.png"
assert os.path.exists(img_path), "file: '{}' dose not exist.".format(img_path)
img = Image.open(img_path).convert('RGB')
img = np.array(img, dtype=np.uint8)
# img = center_crop_img(img, 224) # [C, H, W]
img_tensor = data_transform(img)
# expand batch dimension
# [C, H, W] -> [N, C, H, W]
input_tensor = torch.unsqueeze(img_tensor, dim=0) cam = GradCAM(model=model, target_layers=target_layers, use_cuda=False) targets = [ClassifierOutputTarget(281)] # tabby, tabby cat
# targets = [ClassifierOutputTarget(254)] # pug, pug-dog # You can also pass aug_smooth=True and eigen_smooth=True, to apply smoothing.
grayscale_cam = cam(input_tensor=input_tensor, targets=targets)
grayscale_cam = grayscale_cam[0, :]
visualization = show_cam_on_image(img.astype(dtype=np.float32) / 255.,
grayscale_cam,
use_rgb=True)
plt.imshow(visualization)
plt.show() if __name__ == '__main__':
main()

3.2 Yolov5-7.0使用grad-cam

代码:https://github.com/z1069614715/objectdetection_script/tree/master/yolo-gradcam

首先安装库 pip install grad-cam,然后运行以下文件

import warnings

warnings.filterwarnings('ignore')
warnings.simplefilter('ignore')
import torch, yaml, cv2, os, shutil
import numpy as np np.random.seed(0)
import matplotlib.pyplot as plt
from tqdm import trange
from PIL import Image
from models.yolo import Model
from utils.general import intersect_dicts
from utils.augmentations import letterbox
from utils.general import xywh2xyxy
from pytorch_grad_cam import GradCAMPlusPlus, GradCAM, XGradCAM
from pytorch_grad_cam.utils.image import show_cam_on_image
from pytorch_grad_cam.activations_and_gradients import ActivationsAndGradients class yolov5_heatmap:
def __init__(self, weight, cfg, device, method, layer, backward_type, conf_threshold, ratio):
device = torch.device(device)
ckpt = torch.load(weight) # 包含模型权重、epoch、data等
model_names = ckpt['model'].names # 80个类别名
csd = ckpt['model'].float().state_dict() # checkpoint state_dict as FP32
model = Model(cfg, ch=3, nc=len(model_names)).to(device) # create model
csd = intersect_dicts(csd, model.state_dict(), exclude=['anchor']) # 筛选预训练权重中的键值对,不加载anchor
model.load_state_dict(csd, strict=False) # load
model.eval()
print(f'Transferred {len(csd)}/{len(model.state_dict())} items') target_layers = [eval(layer)]
method = eval(method) colors = np.random.uniform(0, 255, size=(len(model_names), 3)).astype(np.int_) # 不同类别的颜色
self.__dict__.update(locals()) def post_process(self, result):
logits_ = result[..., 4:]
boxes_ = result[..., :4]
sorted, indices = torch.sort(logits_[..., 0], descending=True)
return logits_[0][indices[0]], xywh2xyxy(boxes_[0][indices[0]]).cpu().detach().numpy() def draw_detections(self, box, color, name, img):
xmin, ymin, xmax, ymax = list(map(int, list(box)))
cv2.rectangle(img, (xmin, ymin), (xmax, ymax), tuple(int(x) for x in color), 2)
cv2.putText(img, str(name), (xmin, ymin - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.8, tuple(int(x) for x in color), 2,
lineType=cv2.LINE_AA)
return img def __call__(self, img_path, save_path):
# remove dir if exist
if os.path.exists(save_path):
shutil.rmtree(save_path)
# make dir if not exist
os.makedirs(save_path, exist_ok=True) # img process
img = cv2.imread(img_path)
img = letterbox(img)[0]
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = np.float32(img) / 255.0
tensor = torch.from_numpy(np.transpose(img, axes=[2, 0, 1])).unsqueeze(0).to(self.device) # init ActivationsAndGradients
grads = ActivationsAndGradients(self.model, self.target_layers, reshape_transform=None) # get ActivationsAndResult
result = grads(tensor) # 从指定中间层提取激活值和梯度
activations = grads.activations[0].cpu().detach().numpy() # postprocess to yolo output
post_result, post_boxes = self.post_process(result[0])
for i in trange(int(post_result.size(0) * self.ratio)):
if post_result[i][0] < self.conf_threshold: # 没有非极大值抑制,只用置信度筛选,所以输出的热力图结果比较多
break self.model.zero_grad()
if self.backward_type == 'conf':
post_result[i, 0].backward(retain_graph=True)
else:
# get max probability for this prediction
score = post_result[i, 1:].max()
score.backward(retain_graph=True) # process heatmap
gradients = grads.gradients[0]
b, k, u, v = gradients.size()
weights = self.method.get_cam_weights(self.method, None, None, None, activations,
gradients.detach().numpy())
weights = weights.reshape((b, k, 1, 1))
saliency_map = np.sum(weights * activations, axis=1)
saliency_map = np.squeeze(np.maximum(saliency_map, 0))
saliency_map = cv2.resize(saliency_map, (tensor.size(3), tensor.size(2))) # resize到原图大小
saliency_map_min, saliency_map_max = saliency_map.min(), saliency_map.max()
if (saliency_map_max - saliency_map_min) == 0:
continue
saliency_map = (saliency_map - saliency_map_min) / (saliency_map_max - saliency_map_min) # scale到0-255之间 # add heatmap and box to image
cam_image = show_cam_on_image(img.copy(), saliency_map, use_rgb=True)
cam_image = self.draw_detections(post_boxes[i], self.colors[int(post_result[i, 1:].argmax())],
f'{self.model_names[int(post_result[i, 1:].argmax())]} {post_result[i][0]:.2f}',
cam_image)
cam_image = Image.fromarray(cam_image)
cam_image.save(f'{save_path}/{i}.png') def get_params():
params = {
'weight': 'yolov5s.pt',
'cfg': 'models/yolov5s.yaml',
'device': 'cuda:0',
'method': 'XGradCAM', # GradCAMPlusPlus, GradCAM, XGradCAM
'layer': 'model.model[-2]',
'backward_type': 'conf', # class or conf
'conf_threshold': 0.6, # 0.6
'ratio': 0.02 # 0.02-0.1
}
return params if __name__ == '__main__':
model = yolov5_heatmap(**get_params())
model(r'data/images/bus.jpg', 'result')

参考

1. SENet概览

2. SE (Squeeze Excitation)模块

3. 经典论文-SeNet论文及实践

4. 注意机制(CBAM)理解

5. Grad-CAM简介

常用的注意力机制模块(SE、CBAM)的更多相关文章

  1. CVPR2021| 继SE,CBAM后的一种新的注意力机制Coordinate Attention

    前言: 最近几年,注意力机制用来提升模型性能有比较好的表现,大家都用得很舒服.本文将介绍一种新提出的坐标注意力机制,这种机制解决了SE,CBAM上存在的一些问题,产生了更好的效果,而使用与SE,CBA ...

  2. Non-local Neural Networks 原理详解及自注意力机制思考

    Paper:https://arxiv.org/abs/1711.07971v1 Author:Xiaolong Wang, Ross Girshick, Abhinav Gupta, Kaiming ...

  3. (转)注意力机制(Attention Mechanism)在自然语言处理中的应用

    注意力机制(Attention Mechanism)在自然语言处理中的应用 本文转自:http://www.cnblogs.com/robert-dlut/p/5952032.html  近年来,深度 ...

  4. 注意力机制(Attention Mechanism)在自然语言处理中的应用

    注意力机制(Attention Mechanism)在自然语言处理中的应用 近年来,深度学习的研究越来越深入,在各个领域也都获得了不少突破性的进展.基于注意力(attention)机制的神经网络成为了 ...

  5. 自然语言处理中的自注意力机制(Self-attention Mechanism)

    自然语言处理中的自注意力机制(Self-attention Mechanism) 近年来,注意力(Attention)机制被广泛应用到基于深度学习的自然语言处理(NLP)各个任务中,之前我对早期注意力 ...

  6. 深度学习之注意力机制(Attention Mechanism)和Seq2Seq

    这篇文章整理有关注意力机制(Attention Mechanism )的知识,主要涉及以下几点内容: 1.注意力机制是为了解决什么问题而提出来的? 2.软性注意力机制的数学原理: 3.软性注意力机制. ...

  7. DeepLearning.ai学习笔记(五)序列模型 -- week2 序列模型和注意力机制

    一.基础模型 假设要翻译下面这句话: "简将要在9月访问中国" 正确的翻译结果应该是: "Jane is visiting China in September" ...

  8. TensorFlow从1到2(十)带注意力机制的神经网络机器翻译

    基本概念 机器翻译和语音识别是最早开展的两项人工智能研究.今天也取得了最显著的商业成果. 早先的机器翻译实际脱胎于电子词典,能力更擅长于词或者短语的翻译.那时候的翻译通常会将一句话打断为一系列的片段, ...

  9. 注意力机制(Attention Mechanism)应用——自然语言处理(NLP)

    近年来,深度学习的研究越来越深入,在各个领域也都获得了不少突破性的进展.基于注意力(attention)机制的神经网络成为了最近神经网络研究的一个热点,下面是一些基于attention机制的神经网络在 ...

  10. 自注意力机制(Self-attention Mechanism)——自然语言处理(NLP)

    近年来,注意力(Attention)机制被广泛应用到基于深度学习的自然语言处理(NLP)各个任务中.随着注意力机制的深入研究,各式各样的attention被研究者们提出.在2017年6月google机 ...

随机推荐

  1. c# Barrier 线程回调

    前言 假如现在有一个这样的需求,我一堆小黄人生产小黄丹,而大黄人要一直吃小黄丹. 如果是这样的话,想到就是一堆小黄人作为一个多线程,然后一直制造,然后另外一个大黄人一直检索是否有小黄丹,有就吃掉. 但 ...

  2. 重新整理数据结构与算法(c#)—— 算法套路分治算法[二十五]

    前言 有一个汉罗塔的游戏如下: 汉诺塔:汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具. 大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘. 大梵天 ...

  3. 一遇到复杂分析查询就卡顿?MySQL分析实例了解一下

    随着企业数据爆发式增长,MySQL分析查询卡顿问题越来越多,用户时效性不能保证,精细化运营诉求不能满足.如何能无缝对接业务库,实现毫秒级针对万亿级数据进行即时的多维分析透视和业务探索,MySQL分析实 ...

  4. 云原生数据仓库TPC-H第一背后的Laser引擎大揭秘

    简介: 作者| 魏闯先阿里云数据库资深技术专家 一.ADB PG 和Laser 计算引擎的介绍 (一)ADB PG 架构 ADB PG 是一款云原生数据仓库,在保证事务ACID 能力的前提下,主要解决 ...

  5. 网关流控利器:结合 AHAS 实现 Ingress/Nginx 流量控制

    ​简介:微服务的稳定性一直是开发者非常关注的话题.随着业务从单体架构向分布式架构演进以及部署方式的变化,服务之间的依赖关系变得越来越复杂,业务系统也面临着巨大的高可用挑战. 作者:涂鸦 微服务的稳定性 ...

  6. LlamaIndex 是什么

    LlamaIndex 是一个基于 LLM(大语言模型)的应用程序数据框架,适用于受益于上下文增强的场景. 这类 LLM 系统被称为 RAG(检索增强生成)系统. LlamaIndex 提供了必要的抽象 ...

  7. [Ethereum] 浅谈 ERC20 在 openzeppelin-contracts 中的结构与实现

    目前 openzeppelin-contracts 的稳定版是 v2.5,截止到本文发布,最新的 Tag 为 v3.0.0-rc.0 以下是 token/ETC20 的文件列表: IERC20.sol ...

  8. python3生成随机单词或者语句

    pip install RandomWords Random words: >>> from random_words import RandomWords >>> ...

  9. 算法~PBKDF2-SHA让密码更安全

    摘要:在当今的数字世界中,密码安全是至关重要的.为了保护用户密码免受未经授权的访问和破解,Password-Based Key Derivation Function 2 (PBKDF2)算法成为了一 ...

  10. ruby执行周期性任务 whenever

    ruby执行周期性任务 下面看看怎么将任务写入cron服务. $ whenever #不带参数的whenever会显示转换程cron任务的代码,不写入cron任务表 $ whenever -w #写入 ...