
前言本文介紹了漸進(jìn)特征金字塔網(wǎng)絡(luò)AFPN及其在YOLO26中的結(jié)合應(yīng)用。AFPN用于目標(biāo)檢測(cè)任務(wù)中的多尺度特征提取解決了傳統(tǒng)特征金字塔網(wǎng)絡(luò)信息丟失和融合效果不佳的問(wèn)題。其創(chuàng)新點(diǎn)在于跨非相鄰層的直接特征融合、自適應(yīng)空間融合操作具備高效計(jì)算性能與廣泛適用性。AFPN通過(guò)漸進(jìn)式融合策略和自適應(yīng)操作避免語(yǔ)義差距和信息沖突。我們將AFPN集成進(jìn)YOLO26替換部分模塊。本文完成 AFPN 在 YOLO26 中的工程接入具體檢測(cè)精度與速度需通過(guò)目標(biāo)數(shù)據(jù)集上的完整訓(xùn)練和消融實(shí)驗(yàn)評(píng)估。文章目錄 YOLO26改進(jìn)大全卷積層、輕量化、注意力機(jī)制、損失函數(shù)、Backbone、SPPF、Neck、檢測(cè)頭全方位優(yōu)化匯總專(zhuān)欄鏈接: 最新YOLO26改進(jìn)專(zhuān)欄文章目錄前言介紹摘要?jiǎng)?chuàng)新點(diǎn)文章鏈接基本原理核心代碼YOLO26引入代碼tasks注冊(cè)步驟1導(dǎo)包步驟2解析多路輸入與通道配置yolo26-AFPN.yaml實(shí)驗(yàn)?zāi)_本結(jié)果介紹摘要在目標(biāo)檢測(cè)任務(wù)當(dāng)中多尺度特征對(duì)于對(duì)具有尺度變化的對(duì)象進(jìn)行編碼起著至關(guān)重要的作用。采用經(jīng)典的自頂向下與自底向上特征金字塔網(wǎng)絡(luò)是提取多尺度特征的常用策略。然而這些方法存在特征信息丟失或降級(jí)的問(wèn)題這對(duì)非相鄰層次之間的融合效果產(chǎn)生了不利影響。本文提出了一種漸進(jìn)特征金字塔網(wǎng)絡(luò)AFPN旨在支持非相鄰層次之間的直接交互。AFPN從融合兩個(gè)相鄰的低級(jí)特征開(kāi)始啟動(dòng)并逐步地將更高級(jí)別的特征納入到融合過(guò)程之中。通過(guò)這種方式能夠避免非相鄰層次之間存在的較大語(yǔ)義差距??紤]到在每個(gè)空間位置的特征融合過(guò)程中存在多對(duì)象信息沖突的可能性進(jìn)一步運(yùn)用自適應(yīng)空間融合操作來(lái)緩解這些不一致情況。我們將所提出的AFPN融入兩階段和單階段目標(biāo)檢測(cè)框架里并利用MS - COCO 2017驗(yàn)證和測(cè)試數(shù)據(jù)集進(jìn)行評(píng)估。實(shí)驗(yàn)評(píng)估結(jié)果顯示相較于其他最先進(jìn)的特征金字塔網(wǎng)絡(luò)我們的方法取得了更具競(jìng)爭(zhēng)力的成果。創(chuàng)新點(diǎn)AFPN漸進(jìn)特征金字塔網(wǎng)絡(luò)的創(chuàng)新點(diǎn)主要體現(xiàn)在以下幾個(gè)方面跨非相鄰層的直接特征融合AFPN通過(guò)漸進(jìn)式的特征融合策略允許非相鄰層次之間的直接交互這有助于防止在特征傳遞和交互過(guò)程中的信息丟失或退化。這種方法與傳統(tǒng)的特征金字塔網(wǎng)絡(luò)FPN不同后者通常僅在相鄰層次之間進(jìn)行特征融合。自適應(yīng)空間融合操作為了處理不同層次特征之間可能出現(xiàn)的信息矛盾AFPN引入了自適應(yīng)空間融合操作。這種方法能夠根據(jù)不同空間位置的特征動(dòng)態(tài)調(diào)整融合權(quán)重從而有效地解決了多目標(biāo)信息沖突問(wèn)題。高效的計(jì)算性能與競(jìng)爭(zhēng)力的檢測(cè)結(jié)果在MS COCO 2017驗(yàn)證和測(cè)試數(shù)據(jù)集上的大量實(shí)驗(yàn)表明AFPN不僅在計(jì)算效率上優(yōu)于其他先進(jìn)的特征金字塔網(wǎng)絡(luò)而且還獲得了更具競(jìng)爭(zhēng)力的檢測(cè)結(jié)果。這表明AFPN能夠在保持高效計(jì)算的同時(shí)提高目標(biāo)檢測(cè)任務(wù)的準(zhǔn)確性。廣泛的應(yīng)用適用性AFPN被成功集成到兩階段和單階段目標(biāo)檢測(cè)框架中并在不同的檢測(cè)模型如Faster R-CNN和YOLOv5上驗(yàn)證了其有效性和提升性能證明了其廣泛的適用性和靈活性。啟發(fā)自HRNet的設(shè)計(jì)AFPN的設(shè)計(jì)受到了高分辨率網(wǎng)絡(luò)HRNet的啟發(fā)它在整個(gè)特征提取過(guò)程中保持了低級(jí)別特征的豐富性并通過(guò)重復(fù)融合低級(jí)別和高級(jí)別特征來(lái)生成更豐富的特征表示。這種設(shè)計(jì)思想在人體姿態(tài)估計(jì)領(lǐng)域已顯示出其優(yōu)勢(shì)AFPN將其成功應(yīng)用于目標(biāo)檢測(cè)任務(wù)。通過(guò)這些創(chuàng)新點(diǎn)AFPN解決了傳統(tǒng)特征金字塔網(wǎng)絡(luò)在處理尺度變化大的對(duì)象時(shí)的限制提高了目標(biāo)檢測(cè)的性能和效率。文章鏈接論文地址論文地址代碼地址代碼地址核心代碼代碼地址基本原理AFPN漸進(jìn)特征金字塔網(wǎng)絡(luò)的核心設(shè)計(jì)理念是在Backbone網(wǎng)絡(luò)的自下而上特征提取過(guò)程中通過(guò)漸進(jìn)的方式集成不同層級(jí)的特征。這個(gè)過(guò)程從低級(jí)別特征的融合開(kāi)始逐步融合更高級(jí)別的特征最終融合頂級(jí)最高級(jí)別的特征。這種方法旨在緩解直接融合非相鄰層次特征時(shí)由于語(yǔ)義差距較大而導(dǎo)致的融合效果不佳的問(wèn)題。通過(guò)逐漸融合特征AFPN能夠使不同層級(jí)的特征在語(yǔ)義上更加接近有效減少了不同層級(jí)特征間的語(yǔ)義差距特別是在最低級(jí)別和最高級(jí)別的特征之間。這種漸進(jìn)的融合策略不僅優(yōu)化了特征的融合效率而且提高了特征表示的豐富性和有效性。在AFPN的設(shè)計(jì)中自適應(yīng)空間融合操作進(jìn)一步增強(qiáng)了不同層次特征融合的靈活性和效果通過(guò)調(diào)整融合策略來(lái)應(yīng)對(duì)特征間的潛在矛盾從而為目標(biāo)檢測(cè)任務(wù)提供了更加精確和魯棒的特征表示。核心代碼class ASFF2(nn.Module): ASFF2 module for YOLO AFPN head https://arxiv.org/abs/2306.15988 def __init__(self, c1, c2, level0): super().__init__() if len(c1) ! 2 or level not in (0, 1): raise ValueError(ASFF2 requires two input channel counts and level 0 or 1) c1_l, c1_h c1 self.level level self.dim c1_l, c1_h self.inter_dim self.dim[self.level] compress_c 8 if level 0: self.stride_level_1 Upsample(c1_h, self.inter_dim) if level 1: self.stride_level_0 Conv(c1_l, self.inter_dim, 2, 2, 0) # downsample 2x self.weight_level_0 Conv(self.inter_dim, compress_c, 1, 1) self.weight_level_1 Conv(self.inter_dim, compress_c, 1, 1) self.weights_levels nn.Conv2d(compress_c * 2, 2, kernel_size1, stride1, padding0) self.conv Conv(self.inter_dim, c2, 3, 1) def forward(self, x): x_level_0, x_level_1 x[0], x[1] if self.level 0: level_0_resized x_level_0 level_1_resized self.stride_level_1(x_level_1) elif self.level 1: level_0_resized self.stride_level_0(x_level_0) level_1_resized x_level_1 level_0_weight_v self.weight_level_0(level_0_resized) level_1_weight_v self.weight_level_1(level_1_resized) levels_weight_v torch.cat((level_0_weight_v, level_1_weight_v), 1) levels_weight self.weights_levels(levels_weight_v) levels_weight F.softmax(levels_weight, dim1) fused_out_reduced level_0_resized * levels_weight[:, 0:1] level_1_resized * levels_weight[:, 1:2] return self.conv(fused_out_reduced) class ASFF3(nn.Module): def __init__(self, c1, c2, level0): super().__init__() if len(c1) ! 3 or level not in (0, 1, 2): raise ValueError(ASFF3 requires three input channel counts and level 0, 1 or 2) c1_l, c1_m, c1_h c1 self.level level self.dim c1_l, c1_m, c1_h self.inter_dim self.dim[self.level] compress_c 8 if level 0: self.stride_level_1 Upsample(c1_m, self.inter_dim) self.stride_level_2 Upsample(c1_h, self.inter_dim, scale_factor4) if level 1: self.stride_level_0 Conv(c1_l, self.inter_dim, 2, 2, 0) self.stride_level_2 Upsample(c1_h, self.inter_dim) if level 2: self.stride_level_0 Conv(c1_l, self.inter_dim, 4, 4, 0) self.stride_level_1 Conv(c1_m, self.inter_dim, 2, 2, 0) self.weight_level_0 Conv(self.inter_dim, compress_c, 1, 1) self.weight_level_1 Conv(self.inter_dim, compress_c, 1, 1) self.weight_level_2 Conv(self.inter_dim, compress_c, 1, 1) self.weights_levels nn.Conv2d(compress_c * 3, 3, kernel_size1, stride1, padding0) self.conv Conv(self.inter_dim, c2, 3, 1) def forward(self, x): x_level_0, x_level_1, x_level_2 x[0], x[1], x[2] if self.level 0: level_0_resized x_level_0 level_1_resized self.stride_level_1(x_level_1) level_2_resized self.stride_level_2(x_level_2) elif self.level 1: level_0_resized self.stride_level_0(x_level_0) level_1_resized x_level_1 level_2_resized self.stride_level_2(x_level_2) elif self.level 2: level_0_resized self.stride_level_0(x_level_0) level_1_resized self.stride_level_1(x_level_1) level_2_resized x_level_2 level_0_weight_v self.weight_level_0(level_0_resized) level_1_weight_v self.weight_level_1(level_1_resized) level_2_weight_v self.weight_level_2(level_2_resized) levels_weight_v torch.cat((level_0_weight_v, level_1_weight_v, level_2_weight_v), 1) w self.weights_levels(levels_weight_v) w F.softmax(w, dim1) fused_out_reduced level_0_resized * w[:, :1] level_1_resized * w[:, 1:2] level_2_resized * w[:, 2:] return self.conv(fused_out_reduced)YOLO26引入代碼在根目錄下的ultralytics/nn/目錄新建一個(gè)featureFusion目錄然后新建一個(gè)以AFPN為文件名的py文件 把代碼拷貝進(jìn)去。importtorchimporttorch.nnasnnfromtorch.nnimportfunctionalasFfromultralytics.nn.modules.convimportConvclassUpsample(nn.Module):Applies convolution followed by upsampling.def__init__(self,c1,c2,scale_factor2):super().__init__()ifscale_factor2:self.cv1nn.ConvTranspose2d(c1,c2,2,2,0,biasTrue)# nn.Upsample(scale_factor2, modenearest)elifscale_factor4:self.cv1nn.ConvTranspose2d(c1,c2,4,4,0,biasTrue)else:raiseValueError(AFPN Upsample supports scale_factor 2 or 4)defforward(self,x):returnself.cv1(x)classASFF2(nn.Module):ASFF2 module for YOLO AFPN head https://arxiv.org/abs/2306.15988def__init__(self,c1,c2,level0):super().__init__()iflen(c1)!2orlevelnotin(0,1):raiseValueError(ASFF2 requires two input channel counts and level 0 or 1)c1_l,c1_hc1 self.levellevel self.dimc1_l,c1_h self.inter_dimself.dim[self.level]compress_c8iflevel0:self.stride_level_1Upsample(c1_h,self.inter_dim)iflevel1:self.stride_level_0Conv(c1_l,self.inter_dim,2,2,0)# downsample 2xself.weight_level_0Conv(self.inter_dim,compress_c,1,1)self.weight_level_1Conv(self.inter_dim,compress_c,1,1)self.weights_levelsnn.Conv2d(compress_c*2,2,kernel_size1,stride1,padding0)self.convConv(self.inter_dim,c2,3,1)defforward(self,x):x_level_0,x_level_1x[0],x[1]ifself.level0:level_0_resizedx_level_0 level_1_resizedself.stride_level_1(x_level_1)elifself.level1:level_0_resizedself.stride_level_0(x_level_0)level_1_resizedx_level_1 level_0_weight_vself.weight_level_0(level_0_resized)level_1_weight_vself.weight_level_1(level_1_resized)levels_weight_vtorch.cat((level_0_weight_v,level_1_weight_v),1)levels_weightself.weights_levels(levels_weight_v)levels_weightF.softmax(levels_weight,dim1)fused_out_reducedlevel_0_resized*levels_weight[:,0:1]level_1_resized*levels_weight[:,1:2]returnself.conv(fused_out_reduced)classASFF3(nn.Module):def__init__(self,c1,c2,level0):super().__init__()iflen(c1)!3orlevelnotin(0,1,2):raiseValueError(ASFF3 requires three input channel counts and level 0, 1 or 2)c1_l,c1_m,c1_hc1 self.levellevel self.dimc1_l,c1_m,c1_h self.inter_dimself.dim[self.level]compress_c8iflevel0:self.stride_level_1Upsample(c1_m,self.inter_dim)self.stride_level_2Upsample(c1_h,self.inter_dim,scale_factor4)iflevel1:self.stride_level_0Conv(c1_l,self.inter_dim,2,2,0)self.stride_level_2Upsample(c1_h,self.inter_dim)iflevel2:self.stride_level_0Conv(c1_l,self.inter_dim,4,4,0)self.stride_level_1Conv(c1_m,self.inter_dim,2,2,0)self.weight_level_0Conv(self.inter_dim,compress_c,1,1)self.weight_level_1Conv(self.inter_dim,compress_c,1,1)self.weight_level_2Conv(self.inter_dim,compress_c,1,1)self.weights_levelsnn.Conv2d(compress_c*3,3,kernel_size1,stride1,padding0)self.convConv(self.inter_dim,c2,3,1)defforward(self,x):x_level_0,x_level_1,x_level_2x[0],x[1],x[2]ifself.level0:level_0_resizedx_level_0 level_1_resizedself.stride_level_1(x_level_1)level_2_resizedself.stride_level_2(x_level_2)elifself.level1:level_0_resizedself.stride_level_0(x_level_0)level_1_resizedx_level_1 level_2_resizedself.stride_level_2(x_level_2)elifself.level2:level_0_resizedself.stride_level_0(x_level_0)level_1_resizedself.stride_level_1(x_level_1)level_2_resizedx_level_2 level_0_weight_vself.weight_level_0(level_0_resized)level_1_weight_vself.weight_level_1(level_1_resized)level_2_weight_vself.weight_level_2(level_2_resized)levels_weight_vtorch.cat((level_0_weight_v,level_1_weight_v,level_2_weight_v),1)wself.weights_levels(levels_weight_v)wF.softmax(w,dim1)fused_out_reducedlevel_0_resized*w[:,:1]level_1_resized*w[:,1:2]level_2_resized*w[:,2:]returnself.conv(fused_out_reduced)tasks注冊(cè)在ultralytics/nn/tasks.py中進(jìn)行如下操作步驟1導(dǎo)包fromultralytics.nn.featureFusion.AFPNimportASFF2,ASFF3步驟2解析多路輸入與通道在parse_model(d, ch, verboseTrue)的模塊判斷鏈中增加以下專(zhuān)用分支。elifmin{ASFF2,ASFF3}:expected_inputs2ifmisASFF2else3ifnotisinstance(f,list)orlen(f)!expected_inputs:raiseValueError(f{m.__name__}requires{expected_inputs}input layers)c2make_divisible(min(args[0],max_channels)*width,8)args[[ch[x]forxinf],c2,*args[1:]]配置yolo26-AFPN.yaml# Ultralytics AGPL-3.0 License - https://ultralytics.com/license# Ultralytics YOLO26 object detection model with P3/8 - P5/32 outputs# Model docs: https://docs.ultralytics.com/models/yolo26# Task docs: https://docs.ultralytics.com/tasks/detect# Parametersnc:80# number of classesend2end:True# whether to use end-to-end modereg_max:1# DFL binsscales:# model compound scaling constants, i.e. modelyolo26n.yaml will call yolo26.yaml with scale n# [depth, width, max_channels]n:[0.50,0.25,1024]s:[0.50,0.50,1024]m:[0.50,1.00,512]l:[1.00,1.00,512]x:[1.00,1.50,512]# YOLO26n backbonebackbone:# [from, repeats, module, args]-[-1,1,Conv,[64,3,2]]# 0-P1/2-[-1,1,Conv,[128,3,2]]# 1-P2/4-[-1,2,C3k2,[256,False,0.25]]-[-1,1,Conv,[256,3,2]]# 3-P3/8-[-1,2,C3k2,[512,False,0.25]]-[-1,1,Conv,[512,3,2]]# 5-P4/16-[-1,2,C3k2,[512,True]]-[-1,1,Conv,[1024,3,2]]# 7-P5/32-[-1,2,C3k2,[1024,True]]-[-1,1,SPPF,[1024,5,3,True]]# 9-[-1,2,C2PSA,[1024]]# 10# YOLO26n head: progressive two-scale and three-scale adaptive fusionhead:-[4,1,Conv,[128,1,1]]# 11 project backbone P3/8-[6,1,Conv,[256,1,1]]# 12 project backbone P4/16-[[11,12],1,ASFF2,[128,0]]# 13 fuse at P3-[[11,12],1,ASFF2,[256,1]]# 14 fuse at P4-[13,2,C3k2,[128,True]]# 15 refine P3-[14,2,C3k2,[256,True]]# 16 refine P4-[10,1,Conv,[512,1,1]]# 17 project backbone P5/32-[[15,16,17],1,ASFF3,[128,0]]# 18 fuse at P3-[[15,16,17],1,ASFF3,[256,1]]# 19 fuse at P4-[[15,16,17],1,ASFF3,[512,2]]# 20 fuse at P5-[18,2,C3k2,[128,True]]# 21 P3/8-small-[19,2,C3k2,[256,True]]# 22 P4/16-medium-[20,1,C3k2,[512,True,0.5,True]]# 23 P5/32-large-[[21,22,23],1,Detect,[nc]]# Detect(P3, P4, P5)實(shí)驗(yàn)?zāi)_本importwarnings warnings.filterwarnings(ignore)fromultralyticsimportYOLOif__name____main__:# 修改為自己的配置文件地址modelYOLO(./ultralytics/cfg/models/26/yolo26-AFPN.yaml)# 修改為自己的數(shù)據(jù)集地址model.train(data./ultralytics/cfg/datasets/coco8.yaml,cacheFalse,imgsz640,epochs10,single_clsFalse,# 是否是單類(lèi)別檢測(cè)batch8,close_mosaic10,workers0,optimizerMuSGD,# optimizerSGD,ampFalse,projectruns/train,nameAFPN,)結(jié)果