《魔改Yolov5》替换MobileNet V3 backbone

《魔改Yolov5》替换MobileNet V3 backbone,第1张

 🌟🌟🌟博主主页:MuggleZero 🌟🌟🌟  《魔改Yolov5》专栏地址:魔改Yolov5

MobileNet V3 论文翻译地址:

MobileNet V3 论文翻译

h_sigmoid复现:

common.py

 class h_sigmoid(nn.Module):
     def __init__(self, inplace=True):
         super(h_sigmoid, self).__init__()
         self.relu = nn.ReLU6(inplace=inplace)
 ​
     def forward(self, x):
         return self.relu(x + 3) / 6
h_swish复现:

common.py

至此已经实现了h_swish公式内容。

 class h_swish(nn.Module):
     def __init__(self, inplace=True):
         super(h_swish, self).__init__()
         self.sigmoid = h_sigmoid(inplace=inplace)
 ​
     def forward(self, x):
         y = self.sigmoid(x)
         return x * y
网络结构复现

主体结构:

NL:使用的非线性层

HS:h-swish

RE:ReLU

NBN:没有批处理规范化

SE: squeeze-and-excite

第一行的意思:使用了h-swish的非线性层的3x3 conv2d,stride=2, out channels=16。复现代码:

 class Conv3BN(nn.Module):
     """
     This equals to
     def conv_3x3_bn(inp, oup, stride):
         return nn.Sequential(
             nn.Conv2d(inp, oup, 3, stride, 1, bias=False),
             nn.BatchNorm2d(oup),
             h_swish()
         )
     """
 ​
     def __init__(self, inp, oup, stride):
         super(Conv3BN, self).__init__()
         self.conv = nn.Conv2d(inp, oup, 3, stride, 1, bias=False)
         self.bn = nn.BatchNorm2d(oup)
         self.act = h_swish()
 ​
     def forward(self, x):
         return self.act(self.bn(self.conv(x)))
 ​
     def fuseforward(self, x):
         return self.act(self.conv(x))
squeeze-and-excite

MobileNet v3 中 引用的Squeeze-and-Excite是怎么回事

 AdaptiveAvgPool2d
 Linear
 ReLU
 Linear
 h_sigmoid

对应的 *** 作:

  • Squeeze(Fsq)

    用AdaptiveAvgPool2d将H × W × C H的feature map压缩为1 × 1 × C

  • Excitation(Fex)

    得到Squeeze的1 × 1 × C 的feature map后,使用FC全连接层,对每个通道的重要性进行预测,得到不同channel的重要性大小。有两个全连接,一个降维,一个恢复维度。

  • Scale

    最后将学习到的各个channel的激活值(sigmoid激活,值0~1)乘以之前的feature map的对应channel上。

