YOLOv5中 FOCUS模块

1. Focus层原理

        Focus层原理和PassThrough层很类似。它采用切片操作把高分辨率的图片 (特征图)拆分成多个低分辨率的图片/特征图,即隔列采样+拼接。原理图如 下:

        原始的640 × 640 × 3的图像输入Focus结构,采用切片(slice)操作,先 变成320 × 320 × 12的特征图,拼接(Concat)后,再经过一次卷积(CBL(后 期改为SiLU,即为CBS))操作,最终变成320 × 320 × 64的特征图。 

        Focus层将w-h平面上的信息转换到通道维度,再通过3*3卷积的方式提取 不同特征。采用这种方式可以减少下采样带来的信息损失 。

2.代码分析

        Focus层及其相关代码如下(models/common.py)

        YOLOv5源码:https://github.com/ultralytics/yolov5

def autopad(k, p=None): # kernel, padding自动填充的设计,更加灵
活多变
   # Pad to 'same'
   if p is None:
       p = k // 2 if isinstance(k, int) else [x // 2 for x 
in k]  
# auto-pad自动填充,通过自动设置填充数p
       #如果k是整数,p为k与2整除后向下取整;如果k是列表等,p对应的是
列表中每个元素整除2。
   return p
 
class Conv(nn.Module):
   # 这里对应结构图部分的CBL,CBL = conv+BN+Leaky ReLU
   def __init__(self, c1, c2, k=1, s=1, p=None, g=1, 
act=True): # ch_in, ch_out, kernel, stride, padding, groups
       super().__init__()
       self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), 
groups=g, bias=False)
       self.bn = nn.BatchNorm2d(c2) 
#将其变为均值为0,方差为1的正态分布,通道数为c2先采取切片操作(x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2] 
)把图片分成1,2,3,4共4块(如上面的原理图)
然后进行一个连接
然后再来一次卷积,这里的卷积是自定义卷积:先进行一次卷积,然后变
化成正态分布,最后来个SiLU激活,完成。
第四节: YOLOv5中 backbone讲解
3, Focus的作用
参数数量(params):关系到模型大小,单位通常是M,通常参数用
float32表示,所以模型大小是参数数量的4倍。
       self.act = nn.SiLU() if act is True else (act if 
isinstance(act, nn.Module) else nn.Identity())
#其中nn.Identity()是网络中的占位符,并没有实际操作,在增减网络过程
中,可以使得整个网络层数据不变,便于迁移权重数据;nn.SiLU()一种激活函
数(S形加权线性单元)。
 
   def forward(self, x):#正态分布型的前向传播
       return self.act(self.bn(self.conv(x)))
 
   def forward_fuse(self, x):#普通前向传播
       return self.act(self.conv(x))
 
class Focus(nn.Module):
   # Focus wh information into c-space
   def __init__(self, c1, c2, k=1, s=1, p=None, g=1, 
act=True): # ch_in, ch_out, kernel, stride, padding, groups
       super().__init__()
       self.conv = Conv(c1 * 4, c2, k, s, p, g, act)
       # self.contract = Contract(gain=2)
 
   def forward(self, x): # x(b,c,w,h) -> y(b,4c,w/2,h/2)
       return self.conv(torch.cat([x[..., ::2, ::2], x[..., 
1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]], 1)) 
       #图片被分为4块。x[..., ::2, ::2]指图片的左上角那一块, 
x[..., 1::2, ::2]指右上角那一块,x[..., ::2, 1::2]指左下角那一块,
x[..., 1::2, 1::2]指右下角那一块。都是每隔一个采样(采奇数列)。用
cat连接这些采样图,生成通道数为12的特征图
       # return self.conv(self.contract(x))

        先采取切片操作(x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2] )把图片分成1,2,3,4共4块(如上面的原理图) 然后进行一个连接 然后再来一次卷积,这里的卷积是自定义卷积:先进行一次卷积,然后变 化成正态分布,最后来个SiLU激活,完成。

3, Focus的作用

        参数数量(params):关系到模型大小,单位通常是M,通常参数用 float32表示,所以模型大小是参数数量的4倍。      

        计算量(FLOPs):即浮点运算数,可以用来衡量算法/模型的复杂度,这 关系到算法速度,大模型的单位通常为G,小模型单位通常为M;通常只考虑乘 加操作的数量,而且只考虑Conv和FC等参数层的计算量,忽略BN和PReLU 等,一般情况下,Conv和FC层也会忽略仅纯加操作的计算量,如bias偏置加和 shoutcut残差加等,目前技术有BN和CNN可以不加bias。

        params计算公式: Kh × Kw × Cin × Cout FLOPs

        计算公式:

         Kh × Kw × Cin × Cout × H × W = 即(当前层filter × 输出的feature map) = params × H × W

        总所周知,图片在经过Focus模块后,最直观的是起到了下采样的作用,但 是和常用的卷积下采样有些不一样,可以对Focus的计算量和普通卷积的下采样 计算量进行做个对比:

        在yolov5s的网络结构中,可以看到,Focus模块的卷积核是3 × 3,输出通 道是32:

        那么做个对比:

         普通下采样:即将一张640 × 640 × 3的图片输入3 × 3的卷积中,步长为 2,输出通道32,下采样后得到320 × 320 × 32的特征图,那么普通卷积下采样 理论的计算量为:

        FLOPs(conv) = 3 × 3 × 3 × 32 × 320 × 320 = 88473600(不考虑bias情 况下)

