1. DarkNet网络结构
Yolov3、Yolov4的backbone采用了CSP_DarkNet_53网络,其激活函数采用Mish。本文章复现DarkNet_53激活函数采用LeakyReLu,两者结构基本一致。
1.1 卷积单元----Convolutional
Convolutional卷积单元由Conv+BN+LeakyReLu组成
class Conv_BN_LRelu(nn.Module):
def __init__(self, input_ch, output_ch, kernel_s, s, p=1, bias=False):
super(Conv_BN_Mish, self).__init__()
self.conv_bn_leaky = nn.Sequential(
nn.Conv2d(input_ch, output_ch, kernel_s, s, p),
nn.BatchNorm2d(output_ch),
nn.LeakyReLU(0.01),
)
def forward(self, x):
return self.conv_bn_leaky(x)
1.2 Residual
Residual由一个1x1的卷积和一个3X3的卷积组成,前者卷积将输入的通道数减半,后者卷积则恢复原来的通道数,如图黄色所示。优点:更好提取特征的同时又保留了原始信息。
class Residual(nn.Module):
def __init__(self, input_ch):
super(Residual, self).__init__()
output_ch = input_ch//2
self.residual = nn.Sequential(
Conv_BN_LRelu(input_ch, output_ch, 1, 1, 0),
Conv_BN_LRelu(output_ch, input_ch, 3, 1, 1)
)
def forward(self, x):
return x + self.residual(x)
二、Pytorch实现
import torch
from torch import nn
from torch.utils.tensorboard import SummaryWriter
from torchsummary import summary
import torch.nn.functional as F
class Conv_BN_LRelu(nn.Module):
def __init__(self, input_ch, output_ch, kernel_s, s, p=1, bias=False):
super(Conv_BN_LRelu, self).__init__()
self.conv_bn_leaky = nn.Sequential(
nn.Conv2d(input_ch, output_ch, kernel_s, s, p),
nn.BatchNorm2d(output_ch),
nn.LeakyReLU(0.01),
)
def forward(self, x):
return self.conv_bn_leaky(x)
class Residual(nn.Module):
def __init__(self, input_ch):
super(Residual, self).__init__()
output_ch = input_ch//2
self.residual = nn.Sequential(
Conv_BN_LRelu(input_ch, output_ch, 1, 1, 0),
Conv_BN_LRelu(output_ch, input_ch, 3, 1, 1)
)
def forward(self, x):
return x + self.residual(x)
class Darknet(nn.Module):
def __init__(self, feature, num_class=1000):
super(Darknet, self).__init__()
self.feature = feature
self.classifier = nn.Sequential(
nn.Linear(1024, num_class)
)
def forward(self, x):
x = self.feature(x)
m = nn.AdaptiveAvgPool2d((1, 1))
x = m(x)
x = torch.flatten(x, 1)
x = self.classifier(x)
x = F.softmax(x,dim=0)
return x
def make_layers(cfg):
i = 0
layers = []
input_ch = 3
for d in cfg:
if d == 'R':
layers.append(Residual(input_ch))
else:
i = i + 1
s = 1 if i == 1 else 2
layers.append(Conv_BN_LRelu(input_ch, d, 3, s))
input_ch = d
return nn.Sequential(*layers)
cfgs = {
'DarkNet': [32, 64, 'R', 128, 'R', 'R', 256, 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 512, 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 1024, 'R', 'R', 'R', 'R'],
}
def darknet():
model = Darknet(make_layers(cfgs['DarkNet']))
return model