一、本文介紹
本文給大家帶來的改進機制是結合目前SOTAYOLOv9的思想利用雙主干網絡來改進RT-DETR(本專欄目前發布以來改進最大的內容,同時本文內容為我個人一手整理全網獨家首發 | 就連V9官方不支持的模型寬度和深度修改我都均已提供,本文內容支持RT-DETR全系列模型均可使用),本文的內容超級適合想要發表論文的讀者創新性不夠,工作量不夠的,本文的改進在感官上給人就有一種工作量多和創新點十足的感覺,同時本專欄內容以后均采用NEU-DET數據集進行對比實驗模型(避免大家質疑數據集質量的問題),本文內容為獨家整理!。
??歡迎大家訂閱我的專欄一起學習RT-DETR!?
專欄目錄:?RT-DETR改進有效系列目錄 | 包含卷積、主干、RepC3、注意力機制、Neck上百種創新機制
專欄鏈接:RT-DETR劍指論文專欄,持續復現各種頂會內容——論文收割機RT-DETR????
目錄
一、本文介紹
二、原理介紹
2.1 可編程梯度信息
2.1.1 輔助可逆分支
2.1.2 多級輔助信息
2.2?Generalized ELAN
三、核心代碼
四、手把手教你添加雙主干網絡
4.1 修改一
4.2 修改二?
4.3 修改三?
4.4 修改四?
4.5 修改五?
4.6 修改六
4.7 修改七?
五、雙主干網絡的yaml文件和運行記錄
5.1 雙主干網絡的yaml文件
5.2 訓練代碼?
5.3 雙主干網絡的訓練過程截圖?
五、本文總結
二、原理介紹
?
這張圖(圖3)展示了可編程梯度信息(PGI)及其相關網絡架構和方法。圖中展示了四種不同的網絡設計:
a) PAN (Path Aggregation Network):這種網絡結構主要用于改進特征融合,以提高目標檢測的性能。然而,由于信息瓶頸的存在,網絡中可能會丟失一些信息。
b) RevCol (Reversible Columns):這是一種旨在減少信息丟失的網絡設計。它通過可逆的列結構來嘗試維持信息流通不受損失,但如圖中“Heavy Cost”所示,這種結構會增加計算成本。
c) 深度監督:這種方法通過在網絡的多個層次中插入額外的監督信號來提高學習的效率和最終模型的性能。圖中顯示了通過深度監督連接的各個層。
d) 可編程梯度信息 (PGI):PGI是作者提出的一種新方法(我理解的這種方法就是在前向傳播的過程中沒有跳級鏈接),它主要由三個部分組成:
? ?1. 主分支:用于推理的架構。
? ?2. 輔助可逆分支:生成可靠的梯度,以供給主分支進行反向傳播。
? ?3. 多級輔助信息:控制主分支學習可規劃的多級語義信息。PGI的目的是通過輔助可逆分支(如圖中虛線框所示)來解決信息瓶頸問題,以便在不增加推理成本的情況下為深度網絡提供更可靠的梯度。通過這種設計,即使是輕量級和淺層的神經網絡也可以實現有效的信息保留和準確的梯度更新。如圖中的深色方框所示的主分支,通過輔助可逆分支提供的可靠梯度信息,可以獲得更有效的目標任務特征,而不會因為信息瓶頸而損失重要信息。
圖中的符號代表不同的操作:灰色圓形代表池化操作,白色圓形代表上采樣操作,灰色方塊代表預測頭,藍色方塊代表輔助分支,深色方塊代表主分支。這種設計允許網絡在保持高效計算的同時,也能夠處理復雜的目標檢測任務。
2.1 可編程梯度信息
為了解決前述問題,我們提出了一種新的輔助監督框架,稱為可編程梯度信息(PGI),如圖3(d)所示。PGI主要包括三個部分,即(1)主分支,(2)輔助可逆分支和(3)多級輔助信息。從圖3(d)我們可以看到,PGI的推理過程只使用主分支,因此不需要任何額外的推理成本。至于其他兩個部分,它們用于解決或減緩深度學習方法中的幾個重要問題。其中,輔助可逆分支旨在處理由神經網絡加深造成的問題。網絡加深將導致信息瓶頸,這將使得損失函數無法生成可靠的梯度。至于多級輔助信息,它旨在處理由深度監督造成的誤差累積問題,特別是對于具有多個預測分支的架構和輕量型模型。接下來,我們將逐步介紹這兩個部分??。?
2.1.1 輔助可逆分支
在PGI中,我們提出了輔助可逆分支來生成可靠的梯度并更新網絡參數。通過提供從數據到目標的映射信息,損失函數可以提供指導,并避免從與目標關系較小的不完整前饋特征中找到錯誤相關性的可能性。我們提出通過引入可逆架構來維持完整信息,但在可逆架構中添加主分支將消耗大量的推理成本。我們分析了圖3(b)的架構,并發現在深層到淺層添加額外連接時,推理時間將增加20%。當我們反復將輸入數據添加到網絡的高分辨率計算層(黃色框),推理時間甚至超過了兩倍。
由于我們的目標是使用可逆架構來獲取可靠的梯度,因此“可逆”并不是推理階段的唯一必要條件。鑒于此,我們將可逆分支視為深度監督分支的擴展,并設計了如圖3(d)所示的輔助可逆分支。至于主分支,由于信息瓶頸可能會丟失重要信息的深層特征,將能夠從輔助可逆分支接收可靠的梯度信息。這些梯度信息將推動參數學習,以幫助提取正確和重要的信息,并使主分支能夠獲取更有效的目標任務特征。此外,由于復雜任務需要在更深的網絡中進行轉換,可逆架構在淺層網絡上的表現不如在一般網絡上。我們提出的方法不強迫主分支保留完整的原始信息,而是通過輔助監督機制生成有用的梯度來更新它。這種設計的優勢是,所提出的方法也可以應用于較淺的網絡。最后,由于輔助可逆分支可以在推理階段移除,因此可以保留原始網絡的推理能力。我們還可以在PGI中選擇任何可逆架構來充當輔助可逆分支的角色。
2.1.2 多級輔助信息
在本節中,我們將討論多級輔助信息是如何工作的。包含多個預測分支的深度監督架構如圖3(c)所示。對于對象檢測,可以使用不同的特征金字塔來執行不同的任務,例如它們可以一起檢測不同大小的對象。因此,連接到深度監督分支后,淺層特征將被引導學習小對象檢測所需的特征,此時系統將將其他大小的對象位置視為背景。然而,上述行為將導致深層特征金字塔丟失很多預測目標對象所需的信息。對于這個問題,我們認為每個特征金字塔都需要接收所有目標對象的信息,以便后續主分支能夠保留完整信息來學習對各種目標的預測。
多級輔助信息的概念是在輔助監督的特征金字塔層之間和主分支之間插入一個集成網絡,然后使用它來結合不同預測頭返回的梯度,如圖3(d)所示。然后,多級輔助信息將匯總包含所有目標對象的梯度信息,并將其傳遞給主分支然后更新參數。此時,主分支的特征金字塔層次的特性不會被某些特定對象的信息所主導。因此,我們的方法可以緩解深度監督中的斷裂信息問題。此外,任何集成網絡都可以在多級輔助信息中使用。因此,我們可以規劃所需的語義級別來指導不同大小的網絡架構的學習。
2.2?Generalized ELAN
在本節中,我們描述了提出的新網絡架構 - GELAN。通過結合兩種神經網絡架構CSPNet和ELAN,這兩種架構都是以梯度路徑規劃設計的,我們設計了考慮了輕量級、推理速度和準確性的廣義高效層聚合網絡(GELAN)。其整體架構如圖4所示。我們推廣了ELAN的能力,ELAN原本只使用卷積層的堆疊,到一個新的架構,可以使用任何計算塊。
這張圖(圖4)展示了廣義高效層聚合網絡(GELAN)的架構,以及它是如何從CSPNet和ELAN這兩種神經網絡架構演變而來的。這兩種架構都設計有梯度路徑規劃。
a) CSPNet:在CSPNet的架構中,輸入通過一個轉換層被分割為兩部分,然后分別通過任意的計算塊。之后,這些分支被重新合并(通過concatenation),并再次通過轉換層。
b) ELAN:與CSPNet相比,ELAN采用了堆疊的卷積層,其中每一層的輸出都會與下一層的輸入相結合,再經過卷積處理。
c) GELAN:結合了CSPNet和ELAN的設計,提出了GELAN。它采用了CSPNet的分割和重組的概念,并在每一部分引入了ELAN的層級卷積處理方式。不同之處在于GELAN不僅使用卷積層,還可以使用任何計算塊,使得網絡更加靈活,能夠根據不同的應用需求定制。
GELAN的設計考慮到了輕量化、推理速度和精確度,以此來提高模型的整體性能。圖中顯示的模塊和分區的可選性進一步增加了網絡的適應性和可定制性。GELAN的這種結構允許它支持多種類型的計算塊,這使得它可以更好地適應各種不同的計算需求和硬件約束。
總的來說,GELAN的架構是為了提供一個更加通用和高效的網絡,可以適應從輕量級到復雜的深度學習任務,同時保持或增強計算效率和性能。通過這種方式,GELAN旨在解決現有架構的限制,提供一個可擴展的解決方案,以適應未來深度學習的發展。
大家看圖片一眼就能看出來它融合了什么,就是將CSPHet的anyBlock模塊堆疊的方式和ELAN融合到了一起。
三、核心代碼
核心代碼的使用方式看章節四!
import torch
import torch.nn as nn
import torch.nn.functional as F__all__ = ['CBFuse', 'CBLinear', 'Silence']class Silence(nn.Module):def __init__(self):super(Silence, self).__init__()def forward(self, x):return xdef autopad(k, p=None, d=1): # kernel, padding, dilation# Pad to 'same' shape outputsif d > 1:k = d * (k - 1) + 1 if isinstance(k, int) else [d * (x - 1) + 1 for x in k] # actual kernel-sizeif p is None:p = k // 2 if isinstance(k, int) else [x // 2 for x in k] # auto-padreturn pclass CBLinear(nn.Module):def __init__(self, c1, c2s, k=1, s=1, p=None, g=1): # ch_in, ch_outs, kernel, stride, padding, groupssuper(CBLinear, self).__init__()self.c2s = c2sself.conv = nn.Conv2d(c1, sum(c2s), k, s, autopad(k, p), groups=g, bias=True)def forward(self, x):outs = self.conv(x).split(self.c2s, dim=1)return outsclass CBFuse(nn.Module):def __init__(self, idx):super(CBFuse, self).__init__()self.idx = idxdef forward(self, xs):target_size = xs[-1].shape[2:]res = [F.interpolate(x[self.idx[i]], size=target_size, mode='nearest') for i, x in enumerate(xs[:-1])]out = torch.sum(torch.stack(res + xs[-1:]), dim=0)return out
四、手把手教你添加雙主干網絡
4.1 修改一
第一還是建立文件,我們找到如下ultralytics/nn/modules文件夾下建立一個目錄名字呢就是'Addmodules'文件夾(用群內的文件的話已經有了無需新建)!然后在其內部建立一個新的py文件將核心代碼復制粘貼進去即可。
?
?
4.2 修改二?
第二步我們在該目錄下創建一個新的py文件名字為'__init__.py'(用群內的文件的話已經有了無需新建),然后在其內部導入我們的檢測頭如下圖所示。
4.3 修改三?
第三步我門中到如下文件'ultralytics/nn/tasks.py'進行導入和注冊我們的模塊(用群內的文件的話已經有了無需重新導入直接開始第四步即可)!
從今天開始以后的教程就都統一成這個樣子了,因為我默認大家用了我群內的文件來進行修改!!
?
4.4 修改四?
都是同一個文件大家按照我的修改就行從下面開始(此處大家如果修改了主干網絡代碼那么此處就需要修改,如果你沒有修改我主干網絡的添加教程此處就無需修改)
4.5 修改五?
按照我的添加在parse_model里添加即可。
elif m is CBLinear:two_backbone = Truec2 = [int(x * width) for x in args[0]]c1 = ch[f]args = [c1, c2, *args[1:]]elif m is CBFuse:c2 = ch[f[-1]]
4.6 修改六
(此處大家如果修改了主干網絡代碼那么此處就需要修改,如果你沒有修改我主干網絡的添加教程此處就無需修改)
4.7 修改七?
(此處大家如果修改了主干網絡代碼那么此處就需要修改,如果你沒有修改我主干網絡的添加教程此處就無需修改)?
到此就修改完成了,大家可以復制下面的yaml文件運行。
五、雙主干網絡的yaml文件和運行記錄
5.1 雙主干網絡的yaml文件
# Ultralytics YOLO 🚀, AGPL-3.0 license
# RT-DETR-l object detection model with P3-P5 outputs. For details see https://docs.ultralytics.com/models/rtdetr# Parameters
nc: 80 # number of classes
scales: # model compound scaling constants, i.e. 'model=yolov8n-cls.yaml' will call yolov8-cls.yaml with scale 'n'# [depth, width, max_channels]l: [1.00, 1.00, 1024]# gelan backbone
backbone:[[-1, 1, Silence, []],# conv down[-1, 1, Conv, [64, 3, 2]], # 1-P1/2# conv down[-1, 1, Conv, [128, 3, 2]], # 2-P2/4# elan-1 block[-1, 1, RepC3, [256]], # 3# avg-conv down[-1, 1, Conv, [256, 3, 2]], # 4-P3/8# elan-2 block[-1, 1, RepC3, [512]], # 5# avg-conv down[-1, 1, Conv, [512, 3, 2]], # 6-P4/16# elan-2 block[-1, 1, RepC3, [1024]], # 7# avg-conv down[-1, 1, Conv, [1024, 3, 2]], # 8-P5/32# elan-2 block[-1, 1, RepC3, [1024]], # 9# routing[1, 1, CBLinear, [[64]]], # 10[3, 1, CBLinear, [[64, 128]]], # 11[5, 1, CBLinear, [[64, 128, 256]]], # 12[7, 1, CBLinear, [[64, 128, 256, 512]]], # 13[9, 1, CBLinear, [[64, 128, 256, 512, 1024]]], # 14# conv down fuse[0, 1, Conv, [64, 3, 2]], # 15-P1/2[[10, 11, 12, 13, 14, -1], 1, CBFuse, [[0, 0, 0, 0, 0]]], # 16# conv down fuse[-1, 1, Conv, [128, 3, 2]], # 17-P2/4[[11, 12, 13, 14, -1], 1, CBFuse, [[1, 1, 1, 1]]], # 18# elan-1 block[-1, 1, RepC3, [256]], # 19# avg-conv down fuse[-1, 1, Conv, [256, 3, 2]], # 20-P3/8[[12, 13, 14, -1], 1, CBFuse, [[2, 2, 2]]], # 21# elan-2 block[-1, 1, RepC3, [512]], # 22# avg-conv down fuse[-1, 1, Conv, [512, 3, 2]], # 23-P4/16[[13, 14, -1], 1, CBFuse, [[3, 3]]], # 24# elan-2 block[-1, 1, RepC3, [1024]], # 25# avg-conv down fuse[-1, 1, Conv, [1024, 3, 2]], # 26-P5/32[[14, -1], 1, CBFuse, [[4]]], # 27# elan-2 block[-1, 1, RepC3, [1024]], # 28]# gelan head
head:[# elan-spp block[28, 1, AIFI, [1024, 8]], # 29[-1, 1, Conv, [256, 1, 1]], # 30, Y5, lateral_convs.0[-1, 1, nn.Upsample, [None, 2, 'nearest']],[25, 1, Conv, [256, 1, 1, None, 1, 1, False]], # 32 input_proj.1[[-2, -1], 1, Concat, [1]],[-1, 3, RepC3, [256]], # 33, fpn_blocks.0[-1, 1, Conv, [256, 1, 1]], # 34, Y4, lateral_convs.1[-1, 1, nn.Upsample, [None, 2, 'nearest']], #35[22, 1, Conv, [256, 1, 1, None, 1, 1, False]], # 36 input_proj.0[[-2, -1], 1, Concat, [1]], # cat backbone P4[-1, 3, RepC3, [256]], # X3 (38), fpn_blocks.1[-1, 1, Conv, [256, 3, 2]], # 39, downsample_convs.0[[-1, 34], 1, Concat, [1]], # cat Y4[-1, 3, RepC3, [256]], # F4 (41), pan_blocks.0[-1, 1, Conv, [256, 3, 2]], # 42, downsample_convs.1[[-1, 30], 1, Concat, [1]], # cat Y5[-1, 3, RepC3, [256]], # F5 (44), pan_blocks.1# detect[[38, 41, 44], 1, RTDETRDecoder, [nc]], # Detect(P3, P4, P5)]
5.2 訓練代碼?
大家可以創建一個py文件將我給的代碼復制粘貼進去,配置好自己的文件路徑即可運行。
import warnings
warnings.filterwarnings('ignore')
from ultralytics import RTDETRif __name__ == '__main__':model = RTDETR('ultralytics/cfg/models/rt-detr/rt-detr.yaml')# model.load('yolov8n.pt') # loading pretrain weightsmodel.train(data=r'C:\Users\Administrator\Desktop\yolov5-master\yolov5-master\Construction Site Safety.v30-raw-images_latestversion.yolov8\data.yaml',# 如果大家任務是其它的'ultralytics/cfg/default.yaml'找到這里修改task可以改成detect, segment, classify, posecache=False,imgsz=640,epochs=150,single_cls=False, # 是否是單類別檢測batch=4,close_mosaic=10,workers=0,device='0',optimizer='SGD', # using SGD# resume='', # 如過想續訓就設置last.pt的地址amp=False, # 如果出現訓練損失為Nan可以關閉ampproject='runs/train',name='exp',)
5.3 雙主干網絡的訓練過程截圖?
五、本文總結
到此本文的正式分享內容就結束了,在這里給大家推薦我的YOLOv8改進有效漲點專欄,本專欄目前為新開的平均質量分98分,后期我會根據各種最新的前沿頂會進行論文復現,也會對一些老的改進機制進行補充,如果大家覺得本文幫助到你了,訂閱本專欄,關注后續更多的更新~
專欄鏈接:RT-DETR劍指論文專欄,持續復現各種頂會內容——論文收割機RT-DETR????