params参数量(conv) = 3 × 3 × 3 × 32 +32 +32 = 928 (后面两个32分别为 bias和BN层参数)

        Focus:将640 × 640 × 3的图像输入Focus结构,采用切片操作,先变成 320 × 320 × 12的特征图,再经过3 × 3的卷积操作,输出通道32,最终变成320 × 320 × 32的特征图,那么Focus理论的计算量为:

FLOPs(Focus) = 3 × 3 × 12 × 32 × 320 × 320 = 353894400(不考虑 bias情况下) params参数量(Focus)= 3 × 3 × 12 × 32 +32 +32 =3520 (为了呼应上图输 出的参数量,将后面两个32分别为bias和BN层的参数考虑进去,通常这两个占 比比较小可以忽略) 可以明显的看到,Focus的计算量和参数量要比普通卷积要多一些,是普通卷积 的4倍,但是下采样时没有信息的丢失。

        2021-07-01更新:作者有在issues中提到Focus是为了提速,和mAP无 关,但是也没有说是什么原理,我也是一知半解,本文也仅从计算量和参数量 去分析该模块,如果有看懂作者这样作法的同学望评论区告知。

        2021-08-16更新:作者终于在issues上做了具体的解答,和之前分析的思 路一样,都是从计算量和参数量出发,不同的是,在作者解答之前我们并不知 道作者改进的出发点是什么,也就是不清楚他在何结构上进行的改进,文中我 理解为只是对一层普通下采样卷积做的改进,实际上有三层,所以经过改进后 参数量其实还是变少了的,也确实达到了提速的效果,具体内容可以结合本文 分析过程和作者给的issues结合起来看。

### YOLOv8 Focus模块的作用及实现方式 #### 1. **Focus模块概述** Focus 是一种特殊的下采样技术,在早期版本的 YOLO(如 YOLOv5)中被广泛采用。其主要目的是通过重新排列输入图像的空间维度来减少计算量并提高效率[^1]。 然而,随着模型架构的发展,在 YOLOv5 的后续更新以及 YOLOv8 中,Focus 层已经被替代。YOLOv8 不再使用传统的 Focus 模块,而是采用了更高效的卷积操作来进行特征提取和降维处理[^2]。 --- #### 2. **YOLOv8中的替换方案** 在 YOLOv8 中,Focus 被一个标准的 $6 \times 6$ 卷积层所取代,该卷积层具有步长为 2 的特性。这种设计简化了网络结构,并保持了较高的性能表现。 以下是具体的实现细节: - 替代后的卷积层参数设置如下: - 输入通道数:C_in - 输出通道数:C_out - 卷积核大小:$6 \times 6$ - 步幅:2 (stride=2) 这一改动不仅减少了复杂度,还使得整个框架更加统一化,便于维护与扩展。 --- #### 3. **代码实现** 下面展示了如何用 PyTorch 实现类似的逻辑以模拟 YOLOv8 对应部分的功能: ```python import torch.nn as nn class Conv(nn.Module): def __init__(self, c1, c2, k=1, s=1, p=None): super().__init__() self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), bias=False) self.bn = nn.BatchNorm2d(c2) self.act = nn.SiLU() def forward(self, x): return self.act(self.bn(self.conv(x))) # 定义类似于 YOLOv8 的初始层 class InitialLayer(nn.Module): def __init__(self, in_channels, out_channels): super(InitialLayer, self).__init__() self.conv = Conv(in_channels, out_channels, k=6, s=2) def forward(self, x): return self.conv(x) ``` 上述代码片段定义了一个 `Conv` 类用于构建基础卷积单元,并基于此创建了新的初始化层——即代替传统 Focus 的功能。 --- #### 4. **作用分析** 尽管 YOLOv8 已经移除了原始意义上的 Focus 结构,但从其实现效果来看,它依然保留了以下几个核心目标: - 提高空间分辨率压缩能力; - 减少不必要的冗余运算; - 增强对细粒度特征的学习能力; 这些改进共同促进了检测精度与推理速度之间的平衡优化。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值