养蚕最怕的就是数蚕。一板蚕种孵化出来,上万头蚁蚕密密麻麻趴在蚕座上,要估算孵化率、统计存活数、判断生长龄期,过去全靠技术员肉眼一个个看,数完一轮眼睛基本是花的。这活儿不仅枯燥,而且极度依赖经验——新手分不清二三龄蚕,老师傅退休以后经验就断层了。我做的这套基于VFNet的蚕虫智能检测与识别系统,就是用深度学习目标检测把“数蚕”这份工作接过来:摄像头对着蚕座拍一张图,自动完成蚕虫定位、计数、龄期分类和病蚕筛查,整套流程从数据采集、模型训练到边缘部署都跑通了。实测下来,数蚕效率比人工快了一个数量级,关键龄期的识别准确率也稳得住。这篇文章适合两类人:一类是想在农业细分场景里落地目标检测的开发者,另一类是刚接触检测模型、想找个真实业务案例练手的初学者。我会把方案选型、数据集处理、训练调参和部署踩坑的完整过程都写出来,你可以直接拿去参考。
1. 蚕桑业怎么就需要目标检测了
1.1 养蚕人绕不开的“数蚕”难题
蚕桑业不是播下去就等着收的粗放农业。从蚕种孵化开始,就要记录孵化率;小蚕期要控温控湿,观察蚕群齐不齐;大蚕期食桑量猛增,养蚕人要判断个体大小分布,决定给桑量;到快结茧的时候,蚕体会从青白变成透亮,食欲减退,这个状态叫熟蚕,必须及时捡起来放到蔟具上,晚几个小时茧质就受影响。
这些环节逃不开一个动作:数蚕。数蚕不只是报个数,还要分龄期、分状态。过去这套工作完全靠有经验的技术员完成:拿一张白纸,拨开蚕座,一五一十地数,一板蚕下来几百上千条是常事。到了蚕种繁育这种规模化生产场景,一个技术员一天要处理几十个蚕座,工作量相当惊人,而且年轻人普遍不愿意干这种高强度重复劳动。
蚕虫本身还特别难识别。蚁蚕阶段体长只有几毫米,颜色跟桑叶残留、蚕粪混在一起很难分辨;蚕虫姿态弯弯扭扭,互相叠压;不同龄期之间的外形差异也没有想象中那么大。这些特性叠加起来,恰好是传统图像处理搞不定的问题——颜色阈值分割会被桑叶干扰,边缘检测在密集碰撞场景下压根分不开。这也是为什么必须上深度学习目标检测,而不是靠图像处理的老办法硬做。
1.2 我为什么在众多检测模型里挑了VFNet
目标检测模型这几年可选方案实在太多。两阶段的Faster R-CNN精度高,但推理速度相对较慢,部署成本也高;YOLO系列速度快,在小目标、密集场景下的表现只能说中规中矩;FCOS这类无锚框方法省去了锚框调参,对密集目标比较友好;RetinaNet用Focal Loss解决正负样本不平衡,在当时已经很能打。
我最终选择VFNet,比来比去主要是三条理由。第一,蚕虫是典型的小目标、密集目标,一张图里几十上百条蚕挤在一起,背景蚕座、桑叶、蚕粪占了绝大比例,正负样本极度不平衡。VFNet的Varifocal Loss在这个场景下比Focal Loss更细,它不是一刀切地给难样本固定降权,而是根据每个样本的定位质量动态调节损失权重。第二,蚕虫检测不仅要“框住”,还要判断是几龄蚕,分类和定位的质量必须对齐。VFNet用IoU感知分类分数把这两个任务捆绑在一起,框得准和分得对被统一建模,非常贴合蚕虫场景。第三,VFNet在目标检测标准数据集上的精度在同量级单阶段模型里排名靠前,推理速度又比两阶段快不少,更贴合养殖场所能接受的硬件成本。
| 对比维度 | Faster R-CNN | YOLOv5系列 | VFNet |
|---|---|---|---|
| 推理速度 | 较慢 | 很快 | 快 |
| 小目标能力 | 较强 | 一般 | 强 |
| 密集场景 | 一般 | 偏弱 | 强 |
| 分类定位对齐 | 弱 | 弱 | 强 |
| 训练收敛难度 | 中 | 低 | 中 |
后来实际跑下来的体验也印证了这个判断:VFNet在蚕虫这种细长形变目标上的稳定表现,比我在同样数据上试过的其他单阶段模型明显更好。
1.3 这套系统到底能识别什么
系统最终实现了五个核心能力,每一块都对应一个具体的生产场景。
- 蚕虫计数:输入单张蚕座图像,输出检测框数量和密度估算。典型蚕座图像里蚕虫数量从几十到几百不等,全自动计数省掉了人工拆块统计的步骤。
- 龄期识别:把蚕虫划分为五龄类别。我把“蚁蚕/1龄”单独作为一类,后四种龄期再用外形特征区分。实测1龄的识别最准,4龄和5龄之间偶尔会混,但生产上通常把4、5龄合并展示为“大蚕期”,影响不大。
- 病蚕筛查:蚕病种类不少,从症状上看主要是体色异常、体型瘦小、行动迟缓。病蚕样本相对少,这部分我在迁移学习的第二期单独加了几个小时的训练数据,效果才过得去。
- 熟蚕预警:熟蚕透亮、不再进食,检测出来后自动弹提醒,管理人员可以及时准备蔟具。这个模块生产端反馈最直接,一个提前提醒能省下不少损失。
- 密度热力图:检测结果按蚕座网格聚合,生成密度分布图,辅助判断蚕群健康程度和给桑均匀度。
现实里养蚕户还会问“能不能测蚕体重量”“能不能看出是哪种蚕病”这类更深一层的问题,当前系统还没做到。但检测框和分类结果搭好以后,下游再接一个数值回归模型去估算体长体宽,是完全可行的扩展方向。基础检测能力永远是最先要打好的地基。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 数据集搭建,工程里最花时间的环节
2.1 现场采集:拍什么、怎么拍、拍多少
数据集的准备工作比模型训练重得多,这一点很多人一开始意识不到。我实际采集了大约1.2万张图像,来源覆盖三个不同蚕房、两个养蚕季。采集设备用的是带固定支架的普通工业相机,分辨率500万像素,另外补了一部分手机拍摄的场景图,用来提升模型的泛化性。
拍摄时我强调三件事。第一,角度要覆盖俯拍、侧拍和斜45度三种。蚕座是立体环境,蚕虫会爬上桑叶背面,有时候还会从蚕座边缘往下爬,只用单一俯拍视角会导致漏检。第二,光照不能只挑“好看”的时段拍。白天自然光、晚上棚内灯光、人工补光各拍一部分,把色温和亮度差异直接丢给模型去学。第三,蚕虫姿态尽量拍出多样性,蜷缩、伸展、在桑叶上、在蚕座边缘、被同伴覆盖的状态都保留下来。不要采集完自己觉得“不好看”就删掉,那些丑图恰恰是模型最难啃的训练样本。
图片采集完成后做了简单清洗:去掉完全模糊的、镜头起雾造成的、还有蚕虫占比过小的图片。最后有效图像大概1.1万张,按训练、验证、测试6:2:2划分。测试集保证完全独立,不参与训练和验证调参,只用来评估最终效果。
2.2 标注类别与标注规范
标注类别我定义了六个:1龄(蚁蚕)、2龄、3龄、4龄、5龄(接近熟蚕)、病蚕。按生产习惯,养蚕人更熟的是“小蚕期、大蚕期”这种粗分法,但模型训练需要更细的粒度,所以拆分成了五龄加病蚕六类。
刚开始试点标注时有一个问题:2龄和3龄在形态上真的不好分,让标注员硬分出来的标签噪声特别大。后来我调整了策略:正式模型里保留五个龄期类别,训练时接受相近龄期之间的标签噪声,重点保证1龄和5龄的判别准确,因为生产上这两个节点最敏感。这个取舍非常重要——如果强行追求六个类别纯度,反而会把其他类别的标注成本推高好几倍。
标注工具我用的是常见的开源工具LabelImg,画矩形框导出Pascal VOC格式,再转成COCO格式喂给训练。规范上特别强调了几条硬性规则:
- 蚕虫互相叠压时,抠得清晰的主体一定要框,被压得只剩四分之一的个体可以跳过,避免标注者凭臆测勾框。
- 病蚕只要体色异常就单独标出来,不要混在正常蚕框里。
- 框要紧贴蚕体,但不能切进蚕体导致边界溢出到背景。
标注质量检查过两轮:第一轮是标注员之间互查,第二轮我自己随机抽查了600张图,统计漏标和错标情况,把有问题的图像返工。整个标注过程前后花了两周,但非常值得。我见过有人为了省时间直接拖模型预测生成标注,结果预测噪声被当成真值反复放大,模型精度怎么都提不上去,最后还得回头重新标。
2.3 数据增强:让模型见多识广
蚕房现场的光线、相机位置、蚕座新旧程度都会变化,训练阶段必须靠增强把模型“虐”出来。我用到的增强分三层:
- 几何层:随机水平翻转、随机缩放(0.5到1.5倍)、随机旋转(90度整数倍)、随机裁剪拼接的Mosaic增强。Mosaic对密集小目标的帮助非常大,一张图里能同时看到多个蚕座区域的视角,等于变相扩大了训练样本多样性。
- 色彩层:亮度抖动、对比度抖动、随机RGB通道扰动。这套增强专门模拟蚕房灯光不稳定、早晚色温变化的情况。
- 尺度层:多尺度训练启用了从640到1280的随机尺度采样,让模型适应不同拍摄距离下蚕虫的大小差异。
增强力度也不是越大越好。一开始我把随机旋转放开成任意角度,结果模型在蚕虫倾斜超过60度的时候预测框抖动得厉害;后来改成只在±30度范围内轻微扰动,加上90度整数倍旋转,稳定性立刻好了。这里的原则是:增强要贴近真实拍摄的变体空间,而不是制造现实中不存在的诡异图像。过度拟合训练数据的增广方式,反而会让模型在真实环境下失效。
2.4 标注质量与数据量平衡
真要给一个经验值,我的感受是:在蚕虫这种目标比较单一、场景相对固定的任务里,质量合格的数据集一万张左右就足够训练出实用模型了。少到两三千张也能跑通,但很容易遇到小龄期类别过拟合和光照变体下漏检。数据采集实在困难的话,优先保证每类数量均衡;病蚕这种稀有类别哪怕只有几百个实例,也比完全没有强很多。
另外一个容易被忽视的点:测试集的拍摄条件和训练集不能太像。比如训练集中晚上灯光下拍的图已经很多,测试集就要专门塞一些白天自然光下的新图。用生产环境实拍的图当测试集,是判断落地效果的唯一标准。离线指标再漂亮,也代替不了现场验证。
3. VFNet的原理,用大白话拆开讲
3.1 Varifocal Loss:把力气花在最该花的地方
Focal Loss的核心思想是给容易分对的样本降权,给难分对的样本升权,用固定的γ参数控制权重曲线。它的问题在于γ是全局的、手工设定的,对每个样本的“难度”只能用是否分对来粗粒度刻画。
Varifocal Loss做了自适应。它把每个正样本的监督目标直接设为该样本的定位质量,也就是预测框和真实框之间的IoU。简单理解:一个正样本,模型预测的框越准、IoU越高,损失权重就越大;预测得差但被分成了正样本,损失会被压下来。对负样本,只有当预测分数偏高(模型很自信但其实是错的)的时候才使用较大权重惩罚。
把这个放到养蚕场景里就很好理解了。蚕虫稠密,生成成千上万个候选框,绝大多数都是背景。背景里突然冒出来的噪声框会被高效压制,模型学到的是“有蚕虫的地方才响应”,而不是“看着像蚕的东西就框一下”。这跟Focal Loss那种“所有难样本统一吃重权”的做法比,少了很多误伤。
3.2 IACS:分类和定位不再各说各话
常规检测器里,分类分支输出一个“这个框里是蚕虫的概率”,回归分支输出“这个框在哪儿”。最后用NMS合并重复框时,很多方法直接把分类分数拿来排序,分数高的框留下。
这里有个明显的漏洞:分类分数很高的框,位置很可能没对准;而位置很准的框,分类分数反而偏低。蚕虫互相叠压的时候这个问题极端明显——一个框同时罩住两条蚕,模型很自信地认为是“蚕”,但位置信息其实很差。
IACS的全称是IoU-aware Classification Score,训练时把分类分支的监督目标改为“类别概率乘以IoU”。一句话:预测的框既要分类对,又要位置准,才给它高分。这个设计跟密集场景天然匹配,因为密集场景下本来就容易出现位置不准但分类自信的框,IACS把这类“高分误框”在源头就压掉了。这也是VFNet和RetinaNet、FCOS这类模型在密集场景表现拉开差距的关键原因。
3.3 STAR模块与可变形卷积:学会看蚕虫的形状
STAR是VFNet里的特征提取模块。老方案往往只在目标中心点采样卷积特征,但蚕虫又细又长、蜷缩成各种形状,中心点采样会丢失大量边界信息。STAR用五个基准点——中心点和四个角点——去框定目标的特征范围,在这五个点附近用可变形卷积做自适应采样。可变形卷积的偏移量是网络自己学出来的,相当于模型自己决定“应该看哪个位置才能把这条蚕的轮廓拼出来”。
从直观上讲,普通卷积看蚕虫是“瞪大眼睛老老实实从左往右扫”,可变形卷积是“眼睛会跟着蚕虫弯曲的轮廓走”。VFNet把这两者结合起来,既保留了全局感受野,又能刻画蚕虫的非刚性形变,效果在细长目标上比固定网格卷积明显要稳。蚕虫弯曲、叠压、侧卧这些姿态变化,对这个模块来说都是可适应范围内的变形。
3.4 VFNet整体结构速览
把VFNet拆开看,骨干网络用的是ResNet-50加特征金字塔FPN,把不同尺度的特征融合起来,让模型同时照顾到小蚕和大蚕。颈部之上接了一个共享检测头,分类分支输出IACS分数,回归分支输出框位置,最后用ATSS自适应选择正负样本。
ATSS的核心逻辑是:根据统计特性自动挑选合适的正样本,而不是靠固定的IoU阈值。这对目标尺度变化很大的蚕虫场景非常有用——一张图里可能同时出现蚁蚕和5龄大蚕,固定阈值必然顾此失彼。实际训练时,我直接复用官方VFNet在COCO上的预训练权重,骨干网络冻结前两个阶段,后面全部放开微调。这样收敛速度比从头训练快得多,病蚕这种样本量少的类别也能学到有效特征。
4. 训练实施与调参记录
4.1 环境搭建与数据集准备
训练用的是一张中端消费级GPU,显存12G,系统是Ubuntu 20.04,深度学习框架选了PyTorch 1.10,模型库用的是开源的目标检测工具箱MMDetection。装环境最大的坑是版本匹配:Python 3.8配PyTorch 1.10,CUDA用11.3,配套的深度学习基础库必须用编译版本,装错一个版本就得全部重来。建议直接用官方提供的Docker镜像,能省下整整一个下午的折腾。
数据集转换后按COCO格式存放:
text复制data/silkworm/
├── annotations/
│ ├── instances_train.json
│ ├── instances_val.json
│ └── instances_test.json
├── train/
├── val/
└── test/
类别按class_id从0到5分别对应1龄到5龄、病蚕。类别注册信息在MMDetection里通过配置文件定义,模型输出层自动按类别数调整。
4.2 关键配置解读
我贴一份实际用过的简化配置,只保留跟蚕虫场景强相关的核心项:
python复制model = dict(
type='VFNet',
backbone=dict(
type='ResNet',
depth=50,
frozen_stages=1,
norm_eval=True),
neck=dict(
type='FPN',
in_channels=[256, 512, 1024, 2048],
out_channels=256,
start_level=1,
add_extra_convs='on_output',
num_outs=5),
bbox_head=dict(
type='VFNetHead',
num_classes=6,
in_channels=256,
stacked_convs=3,
feat_channels=256,
strides=[8, 16, 32, 64, 128],
use_atss=True,
loss_vfl=dict(
type='VarifocalLoss',
alpha=0.75,
gamma=2.0,
iou_weighted=True,
loss_weight=1.0),
loss_bbox=dict(type='GIoULoss', loss_weight=1.5),
loss_bbox_final=dict(type='GIoULoss', loss_weight=2.0)))
几个关键参数值得展开:
frozen_stages=1:保留预训练骨干的前两个阶段不参与微调。蚕虫数据和通用数据集里的物体特征差异较大,但底层边缘、纹理特征还是通用的。冻住底层收敛速度快,也省显存。strides=[8, 16, 32, 64, 128]:五层FPN输出的下采样倍数。小蚕对应高层特征图(8倍、16倍),大蚕对应低层特征图。如果蚕虫特别小,可以加一个P2输出层把下采样倍数推到4,代价是显存暴涨。use_atss=True:正负样本分配用ATSS,按特征层内统计的自适应topk选正样本。极端尺度分布下比固定IoU阈值稳定。loss_bbox_final:这是VFNet对最终预测框的GIoU损失,权重设成2.0,意思是模型提交的框精度是硬指标,宁可少检几条,也不允许框得稀烂。
4.3 我的训练策略与调参过程
训练用官方COCO预训练权重起步,总epoch设计为36。第一次跑的时候直接用了官方默认的0.01学习率,batch size为8,结果到第五个epoch验证mAP只有0.15,训练集上损失也降不下去,典型过拟合征兆。排查后把学习率降到0.0025,并在前500步做warmup,之后余弦下降到接近0。第二次跑到第20个epoch时,验证mAP到了0.63。
这里有个重要经验:数据量只有标准数据集的十分之一,预训练权重和全局学习率必须成比例缩小。预训练权重已经见过太多通用特征,学习率调太高,等于把它学到的结构直接冲掉了。我按“数据量每缩小一个数量级,初始学习率大约除以4到8”的经验来调,蚕虫这种场景数据量不大,学习率必须保守。
类别不平衡方面,1龄和5龄样本多,病蚕样本少。我没有粗暴地对稀有类别过采样,而是把Varifocal Loss里的alpha从官方默认的0.75提调到0.8,让负样本中的难负样本再多吃一点惩罚;同时把病蚕类别的训练样本做了一倍的在线随机重复采样,只重复这一类的正样本。病蚕类的mAP从0.31涨到0.48,效果非常明显。
训练监控用的TensorBoard,主要盯三个曲线:总loss、验证mAP、还有每个类别的AP散点。loss值本身不是最重要的,它下降到平台期不代表模型就好了,要看验证集每个类别的AP。第32个epoch时达到最佳验证mAP约0.71,平均框回归IoU为0.83。
4.4 评估指标与实际效果
测试集的指标分布:AP50在所有类别上约0.88,AP75约0.67,小目标AP约0.61。放到生产视角,更关键的是“数蚕误差”。我拿30张未参与训练的蚕座图,让两位技术员人工点数作为真值,再和模型输出比对。模型计数误差在±6%以内,两位技术员自身点数误差也在±5%左右——说明模型已经进入了和人类专家同量级的水平。龄期识别方面,1龄和5龄准确率高,最难的是2龄和3龄,模型经常相互混。实际系统就把2、3龄合并展示为“小蚕期”,4、5龄合并为“大蚕期”,生产上完全够用。
评估到这一步,我心里才踏实:模型的离线指标只是及格线,能不能替技术员把实际数蚕这件事接住,才是落地真正要考虑的问题。
5. 系统部署与落地实现
5.1 从训练模型到推理服务的转换
训练完不是直接把PyTorch权重拿过去跑生产环境,要做格式转换和加速。我的流程是:先把PyTorch模型导出成ONNX格式,再用TensorRT封装成推理引擎。
转换过程中最大的坑是自定义算子的兼容性。VFNet里的可变形卷积在ONNX导出时经常遇到算子不兼容问题,导出的中间文件在某些环境下无法正常加载。我当时折腾了一阵,最后换了支持新算子的推理环境版本才解决。这里建议:遇到算子问题先查推理后端版本是否落后,别急着改模型结构。可变形卷积是整个模型里最复杂的模块,也是部署时最容易掉链子的一环。
模型转换完还要做精度对齐验证。我的做法是拿同一批测试图,分别在PyTorch原模型和转换后的推理引擎上跑一遍,比较检测输出的差异。如果差异超出预期,优先确认转换过程有没有丢节点或量化过度。
5.2 视频流检测与计数逻辑
部署形态用的是USB工业摄像机加一台边缘主机,摄像头对着蚕座,每隔十秒抓一帧,做流式检测。为什么不直接用实时视频流?养蚕场景蚕虫移动极其缓慢,检测结果按帧更新意义不大,每秒30帧纯属浪费算力。10秒间隔既可以覆盖蚕虫的“慢动作”,又能把主机功耗和散热控制住。
抓帧后的处理流程:
- 做一次轻量级的裁剪,把蚕座区域ROI先抠出来,减少背景干扰。
- 送入推理引擎,输出检测框、类别、分数。
- 对连续多帧做时间域平滑——同一坐标位置的框,连续三帧都存在才记为有效,滤掉摄像头抖动带来的“幽灵检测”。
- 跨帧的同一对象做关联,用中心点距离和类别做简单匈牙利匹配,避免重复计数。
这套逻辑看起来简单,但把误报率压下去了不少。蚕房里的震动、风吹桑叶导致的微小位移,都会被时间域平滑和跨帧关联过滤掉。
5.3 数据上报与业务闭环
检测出的数据除了在屏幕上展示,还要进数据库,并生成几块看板:当天孵化率、各蚕龄数量、病蚕数量趋势、熟蚕预警队列。这些数据最终同步到车间的工单系统——比如熟蚕预警数量超过设定值,系统自动生成一批“准备结茧架”的工单推送给饲养员。
这套闭环是让检测结果真正产生业务价值的关键。如果检测只是停留在“我能把蚕框出来”的展示阶段,那它就是个技术玩具。把它接进生产流程,变成工人手机上的一个提醒、二维码墙上的一块看板、饲养记录本上的一条自动数据,才算真正把数蚕这件事交给了系统。
5.4 现场部署踩的硬件坑
现场部署用的边缘设备是一台六核CPU、无独立GPU的小主机,运行在FP16精度下。单帧耗时从最初的180毫秒降到60毫秒左右,十秒抓一帧完全够用。我还试过INT8量化,单帧能压到45毫秒,但小蚕类别的AP下降了两个多点。最终生产环节保留了FP16方案,理由很简单:多零点几秒的延迟可以接受,小目标精度的损失不可接受。这个选择是典型的“性能够用就行”的务实取舍,不要为了指标好看强行上最低精度。
还有一个硬件层面的教训:边缘主机放在蚕房里,环境湿度高、粉尘多,防尘和散热必须提前考虑。我第一台设备因为进风口被蚕座毛絮堵住,运行两小时直接过热降频,检测延迟翻了一倍。后来加了防尘网和工业散热风扇,才稳定下来。
6. 常见问题与排查技巧实录
6.1 密集蚕虫漏检,NMS把同行蚕虫框删掉了
蚕虫互相叠压的场景里,两条蚕的检测框IoU很高,常规NMS的默认阈值会把其中一个框误删。我一开始把阈值直接调高到0.7,让重叠框更容易保留,但阈值太高又会产生很多重复框。更稳妥的做法是开启Soft-NMS,按置信度衰减而不是暴力删除重叠框。实测用Soft-NMS在密集蚕虫上的recall提升了0.12,重复框数量还保持稳定。如果你想快速见效,从默认NMS换到Soft-NMS,是所有方案里改动最小、收益最直接的。
6.2 小目标检测效果差,蚕蚁和1龄蚕总是漏
蚕蚁和1龄蚕目标面积只占整图的0.2%,在高层特征图上早就塌缩成几个像素,很难检测。我试过几个改进手段,按效果排序:
- 提高输入分辨率,从800乘1333拉到1280乘1920,但显存占用翻倍。
- 引入更高分辨率的特征层,就是把FPN下采样倍数从8降到4,代价同样是显存和计算量上升。
- 切图检测:把整图分割成瓦片,每块瓦片单独推理再拼接结果,瓦片之间重叠15%防止边界蚕虫被截断。
切图检测对小目标场景非常友好,几乎不需要改模型结构。我在生产环境的主力方案就是ROI裁剪加切图,既不牺牲小目标精度,也不用升级昂贵的GPU。如果分辨率不够,优先试切图,而不是盲目加大输入。
6.3 光照不均与反光干扰
蚕房灯光不均匀,局部阴影、桑叶和塑料膜的强反光都会形成假前景。有一次模型在白色塑料蚕座边缘反光区域输出了一堆框,全集中在反光带上,排查下来就是训练数据里反光样本太少。解决办法分两条腿走:一方面主动采集反光样本,补进训练集;另一方面在增强阶段加入“随机高光遮挡”模拟。现场能控制的话,就在蚕房各装一盏漫射灯,避免直射光源,这是成本最低的解法。
6.4 训练震荡或loss不下降
训练不收敛常见的四种原因,按踩坑频率排:
- 学习率过大,导致loss剧烈震荡。解决:降到原来的四分之一到八分之一,加warmup。
- batch size太小,梯度噪声大。解决:用梯度累积等效增大batch size。
- 数据不对齐,标签和图像错位、标注漏标。解决:写脚本检查标注数据和图像文件名的对应关系,随机抽查标注框是否贴合目标。
- 预训练骨干完全冻结,且学习率过低,导致头部学出来了骨干没动。解决:把冻结层数从2降到1,或者干脆全解冻用小学习率微调。
我遇到最多的是第一种,但最坑的是第三种。数据文件错位这个问题非常隐蔽,模型跑着跑着验证AP突然掉到0,大概率就是标签路径配错了,不一定是模型的问题。
6.5 推理速度太慢怎么办
如果推理速度不达标,按成本从低到高逐级排查:
- 降低输入分辨率,观察小目标精度损失是否可接受。
- 开启FP16推理,精度损失通常很小。
- 提升batch并行度,把多张蚕座图拼接成batch一次推理。
- 模型量化到INT8,精度损失大,但速度提升明显。
如果以上都试完还不够,就把蚕房场景拆成多个小区域,每个区域单独检测,利用多路并发提高整体吞吐量。蚕房摄像头通常可以并排装好几个,每个负责一块蚕座,总体覆盖率反而更好。
| 存在问题 | 症状 | 快速处理 |
|---|---|---|
| NMS误删 | 密集蚕虫少了框 | 换Soft-NMS,调低重叠保留阈值 |
| 小目标漏检 | 蚁蚕完全检不到 | 切图检测或增加高分辨率特征层 |
| 反光误检 | 反光区域大量假框 | 补反光样本、做随机高光增强 |
| 训练震荡 | loss抖动不收敛 | 降低学习率、加warmup、检查数据对齐 |
| 推理慢 | 检测延迟过高 | 降分辨率、FP16、INT8量化、多路并行 |
整个项目做下来,我最深的体会是:模型性能再好,也不如让现场业务平滑跑起来重要。开始时我花了很多时间刷mAP,但从落地的角度看,“识别出一条5龄蚕是不是熟蚕”这个信号,能不能准时触发一条工单给车间,才是真正的价值所在。通用目标检测模型在公共数据上很强大,但真要落到蚕桑这种细分农业场景,大多数时间和难点反而是数据和业务理解。如果再做一次这个项目,我会先驻场一周去理解养蚕流程,再动手采集数据和训练模型——顺序反了,返工量会大得多。
