Focus原理:
在YOLOv5中,图片进入backbone前会对图片进行切片处理。具体操作是在一张图片中每隔一个像素拿到一个值,类似于邻近下采样,这样就拿到了四张图片,四张图片互补,没有信息丢失。这样一来,将W、H信息就集中到了通道空间,输入通道扩充了4倍,即拼接起来的图片相对于原先的RGB三通道模式变成了12个通道,最后将得到的新图片再经过卷积操作,最终得到了没有信息丢失情况下的二倍下采样特征图。
以yolov5s为例,原始的640 × 640 × 3的图像输入Focus结构,采用切片操作,先变成320 × 320 × 12的特征图,再经过一次卷积操作,最终变成320 × 320 × 32的特征图。切片操作如下:
代码:
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))
# return self.conv(self.contract(x))
代码解释:
list_[::]:括号中的参数意义分别是:[开始索引:结束索引:步长],即list_[开始索引:结束索引:步长]。
- 第一个位置(开始索引)为空,默认为0
- 第二个位置(结束索引)为空,默认为最后一个元素位置
- 第三个元素(步长)为空,默认步长为1
- 当步长取负值的时候,表示的是 逆序 !
x[通道,宽,高] (根据网友P.J.189建议修改) x[通道,行,列],则x[..., ::2, ::2]表示:遍历三张大图;每张从第一行左上角的红色1开始,到最后一行,步长为2;从第一列红色1开始,到最后一列,步长为2。
所以最后得出的特征图为:红 ==》绿 ==》黄 ==》蓝