💡💡💡本專欄所有程序均經過測試,可成功執行💡💡💡
輕量級卷積神經網絡由于其低計算預算限制了CNNs的深度(卷積層數)和寬度(通道數),導致了性能下降和表示能力受限的問題。而動態卷積恰好能解決這一問題,這是一種增加模型復雜性而不增加網絡深度或寬度的新設計。本文給大家帶來的教程是將YOLOv5的Conv用Dynamic_conv替換來提取特征。文章在介紹主要的原理后,將手把手教學如何進行模塊的代碼添加和修改,并將修改后的完整代碼放在文章的最后,方便大家一鍵運行,小白也可輕松上手實踐。此外還增加了進階模塊,來提高學有能力的同學進一步增長知識。幫助您更好地學習深度學習目標檢測YOLO系列的挑戰。
專欄地址:?YOLOv5改進+入門——持續更新各種有效漲點方法 點擊即可跳轉
目錄
1.原理
2. 代碼實現
2.1 將代碼添加到YOLOv5中
2.2 新增yaml文件
2.3 注冊模塊
2.4 執行程序
3. 完整代碼分享
4. GFLOPs
5. 進階
6. 總結
1. 原理
論文地址:Dynamic Convolution: Attention over Convolution Kernels——點擊即可跳轉
官方代碼:官方代碼倉庫——點擊即可跳轉
動態卷積的是基于注意力機制的,它允許網絡動態地選擇和組合多個卷積核,以適應輸入數據的不同部分或特征。
-
多個卷積核的選擇:
在傳統的卷積操作中,每個卷積層通常使用固定的卷積核。而在動態卷積中,會事先定義一組多個卷積核,這些卷積核可能具有不同的大小和形狀。 -
注意力機制:
動態卷積通過引入注意力機制來決定在每個位置使用哪些卷積核。這個注意力可以根據輸入數據的不同部分或特征動態地調整,以使網絡能夠更好地捕捉輸入數據的相關信息。 -
卷積核的組合:
根據注意力機制的輸出,動態卷積會動態地選擇并組合多個卷積核。這種組合可以通過加權求和的方式進行,其中每個卷積核的權重由注意力機制確定。 -
非線性激活:
組合后的卷積核將應用于輸入數據,并通過非線性激活函數(如ReLU)產生輸出特征圖。 -
網絡訓練:
在訓練過程中,網絡將根據損失函數反向傳播并更新注意力機制的參數,以使網絡能夠學習到適合任務的最佳注意力分配方式。
總的來說,動態卷積通過引入注意力機制和動態地選擇和組合多個卷積核,使網絡能夠更靈活地適應輸入數據的不同部分或特征,從而提高網絡的表征能力和性能。
2. 代碼實現
2.1 將代碼添加到YOLOv5中
關鍵步驟一: 將下面代碼粘貼到/projects/yolov5-6.1/models/common.py文件中
import torch
import torch.nn as nn
import torch.nn.functional as Fclass attention2d(nn.Module):def __init__(self, in_planes, ratios, K, temperature, init_weight=True):super(attention2d, self).__init__()assert temperature%3==1self.avgpool = nn.AdaptiveAvgPool2d(1)if in_planes!=3:hidden_planes = int(in_planes*ratios)else:hidden_planes = Kself.fc1 = nn.Conv2d(in_planes, hidden_planes, 1, bias=False)self.fc2 = nn.Conv2d(hidden_planes, K, 1, bias=False)self.temperature = temperatureif init_weight:self._initialize_weights()def _initialize_weights(self):for m in self.modules():if isinstance(m, nn.Conv2d):nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')if m.bias is not None:nn.init.constant_(m.bias, 0)def updata_temperature(self):if self.temperature!=1:self.temperature -=3print('Change temperature to:', str(self.temperature))def forward(self, x):x = self.avgpool(x)x = self.fc1(x)x = F.relu(x)x = self.fc2(x).view(x.size(0), -1)return F.softmax(x/self.temperature, 1)class Dynamic_conv2d(nn.Module):def __init__(self, in_planes, out_planes, kernel_size, ratio=0.25, stride=1, padding=0, dilation=1, groups=1, bias=True, K=4,temperature=34, init_weight=True):super(Dynamic_conv2d, self).__init__()assert in_planes%groups==0self.in_planes = in_planesself.out_planes = out_planesself.kernel_size = kernel_sizeself.stride = strideself.padding = paddingself.dilation = dilationself.groups = groupsself.bias = biasself.K = Kself.attention = attention2d(in_planes, ratio, K, temperature)self.weight = nn.Parameter(torch.Tensor(K, out_planes, in_planes//groups, kernel_size, kernel_size), requires_grad=True)if bias:self.bias = nn.Parameter(torch.Tensor(K, out_planes))else:self.bias = Noneif init_weight:self._initialize_weights()#TODO 初始化def _initialize_weights(self):for i in range(self.K):nn.init.kaiming_uniform_(self.weight[i])def update_temperature(self):self.attention.updata_temperature()def forward(self, x): # 將batch視作維度變量,進行組卷積,因為組卷積的權重是不同的,動態卷積的權重也是不同的softmax_attention = self.attention(x)batch_size, in_planes, height, width = x.size()x = x.view(1, -1, height, width)# 變化成一個維度進行組卷積weight = self.weight.view(self.K, -1)# 動態卷積的權重的生成, 生成的是batch_size個卷積參數(每個參數不同)aggregate_weight = torch.mm(softmax_attention, weight).view(-1, self.in_planes, self.kernel_size, self.kernel_size)if self.bias is not None:aggregate_bias = torch.mm(softmax_attention, self.bias).view(-1)output = F.conv2d(x, weight=aggregate_weight, bias=aggregate_bias, stride=self.stride, padding=self.padding,dilation=self.dilation, groups=self.groups*batch_size)else:output = F.conv2d(x, weight=aggregate_weight, bias=None, stride=self.stride, padding=self.padding,dilation=self.dilation, groups=self.groups * batch_size)output = output.view(batch_size, self.out_planes, output.size(-2), output.size(-1))return output
動態卷積的流程如下:
-
準備多個卷積核:
首先,定義一組多個卷積核,這些卷積核可能具有不同的大小和形狀。這些卷積核將作為動態卷積的基本構建單元。 -
計算注意力分布:
對于輸入數據的每個位置,通過一個注意力網絡或者其他注意力機制,計算出相應位置的注意力分布。這個注意力分布表示了不同卷積核在當前位置的重要程度。 -
動態卷積操作:
根據注意力分布,動態地選擇和組合多個卷積核。通常是通過對每個卷積核的權重進行加權求和來實現,其中每個卷積核的權重由對應位置的注意力分布確定。 -
應用非線性激活:
將組合后的卷積核應用于輸入數據,并通過非線性激活函數(如ReLU)產生輸出特征圖。 -
網絡訓練:
訓練過程中,通過反向傳播算法優化注意力網絡或其他注意力機制的參數,以使網絡能夠學習到適合任務的最佳注意力分配方式。同時,也會更新卷積核的參數,使得網絡能夠學習到更好的特征表示。 -
重復步驟3至5:
在每個位置上重復執行動態卷積操作,直到整個輸入數據被處理完畢,生成最終的輸出特征圖。
總結,動態卷積通過引入注意力機制來動態選擇和組合多個卷積核,從而使網絡能夠更靈活地適應輸入數據的不同部分或特征,從而提高網絡的表征能力和性能。
2.2 新增yaml文件
關鍵步驟二:在/projects/yolov5-6.1/models下新建文件 yolov5_dynamic.yaml并將下面代碼復制進去
# YOLOv5 🚀 by Ultralytics, GPL-3.0 license# Parameters
nc: 80 # number of classes
depth_multiple: 1.0 # model depth multiple
width_multiple: 1.0 # layer channel multiple
anchors:- [10,13, 16,30, 33,23] # P3/8- [30,61, 62,45, 59,119] # P4/16- [116,90, 156,198, 373,326] # P5/32# YOLOv5 v6.0 backbone
backbone:# [from, number, module, args][[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2[-1, 1, Conv, [128, 3, 2]], # 1-P2/4[-1, 3, C3, [128]],[-1, 1, Conv, [256, 3, 2]], # 3-P3/8[-1, 6, C3, [256]],[-1, 1, Conv, [512, 3, 2]], # 5-P4/16[-1, 9, C3, [512]],[-1, 1, Conv, [1024, 3, 2]], # 7-P5/32[-1, 3, C3, [1024]],[-1, 1, SPPF, [1024, 5]], # 9]# YOLOv5 v6.0 head
head:[[-1, 1, Dynamic_conv2d, [512, 1, 1]],[-1, 1, nn.Upsample, [None, 2, 'nearest']],[[-1, 6], 1, Concat, [1]], # cat backbone P4[-1, 3, C3, [512, False]], # 13[-1, 1, Dynamic_conv2d, [256, 1, 1]],[-1, 1, nn.Upsample, [None, 2, 'nearest']],[[-1, 4], 1, Concat, [1]], # cat backbone P3[-1, 3, C3, [256, False]], # 17 (P3/8-small)[-1, 1, Conv, [256, 3, 2]],[[-1, 14], 1, Concat, [1]], # cat head P4[-1, 3, C3, [512, False]], # 20 (P4/16-medium)[-1, 1, Conv, [512, 3, 2]],[[-1, 10], 1, Concat, [1]], # cat head P5[-1, 3, C3, [1024, False]], # 23 (P5/32-large)[[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)]
溫馨提示:本文只是對yolov5l基礎上添加swin模塊,如果要對yolov8n/l/m/x進行添加則只需要指定對應的depth_multiple 和 width_multiple。
# YOLOv5n
depth_multiple: 0.33 # model depth multiple
width_multiple: 0.25 # layer channel multiple# YOLOv5s
depth_multiple: 0.33 # model depth multiple
width_multiple: 0.50 # layer channel multiple# YOLOv5l
depth_multiple: 1.0 # model depth multiple
width_multiple: 1.0 # layer channel multiple# YOLOv5m
depth_multiple: 0.67 # model depth multiple
width_multiple: 0.75 # layer channel multiple# YOLOv5x
depth_multiple: 1.33 # model depth multiple
width_multiple: 1.25 # layer channel multiple
2.3 注冊模塊
關鍵步驟三:在yolo.py中注冊, 大概在260行左右添加 ‘Dynamic_conv2d’
2.4 執行程序
在train.py中,將cfg的參數路徑設置為yolov5_AKConv.yaml的路徑
建議大家寫絕對路徑,確保一定能找到
?🚀運行程序,如果出現下面的內容則說明添加成功🚀
3. 完整代碼分享
https://pan.baidu.com/s/1iePDb_lNUhRKhWOevDRp3g?pwd=xs2y
提取碼: xs2y?
4. GFLOPs
關于GFLOPs的計算方式可以查看:百面算法工程師 | 卷積基礎知識——Convolution
未改進的YOLOv5l的GFLOPs
?改進后的YOLOv5l的GFLOPs
5. 進階
如果想計算量變化更小,如何修改呢,看過我的修改你是否學會了呢?不如動手試試吧
如果你想嘗試但又不知從何下手,可以在評論區問問大家,我看到后也會及時回復
6. 總結
動態卷積是一種通過引入注意力機制,動態選擇和組合多個卷積核的方法,以提高卷積神經網絡的表征能力和性能。通過在每個位置上根據輸入數據的不同部分或特征動態調整卷積核的選擇和權重,動態卷積能夠更靈活地捕獲輸入數據的相關信息,并產生更具表征能力的特征表示。在訓練過程中,網絡通過反向傳播算法優化注意力機制的參數,并更新卷積核的參數,從而學習到適合任務的最佳注意力分配方式和特征表示,進而提高了網絡的性能,優化圖像分類或目標檢測的準確率。