前言:Hello大家好,我是小哥談。在計算機視覺任務中,特征金字塔網絡(FPN)是一種常用的方法,它通過構建不同尺度的特征圖來捕獲不同尺度的目標。然而,傳統的FPN存在一些缺點,如特征融合效率低、信息流通不充分等。BIFPN則通過引入雙向的特征融合機制和加權的特征融合方法來克服這些問題。🌈 ?
? ? ?目錄
🚀1.基礎概念
🚀2.網絡結構
🚀3.添加步驟
🚀4.改進方法
🍀🍀步驟1:block.py文件修改
🍀🍀步驟2:__init__.py文件修改
🍀🍀步驟3:tasks.py文件修改
🍀🍀步驟4:創建自定義yaml文件
🍀🍀步驟5:新建train.py文件
🍀🍀步驟6:模型訓練測試
🚀1.基礎概念
加權雙向特征金字塔(Weighted Bi-directional Feature Pyramid Network,簡稱BiFPN)是一種改進的特征金字塔網絡架構,它是在傳統的Feature Pyramid Network (FPN)基礎上發展而來。相較于單向的上采樣和下采樣,BiFPN引入了雙向信息流,即不僅從低層金字塔向上層傳遞特征,也從高層金字塔向下層傳播加強過的特征。
在BiFPN中,每個級別都包含兩個路徑:一個是自底向上的路徑,用于增強底層特征;另一個是從頂到底部的路徑,通過跨層級融合的方式,使得頂層的高級語義信息能夠傳達給低層。這樣做的目的是為了捕獲更豐富、更大范圍的上下文信息,提高特征表示的精確性和魯棒性。
此外,BiFPN通常會采用一些權重機制來調整信息流動的方向和程度,以便優化特征融合的質量。這些權重可以根據特征的重要性或者其他學習策略動態計算。
性能比較:
核心思想:?
雙向特征融合:傳統的FPN是單向的,即從高層特征圖向低層特征圖傳遞信息。而BiFPN在此基礎上增加了反向的信息傳遞,即從低層特征圖向高層特征圖傳遞信息。這種雙向的信息流動使得特征圖之間的信息融合更加充分。
加權特征融合:在BiFPN中,不同尺度的特征圖在融合時會分配不同的權重。這些權重是可學習的參數,模型在訓練過程中會自動調整它們,以最優地融合不同尺度的特征。這樣一來,模型能夠更好地利用每個特征圖的信息,提高整體的特征表示能力。
論文題目:《EfficientDet: Scalable and Efficient Object Detection》
論文地址:??http://arxiv.org/pdf/1911.09070
代碼實現:??https://github.com/google/automl/tree/master/efficientdet
說明:??????
BiFPN是本文中提出的最重要的一個結構。在此之前介紹一下其他的特征金字塔網絡(FPN)結構:
FPN:采用一種自上而下的方法來組合多尺度特征
PANet:在FPN之上增加了一個額外的自下而上的路徑聚合網絡
STDL:提出了一個利用跨尺度特征的尺度轉換模塊
M2det:提出一種融合多尺度特征的U形模塊
NAS-FPN:利用神經架構搜索來自動設計特征網絡拓撲結構
BiFPN:高效的雙向跨尺度連接和加權特征融合
🚀2.網絡結構
本文的改進是基于YOLOv10,關于其網絡結構具體如下圖所示:
YOLOv10官方倉庫地址:
https://github.com/THU-MIG/yolov10
本文所作的改進是將Neck網絡更換為BiFPN。改進后的網絡結構圖具體如下圖所示:
🚀3.添加步驟
針對本文的改進,具體步驟如下所示:👇
步驟1:block.py文件修改
步驟2:__init__.py文件修改
步驟3:tasks.py文件修改
步驟4:創建自定義yaml文件
步驟5:新建train.py文件
步驟6:模型訓練測試
🚀4.改進方法
🍀🍀步驟1:block.py文件修改
在源碼中找到block.py文件,具體位置是ultralytics/nn/modules/block.py,然后將BiFPN模塊代碼添加到block.py文件末尾位置。
BiFPN模塊代碼:
# By CSDN 小哥談
class Concat_BiFPN(nn.Module):def __init__(self, dimension=1):super(Concat_BiFPN, self).__init__()self.d = dimensionself.w = nn.Parameter(torch.ones(3, dtype=torch.float32), requires_grad=True)self.epsilon = 0.0001def forward(self, x):w = self.wweight = w / (torch.sum(w, dim=0) + self.epsilon) # 將權重進行歸一化# Fast normalized fusionx = [weight[0] * x[0], weight[1] * x[1]]return torch.cat(x, self.d)
然后,在block.py文件最上方下圖所示位置加入Concat_BiFPN。
🍀🍀步驟2:__init__.py文件修改
在源碼中找到__init__.py文件,具體位置是ultralytics/nn/modules/__init__.py。
修改1:在下圖所示位置加入Concat_BiFPN,具體如下圖所示:
修改2:在下圖所示位置加入Concat_BiFPN,具體如下圖所示:
🍀🍀步驟3:tasks.py文件修改
在源碼中找到tasks.py文件,具體位置是ultralytics/nn/tasks.py。
修改1:在from ultralytics.nn.modules import ()中加入Concat_BiFPN,具體如下圖所示:
修改2:找到parse_model函數(829行左右),在下圖中所示位置添加如下代碼。
# ------------start--------------elif m is Concat_BiFPN:c2 = sum(ch[x] for x in f)# ------------ end---------------
具體添加位置如下圖所示:
🍀🍀步驟4:創建自定義yaml文件
在源碼ultralytics/cfg/models/v10目錄下創建yaml文件,并命名為:yolov10n_BiFPN.yaml。具體如下圖所示:
備注:其他版本yaml文件同理。
關于yolov10n_BiFPN.yaml文件的完整代碼如下所示:👇
# By CSDN 小哥談
# Parameters
nc: 80 # number of classes
scales: # model compound scaling constants, i.e. 'model=yolov8n.yaml' will call yolov8.yaml with scale 'n'# [depth, width, max_channels]n: [0.33, 0.25, 1024] # YOLOv8.0n backbone
backbone:# [from, repeats, module, args]- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4- [-1, 3, C2f, [128, True]]- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8- [-1, 6, C2f, [256, True]]- [-1, 1, SCDown, [512, 3, 2]] # 5-P4/16- [-1, 6, C2f, [512, True]]- [-1, 1, SCDown, [1024, 3, 2]] # 7-P5/32- [-1, 3, C2f, [1024, True]]- [-1, 1, SPPF, [1024, 5]] # 9- [-1, 1, PSA, [1024]] # 10# YOLOv8.0n head
head:- [-1, 1, nn.Upsample, [None, 2, "nearest"]]- [[-1, 6], 1, Concat, [1]] # cat backbone P4- [-1, 3, C2f, [512]] # 13- [-1, 1, nn.Upsample, [None, 2, "nearest"]]- [[-1, 4], 1, Concat, [1]] # cat backbone P3- [-1, 3, C2f, [256]] # 16 (P3/8-small)- [-1, 1, Conv, [256, 3, 2]]- [[-1, 13], 1, Concat, [1]] # cat head P4- [-1, 3, C2f, [512]] # 19 (P4/16-medium)- [-1, 1, SCDown, [512, 3, 2]]- [[-1, 10], 1, Concat, [1]] # cat head P5- [-1, 3, C2fCIB, [1024, True, True]] # 22 (P5/32-large)- [[16, 19, 22], 1, v10Detect, [nc]] # Detect(P3, P4, P5)
🍀🍀步驟5:新建train.py文件
在所下載的YOLOv10源碼根目錄下新建train.py文件,文件完整代碼如下所示:
# coding:utf-8
# By CSDN 小哥談
from ultralytics import YOLOv10
# 模型配置文件
model_yaml_path = "ultralytics/cfg/models/v10/yolov10n_BiFPN.yaml"
# 數據集配置文件
data_yaml_path = 'ultralytics/cfg/datasets/helmet.yaml'
# 預訓練模型
pre_model_name = 'weights/yolov10n.pt'if __name__ == '__main__':# 加載預訓練模型model = YOLOv10("ultralytics/cfg/models/v10/yolov10n_BiFPN.yaml").load('weights/yolov10n.pt')# 訓練模型results = model.train(data=data_yaml_path,epochs=100,batch=8,name='train_v10')
🍀🍀步驟6:模型訓練測試
在train.py文件,點擊“運行”,在作者自制的安全帽佩戴檢測數據集上,模型可以正常訓練。
參數量對比:🌈
YOLOv10n.yaml | ?385 layers | 2707820 parameters | 2707804 gradients | 8.4 GFLOPs |
YOLOv10n_BiFPN.yaml | 385 layers | 2707829 parameters | 2707813 gradients | 8.4 GFLOPs |
?說明:關于測試數據集,小伙伴們可根據個人情況進行更換!~🍉 🍓 🍑 🍈 🍌 🍐???