☰
DSOD从零训练目标检测器:深层监督与密集连接替代预训练
2026/10/12 13:24:52 网站建设 项目流程

1. 从零训练检测器这件事,到底卡在哪

目标检测这个领域,过去这些年基本被一条默认规则统治着:想得到一个能用的检测器,先拿一个在大型分类数据集上训过的骨干网络来初始化,然后再到检测数据集上做微调。这条路线从 Faster R-CNN 时代开始就成了标配,后来 SSD、YOLO、RetinaNet 一路沿用,大家默认"预训练骨干"是必需品,就像做菜默认得先有口锅一样。

但这里有个问题一直被有意无意地忽略了:预训练模型本身不是凭空来的。它需要海量带标签的分类数据、大量的算力、漫长的训练周期。当你想把检测能力迁移到一个全新领域时,比如某种特殊的工业质检场景、某种少见的遥感目标、或者一个数据分布和通用分类集差得很远的任务,那个预训练骨干带来的"先验知识"未必是助力,有时反而是包袱。更现实的是,很多场景下你根本拿不到合适的预训练权重,或者不允许使用外部数据,这时候整条路线就卡死了。

DSOD(Deeply Supervised Object Detector)就是冲着这个卡点去的。它要回答一个很硬核的问题:如果完全不用任何预训练模型,从随机初始化开始,能不能训出一个精度可用的目标检测器?这不是一个纯学术的好奇心,它背后对应的是真实工程里"数据不能外流""没有可用预训练权重""需要端到端从头定制"这类约束。我最初接触这个方向,就是因为手上有个项目明确要求所有训练数据必须来自自有数据集,任何外部预训练权重都不能引入,当时第一反应是"这精度怕是要崩",后来把 DSOD 的思路啃了一遍,才发现它把"从零训练"这件事拆解得相当有章法。

这篇文章我会把 DSOD 的核心机制、它为什么能work、具体怎么落地、以及我在复现过程中踩过的坑,完整地讲一遍。适合两类人看:一类是想理解"无预训练检测"底层逻辑的算法同学,另一类是手上真有从零训练需求、需要一套可操作方案的工程同学。不需要你事先精通检测框架,但最好对卷积网络和检测的基本流程有个概念,不然有些地方会有点吃力。

2. 无预训练检测为什么难,难在哪个环节

2.1 预训练骨干到底给了检测器什么

要理解 DSOD 的价值,得先搞清楚预训练模型在检测任务里究竟贡献了什么。很多人以为预训练只是"让网络收敛快一点",这个理解太浅了。预训练骨干实际上提供了三样东西,而且这三样缺一不可。

第一是通用的底层特征提取能力。卷积网络的前几层学到的是边缘、纹理、颜色块这类低级特征,这些特征在任何视觉任务里都通用。预训练相当于把这些通用特征提前学好了,检测训练时不用从零去学"什么是边缘"。

第二是良好的初始化分布。随机初始化的网络,权重是高斯噪声,前向传播时特征图的值分布很乱,梯度也乱。预训练权重让网络一开始就处在一个"特征有结构"的状态,优化器不用在早期浪费大量迭代去把权重从噪声拉到一个合理区间。

第三是隐式的正则化效果。预训练在大数据集上学到的特征本身带有泛化性,相当于给检测训练加了一个强先验,能缓解小数据集上的过拟合。

DSOD 要做的,就是在完全没有这三样东西的前提下,靠网络结构设计和训练策略,把这三样"补"回来。这就是它的核心命题。

2.2 从零训练检测器的三个真实障碍

我在实际尝试从零训练检测器时,遇到的障碍可以归成三类,这三类也正好对应 DSOD 要解决的三个问题。

障碍一:梯度消失导致深层网络训不动。检测骨干通常要十几到几十层,从随机初始化开始,反向传播的梯度传到浅层时已经衰减得几乎为零,浅层权重基本不更新,整个网络等于只有后半部分在学。这个问题在分类任务里靠 BatchNorm 和残差连接缓解了不少,但检测任务因为还有额外的检测头和多尺度分支,情况更复杂。

障碍二:特征复用不足,参数效率低。预训练骨干的一个隐藏好处是,它的特征被下游任务反复复用。而从零训练时,如果网络设计得不好,浅层特征和深层特征之间缺乏有效连接,每个尺度都得自己从头学特征,参数利用率极低,收敛自然慢。

