<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      常用的注意力機制模塊(SE、CBAM)

       【深度學習】總目錄

      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簡介
      posted @ 2023-07-08 16:11  灣仔碼農  閱讀(12470)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 日本免费一区二区三区日本| 国产精品欧美福利久久| 4hu44四虎www在线影院麻豆| 亚洲乱人伦中文字幕无码| 国产精品自拍中文字幕| 亚洲精品一区二区三区蜜臀| 国偷自产一区二区三区在线视频 | 日韩丝袜人妻中文字幕| 国产午夜亚洲精品福利| 99在线国内在线视频22| 清流县| 非会员区试看120秒6次| 免费国产高清在线精品一区| 中文字幕亚洲精品人妻| 乱熟女高潮一区二区在线| 成人亚洲欧美一区二区三区 | 亚洲综合另类小说色区一| 国产亚洲无线码一区二区| 精品国产综合一区二区三区| 人妻聚色窝窝人体WWW一区 | 久久精品久久电影免费理论片| 1000部拍拍拍18勿入免费视频下载 | 久久青青草原亚洲AV无码麻豆| 丰满人妻熟妇乱精品视频| 日韩亚洲精品中文字幕| 99精品高清在线播放| 翘臀少妇被扒开屁股日出水爆乳| 亚洲精品自拍视频在线看| 国产成人无码免费网站| 乱码中文字幕| 亚洲色最新高清AV网站| 亚洲国产日韩a在线播放| 日本精品网| 最新国产精品拍自在线观看| 国产老女人免费观看黄A∨片| 久久亚洲日本激情战少妇| 国产尤物精品自在拍视频首页| 中文字幕丰满伦子无码ab| 久久中文字幕日韩无码视频| 自拍亚洲综合在线精品| 国产精品午夜爆乳美女视频|