完整代码百度云直达链接(包含预训练权重)(小白注释)
https://pan.baidu.com/s/1US6e93OaCYOghmF21v0UIA
提取码:z8at
参考链接
【注】代码是大神的代码,在此基础上添加了详细的小白注释,方便我以后阅读。
本系列代码基于yolov3的pytorch版本。
本节代码所在文件pytorch_yolo3/nets/darknet.py
darknet53网络结构图
文字版:卷积+(下采样卷积+1残差块)+(下采样卷积+2残差块)+(下采样卷积+8残差块)+(下采样卷积+8残差块)+(下采样卷积+4*残差块)
鸣谢:图片来源

是不是很有规律?不难看出,darknet53就是重复堆叠下采样卷积+n*残差块(n为残差块的个数)这个结构而组成的。而更基本的结构就是残差块了,因此我们先构建出残差块,然后重复堆叠上述结构darknet53就完成了。
残差块结构
残差块结构不止下图这一种,但我们只讨论darknet53中用到的这种。如下图所示,残差块结构由两条支路组成,一条支路将上一层输出的feature map进行卷积等操作,另一条支路将上一层输出的feature map恒等映射,并与刚才卷积操作完的feature map进行逐元素相加,因此两条支路的通道数必须相等。也就是说发生卷积等操作的那条支路(残差路)的输出不能改变feature map的通道数。

另外,darknet53在所有的卷积之后和激活(leakyrelu)之前会插入bn层(batch normalization)。
import torch
import torch.nn as nn
# 残差模块
class ResidualBlock(nn.Module):
def __init__(self,inplanes,planes):
# inplanes是下采样卷积完输入到残差支路的通道数,planes是一个列表,planes[0]是残差第一个卷积操作输出通道数,也是第二个卷积操作输入通道数
# planes[1]是残差第二个卷积操作输出通道数
super(ResidualBlock,self).__init__()
# 残差支路的第一个卷积操作:卷积核1*1,步长1,不填充,不加偏置
self.conv1 = nn.Conv2d(inplanes,planes[0],kernel_size=1,stride=1,padding=0,bias=False)
# bn层的输入参数是上一层输出的通道数
self.bn1 = nn.BatchNorm2d(planes[0])
# LeakyReLU的参数是负半轴的斜率,正半轴是1
self.relu1 = nn.LeakyReLU(0.1)
# 残差支路的第二个卷积操作:卷积核3*3,步长1,填充1(p=1),不加偏置
# 卷积输出尺寸计算公式 (n-f+2p)/s+1 此处f=3,p=1,s=1
self.conv2 = nn.Conv2d(planes[0],planes[1],kernel_size=3,stride=1,padding=1,bias=False)
self.bn2 = nn.BatchNorm2d(planes[1])
self.relu2 = nn.<

本文基于yolov3的pytorch版本,详细介绍了darknet53网络的构建。先给出代码百度云链接,接着阐述darknet53由重复堆叠下采样卷积+n*残差块组成,分析了残差块结构,说明了基本结构为下采样卷积+残差块,最后完成darknet53网络构建,还提及后续将详解yolo3整体网络代码。
8564

被折叠的 条评论
为什么被折叠?