class SELayer(nn.Module):
     def __init__(self, channel, reduction=4):
         super(SELayer, self).__init__()
         #用1x1的卷积
         self.avg_pool = nn.AdaptiveAvgPool2d(1) #Squeeze,将H × W × C H的feature map压缩为1 × 1 × C
         self.fc = nn.Sequential(
             nn.Linear(channel, channel // reduction),
             nn.ReLU(inplace=True),
             nn.Linear(channel // reduction, channel),
             h_sigmoid() # h_sigmoid,修改了x
         ) # 使用FC全连接层,对每个通道的重要性进行预测,得到不同channel的重要性大小
 ​
     def forward(self, x):
         # b=1,c=16,_=64,16个数据组成一行,一共64排数据。
         b, c, _, _ = x.size() #返回x张量行数、列数、深度.
         # Squeeze
         y = self.avg_pool(x).view(b, c)  #池化后的1 × 1 × C feature map重塑为 b*c 的张量
         
         # Excitation 预测并重塑为 b*c*1*1张量
         y = self.fc(y).view(b, c, 1, 1)
         
         # Scale
         return x * y

滤波器4维张量:

 [height,width,input_channels,output_channels]   //滤波器张量
 [卷积核高度,卷积核宽度,图像通道数,卷积核个数]  //第三维input_channels为input张量的第四维。

图像4维张量张量:

 [batch_size,height,width, channels]  //图像张量
 [个数,高度,宽度,通道数]

InvertedResidual

InvertedResidual(论文中是bneck)是MobileNetv2中提出的,stride=1和stride=2在走向是有差异的。

stride=1的时候:

1、point-wise升维 2、depth-wise提取特征 3、通过Linear的point-wise降维。 4、input与结果 相加(残差结构)

第一层bneck是支持relu6的3x3卷积,第二个箭头所指的bneck是支持hswish的5x5卷积。

整体结构如下所示,

即先利用1x1卷积进行升维度,再进行下面的 *** 作,并具有残差边:

 

在输入1x1卷积进行升维度后,进行3x3深度可分离卷积:

注意力机制调整每个通道的权重:

1x1卷积:

class InvertedResidual(nn.Module):
     def __init__(self, inp, oup, hidden_dim, kernel_size, stride, use_se, use_hs):
         super(InvertedResidual, self).__init__()
         assert stride in [1, 2]
 ​
         self.identity = stride == 1 and inp == oup
         # 如果输入通道等于 隐藏层的维数,来一个dw
         if inp == hidden_dim:
             self.conv = nn.Sequential(
                 # dw Depth-wise
                 nn.Conv2d(hidden_dim, hidden_dim, kernel_size, stride, (kernel_size - 1) // 2, groups=hidden_dim,
                           bias=False),
                 nn.BatchNorm2d(hidden_dim),
                 h_swish() if use_hs else nn.ReLU(inplace=True),
                 # Squeeze-and-Excite
                 SELayer(hidden_dim) if use_se else nn.Sequential(),
                 # pw-linear
                 nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False),
                 nn.BatchNorm2d(oup),
             )
         else:
             self.conv = nn.Sequential(
                 # pw Point-wise 1x1 
                 nn.Conv2d(inp, hidden_dim, 1, 1, 0, bias=False),
                 nn.BatchNorm2d(hidden_dim),
                 h_swish() if use_hs else nn.ReLU(inplace=True),
                 # dw Depth-wise
                 nn.Conv2d(hidden_dim, hidden_dim, kernel_size, stride, (kernel_size - 1) // 2, groups=hidden_dim,
                           bias=False),
                 nn.BatchNorm2d(hidden_dim),
                 # Squeeze-and-Excite
                 SELayer(hidden_dim) if use_se else nn.Sequential(),
                 h_swish() if use_hs else nn.ReLU(inplace=True),
                 # pw-linear
                 nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False),
                 nn.BatchNorm2d(oup),
             )
 ​
     def forward(self, x):
         y = self.conv(x)
         # stride=1时,输入加输出
         if self.identity:
             return x + y
         else:
             return y
yaml定义:

依次是传入上面函数的[ oup, hidden_dim(exp size), kernel_size, stride, use_se, use_hs ]

 # YOLOv5 backbone
 backbone:
   # MobileNetV3-small
   # [from, number, module, args]
   [[-1, 1, Conv3BN, [16, 2]],                         # 0-p1/2
    [-1, 1, InvertedResidual, [16,  16, 3, 2, 1, 0]],  # 1-p2/4
    [-1, 1, InvertedResidual, [24,  72, 3, 2, 0, 0]],  # 2-p3/8
    [-1, 1, InvertedResidual, [24,  88, 3, 1, 0, 0]],  # 3-p3/8
    [-1, 1, InvertedResidual, [40,  96, 5, 2, 1, 1]],  # 4-p4/16
    [-1, 1, InvertedResidual, [40, 240, 5, 1, 1, 1]],  # 5-p4/16
    [-1, 1, InvertedResidual, [40, 240, 5, 1, 1, 1]],  # 6-p4/16
    [-1, 1, InvertedResidual, [48, 120, 5, 1, 1, 1]],  # 7-p4/16
    [-1, 1, InvertedResidual, [48, 144, 5, 1, 1, 1]],  # 8-p4/16
    [-1, 1, InvertedResidual, [96, 288, 5, 2, 1, 1]],  # 9-p5/32
    [-1, 1, InvertedResidual, [96, 576, 5, 1, 1, 1]],  # 10-p5/32
    [-1, 1, InvertedResidual, [96, 576, 5, 1, 1, 1]],  # 11-p5/32
   ]

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/904476.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-15
下一篇 2022-05-15

发表评论

登录后才能评论

评论列表(0条)

保存