YOLOv5中的Focus层
一、背景介绍
Focus层是在YOLOv5中被提出来的。感觉像是一种特殊的下采样的方式。
1.下采样
下采样就是一种缩小图像的手法,用来降低特征的维度并保留有效信息,一定程度上避免过拟合,都是以牺牲部分信息为代价,换取数据量的减少。下采样就是池化操作。但是池化的目的不仅如此,还需要考虑旋转、平移、伸缩不变形等。采样有最大值采样,平均值采样,随机区域采样等,对应池化:比如最大值池化,平均值池化,随机池化等。
2.常见下采样做法
平均值池化:对邻域内特征点只求平均,有点像平滑滤波,根据滑窗的尺寸控制下采样的力度,尺寸越大,它的采样率越高,但边缘信息损失越大。
最大值池化:对邻域内特征点取最大,类似锐化,突出滑窗内的细节点(特殊点)。
具体如下图所示:
二、前身:YOLOv2中的PassThrough层
PassThrough层和YOLOv5中的Focus层很像(前身?感觉好像作用一样啊,有没有知道的大佬可以给我讲讲)。他是将相邻的特征堆积在不同的通道中,这样可以将大尺度特征图下采样后与小尺度特征图进行融合,进而增加了小目标检测的精确度。
原理如下:
三、Focus层
1.原理
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源码:GitHub - ultralytics/yolov5: YOLOv5 🚀 in PyTorch > ONNX > CoreML > TFLite:)
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,后来改成了SiLU(CBS) 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 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]即行按2叠加取,列也是,对应上面原理图的“1”块块), x[..., 1::2, ::2]对应“3”块块,x[..., ::2, 1::2]指“2”块块,x[..., 1::2, 1::2]指“4”块块。都是每隔一个采样(采奇数列)。用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,3,2,4共4块(如上面的原理图)
然后进行一个连接
然后再来一次卷积,这里的卷积是自定义卷积:先进行一次卷积,然后变化成正态分布,最后来个SiLU激活,完成。
本文来自博客园,作者:海_纳百川,转载请注明原文链接:https://www.cnblogs.com/chentiao/p/17534171.html,如有侵权联系删除