求一个把yolov4在pytorch中训练的.pth权重文件转为在darknet中训练的.weight权重文件的脚本
不知道你这个问题是否已经解决, 如果还没有解决的话:首先回想一下
YOLOv2中提出的Darknet-19网络结构作为主干特征提取网络。考虑到对于小物体的检测,结合FPN(特征金字塔)的思想,YOLOv2简单添加一个 passthrough layer,把浅层特征图(分辨率为26 × 26,即提取特征图的倒数第二卷积层结果)连接到深层特征图。通过把高低分辨率的特征图做连结,叠加相邻特征到不同通道(而非空间位置),类似于ResNet中的identity mappings。 在YOLOv3中,作者可能觉得Darknet-19网络还是不够深(因为更深的网络结构可以学习到更加丰富的特征),故再次借鉴ResNet网络和FPN(特征金字塔)的思想,提出了Darknet-53
网络结构,如下图所示(图片来源)。
Darknet53中的Residual Block
进行一次3X3、步长为2的卷积,然后保存该卷积结果layer;再进行一次1X1的卷积和一次3X3的卷积,并把这个结果加上layer作为最后的结果。 残差网络的特点是容易优化,并且能够通过增加相当的深度来提高准确率。其内部的残差块使用了跳跃连接,缓解了在深度神经网络中增加深度带来的梯度消失问题。
上图中左半部分虚线框内即为Darknet-53网络机构,可以看到该网络结构的输入为 416×416×3
,之后通过一个3×3
的卷积层来扩增通道数。接下来通过堆叠一系列Residual Block来构建网络,其具体个数为[1, 2, 8, 8, 4]
,最终主干网络输出大小为13×13、26×26、52×52
三个大小的特征图,目的是可以检测到图像中更小的物体。特征图分割越密集,则每一个特征点相对于原图中的区域越小,从而可以监测到更小的物体。
下图为9种先验框的尺寸,其中蓝色框为聚类得到的先验框。黄色框是ground truth,红框是检测对象中心点所在的网格。
Darknet-53主干网络代码如下:
import torch
import torch.nn as nn
import math
from collections import OrderedDict
# 基本的darknet块
class BasicBlock(nn.Module):
def __init__(self, inplanes, planes): # resnet block中是 先进行一个1×1卷积 再进行一个3×3卷积
super(BasicBlock, self).__init__()
self.conv1 = nn.Conv2d(inplanes, planes[0], kernel_size=1, # 1×1卷积目的是下降通道数
stride=1, padding=0, bias=False)
self.bn1 = nn.BatchNorm2d(planes[0])
self.relu1 = nn.LeakyReLU(0.1)
self.conv2 = nn.Conv2d(planes[0], planes[1], kernel_size=3, # 3×3卷积目的是扩张通道数,注意这里并不减少特征图的大小!!
stride=1, padding=1, bias=False) # 这样做可以帮助减少参数量
self.bn2 = nn.BatchNorm2d(planes[1])
self.relu2 = nn.LeakyReLU(0.1)
def forward(self, x):
residual = x
out = self.conv1(x)
out = self.bn1(out)
out = self.relu1(out)
out = self.conv2(out)
out = self.bn2(out)
out = self.relu2(out)
out += residual
return out
class DarkNet(nn.Module):
def __init__(self, layers):
super(DarkNet, self).__init__()
self.inplanes = 32
self.conv1 = nn.Conv2d(3, self.inplanes, kernel_size=3, stride=1, padding=1, bias=False) # 第一个卷积 3->32
self.bn1 = nn.BatchNorm2d(self.inplanes)
self.relu1 = nn.LeakyReLU(0.1)
self.layer1 = self._make_layer([32, 64], layers[0])
self.layer2 = self._make_layer([64, 128], layers[1])
self.layer3 = self._make_layer([128, 256], layers[2])
self.layer4 = self._make_layer([256, 512], layers[3])
self.layer5 = self._make_layer([512, 1024], layers[4])
self.layers_out_filters = [64, 128, 256, 512, 1024]
# 进行权值初始化
for m in self.modules():
if isinstance(m, nn.Conv2d):
n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
m.weight.data.normal_(0, math.sqrt(2. / n))
elif isinstance(m, nn.BatchNorm2d):
m.weight.data.fill_(1)
m.bias.data.zero_()
def _make_layer(self, planes, blocks): # 进行下采样且不断堆叠残差块
layers = []
# 下采样,步长为2,卷积核大小为3,用于减少特征图尺寸
layers.append(("ds_conv", nn.Conv2d(self.inplanes, planes[1], kernel_size=3,
stride=2, padding=1, bias=False)))
layers.append(("ds_bn", nn.BatchNorm2d(planes[1])))
layers.append(("ds_relu", nn.LeakyReLU(0.1)))
# 加入darknet模块
self.inplanes = planes[1]
for i in range(0, blocks):
layers.append(("residual_{}".format(i), BasicBlock(self.inplanes, planes)))
return nn.Sequential(OrderedDict(layers))
def forward(self, x):
x = self.conv1(x)
x = self.bn1(x)
x = self.relu1(x)
x = self.layer1(x)
x = self.layer2(x)
out3 = self.layer3(x)
out4 = self.layer4(out3)
out5 = self.layer5(out4)
return out3, out4, out5
# pretrained为权重文件路径
def darknet53(pretrained, **kwargs):
model = DarkNet([1, 2, 8, 8, 4])
if pretrained:
if isinstance(pretrained, str):
model.load_state_dict(torch.load(pretrained))
else:
raise Exception("darknet request a pretrained path. got [{}]".format(pretrained))
return model
网络结构的右半部分包括将主干网络Darknet-53的输出进行生成特征金字塔。具体做法为首先将13×13×1024
的特征层进行上采样变为26×26×256
,再与26×26×512
的特征层进行堆叠,其结果为26×26×768
大小的特征;同理,大小为52×52×256
的特征层与下一层网络堆叠后的结果为52×52×384
。
对于这三个堆叠后的结果,分别在进行5次卷积操作,最后接上一个3×3
的卷积和1×1
的卷积,用于输出预测结果,三个层对应的输出结果大小分别为13×13×75、26×26×75、52×52×75
。其中75 = (4+1+20)×3
,4表示一个边界框对应的调整参数x, y, w, h
,1表示置信度,20表示VOC数据集分为20个类,3表示特征图上的每一个点对应有3个anchor。
我可以为您提供一份将yolov4在pytorch中训练所得的.pth权重文件转换为darknet中训练所需的.weight权重文件的脚本。
首先,您需要安装好Pytorch和Darknet框架,并下载好权重文件。
步骤如下:
1.新建weights文件夹,在其中放入pytorch训练得到的.pth权重文件和darknet的配置文件。请确保配置文件和权重文件的名称和路径与下面的代码中相对应。
2.在终端中运行以下代码:
pip install pytorch2darknet
# 导入相关库
import pytorch2darknet
# 输入pytorch权重文件路径和darknet的cfg配置文件路径,生成相应的.darknet权重文件
pytorch2darknet.pytorch_2_darknet('path_to_pytorch_weights.pt', 'path_to_darknet_cfg.cfg', output_path='output_path_to_weights.weight')
将上述代码中的“path_to_pytorch_weights.pt”替换为pytorch训练得到的.pth权重文件的路径;将“path_to_darknet_cfg.cfg”替换为darknet配置文件的路径;将“output_path_to_weights.weight”替换为将要输出的权重文件的路径。
提醒:如果您使用的不是yolov4,而是其他版本的yolo,请将以上过程中的“darknet.cfg”文件换成您所使用yolo对应的cfg文件。
希望能对您有所帮助!