# Darknet卷积模块

Yolo系列的作者把yolo网络叫做Darknet，其实其他神经网络库都已经把卷积层写好了，直接堆叠起来即可。

darknet卷积模块是这个模型里最基本的网络单元，包括卷积层、batch norm(BN)层、激活函数，因此类型命名为 DarknetConv2D_BN_Leaky。原keras实现是卷积层加了L2正则化预防过拟合，Pytorch是把这个操作放到了Optimizer中，所以将在第三部分讲解。

import torch.nn as nn
import torch
class DarknetConv2D_BN_Leaky(nn.Module):
def __init__(self, numIn, numOut, ksize, stride = 1, padding = 1):
super(DarknetConv2D_BN_Leaky, self).__init__()
self.conv1 = nn.Conv2d(numIn, numOut, ksize, stride, padding)#regularizer': l2(5e-4)
self.bn1 = nn.BatchNorm2d(numOut)
self.leakyReLU = nn.LeakyReLU(0.1)

def forward(self, x):
x = self.conv1(x)
x = self.bn1(x)
x = self.leakyReLU(x)
return x

# 残差模块

class ResidualBlock(nn.Module):
def __init__(self, numIn, numOut, numBlock):
super(ResidualBlock, self).__init__()
self.numBlock = numBlock
self.dark_conv1 = DarknetConv2D_BN_Leaky(numIn, numOut, ksize = 3, stride = 2, padding = 1)
self.dark_conv2 = []
for i in range(self.numBlock):
layers = []
layers.append(DarknetConv2D_BN_Leaky(numOut, numOut//2, ksize = 1, stride = 1, padding = 0))
layers.append(DarknetConv2D_BN_Leaky(numOut//2, numOut, ksize = 3, stride = 1, padding = 1))
self.dark_conv2.append(nn.Sequential(*layers))
self.dark_conv2 = nn.ModuleList(self.dark_conv2)
def forward(self, x):
x = self.dark_conv1(x)
for convblock in self.dark_conv2:
residual = x
x = self.convblock(x)
x = x + residual
return x

# 后端输出模块

class LastLayer(nn.Module):
def __init__(self, numIn, numOut, numOut2):
super(LastLayer, self).__init__()
self.dark_conv1 = DarknetConv2D_BN_Leaky(numIn, numOut, ksize = 1, stride = 1, padding = 0)
self.dark_conv2 = DarknetConv2D_BN_Leaky(numOut, numOut*2, ksize = 3, stride = 1, padding = 1)
self.dark_conv3 = DarknetConv2D_BN_Leaky(numOut*2, numOut, ksize = 1, stride = 1, padding = 0)
self.dark_conv4 = DarknetConv2D_BN_Leaky(numOut, numOut*2, ksize = 3, stride = 1, padding = 1)
self.dark_conv5 = DarknetConv2D_BN_Leaky(numOut*2, numOut, ksize = 1, stride = 1, padding = 0)

self.dark_conv6 = DarknetConv2D_BN_Leaky(numOut, numOut*2, ksize = 3, stride = 1, padding = 1)
self.conv7 = nn.Conv2d(numOut*2, numOut2, 1, stride = 1, padding = 0)

def forward(self, x):
x = self.dark_conv1(x)
x = self.dark_conv2(x)
x = self.dark_conv3(x)
x = self.dark_conv4(x)
x = self.dark_conv5(x)

y = self.dark_conv6(x)
y = self.conv7(y)
return x,y

# Yolov3模型

class Yolov3(nn.Module):
def __init__(self, numAnchor, numClass):
super(Yolov3, self).__init__()
self.dark_conv1 = DarknetConv2D_BN_Leaky(3, 32, ksize = 3, stride = 1, padding = 1)
self.res1 = ResidualBlock(32, 64, 1)
self.res2 = ResidualBlock(64, 128, 2)
self.res3 = ResidualBlock(128, 256, 8)
self.res4 = ResidualBlock(256, 512, 8)
self.res5 = ResidualBlock(512, 1024, 4)

self.last1 = LastLayer(1024, 512, numAnchor*(numClass+5))
self.up1 = nn.Sequential(DarknetConv2D_BN_Leaky(512, 256, ksize = 1, stride = 1, padding = 0),
nn.Upsample(scale_factor=2))
self.last2 = LastLayer(768, 256, numAnchor*(numClass+5))
self.up2 = nn.Sequential(DarknetConv2D_BN_Leaky(256, 128, ksize = 1, stride = 1, padding = 0),
nn.Upsample(scale_factor=2))
self.last3 = LastLayer(384, 128, numAnchor*(numClass+5))

def forward(self, x):
x = self.dark_conv1(x)#32x256x256
x = self.res1(x)#64x128x128
x = self.res2(x)#128x64x64
x3 = self.res3(x)#256x32x32
x4 = self.res4(x3)#512x16x16
x5 = self.res5(x4)#1024x8x8

x,y1 = self.last1(x5)#512x8x8,
x = self.up1(x)#256x16x16
x = torch.cat((x, x4), 1)#768x16x16
x,y2 = self.last2(x)#256x16x16
x = self.up2(x)#128x32x32
x = torch.cat((x, x3), 1)#384x32x32
x,y3 = self.last3(x)#128x32x32

return y1,y2,y3

Yolov3 论文：https://pjreddie.com/media/files/papers/YOLOv3.pdf

Yolov3 Keras实现:https://github.com/qqwweee/keras-yolo3

posted on 2018-10-25 23:24 J博士 阅读(...) 评论(...) 编辑 收藏