Yolov3之Darknet53
关于Darknet训练模型,可以见我的其他文章Darknet训练数据集Linux,环境配置win/lin
Darknet网络结构
Darknet的最大创新之处在于将卷积和残差链接,网络结构如图所示,最后三层 Avgpool、Connected 和 Softmax 层没有标注,用来在 ImageNet 数据集上训练分类任务时使用
该表格与Darknet53模块相对应,一起看效果更佳
图片来源CSDN Tc.小浩
Darknet53的卷积单元CBL,在Yolov5网络结构及其他有提到,
CBL为标准卷积模块,包括普通卷积层Conv、批量归一化层BN和LeakyReLU激活函数层
CBL模块
import torch
import torch.nn as nn
def autopad(k, p=None): # kernel,padding
# pad to "same":
# H_out=H_in;W_out=W_in
# H_out=(H_in+2p-k)/s+1
# W_out=(W_in+2p-k)/s+1
if p is None:
if isinstance(k,int):
p = k//2 if k%2==1 else k//2 -1
else:
p = [x // 2 if x % 2 == 1 else x // 2 - 1 for x in k]
return p
class Conv(nn.Module):
def __init__(self,c1,c2,k=1,s=1,p=None,g=1,act=True):
super(Conv,self).__init__() # 初始化
self.conv=nn.Conv2d(c1,c2,k,s,autopad(k, p),groups=g,bias=False) # 分组与偏置项即b
self.bn=nn.BatchNorm2d(c2)
self.act=nn.LeakyReLU(0.01) if act else nn.Identity
def forward(self,x):
return self.act(self.bn(self.conv(x)))
残差模块
class ResidualLayer(nn.Module):
def __init__(self, c1): # converlution * 2 + residual
c_ = c1 // 2
super(ResidualLayer, self).__init__()
self.conv = nn.Sequential(
Conv(c1, c_, k=1, s=1,p=0), # kernel_size = 1降通道
Conv(c_, c1, k=3, s=1,p=1), # 再用kernel_size = 3通道升
)
def forward(self, x):
return x + self.conv(x) # 前向传播,增加残差,原始信息与特征连接
Darknet53模块
class Darknet53(nn.Module):
def __init__(self):
super(Darknet53, self).__init__()
self.conv1 = Conv(3, 32, 3, 1, 1) # 一个卷积块 = 1层卷积
self.conv2 = Conv(32, 64, 3, 2, 1)
self.conv3_4 = ResidualLayer(64) # 一个残差块 = 2层卷积
self.conv5 = Conv(64, 128, 3, 2, 1)
self.conv6_9 = nn.Sequential( # = 4层卷积
ResidualLayer(128),
ResidualLayer(128),
)
self.conv10 = Conv(128, 256, 3, 2, 1)
self.conv11_26 = nn.Sequential( # = 16层卷积
ResidualLayer(256),
ResidualLayer(256),
ResidualLayer(256),
ResidualLayer(256),
ResidualLayer(256),
ResidualLayer(256),
ResidualLayer(256),
ResidualLayer(256),
)
self.conv27 = Conv(256, 512, 3, 2, 1)
self.conv28_43 = nn.Sequential( # = 16层卷积
ResidualLayer(512),
ResidualLayer(512),
ResidualLayer(512),
ResidualLayer(512),
ResidualLayer(512),
ResidualLayer(512),
ResidualLayer(512),
ResidualLayer(512),
)
self.conv44 = Conv(512, 1024, 3, 2, 1)
self.conv45_52 = nn.Sequential( # = 8层卷积 Darknet53有52层卷积以及1层输出
ResidualLayer(1024),
ResidualLayer(1024),
ResidualLayer(1024),
ResidualLayer(1024),
)
def forward(self, entry):
conv1 = self.conv1(entry)
conv2 = self.conv2(conv1)
conv3_4 = self.conv3_4(conv2)
conv5 = self.conv5(conv3_4)
conv6_9 = self.conv6_9(conv5)
conv10 = self.conv10(conv6_9)
conv11_26 = self.conv11_26(conv10)
conv27 = self.conv27(conv11_26)
conv28_43 = self.conv28_43(conv27)
conv44 = self.conv44(conv28_43)
conv45_52 = self.conv45_52(conv44)
return conv45_52, conv28_43, conv11_26 # YOLOv3用,所以输出了3次特征
测试
Darknetmodel = Darknet53()
if __name__ == '__main__':
# 输入一张416*416的图片,batch输入维度为(1,3,416,416)
batch = torch.randn(1, 3, 416, 416)
conv45_52, conv28_43, conv11_26 = Darknetmodel(batch)
print(conv45_52.shape)
print(conv28_43.shape)
print(conv11_26.shape)
"""
torch.Size([1, 1024, 13, 13])
torch.Size([1, 512, 26, 26])
torch.Size([1, 256, 52, 52])
"""