障碍三:多尺度检测的监督信号太稀疏。检测任务本身的正样本就少(相比分类),多尺度检测里每个尺度分到的监督信号更少。从零训练时,这种稀疏监督会让某些尺度的分支学得非常慢,甚至学废。

理解了这三个障碍,再看 DSOD 的设计,就会发现它的每一个改动都不是拍脑袋,而是精准地对着某个障碍去的。

3. DSOD 的两把核心武器:深层监督与密集连接

3.1 深层监督:让每一层都收到明确的梯度

DSOD 全称里的"Deeply Supervised"是它的第一把武器。传统检测网络里,监督信号只在最后的检测头产生,梯度要一层层往回传,传到浅层时已经很弱。深层监督的思路是:在网络中间的多个层级都接出辅助的检测分支,让这些中间层也直接收到检测损失的监督。

这个思路不是 DSOD 首创,GoogLeNet 里的辅助分类器就是这个思想。但 DSOD 把它用在了检测任务上,而且做得更彻底。具体来说,它在骨干网络的多个阶段后面都挂上检测头,每个检测头都产生自己的分类损失和回归损失,这些损失加权求和后一起反传。

这样做的好处很直接:浅层不再只能通过深层间接获得梯度,而是有了自己的"直达通道"。梯度不用穿越十几层才到达浅层,衰减问题被大幅缓解。我在复现时对比过,加了深层监督之后,浅层权重的更新幅度明显变大,前几个 epoch 的特征图可视化出来,边缘响应比不加时清晰得多。

这里有个实操细节值得说:辅助分支的损失权重不能设得和主分支一样大。我一开始图省事,所有分支权重都设成 1.0,结果训练早期辅助分支的损失主导了优化,主检测头的收敛反而被拖慢。后来把辅助分支权重降到 0.3 到 0.5 之间,主分支保持 1.0,整体收敛曲线才正常。这个权重具体取多少,和你的数据集规模、网络深度都有关,建议从 0.4 开始试。

3.2 密集连接:把特征复用做到极致

第二把武器是密集连接(Dense Connection),这也是 DSOD 名字里"DS"容易被误解的地方——它其实同时指 Deeply Supervised 和 Dense Structure。密集连接的核心思想是:每一层的输入不仅来自上一层,而是来自前面所有层的拼接。

在标准卷积网络里,第 L 层的输入只有第 L-1 层的输出。密集连接里,第 L 层的输入是第 1 到 L-1 层所有输出的拼接。这意味着浅层特征可以直接"跳"到很深的层,不用经过中间层的逐层变换。

对从零训练来说,这个设计解决了前面说的"特征复用不足"问题。浅层学到的通用特征,通过密集连接被深层直接复用,深层不用重新学一遍。参数效率上去了,收敛自然快。而且密集连接还有个副作用是梯度流更顺畅,因为反向传播时梯度可以通过这些跳跃连接直接回到浅层,和深层监督形成互补。

不过密集连接有个众所周知的代价:显存占用大。因为每层都要拼接前面所有层的特征图,特征图的通道数会线性增长。我在一张显存有限的卡上跑的时候,不得不把增长率(growth rate,即每层新增的通道数)从常见的 48 降到 32,才勉强跑起来。如果你的显存也紧张,这个参数是第一个该动的。

3.3 两者结合为什么能替代预训练

单独看深层监督和密集连接,都是已知的技术。DSOD 的贡献在于把它们组合起来,并且证明了这个组合能替代预训练。逻辑是这样的:

密集连接保证了特征的高效复用和顺畅的梯度流,让深层网络从随机初始化开始就能训得动;深层监督保证了每一层都有明确的监督信号,让浅层也能快速学到有用的特征。两者叠加,等于把预训练提供的"通用特征"和"良好初始化"这两个好处,用结构设计的方式补了回来。

至于第三个好处"正则化",DSOD 靠的是检测任务本身的多样性和密集连接带来的隐式正则。实测下来,在中等规模数据集上,DSOD 从零训练的精度能接近甚至在某些类别上超过用预训练骨干的同类检测器,这个结果第一次看到时确实有点反直觉。

