谈谈Darknet53为啥这么难训练

 在我使用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) + xreturn 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 Nonedef 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.mzph.cn/news/743009.shtml

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

相关文章

Java集合基础知识总结(绝对经典)

List接口继承了Collection接口,定义一个允许重复项的有序集合。该接口不但能够对列表的一部分进行处理,还添加了面向位置的操作。 实际上有两种list:一种是基本的ArrayList,其优点在于随机访问元素,另一种是更强大的L…

利用HubSpot出海CRM和人工智能技术提升出海业务的效率和效果

在当今数字化时代,智能化营销已经成为企业获取客户和扩大市场份额的关键策略。特别是对于出海业务而言,利用智能化营销技术来应对不同文化、语言和市场的挑战,已经成为企业竞争的关键优势。今天运营坛将带领大家探讨如何利用HubSpot CRM和人工…

技术方案|某工业集团PaaS容灾方案

在当今快速发展的数字化时代,业务的连续性和稳定性已成为企业核心竞争力的重要组成部分。然而,由于各种原因,企业常常面临着数据丢失、系统瘫痪等潜在风险。因此,制定一套科学、高效的容灾方案至关重要。本文将围绕某全球领先的工…

css实现梯形?

HTML: <div class"box"></div> CSS: .box{width:50px;height:0;border-bottom:50px solid pink;border-left:50px solid #fff;border-right:50px solid #fff; } 效果&#xff1a;

opencv dnn模块 示例(25) 目标检测 object_detection 之 yolov9

文章目录 1、YOLOv9 介绍2、测试2.1、官方Python测试2.1.1、正确的脚本2.2、Opencv dnn测试2.2.1、导出onnx模型2.2.2、c测试代码 2.3、测试统计 3、自定义数据及训练3.1、准备工作3.2、训练3.3、模型重参数化 1、YOLOv9 介绍 YOLOv9 是 YOLOv7 研究团队推出的最新目标检测网络…

IDEA开启Run Dashboard

1、Run Dashboard是什么&#xff0c;为什么要使用 Run Dashboard 是 IntelliJ IDEA 中的一个工具窗口&#xff0c;用于管理和监视项目中正在运行的应用程序和配置。它提供了一种集中管理运行和调试过程的方式&#xff0c;可以让开发人员更方便地查看和控制正在运行的应用程序。…

2061:【例1.2】梯形面积

时间限制: 1000 ms 内存限制: 65536 KB 提交数:201243 通过数: 79671 【题目描述】 在梯形中阴影部分面积是150平方厘米&#xff0c;求梯形面积。 【输入】 (无&#xff09; 【输出】 输出梯形面积&#xff08;保留两位小数&#xff09;。 【输入样例】 &#xff…

数据结构-链表(二)

1.两两交换列表中的节点 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09;。 输入&#xff1a;head [1,2,3,4] 输出&#xff1a;[2…

Java学习笔记------常用API(三)

BigInteger 在Java中&#xff0c;整数类型有四种类型&#xff1a;byte&#xff08;一个字节&#xff09;、short&#xff08;2个字节&#xff09;、int&#xff08;四个字节&#xff09;、long&#xff08;8个字节&#xff09; 超出取值范围上面类型无法使用&#xff0c;这时…

Docker学习之容器管理(超详解析)

容器相关命令&#xff1a; 容器操作&#xff1a; 启动容器 方法1:先创建一个容器&#xff1a;docker create 镜像名再启动容器&#xff1a;docker start 容器名(不推荐) [rootlocalhost ~]# docker create -it myubuntu:18.04 //创建容器 7bc99c9ea102ab49cc400437824a954949…

白酒:生产过程的智能化与自动化升级改造

在当今的工业生产中&#xff0c;智能化与自动化已成为提进一步率、品质和竞争力的关键因素。云仓酒庄紧跟时代步伐&#xff0c;对豪迈白酒的生产过程进行了一系列智能化与自动化升级改造&#xff0c;旨在提升生产效率、确保产品质量的同时&#xff0c;降低生产成本。 首先&…

Express学习(四)

使用Express写接口 创建基本的服务器 创建API路由模块 编写GET接口 编写POST接口 CORS跨域资源共享 什么是CORS CORS由一系列HTTP响应头组成&#xff0c;这些HTTP响应头决定浏览器是否阻止前端JS代码跨域获取资源。浏览器的同源安全策略默认会阻止网页“跨域”获取资源。但如…

数据结构和算法:栈与队列

栈 栈 &#xff08;stack&#xff09;是一种遵循先入后出逻辑的线性数据结构 把堆叠元素的顶部称为“栈顶”&#xff0c;底部称为“栈底”。 将把元素添加到栈顶的操作叫作“入栈”&#xff0c;删除栈顶元素的操作叫作“出栈”。 栈的常用操作 /* 初始化栈 */ stack<int&g…

专升本 C语言笔记-07 逗号运算符

1.逗号表达式的用法 就是用逗号隔开的多个表达式。逗号表达式&#xff0c;从左向右依次执行。 2.逗号表达式的特性 2.1.当没有括号时&#xff0c;第一个表达式为整个表达式的值。 代码 int x 3,y 5,a 0; a x,y; printf("a %d",a); 说明:因为逗号优先级最低,会…

【CSS颜色】

本文章属于学习笔记&#xff0c;在https://www.freecodecamp.org/chinese/learn/2022/responsive-web-design/中练习 三、CSS颜色 1、有两种主要的颜色模型:电子设备中使用的加性RGB(红、绿、蓝)模型和印刷品中使用的减色CMYK(青色、品红、黄色、黑色)模型。 使用RGB模型。这…

学习JAVA的第二十一天(基础)

多线程 线程&#xff1a; 线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中&#xff0c;是进程中的实际运作单位。 进程&#xff1a; 程序的基本执行实体 并发&#xff1a; 在同一时刻&#xff0c;有多个指令在单个CPU上交替执行 并行&#xff1a; 在同一时刻&…

【C语言】Windows下的C语言线程编程详解

文章目录 1. 头文件1.1 windows.h1.2 process.h 2. 创建线程3. 线程同步3.1 线程同步方式3.1 互斥量&#xff08;Mutex&#xff09;3.2 事件&#xff08;Event&#xff09; 4. 线程的结束与资源管理5.线程池&#xff08;简要&#xff09; 在Windows平台下&#xff0c;C语言提供…

活动会议线上直播,如何扩大曝光?媒体直播分流解析

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 线上直播扩大曝光与媒体直播分流解析 一、扩大曝光策略&#xff1a; 平台选择&#xff1a;选择用户基数大、活跃度高的直播平台进行直播。 预告宣传&#xff1a;提前发布直播预告&…

k8s-Istio服务网络 27

官网&#xff1a;https://istio.io/latest/zh/about/service-mesh/ Istio与k8s的区别 SpringCloud传统微服务结合k8s与Istio与k8s结合&#xff1a; Istio数据面&#xff1a;通过envoy以sidecar方式拦截svc的流量来进行治理。 Istio控制面&#xff1a;pilot list/watch APIserv…

HarmonyOS NEXT应用开发之异常处理案例

介绍 本示例介绍了通过应用事件打点hiAppEvent获取上一次应用异常信息的方法&#xff0c;主要分为应用崩溃、应用卡死以及系统查杀三种。 效果图预览 使用说明&#xff1a; 点击构建应用崩溃事件&#xff0c;3s之后应用退出&#xff0c;然后打开应用进入应用异常页面&#x…