2020年2月21日,Joseph Redmon 宣布退出计算机视觉领域,表明不再更YOLOv3。之后AlexeyAB 继承了 YOLO 系列的思想和理念,在 YOLOv3 的基础上不断进行改进和开发,于该年四月份发布了 YOLOv4。并得到了原作者 Joseph Redmon 的承认。
YOLOV4
论文: https://arxiv.org/pdf/2004.10934.pdf
目录
YOLOV4主要构成:
Backbones(在不同图像细粒度上聚合并形成图像特征的卷积神经网络。):CSPDarknet53
Neck(一系列混合和组合图像特征的网络层,并将图像特征传递到预测层。):(1)Additional blocks:SPP (2)Path-aggregation blocks:PANet(FPN+PAN)
Heads(对图像特征进行预测,生成边界框和并预测类别。):YOLOv3
CBM和CBL模块:
Mish:光滑的非单调激活函数
Mish(x) = x・tanh(ς(x)),其中, ς(x) = ln(1+e^x),是一个softmax激活函数和。
LeakyReLU:非饱和激活函数
实现代码如下:
#CBM
class CBM(nn.Module):
def __init__(self,in_channels,out_channels,kernel_size,stride,bias=False):
super().__init__()
self.Conv1 = nn.Conv2d(in_channels,out_channels,kernel_size,stride,padding=(kernel_size - 1) // 2)
self.BN = nn.BatchNorm2d(out_channels)
def forward(self, x):
x = self.Conv1(x)
x = self.BN(x)
x = x * (torch.tanh(torch.nn.functional.softplus(x)))
return x
#CBL
class CBL(nn.Module):
def __init__(self,in_channels,out_channels,kernel_size,stride,bias=False):
super().__init__()
self.Conv1 = nn.Conv2d(in_channels,out_channels,kernel_size,stride,padding=(kernel_size - 1) // 2)
self.BN = nn.BatchNorm2d(out_channels)
self.Leakyrelu = nn.LeakyReLU(inplace=True)
def forward(self, x):
x = self.Conv1(x)
x = self.BN(x)
x = self.Leakyrelu(x)
return x
SPP结构:
主要是通过解决中不同尺寸的特征图如何进入全连接层的,对任意尺寸的特征图直接进行固定尺寸的池化,来得到固定数量的特征,从而增加感受野。
比如上图:对整个特征图进行一个最大值池化以及划分成2x2和4x4的网格之后进行最大值池化,分别得到1*d、4*d、16*d的特征,接着将每个池化得到的特征融合起来即可得到固定长度的特征个数。
实现代码如下:
#SPP
class SPP(nn.Module):
def __init__(self):
super().__init__()
self.Maxpool1 = nn.MaxPool2d(kernel_size=5, stride=1, padding=5 // 2)
self.Maxpool2 = nn.MaxPool2d(kernel_size=9, stride=1, padding=9 // 2)
self.Maxpool3 = nn.MaxPool2d(kernel_size=13, stride=1, padding=13 // 2)
def forward(self, x):
x1 = self.Maxpool1(x)
x2 = self.Maxpool2(x)
x3 = self.Maxpool3(x)
x = torch.cat((x, x1, x2, x3), dim=1)
return x
CSP结构:
CSPNet论文地址:https://arxiv.org/pdf/1911.11929
CSPNet全称是Cross Stage Paritial Network,主要从网络结构设计的角度解决推理中从计算量很大的问题。
CSPNet的作者认为推理计算过高的问题是由于网络优化中的梯度信息重复导致的。因此采用CSP模块先将基础层的特征映射划分为两部分,然后通过跨阶段层次结构将它们合并,在减少了计算量的同时可以保证准确率。
主要是将输入分为两个分支,一个分支先通过CBM,再经过Resunit * N(残差结构:为了使网络构建的更深),再通过一次CBM;另一个分支直接通过CBM;然后两个分支进行concat融合。
实现代码如下:
#Res_unit
class Res_unit(nn.Module):
def __init_