4. 把 DSOD 跑起来:结构搭建与训练配置

4.1 骨干网络的具体搭建方式

DSOD 的骨干是基于 DenseNet 改造的,但不是照搬。我按自己的理解把关键结构列一下,方便你对照实现。

整个骨干分成几个 stage,每个 stage 由若干个密集块(Dense Block)和过渡层(Transition Layer)组成。密集块内部是密集连接,过渡层负责下采样和通道压缩。和标准 DenseNet 的区别主要在两点:一是去掉了最后的全局池化和分类层,换成检测头;二是为了检测任务调整了各 stage 的输出分辨率和通道数。

一个我实际用过的配置大致是这样:输入分辨率 300x300,第一个卷积层用 stride 2 下采样到 150x150,然后四个 stage 分别输出 150、75、38、19 的分辨率,对应检测的四个尺度。增长率设 32,每个密集块的层数从 4 到 8 递增。这个配置在单卡 11G 显存上能跑 batch size 8 左右。

提示:如果你是从 SSD 的代码改过来,注意 DSOD 的默认框(prior box)设置和 SSD 不完全一样。DSOD 因为特征来源不同,各尺度的感受野分布有差异,默认框的尺度和长宽比需要重新统计。我一开始直接套用 SSD 的默认框配置,小目标的召回明显偏低,后来按自己数据集的标注框分布重新聚类了一遍才正常。

4.2 训练超参的取舍逻辑

从零训练和微调训练,超参策略差别很大,这是很多人容易忽略的地方。微调时学习率可以设得很小,因为权重已经在一个好位置了;从零训练时,学习率设太小根本训不动,设太大又容易发散。

我的经验是,从零训练的初始学习率要比微调大一个量级左右。如果用 SGD,初始学习率可以设到 0.1 附近,配合 warmup——前 500 到 1000 次迭代把学习率从很小的值线性升到初始值。warmup 这一步在从零训练里几乎是必须的,因为随机初始化的网络在最初几次迭代梯度非常不稳定,直接上大学习率很容易把权重带飞。

权重衰减我设的是 5e-4,比微调常用的 1e-4 大一些,目的是加强正则,缓解从零训练容易过拟合的问题。动量用 0.9。学习率衰减用余弦退火或者阶梯衰减都行,我倾向余弦退火,因为从零训练的收敛曲线更平滑,余弦退火不容易在衰减点出现震荡。

BatchNorm 在从零训练里作用被放大了。因为没有了预训练权重的"稳定分布",BatchNorm 成了维持各层输入分布稳定的关键。我建议骨干里每个卷积后面都跟 BatchNorm,检测头里也是。有个细节:如果 batch size 太小(比如小于 4),BatchNorm 的统计量会很不准,这时候可以考虑用 GroupNorm 替代,代价是收敛稍慢一点。

4.3 数据增强的强度要重新拿捏

从零训练对数据增强的依赖比微调更强,因为模型没有预训练先验,全靠数据本身提供多样性。但增强强度也不能无脑拉满,太强会让本来就难训的模型更训不动。

我实际用的增强组合是:随机裁剪加缩放、随机水平翻转、颜色抖动(亮度、对比度、饱和度各 0.3 左右)。 mosaic 增强我试过,在从零训练早期反而有害,因为拼接后的图像分布和自然图像差太多,模型早期学不到干净的特征。我的做法是前 1/3 的训练轮次不用 mosaic,等模型基本收敛了再开启,效果比全程开启好。

另外一个小技巧:从零训练时,前几个 epoch 可以先用较小的输入分辨率,比如 224,让模型先学到大致的特征,再切到 300 或更高分辨率精调。这样能省不少早期算力,收敛也更稳。

5. 复现路上我踩过的那些坑

5.1 损失不下降,先别急着调学习率

我第一次跑 DSOD 的时候,训练了十几个 epoch,总损失几乎不动,第一反应是学习率设小了,调大之后直接发散。后来冷静下来逐项排查,发现问题出在默认框的匹配策略上。

检测训练里,每个默认框要和真实框做匹配,匹配上的才算正样本参与分类和回归损失。如果匹配阈值设得不合理,正样本太少,损失自然降不下去。我当时的匹配阈值沿用了某个开源实现的默认值,但那个值是为预训练模型调的,从零训练时特征还没学好,预测框和真实框的 IoU 普遍偏低,导致大量本该是正样本的框被划成了负样本。

