yolov4权重文件.pth转.weight

求一个把yolov4在pytorch中训练的.pth权重文件转为在darknet中训练的.weight权重文件的脚本

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 这篇博客也许可以解决你的问题👉 :yolov3(pytorch)训练问题,完美解决./darknet无法运行问题
  • 除此之外, 这篇博客: YOLOv3 损失函数详解【论文笔记 + pytorch实现 附.pth权重文件】中的 2 Darknet-53网络结构 部分也许能够解决你的问题, 你可以仔细阅读以下内容或者直接跳转源博客中阅读:

         首先回想一下

    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。

  • 以下回答来自chatgpt:

    我可以为您提供一份将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文件。

    希望能对您有所帮助!


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^