谈谈Darknet53为啥这么难训练

news2024/11/18 23:33:36

 在我使用Imagenet2012对Darknet53进行预训练的时候,往往训练到一半,就会出现过拟合,导致无法继续向下训练,尝试了很多方法,最后发现问题出现在下图红框的部分。

得出这个结论是因为当我使用Resnet中,包含有下采样作用的 BTNK1结构代替了上面红框里的卷积层后,模型变得可以训练了。

表现在代码里:

原代码:

class ResidualBlock(Module):
    def __init__(self, in_channels):
        super(ResidualBlock, self).__init__()
        self.conv1 = Conv2d(in_channels=in_channels, out_channels=in_channels // 2, kernel_size=1, stride=1, padding=0)
        self.bn1 = BatchNorm2d(in_channels // 2)
        self.conv2 = Conv2d(in_channels // 2, in_channels, 3, 1, 1)
        self.bn2 = BatchNorm2d(in_channels)

    def forward(self, x):
        y = self.conv1(x)
        y = self.bn1(y)
        y = leaky_relu(y)
        y = self.conv2(y)
        y = self.bn2(y)
        y = leaky_relu(y) + x
        return y

修改后的代码:

class ResidualBlock(Module):
    def __init__(self, in_channels, hidden_channels, shortcut=False, stride=1):
        super(ResidualBlock, self).__init__()
        self.conv1 = Conv2dBnLeakyReLU(in_channels, hidden_channels, 1, 1, 0)
        self.conv2 = Conv2dBnLeakyReLU(hidden_channels, hidden_channels * 4, 3, stride, 1)
        # self.conv3 = Conv2dBnLeakyReLU(hidden_channels, hidden_channels * 4, 1, 1, 0)
        self.shortcut = Conv2dBnLeakyReLU(in_channels, hidden_channels * 4, 1, stride, 0) if shortcut else None

    def forward(self, x):
        if self.shortcut is None:
            return x + self.conv2(self.conv1(x))
        else:
            return self.shortcut(x) + self.conv2(self.conv1(x))

 原模型代码:

class Darknet53(Module):
    def __init__(self, init_weights=True, num_classes=1000):
        super(Darknet53, self).__init__()
        self.conv1 = Conv2dBnLeakyReLU(3, 32, 3, 1, 1)
        self.conv2 = Conv2dBnLeakyReLU(32, 64, 3, 2, 1)
        self.residual_block1 = ResidualBlock(64)
        self.conv3 = Conv2dBnLeakyReLU(64, 128, 3, 2, 1)
        self.residual_block2 = Sequential(*([ResidualBlock(128)] * 2))
        self.conv4 = Conv2dBnLeakyReLU(128, 256, 3, 2, 1)
        self.residual_block3 = Sequential(*([ResidualBlock(256)] * 8))
        self.conv5 = Conv2dBnLeakyReLU(256, 512, 3, 2, 1)
        self.residual_block4 = Sequential(*([ResidualBlock(512)] * 8))
        self.conv6 = Conv2dBnLeakyReLU(512, 1024, 3, 2, 1)
        self.residual_block5 = Sequential(*([ResidualBlock(1024)] * 4))
        self.avg_pool = AdaptiveAvgPool2d(1)
        self.fn = Linear(1024, num_classes)

        if init_weights:
            self._initialize_weights()

修改后的模型代码:

class Darknet53(Module):
    def __init__(self, init_weights=True, num_classes=1000):
        super(Darknet53, self).__init__()
        self.conv1 = Conv2dBnLeakyReLU(3, 32, 3, 1, 1)
        # self.conv2 = Conv2dBnLeakyReLU(32, 64, 3, 2, 1)
        self.conv2 = ResidualBlock(32, 16, shortcut=True, stride=2)
        self.residual_block1 = ResidualBlock(64, 16)
        # self.conv3 = Conv2dBnLeakyReLU(64, 128, 3, 2, 1)
        self.conv3 = ResidualBlock(64, 32, shortcut=True, stride=2)
        self.residual_block2 = Sequential(*([ResidualBlock(128, 32)] * 2))
        # self.conv4 = Conv2dBnLeakyReLU(128, 256, 3, 2, 1)
        self.conv4 = ResidualBlock(128, 64, shortcut=True, stride=2)
        self.residual_block3 = Sequential(*([ResidualBlock(256, 64)] * 8))
        # self.conv5 = Conv2dBnLeakyReLU(256, 512, 3, 2, 1)
        self.conv5 = ResidualBlock(256, 128, shortcut=True, stride=2)
        self.residual_block4 = Sequential(*([ResidualBlock(512, 128)] * 8))
        # self.conv6 = Conv2dBnLeakyReLU(512, 1024, 3, 2, 1)
        self.conv6 = ResidualBlock(512, 256, shortcut=True, stride=2)
        self.residual_block5 = Sequential(*([ResidualBlock(1024, 256)] * 4))
        self.avg_pool = AdaptiveAvgPool2d(1)
        self.fn = Linear(1024, num_classes)

        if init_weights:
            self._initialize_weights()

于是有了大胆的猜测,Darknet相比Resnet,因为中间的下采样卷积层没有残差结构连接,所以模型实际上是被分割了,小loss很难向后传播到模型头部,所以会逐渐倾向于用尾部的几层网络来拟合数据,刚好Darknet的尾部很重,所以模型会逐渐走向过拟合,


以下内容就是发牢骚,但我真的好气呀,明明这么信任它。



熟悉YOLO系列的同学应该都知道,Darknet53是YOLOv3的主干网络,本人乘着暑假也在学习YOLO,从1学到了3,基本上都会用代码复现一遍,和作者所说的效果过基本吻合以后再开始新的篇章,直到遇上了Darknet53,按照作者的话说,Darknet53在ImageNet2012上的效果堪比Resnet152,而速度几乎是Resnet的2两倍。才看到这句话,我是不信的,人家Resnet152比你怎么说也多了近100层,你说这效果差不多,那Resnet家族不是很尴尬,这家人以后还怎么混是吧。但一想,YOLOv3也是久经考验的老同志了,要是数据造假,那不是早就被拖出来游街了,奈何网上又找不到相关的资料,那就自己上手训练吧。

Darknet53的网络并不复杂,用pytorch不用半个小时就搭建好了,上数据,开炼。

本人只有一张游戏显卡,为了速度上了混合精度,懒得调参,优化器用了Adam,100个epoch差不多也跑了一整天。

一看效果,在train上Top1 acc到了80,而在val上有65。这可比论文里的77.2差远了,可能是开了混合精度造成的损失?关了试一试吧,好,又是两天过去了,这次再val上的Top1 acc到了68,步子迈进了一步,可还是离77.2差了一截,难道是Adam的锅,那换SGDM再来!没想到,噩梦开始了。

自从换上SGDM,val的指标没有再突破过50,val在上升一定数值后就会逐步下降,毫无疑问,过拟合了。

batchsize小了?上梯度累计,不行!

weight_decay大了?换!,1e-4,1e-3,1e-2,1e-1,1...不行!

学习率设置大了?上指数衰减,上余弦衰减,上重启机制,全都失败。

找github看别人的代码,一行行对比,没什么区别。

怀疑过激活函数,怀疑过batchnorm,统统没用!!!

impossible!‘质子’干扰了实验。

啥都怀疑过,就是没怀疑过是网络本身的问题,毕竟有人复现过,当然都没说100%,github的同学跑出的数据是75,那也比咱强。

直到前前后后快半个月,所有能想到的方案我都试过后,一切的矛头都指向了Darknet53本身,它怎么就那么爱背答案。

砍,把后面的残差块砍掉一半。

可它死性不改,就是背。

明明Resnet50和它的层数差不多,但人家就没那么爱过拟合,到底是哪里出问题了。

抱着这个疑问,那就一点点测。

把Resnet的三层残差结构给他,不行!

把Resnet顶部的7X7卷积给他,不行!

直到!直到!直到!把Resnet用来代替池化层的BTNK1给它。

动了,它动了!问题找到了,是连接残差块的卷积层,它阻塞了loss向深度回传,在加上Darknet53很重的脚,所以只能走向过拟合。

这里面还出现了一个有意思的现象,在大学习率阶段,这种过拟合并不会太明显,但当学习率开始衰减,那么网络就会开始走向灭亡,这可能是由于在学习率较大时,loss还能有部分穿过残差块之间的间隙,而学习率逐步衰减,网络就只能靠底部的神经元进行学习了。

最后就只剩一个疑问,github上那些跑到75+的代码究竟用了什么魔法喂!。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1514755.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

力扣654 最大二叉树 Java版本

文章目录 题目描述解题思路代码 题目描述 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点,其值为 nums 中的最大值。 递归地在最大值 左边 的 子数组前缀上 构建左子树。 递归地在最大值 右边 的 子数组后缀上…

【DVWA】19. Insecure CAPTCHA 不安全的验证码(全等级)

文章目录 1. Low1) 源码分析2&#xff09;实操 2. Medium1) 源码分析2&#xff09;实操 3. High1) 源码分析2&#xff09;实操 4. Impossible1) 源码分析 1. Low 1) 源码分析 <?phpif( isset( $_POST[ Change ] ) && ( $_POST[ step ] 1 ) ) {// Hide the CAPTC…

WPF图表库LiveCharts的使用

这个LiveCharts非常考究版本&#xff0c;它有非常多个版本&#xff0c;.net6对应的是LiveChart2 我这里的wpf项目是.net6&#xff0c;所以安装的是这三个&#xff0c;搜索的时候要将按钮“包括愈发行版”打勾 git&#xff1a;https://github.com/beto-rodriguez/LiveCharts2?…

BUGKU-WEB never_give_up

题目描述 题目截图如下&#xff1a; 进入场景看看&#xff1a; 解题思路 F12查看请求和响应&#xff0c;查找线索 相关工具 base64解码URL解码Burp Suit抓包 解题步骤 F12查看请求和响应&#xff0c;发现一行注释包含一个文件名称【1p.html】&#xff0c;这应该就是提…

GaN HEMTs在电力电子应用中的交叉耦合与基板电容分析与建模

来源&#xff1a;Analysis and Modeling of Cross-Coupling and Substrate Capacitances in GaN HEMTs for Power-Electronic Applications&#xff08; TED 17年&#xff09; 摘要 本文提出了一种考虑了基板电容与场板之间交叉耦合效应的场板AlGaN/GaN高电子迁移率晶体管(HE…

RabbitMQ自学笔记——消息可靠性问题

1.发送者的可靠性 1.1生产者重连 有时由于网络波动等原因&#xff0c;发送方一次可能没有连接上RabbitMQ&#xff0c;我们可以配置发送方的连接失败重试机制。但需要注意的是&#xff1a;SpringAMQP提供的重试机制是阻塞式的重试&#xff0c;也就是说多次重试等待的过程中&am…

[JAVAEE]—进程和多线程的认识

文章目录 什么是线程什么是进程进程的组成什么是pcb 进程概括线程线程与进程的关系线程的特点 创建线程创建线程方法创建线程的第二种方法对比 其他的方式匿名内部类创建线程匿名内部类创建Runable的子类lambda表达式创建一个线程 多线程的优势 什么是线程 什么是进程 首先想…

iOS 判断触摸位置是否在图片的透明区域

装扮功能系列&#xff1a; Swift 使用UIScrollerView 实现装扮功能&#xff08;基础&#xff09;Swift 使用UIScrollerView 实现装扮功能&#xff08;拓展&#xff09;iOS 判断触摸位置是否在图片的透明区域 背景 在装扮功能中&#xff0c;一般都是长按使道具进入编辑状态&…

ES分布式搜索-使用RestClient操作索引库

RestClient操作索引库 1、什么是RestClient&#xff1f; ES官方提供了各种不同语言的客户端&#xff0c;用来操作ES。这些客户端的本质就是组装DSL语句&#xff0c;通过http请求发送给ES。官方文档地址&#xff1a;Elasticsearch Clients官方文档 2、利用JavaRestClient实现…

软考高级:软件架构风格-闭环控制概念和例题

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;大厂高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《Effective Java》独家解析》专栏作者。 热门文章推荐&am…

Python 查找PDF中的指定文本并高亮显示

在处理大量PDF文档时&#xff0c;有时我们需要快速找到特定的文本信息。本文将提供以下三个Python示例来帮助你在PDF文件中快速查找并高亮指定的文本。 查找并高亮PDF中所有的指定文本查找并高亮PDF某个区域内的指定文本使用正则表达式搜索指定文本并高亮 本文将用到国产第三方…

Java学习笔记(11)

面向对象进阶 Static 静态变量 所有对象一起共享&#xff0c;就用static修饰 不属于对象&#xff0c;属于类的 可以用 类名.静态变量 “”&#xff1b;赋值 但是 对象.静态变量也可以访问到内容 Static内存图 Student这个类的字节码文件加载到方法区&#xff0c;并在内…

企业计算机服务器中了eking勒索病毒怎么办?Eking勒索病毒解密工具流程

网络数据安全问题一直是众多企业关心的主要话题&#xff0c;网络在为企业提供便利的同时&#xff0c;也为企业数据安全带来未知的隐患。近日&#xff0c;云天数据恢复中心接到许多企业求助&#xff0c;企业的计算机服务器遭到了eking勒索病毒攻击导致企业计算机服务器系统瘫痪无…

操作系统——cpu、内存、缓存介绍

一、内存是什么 内存就是系统资源的代名词&#xff0c;它是其他硬件设备与 CPU 沟通的桥梁&#xff0c; 计算机中的所有程序都在内存中运行。其作用是暂时存放CPU的运算数据&#xff0c;以及与硬盘交换的数据。也是相当于CPU与硬盘沟通的桥梁。只要计算机在运行&#xff0c;CP…

YOLOv9实例分割教程|(一)训练教程

专栏介绍&#xff1a;YOLOv9改进系列 | 包含深度学习最新创新&#xff0c;主力高效涨点&#xff01;&#xff01;&#xff01; 一、创建数据集及数据配置文件 创新一个文件夹存放分割数据集&#xff0c;包含一个images和labels文件夹。标签格式如下所示&#xff1a; 创新数据集…

Netty线程模型详解

文章目录 概述单Reactor单线程模型单Reactor多线程模型主从Reactor多线程模型 概述 Netty的线程模型采用了Reactor模式&#xff0c;即一个或多个EventLoop轮询各自的任务队列&#xff0c;当发现有任务时&#xff0c;就处理它们。Netty支持单线程模型、多线程模型和混合线程模型…

1、计划任务介绍

Windows计划任务介绍 1、含义&#xff1a; 简单点就是定时执行任务。 在许多场景下&#xff0c;我们定时执行一些任务。比如&#xff1a;定时拉取、备份文件&#xff0c;更新代码等等操作。 WinR打开运行框&#xff0c;输入&#xff1a;control schedtasks&#xff0c;就会…

SAR ADC系列4——比较器的Transient noise仿真--等效输入噪声

仿真出等效输入噪声 加一个快于实际工作的时钟频率&#xff1b;在输入端加一个DC的差&#xff08;比如一端是0.5VDD&#xff0c;另外一端加0.5VDD0.2MV)计算仿真时间内的correct counting number&#xff0c;比如时钟频率是200MHz&#xff0c;仿真时间是5us&#xff0c;那么应…

IMX8MM -- Yocto构建遇见的错误及解决方法:

IMX8MM Yocto构建遇见的错误及解决方法&#xff1a; 1 bison-3.0.4 error2 Opencv BB_NO_NETWORK Error &#xff1a;3 Yocto构建时出现U-boot 问题4 Yocto构建时出现Linux kernel编译问题5 wayland-native6 cross-localedef-native7 wayland-protocols8 mesa 硬件&#xff1a;…

[论文精读]Dynamic Coarse-to-Fine Learning for Oriented Tiny Object Detection

论文网址&#xff1a;[2304.08876] 用于定向微小目标检测的动态粗到细学习 (arxiv.org) 论文代码&#xff1a;https://github.com/ChaselTsui/mmrotate-dcfl 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&…