把匹配阈值适当放宽之后,正样本数量上来了,损失立刻开始正常下降。这个坑的教训是:从零训练时,很多为预训练模型调好的超参都需要重新审视,尤其是和正负样本划分相关的。

5.2 某个尺度的分支学废了怎么办

多尺度检测里,我遇到过某个尺度(通常是最大的那个,负责小目标)的损失一直居高不下,其他尺度都正常。排查下来有两个原因。

一是那个尺度的特征图分辨率最高,计算量最大,但分到的监督信号相对少。解决办法是给这个尺度的损失加一点权重,或者在这个尺度上多接一个辅助监督分支。二是那个尺度的默认框尺度和数据集里的目标尺寸不匹配,这个就得回到数据统计,重新设计默认框。

我后来养成了一个习惯:训练前先统计数据集里所有标注框的宽高分布,画个散点图,然后按分布来设计各尺度的默认框。这个步骤花不了多少时间,但能省掉后面大量的调参。

5.3 显存不够时的取舍顺序

密集连接吃显存是硬伤。显存不够时,按我的经验,调整的优先级是这样的:

调整项对精度影响对显存影响建议优先级
降低增长率中等大高
减小 batch size小大高
减少密集块层数中等中中
降低输入分辨率大大低
减少检测尺度数大中低

优先动增长率和 batch size,这两个对精度影响相对可控。输入分辨率和检测尺度数是最后才动的,因为它们直接决定模型能检测多小的目标。

注意:降低 batch size 之后,BatchNorm 的统计会变差,这时候要么改用 GroupNorm,要么用梯度累积模拟大 batch。我一般用梯度累积,累积步数设成让等效 batch size 回到 8 以上。

5.4 训练轮次和早停的判断

从零训练的收敛曲线和微调很不一样。微调通常几个 epoch 就收敛了,从零训练往往要几十甚至上百个 epoch。我跑的一个中等规模数据集,大概到第 80 个 epoch 验证集精度才基本稳定。

判断是否该早停,不能只看训练损失,要看验证集上的 mAP。而且从零训练的验证 mAP 曲线经常有平台期,可能连续十几个 epoch 不涨,然后又突然涨一截。所以早停的耐心值(patience)要设得比微调大,我一般设 20 到 30 个 epoch。如果算力允许,宁可多训一会儿,从零训练的模型对训练轮次比微调模型更敏感。

6. 什么场景该用 DSOD,什么场景别硬上

6.1 适合从零训练的三个典型场景

场景一:数据不能外流。这是最刚性的需求。某些行业的数据有严格的合规要求,不能用于预训练,也不能引入外部权重。这种情况下 DSOD 这类无预训练方案几乎是唯一选择。

场景二:目标域和通用域差异极大。比如某些特殊的工业缺陷、医学影像里的特定结构、遥感里的非常规目标。这些域的特征和通用分类数据集差得太远,预训练骨干带来的先验帮助有限,甚至可能因为域偏移而拖后腿。这时候从零训练反而更干净。

场景三:需要端到端定制。有些项目要求整个模型从结构到权重都是自研的,不接受任何外部依赖。DSOD 提供了一套完整的从零训练方法论,适合这种需求。

6.2 不建议硬上的情况

如果你的数据集很小(比如只有几百张标注图),从零训练基本没戏,过拟合会非常严重,这时候还是老老实实用预训练加微调。如果算力非常有限,从零训练的收敛轮次是微调的好几倍,算力不够会拖垮整个项目周期。如果任务对精度要求极高且没有合规限制,用预训练骨干加微调仍然是更稳妥的选择,DSOD 的价值在于"没有预训练也能work",而不是"一定比预训练好"。

我个人的判断标准是:先问自己"能不能用预训练",如果能且没有副作用,就用;只有在明确不能用的时候,才考虑 DSOD 这类方案。技术选型要务实,不要为了炫技而选更难的路线。

6.3 一个我实际用过的混合思路

