1.增加网络的深度depth能够得到更加丰富、复杂的特征并且能够很好的应用到其它任务中。但网络的深度过深会面临梯度消失,训练困难的问题。
2.增加网络的width能够获得更高细粒度的特征并且也更容易训练,但对于width很大而深度较浅的网络往往很难学习到更深层次的特征。
3.增加输入网络的图像分辨率能够潜在得获得更高细粒度的特征模板,但对于非常高的输入分辨率,准确率的增益也会减小。但大分辨率图像会增加计算量。
EfficientNet则是通过NAS搜索,同时增加width、depth以及resolution,使网络结构达到最优。
下表为EfficientNet-B0的网络框架(B1-B7就是在B0的基础上修改Resolution,Channels以及Layers),可以看出网络总共分成了9个Stage。
第一个Stage是一个卷积核大小为3x3,stride为2的普通卷积层(包含BN和Swish激活函数);
Stage2~Stage8都是在重复堆叠MBConv结构(Layers表示该Stage重复MBConv结构多少次),Stage9由一个普通的1x1的卷积层 + 平均池化层 + 全连接层组成。
MBConv后的1或6就是倍率因子n,即MBConv中第一个1x1的卷积层会将输入特征矩阵的channels扩充为n倍,其中k3x3或k5x5表示MBConv中Depthwise Conv所采用的卷积核大小。Channels表示通过该Stage后输出特征矩阵的Channels。
MBConv主要由一个 1x1 的卷积进行升维 (它的卷积核个数是输入特征矩阵channel的n倍,n ∈ { 1 , 6 } n \in \left\{1, 6\right\}n∈{1,6},当n=1时,不升维),一个kxk的Depthwise Conv卷积,k主要有3x3和5x5两种情况,一个SE模块,然后接一个1x1的普通卷积进行降维作用,再加一个Droupout,最后再进行特征图融合。
仅当输入MBConv结构的特征矩阵与输出的特征矩阵shape相同时shortcut连接才存在(代码中可通过stride== 1 and inputc_channels==output_channels条件来判断)
假设输入图像H×W×C,第一个全连接层的节点个数是输入该MBConv特征矩阵 channels 乘SERadio,一般SERadio为 0.25,所以channe为 ,然后是Swish激活函数。
第二个全连接层的节点个数等于Depthwise Conv层输出的特征矩阵 channels,即C CC,且使用Sigmoid激活函数,这样就拉伸成了1×1×C,然后再与原图像相乘,将每个通道赋予权重。这样就实现了注意力
class SqueezeExcite_efficientv2(nn.Module):
def __init__(self, c1, c2, se_ratio=0.25, act_layer=nn.ReLU):
super().__init__()
self.gate_fn = nn.Sigmoid()
reduced_chs = int(c1 * se_ratio)
self.avg_pool = nn.AdaptiveAvgPool2d(1)
self.conv_reduce = nn.Conv2d(c1, reduced_chs, 1, bias=True)
self.act1 = act_layer(inplace=True)
self.conv_expand = nn.Conv2d(reduced_chs, c2, 1, bias=True)
def forward(self, x):
# 先全局平均池化
x_se = self.avg_pool(x)
# 再全连接(这里是用的1x1卷积,效果与全连接一样,但速度快)
x_se = self.conv_reduce(x_se)
# ReLU激活
x_se = self.act1(x_se)
# 再全连接
x_se = self.conv_expand(x_se)
# sigmoid激活
x_se = self.gate_fn(x_se)
# 将x_se 维度扩展为和x一样的维度
x = x * (x_se.expand_as(x))
return x
Dropout层在源码实现中只有使用shortcut的时候才有Dropout层。
EfficientNetV1在训练图像的尺寸很大时,训练速度非常慢,而且非常吃显存。
在网络浅层中使用Depthwise convolutions速度会很慢。虽然Depthwise convolutions结构相比普通卷积拥有更少的参数以及更小的FLOPs,但通常无法充分利用现有的一些加速器,于是有人提出了Fused-MBConv结构去更好的利用移动端或服务端的加速器。
Fused-MBConv结构也非常简单,即将原来的MBConv结构主分支中的 conv1x1和depthwise conv3x3替换成一个普通的conv3x3,如图所示。
EfficientNetV2网络框架相比与EfficientNetV1,主要有以下不同:
1:EfficientNetV2中除了使用到MBConv模块外,还使用了Fused-MBConv模块(主要是在网络浅层中使用)。
2:EfficientNetV2使用较小的expansion ratio(MBConv中第一个expand conv1x1或者Fused-MBConv中第一个expand conv3x3)比如4,在EfficientNetV1中基本都是6. 这样的好处是能够减少内存访问开销。
3:EfficientNetV2中更偏向使用更小(3x3)的kernel_size,在EfficientNetV1中使用了很多5x5的kernel_size。通过下表可以看到使用的kernel_size全是3x3的,由于3x3的感受野是要比5x5小的,所以需要堆叠更多的层结构以增加感受野。
4:移除了EfficientNetV1中最后一个步距为1的stage,就是EfficientNetV1中的stage8,可能是因为它的参数数量过多并且内存访问开销过大。
Conv3x3就是普通的3x3卷积 + 激活函数(SiLU)+ BN
Fused-MBConv 模块模块名称后跟的1,4表示expansion ratio,k3x3表示kenel_size为3x3,注意当expansion ratio等于1时是没有expand conv的,还有这里是没有使用到SE结构的(原论文图中有SE)。
当stride=1且输入输出channel相等时才有shortcut连接。
当有shortcut连接时才有Dropout层,而且这里的Dropout层是Stochastic Depth,即会随机丢掉整个block的主分支(只剩捷径分支,相当于直接跳过了这个block)也可以理解为减少了网络的深度。MBConv模块和EfficientNetV1中是一样的,其中模块名称后跟的4,6表示expansion ratio,SE0.25表示使用了SE模块,0.25表示SE模块中第一个全连接层的节点个数是输入该MBConv模块特征矩阵channels的0.25倍
注意当stride=1且输入输出Channels相等时才有shortcut连接。同样这里的Dropout层是Stochastic DepthStride就是步距,注意每个Stage中会重复堆叠Operator模块多次,只有第一个Opertator模块的步距是按照表格中Stride来设置的,其他的默认都是1。 #Channels表示该Stage输出的特征矩阵的Channels,Layers表示该Stage重复堆叠Operator的次数
网络结构
根据这个结构图进行代码编写,首先是一个步长为2的3x3矩阵,输出channel为24,后面当然也是有bn+激活的。这里先写一个base,通过修改yaml文件对其操作。
这一行的yaml参数应该如下:[-1, 1, stem, [24, 3, 2]],
class stem(nn.Module):
def __init__(self, c1, c2, kernel_size=3, stride=1, groups=1):
super().__init__()
# kernel_size为3时,padding 为1,kernel为1时,padding为0
padding = (kernel_size - 1) // 2
# 由于要加bn层,所以不加偏置
self.conv = nn.Conv2d(c1, c2, kernel_size, stride, padding=padding, groups=groups, bias=False)
self.bn = nn.BatchNorm2d(c2, eps=1e-3, momentum=0.1)
self.act = nn.SiLU(inplace=True)
def forward(self, x):
# print(x.shape)
x = self.conv(x)
x = self.bn(x)
x = self.act(x)
return x
然后是FusedMBConv,根据这个流程图编写。
注意,FusedMBConv是没有SE模块的,虽然上面画了SE。
Fused-MBConv1 后面这个1表示expansion=1,不升维;若不等于1,则升维到原维度的n倍;
后面layers=2表示使用两次这个bolck,所以第一个Fused-MBConv1, k3x3的yaml参数应为[-1, 2, FusedMBConv, [24, 3, 1, 1, 0]]
[24:out_channer, 3:kernel_size, 1:stride,1:expansion, 0:se_ration]
# Fused-MBConv 将 MBConv 中的 depthwise conv3×3 和扩展 conv1×1 替换为单个常规 conv3×3。
class FusedMBConv(nn.Module):
def __init__(self, c1, c2, k=3, s=1, expansion=1, se_ration=0, dropout_rate=0.2, drop_connect_rate=0.2):
super().__init__()
# 当stride=1且输入输出Channels相等时才有shortcut连接,只有使用shortcut时,才用dropout
self.has_shortcut = (s == 1 and c1 == c2) # 只要是步长为1并且输入输出特征图大小相等,就是True 就可以使用到残差结构连接
# expansion是为了先升维,再卷积,再降维,再残差
self.has_expansion = expansion != 1 # expansion==1 为false expansion不为1时,输出特征图维度就为expansion*c1,k倍的c1,扩展维度
expanded_c = c1 * expansion
if self.has_expansion:
self.expansion_conv = stem(c1, expanded_c, kernel_size=k, stride=s)
self.project_conv = stem(expanded_c, c2, kernel_size=1, stride=1)
else:
self.project_conv = stem(c1, c2, kernel_size=k, stride=s)
self.drop_connect_rate = drop_connect_rate
if self.has_shortcut and drop_connect_rate > 0:
self.dropout = DropPath(drop_connect_rate)
def forward(self, x):
if self.has_expansion:
result = self.expansion_conv(x)
result = self.project_conv(result)
else:
result = self.project_conv(x)
if self.has_shortcut:
if self.drop_connect_rate > 0:
result = self.dropout(result)
result += x
return result
stage2: Fused-MBConv4, k3x3 2 48 4 表示用kernelsize=3的卷积核,先升维4倍,outchannel=48,重复四次,注意stride=2只有在第一次重复时才有,后面三次的stride都是1,所以yaml应该写为:
第一个的stride为2
[-1, 1, FusedMBConv, [48, 3, 2, 4, 0]]
后面三个的stride为1
[-1, 3, FusedMBConv, [48, 3, 1, 4, 0]]
同理stage 3 Fused-MBConv4, k3x3 2 64 4
[-1, 1, FusedMBConv, [64, 3, 2, 4, 0]],
[-1, 3, FusedMBConv, [64, 3, 1, 4, 0]],
然后是stage 4 MBConv4, k3x3, SE0.25 2 128 6
表示6个MBConv模块,第一次用kernel size=3的卷积核升维四倍,SERadio为0.25,第一次的stride为2,后三次为1,输出channel为128。
yaml参数就应该为:
[-1, 1, MBConv, [128, 3, 2, 4, 0.25]], # 先用步长为2的卷积
[-1, 5, MBConv, [128, 3, 1, 4, 0.25]], # 后面5个block用步长为1的卷积
class MBConv(nn.Module):
def __init__(self, c1, c2, k=3, s=1, expansion=1, se_ration=0, dropout_rate=0.2, drop_connect_rate=0.2):
super().__init__()
self.has_shortcut = (s == 1 and c1 == c2)
expanded_c = c1 * expansion
self.expansion_conv = stem(c1, expanded_c, kernel_size=1, stride=1)
self.dw_conv = stem(expanded_c, expanded_c, kernel_size=k, stride=s, groups=expanded_c)
self.se = SqueezeExcite_efficientv2(expanded_c, expanded_c, se_ration) if se_ration > 0 else nn.Identity()
self.project_conv = stem(expanded_c, c2, kernel_size=1, stride=1)
self.drop_connect_rate = drop_connect_rate
if self.has_shortcut and drop_connect_rate > 0:
self.dropout = DropPath(drop_connect_rate)
def forward(self, x):
# 先用1x1的卷积增加升维
result = self.expansion_conv(x)
# 再用一般的卷积特征提取
result = self.dw_conv(result)
# 添加se模块
result = self.se(result)
# 再用1x1的卷积降维
result = self.project_conv(result)
# 如果使用shortcut连接,则加入dropout操作
if self.has_shortcut:
if self.drop_connect_rate > 0:
result = self.dropout(result)
# shortcut就是到残差结构,输入输入的channel大小相等,这样就能相加了
result += x
return result
同理stage5和stage6的参数分别为:
[-1, 1, MBConv, [160, 3, 2, 6, 0.25]],
[-1, 8, MBConv, [160, 3, 1, 6, 0.25]],
[-1, 1, MBConv, [256, 3, 2, 4, 0.25]],
[-1, 14, MBConv, [256, 3, 1, 4, 0.25]],
注意,我们不需要stage7,因为我们只需要进行特征提取,不需要进行分类
然后是修改concat连接的位置:
yolov5/配置。
下面注释中很清晰的写了特征图大小变化,以及为什么要和那一层连接。默认输入图片尺寸为640*640,配置文件详细如下。
# 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:
[[-1, 1, stem, [24, 3, 2]], # 0-P1/2 efficientnetv2 一开始是Stem = 普通的卷积+bn+激活 640*640*3 --> 320*320*24
# # [out_channel,kernel_size,stride,expansion,se_ration]
[-1, 2, FusedMBConv, [24, 3, 1, 1, 0]], # 1 2个FusedMBConv=3*3conv+se+1*1conv 320*320*24-->320*320*24
[-1, 1, FusedMBConv, [48, 3, 2, 4, 0]], # 2 这里strid2=2,特征图尺寸缩小一半,expansion=4输出特征图的深度变为原来的4倍 320*320*24-->160*160*48
[-1, 3, FusedMBConv, [48, 3, 1, 4, 0]], # 3 三个FusedMBConv
[-1, 1, FusedMBConv, [64, 3, 2, 4, 0]], # 4 160*160*48-->80*80*64
[-1, 3, FusedMBConv, [64, 3, 1, 4, 0]], # 5
[-1, 1, MBConv, [128, 3, 2, 4, 0.25]], # 6 这里strid2=2,特征图尺寸缩小一半, 40*40*128
[-1, 5, MBConv, [128, 3, 1, 4, 0.25]], # 7
[-1, 1, MBConv, [160, 3, 2, 6, 0.25]], # 8 这里 strid2=2,特征图尺寸缩小一半,20*20*160
[-1, 8, MBConv, [160, 3, 1, 6, 0.25]], # 9
[-1, 1, MBConv, [256, 3, 2, 4, 0.25]], # 10 这里strid2=2,特征图尺寸缩小一半,10*10*160
[-1, 14, MBConv, [256, 3, 1, 4, 0.25]], # 11
[-1, 1, SPPF, [1024, 5]], #12
]
# YOLOv5 v6.0 head
head:
[[-1, 1, Conv, [512, 1, 1]], # 13 10*10
[-1, 1, nn.Upsample, [None, 2, 'nearest']], # 14 20*20
[[-1, 9], 1, Concat, [1]], # 15 cat backbone P4 15 这里特征图大小为20*20,所以应该和9号连接
[-1, 3, C3, [512, False]], # 16 20*20
[-1, 1, Conv, [256, 1, 1]], #17 20*20
[-1, 1, nn.Upsample, [None, 2, 'nearest']], #18 40*40
[[-1, 7], 1, Concat, [1]], # cat backbone P3 19 7号特征图大小也是40*40
[-1, 3, C3, [256, False]], # 20 (P3/8-small)
[-1, 1, Conv, [256, 3, 2]], #21 卷积步长为2,所以特征图尺寸缩小,为 20*20
[[-1, 17], 1, Concat, [1]], # cat head P4 17层的特征图也是20*20
[-1, 3, C3, [512, False]], # 23 (P4/16-medium)
[-1, 1, Conv, [512, 3, 2]], # 24 10*10
[[-1, 13], 1, Concat, [1]], # cat head P5 13层的特征图大小就是10*10
[-1, 3, C3, [1024, False]], # 26 (P5/32-large)
[[20, 23, 26], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
]
然后是修改yolo.py,这边很好改,后面加上stem, FusedMBConv, MBConv
if m in [Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv,
BottleneckCSP, C3, C3TR,C3STR, C3SPP, C3Ghost, SE, CBAM, ECA, CoordAtt, C3SE, C3CBAM, C3ECA,
C3CA,nn.ConvTranspose2d,stem, FusedMBConv, MBConv,SwinStage, PatchMerging, PatchEmbed, ]: #nn.ConvTranspose2d添加转置卷积差值🐸,C3STR,
# BiFPN_Concat2,BiFPN_Concat3,BiFPN_Add2,BiFPN_Add3]:#添加C3SE, C3CBAM, C3ECA, C3CA 【 stem, FusedMBConv, MBConv】--(efficientnetv2网络)
c1, c2 = ch[f], args[0]
if c2 != no: # if not output
c2 = make_divisible(c2 * gw, 8)
common.py中应该添加的efficientnet代码如下:
# ------------------------------efficientnetv2--------------------------------------
class stem(nn.Module):
def __init__(self, c1, c2, kernel_size=3, stride=1, groups=1):
super().__init__()
# kernel_size为3时,padding 为1,kernel为1时,padding为0
padding = (kernel_size - 1) // 2
# 由于要加bn层,所以不加偏置
self.conv = nn.Conv2d(c1, c2, kernel_size, stride, padding=padding, groups=groups, bias=False)
self.bn = nn.BatchNorm2d(c2, eps=1e-3, momentum=0.1)
self.act = nn.SiLU(inplace=True)
def forward(self, x):
# print(x.shape)
x = self.conv(x)
x = self.bn(x)
x = self.act(x)
return x
def drop_path(x, drop_prob: float = 0., training: bool = False):
if drop_prob == 0. or not training:
return x
keep_prob = 1 - drop_prob
shape = (x.shape[0],) + (1,) * (x.ndim - 1)
random_tensor = keep_prob + torch.rand(shape, dtype=x.dtype, device=x.device)
random_tensor.floor_() # binarize
output = x.div(keep_prob) * random_tensor
return output
class DropPath(nn.Module):
def __init__(self, drop_prob=None):
super(DropPath, self).__init__()
self.drop_prob = drop_prob
def forward(self, x):
return drop_path(x, self.drop_prob, self.training)
class SqueezeExcite_efficientv2(nn.Module):
def __init__(self, c1, c2, se_ratio=0.25, act_layer=nn.ReLU):
super().__init__()
self.gate_fn = nn.Sigmoid()
reduced_chs = int(c1 * se_ratio)
self.avg_pool = nn.AdaptiveAvgPool2d(1)
self.conv_reduce = nn.Conv2d(c1, reduced_chs, 1, bias=True)
self.act1 = act_layer(inplace=True)
self.conv_expand = nn.Conv2d(reduced_chs, c2, 1, bias=True)
def forward(self, x):
# 先全局平均池化
x_se = self.avg_pool(x)
# 再全连接(这里是用的1x1卷积,效果与全连接一样,但速度快)
x_se = self.conv_reduce(x_se)
# ReLU激活
x_se = self.act1(x_se)
# 再全连接
x_se = self.conv_expand(x_se)
# sigmoid激活
x_se = self.gate_fn(x_se)
# 将x_se 维度扩展为和x一样的维度
x = x * (x_se.expand_as(x))
return x
# Fused-MBConv 将 MBConv 中的 depthwise conv3×3 和扩展 conv1×1 替换为单个常规 conv3×3。
class FusedMBConv(nn.Module):
def __init__(self, c1, c2, k=3, s=1, expansion=1, se_ration=0, dropout_rate=0.2, drop_connect_rate=0.2):
super().__init__()
# shorcut 是指到残差结构 expansion是为了先升维,再卷积,再降维,再残差
self.has_shortcut = (s == 1 and c1 == c2) # 只要是步长为1并且输入输出特征图大小相等,就是True 就可以使用到残差结构连接
self.has_expansion = expansion != 1 # expansion==1 为false expansion不为1时,输出特征图维度就为expansion*c1,k倍的c1,扩展维度
expanded_c = c1 * expansion
if self.has_expansion:
self.expansion_conv = stem(c1, expanded_c, kernel_size=k, stride=s)
self.project_conv = stem(expanded_c, c2, kernel_size=1, stride=1)
else:
self.project_conv = stem(c1, c2, kernel_size=k, stride=s)
self.drop_connect_rate = drop_connect_rate
if self.has_shortcut and drop_connect_rate > 0:
self.dropout = DropPath(drop_connect_rate)
def forward(self, x):
if self.has_expansion:
result = self.expansion_conv(x)
result = self.project_conv(result)
else:
result = self.project_conv(x)
if self.has_shortcut:
if self.drop_connect_rate > 0:
result = self.dropout(result)
result += x
return result
class MBConv(nn.Module):
def __init__(self, c1, c2, k=3, s=1, expansion=1, se_ration=0, dropout_rate=0.2, drop_connect_rate=0.2):
super().__init__()
self.has_shortcut = (s == 1 and c1 == c2)
expanded_c = c1 * expansion
self.expansion_conv = stem(c1, expanded_c, kernel_size=1, stride=1)
self.dw_conv = stem(expanded_c, expanded_c, kernel_size=k, stride=s, groups=expanded_c)
self.se = SqueezeExcite_efficientv2(expanded_c, expanded_c, se_ration) if se_ration > 0 else nn.Identity()
self.project_conv = stem(expanded_c, c2, kernel_size=1, stride=1)
self.drop_connect_rate = drop_connect_rate
if self.has_shortcut and drop_connect_rate > 0:
self.dropout = DropPath(drop_connect_rate)
def forward(self, x):
# 先用1x1的卷积增加升维
result = self.expansion_conv(x)
# 再用一般的卷积特征提取
result = self.dw_conv(result)
# 添加se模块
result = self.se(result)
# 再用1x1的卷积降维
result = self.project_conv(result)
# 如果使用shortcut连接,则加入dropout操作
if self.has_shortcut:
if self.drop_connect_rate > 0:
result = self.dropout(result)
# shortcut就是到残差结构,输入输入的channel大小相等,这样就能相加了
result += x
return result
# ------------------------------efficientnetv2--------------------------------------
应用yolo.py打印模型,遇到通道不匹配问题可依据报错修改。其模型大小未44GFLOPS,fusedmbconv和mbconv模块为深度可分离扩张卷积,本质还是轻量级别得的网络,受限移动设备,网络复杂度低。
训练实验:
截取几轮数据比较,可以看到损失较大,map值不高。
epoch, train/box_loss, train/obj_loss, train/cls_loss, metrics/precision, metrics/recall, metrics/mAP_0.5,metrics/mAP_0.5:0.95, val/box_loss, val/obj_loss, val/cls_loss, x/lr0, x/lr1, x/lr2
19, 0.074788, 0.044272, 0.0062985, 0.74535, 0.63369, 0.66966, 0.27202, 0.073621, 0.02801, 0.0092962, 0.0097773, 0.0097773, 0.0097773
20, 0.073072, 0.045204, 0.0063186, 0.77761, 0.61626, 0.69892, 0.28895, 0.071125, 0.028678, 0.00954, 0.0097649, 0.0097649, 0.0097649
21, 0.072175, 0.044285, 0.006358, 0.80289, 0.61094, 0.72001, 0.29883, 0.070752, 0.028598, 0.0091686, 0.0097525, 0.0097525, 0.0097525
22, 0.072693, 0.044227, 0.0060734, 0.75893, 0.63668, 0.70634, 0.28595, 0.071674, 0.028373, 0.0094815, 0.0097401, 0.0097401, 0.0097401
23, 0.071475, 0.044777, 0.0058495, 0.78662, 0.6274, 0.71517, 0.28471, 0.069076, 0.028033, 0.0085636, 0.0097278, 0.0097278, 0.0097278
比不上自己整合的网络结构。
nc: 80 # number of classes
depth_multiple: 0.67 # model depth multiple 0.67🚀更改了depth和width后,需要调整backbone和head的张量大小,不单只是增大算力
width_multiple: 0.75 # layer channel multiple 0.75
anchors:
- [5,6, 9,4, 7,9]
- [9,12, 17,7, 11,15]
- [13,18, 15,21, 29,12]
- [23,31, 46,20, 70,35]
# YOLOv5 v6.0 backbone 5s自定义模型权重作预训练模型,因该对应模型参数,5m则报错ValueError: loaded state dict contains a parameter group that doesn't match the size of optimizer's group
backbone:
# [输出,内核、步幅、填充、组] resnet
[[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 理
[-1, 1, Conv, [128, 3, 2]], # 1-P2/4
[-1, 3, C3, [128]], #C3下采样,压缩图片
[-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]], # 6
[-1, 1, Conv, [768, 3, 2]], # 7-P5/32
[-1, 3, c3, [768]], #8
[-1, 1, Conv, [1024, 3, 2]], # 9-P6/64 Focus
[-1, 3, C3, [1024]], #互换c3tr/c3str c3tr减少了初始计算,原理:低分辨率重建,引发内存不足
[-1, 3, CBAM, [1024]],
[-1, 1, SPPF, [1024, 5]], # 11
]
# YOLOv5 v6.0 head csutonmize BIFPN_Add通道数是默认的一半,其余不变 backbone在11层,head中11层后注意对应张量大小即可 bifpn_concat:不需对应张量通道,本上就是拼接
head:
[[-1, 1, Conv, [768, 1, 1]], #另增加768🚀
[-1, 1, nn.Upsample, [None, 2, 'nearest']], #上采样,wx2,hx2 最近邻插值
#[-1, 1, nn.ConvTranspose2d, [768, 4, 2, 1, 0, 768]], #设置转置卷积
[[-1, 8], 1, BiFPN_Concat2, [1]], # cat backbone P5 Concat, [1]]---> BIFPN_Add2, [384,384]],---464/s ---576/m
[-1, 3, C3, [768, False]], # 15 :特征融合,
[-1, 1, Conv, [512, 1, 1]],
[-1, 1, nn.Upsample, [None, 2, 'nearest']],
[[-1, 6], 1, BiFPN_Concat2, [1]], # cat backbone P4 Concat, [1]]---> BIFPN_Add2, [256,256]] --312/s --384/m
[-1, 3, C3, [512, False]], # 19
[-1, 1, Conv, [256, 1, 1]], #backbone上添加层数head后9层添加
[-1, 1, nn.Upsample, [None, 2, 'nearest']],
[[-1, 4], 1, BiFPN_Concat2, [1]], # cat backbone P3 🚀 Concat 更换bifpn_Add,相应更改通道 Concat, [1]]--->BIFPN_Add2, [128, 128]],---160/s---192/m
[-1, 3, C3, [256, False]], # 23 (P3/8-small)
[-1, 1, Conv, [256, 3, 2]],
#[-1, 1, nn.Upsample, [None, 2, 'nearest']],
[[-1, 21], 1, BiFPN_Concat2, [1]], # cat head P4 🚀 💣 +1 Concat, [1]], --->[128, 128]], --160/s --192/m
[-1, 3, C3, [512, False]], # 26 (P4/16-medium)
[-1, 1, Conv, [512, 3, 2]],
[[-1, 17], 1, BiFPN_Concat2, [1]], # cat head P5 💣 +1 Concat, [1]],--->[256, 256]], ---312/s ---384/m
[-1, 3, C3, [768, False]], # 29 (P5/32-large)
[-1, 1, Conv, [768, 3, 2]], #另增768🚀
[[-1, 13], 1, BiFPN_Concat2, [1]], # cat head P6 💣
[-1, 3, C3, [1024, False]], # 32 (P6/64-xlarge)
[-1, 1, SimAM, [1024]], #单个1G
[[24, 27, 30, 33], 1, Detect, [nc, anchors]],
结果截取
19, 0.062305, 0.024025, 0.0053463, 0.79097, 0.71554, 0.76898, 0.3536, 0.06422, 0.016084, 0.0094257, 0.0097773, 0.0097773, 0.0097773
20, 0.06294, 0.023891, 0.0056687, 0.8082, 0.69361, 0.76822, 0.36687, 0.062889, 0.016119, 0.0085275, 0.0097649, 0.0097649, 0.0097649
21, 0.06222, 0.023417, 0.0053155, 0.82182, 0.7072, 0.77387, 0.34713, 0.062644, 0.015897, 0.0078961, 0.0097525, 0.0097525, 0.0097525
22, 0.06078, 0.02346, 0.005072, 0.8381, 0.67144, 0.76463, 0.36712, 0.062968, 0.016126, 0.0090247, 0.0097401, 0.0097401, 0.0097401
23, 0.060867, 0.023247, 0.0047429, 0.81921, 0.68499, 0.77609, 0.34067, 0.062621, 0.016231, 0.0093678, 0.0097278, 0.0097278, 0.0097278
EfficientNetV2模块和 SwinStage 均引入了自注意力机制(self-attention)来增强模型在处理图像特征时的表达能力。
自注意力机制是一种能够学习全局依赖关系和跨尺度特征的机制。在 Swin Transformer 中,SwinStage 模块通过引入自注意力机制来实现对图像中全局信息的感知和跨尺度特征的整合。这使得模型可以更好地适应不同类型的目标检测任务。
而在 EfficientNetV2 中,也引入了类似的自注意力机制,以提高模型的表示能力和泛化能力。通过注意力机制,模型可以动态地调整不同通道和位置的特征权重,从而提高模型的表达能力和精确度。
- FusedMBConv:FusedMBConv 主要应用于轻量级图像分类和目标检测任务。由于其轻量级的设计和高效的计算特性,适用于移动设备和嵌入式设备上的图像处理应用。
- FusedMBConv:相对于 Swin Transformer 和传统的卷积模型,FusedMBConv 具有更小的参数量和计算复杂度,适合在资源受限的设备上运行。
效果可能类似 wintransformer。
简述完毕,如有建议,留在评论区。