完全从零训练和完全依赖预训练之间,其实有个中间地带。我做过一个项目,骨干的前几个 stage 从零训练,后面的 stage 用一个在自有小数据集上训过的浅层模型初始化。这样既避免了引入外部数据,又给深层提供了一定的初始化帮助。效果比纯从零训练收敛快不少,精度也略高。

这个思路的本质是:预训练的价值主要在于浅层的通用特征,如果能在自有数据上先训一个浅层特征提取器,就能部分替代预训练的作用。当然这需要额外的训练步骤,适合对周期不那么敏感的项目。

7. 几个容易被忽略的实现细节

7.1 权重初始化方式的选择

从零训练时,权重初始化不再是"随便填个默认值"就行。我对比过几种初始化,对 DSOD 这种密集连接结构,MSRA 初始化(也叫 He 初始化)效果最稳,因为它考虑了 ReLU 带来的方差变化,适合深层网络。如果用 Xavier 初始化,在密集连接结构里深层容易出现激活值过小的问题。

检测头的初始化也要注意。分类分支和回归分支的最后一层,偏置初始化有讲究。分类分支的偏置可以按正负样本比例设一个负值,让初始预测偏向背景,这样训练早期不会因为大量误检而震荡。回归分支的偏置设成能让初始预测框接近默认框的值。这些细节看起来小,但对从零训练的稳定性影响不小。

7.2 学习率 warmup 的具体做法

warmup 不是简单地把学习率从小调到大,中间的过程也有讲究。我用的是线性 warmup:前 N 次迭代,学习率从初始值的 1/100 线性升到初始值。N 一般取总迭代次数的 5% 左右,或者固定 500 到 1000 次。

有个细节:warmup 期间动量也可以相应调整。有些实现会在 warmup 阶段用较小的动量,避免早期梯度噪声被放大。我试过,效果有但不明显,嫌麻烦可以不动。

7.3 多尺度训练的开启时机

多尺度训练(训练时随机改变输入分辨率)对检测精度有帮助,但在从零训练里,开启时机很重要。太早开启会让模型在还没学好单一尺度时就面对尺度变化,收敛更慢。我的做法是前一半训练轮次用固定分辨率,后一半再开启多尺度,尺度范围控制在 0.8 到 1.2 倍之间。这样既拿到了多尺度的收益,又不影响早期收敛。

7.4 验证集的使用方式

从零训练时,验证集不只是用来看精度的,还可以用来指导训练。我习惯每隔几个 epoch 在验证集上跑一次,记录每个类别的 AP。如果发现某些类别一直学不好,可以回头检查这些类别的标注质量、样本数量、以及默认框匹配情况。从零训练因为没有预训练先验兜底,数据层面的问题会暴露得更明显,这其实是个好事,能帮你更早发现数据集本身的毛病。

8. 我在这条路上的一些真实体会

把 DSOD 完整跑通并且调到可用精度,前后花了我大概三周时间,其中大部分时间不是在写代码,而是在和训练稳定性较劲。从零训练最折磨人的地方在于,它把很多在微调时被预训练权重"掩盖"掉的问题全都暴露出来了——数据标注的噪声、默认框设计的不合理、损失权重的失衡,这些在微调时可能被预训练先验压住,从零训练时全都会跳出来。

但反过来,这个过程也让我对检测训练的理解深了一大截。以前用预训练模型,很多超参是"抄来的",不知道为什么这么设。从零训练逼着我去想每一个超参背后的逻辑,去想梯度是怎么流的、特征是怎么被复用的。这种理解上的收获,比单纯跑出一个高精度模型更有价值。

如果你也打算走这条路,我的建议是:先把一个小规模的数据集跑通,哪怕精度不高,先让整个流程能收敛。然后再逐步加数据、加增强、调结构。从零训练最忌讳一上来就上大规模数据和复杂结构,那样一旦不收敛,你根本不知道是哪个环节的问题。小步快跑,逐项验证,是这条路唯一靠谱的走法。

另外,别把 DSOD 当成一个必须严格复现的固定方案。它的核心思想——深层监督加密集连接来替代预训练——是可以灵活组合的。你可以只借鉴深层监督,也可以只借鉴密集连接,甚至可以用别的机制来达到同样的目的。理解了它要解决的问题,你就能根据自己的场景设计出更合适的方案,这比死记硬背结构配置有用得多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询