
棉田生长监测这件事做农业视觉的人应该深有体会无人机拍回来的正射影像分辨率很高但地面棉株一进入封行期棉铃、棉蕾全被叶片盖住人工看图数起来又慢又晕。更麻烦的是棉田目标天生就“小、密、遮挡多、环境变化大”常规目标检测算法在这种场景下不是漏检就是重叠框打架。我这两年一直在折腾一套基于改进DINO-4scale模型的棉田作物生长监测与识别系统从模型选型、数据处理到田间部署踩了不少坑也积累了一套能直接复用的方案。这篇博客就是把这些经验完整拆出来给做农业AI、遥感识别、或者想用DETR系模型做落地项目的朋友一个参考。这个系统本质上做三件事识别棉田里的关键目标棉铃、棉蕾、病害叶片、杂草统计目标数量和空间分布最后定位固定起来判断棉田生长阶段和异常程度。整套方案的核心算法是改进后的DINO-4scale检测模型它不是简单的模型套用而是在小目标召回率、遮挡目标分类、田间复杂背景抗干扰这三个方向上分别做了针对性改动。下面我会按照整个项目的推进顺序把需求分析、模型设计、数据处理、训练调参、部署上线和问题排查的全部过程都讲一遍。1. 项目背景与需求拆解1.1 棉田监测到底要解决什么农业现场的需求往往听起来很简单比如“想知道这块田现在有多少棉铃”“有没有棉铃虫危害”“杂草密度高不高”但落到算法任务上就变成了一个复杂的目标检测问题。第一棉铃尺寸在2到5厘米之间无人机在20米高度航拍影像分辨率按2厘米/像素算一个成熟棉铃可能只占二三十个像素属于典型的小目标。第二棉花分枝多、叶片大很多棉铃藏在叶幕下方可见光影像里只有一小部分暴露出来模型没法靠完整轮廓去识别。第三棉蕾、棉铃、枯铃、棉叶病斑在颜色和纹理上非常接近类别边界模糊标注员都容易犯难更别说模型。所以这套监测系统不是简单做一个“有没有棉花”的分类器而是要在真实田间条件下做到可用。具体需求拆成三个维度第一是识别的粒度至少要能分清楚棉铃、棉蕾、病害斑块和主要杂草类别而不是只输出一个笼统的“棉花目标”第二是计数的稳定性同一块田重复飞行两次计数结果偏差不能超过10%否则没法指导农事决策第三是响应速度无人机采集完一个架次的数据后最好在短时间内完成全图推理不能等到第二天才出结果。1.2 为什么选DINO系模型而不是YOLO系一开始团队内部也有争议因为YOLO在工程上实在太成熟了部署方便、推理快很多农业检测项目默认就是YOLO。我当时的考虑是棉田场景的难点不在“实时视频流”而在“高分辨率大图的精细检测”。YOLO系模型在密集小目标场景里主要吃亏在两处一是后处理依赖NMS棉铃棉蕾挨得太近NMS阈值稍微调低就大量合并调高就产生大量重框二是anchor机制对尺度变化敏感棉铃尺寸分布宽从刚结铃到吐絮膨大更要不停调anchor。DINO作为DETR系端到端检测模型直接去掉了NMS通过集合预测的方式输出一组唯一的检测框在密集场景下天然有优势。另外DINO解决的是原始DETR训练收敛慢和不稳定问题它用“去噪训练”和“对比去噪”让模型在训练时更早学到准确的定位信号而且本身就支持多尺度特征。DINO-4scale里的“4scale”就是输入给Transformer解码器的特征来自4个不同分辨率的特征层这对多尺寸目标混存的情况非常重要。我们最后定的基线就是基于DINO的4尺度版本然后针对棉田细粒度目标做了二次改进。1.3 整体技术方案的三个关键拆解整个系统我分成三个模块来设计刻意把算法和工程解耦。第一个模块是数据采集与自动标注确定无人机航拍方案、地面采集车的拍照流程以及标注规范和半自动标注工具链。第二个模块是模型训练与迭代包含改进的DINO-4scale模型、训练配置、效果评估和困难样本挖掘。第三个模块是推理与田间应用包括大图切片推理、目标计数、结果可视化和周期性重飞对比。这么拆的好处是算法调优的时候不会因为数据格式混乱而返工部署的时候也不会因为模型输入尺寸和切片策略没定好而推倒重来。在方案规划阶段我把90%的精力压在了前两个模块因为农业场景的数据质量和模型对“遮挡目标”的适应能力决定了系统上线后的真正效果。2. 改进DINO-4scale模型的核心细节2.1 DINO-4scale基线回顾要讲清楚我做了什么改进得先把DINO-4scale的工作原理简单过一遍。DINO整体还是Encoder-Decoder的Transformer结构。CNN骨干网络先提取特征把不同尺度的特征图展平后送入EncoderDecoder端有一组可学习的“目标查询”向量这些查询向量通过交叉注意力机制从编码特征中“捞出”目标对应的位置和类别信息最后直接输出预测框和类别概率。DINO最大的特点是引入锚点框作为查询的初始化并且通过混合查询、查询选择和去噪训练来稳定训练过程。在DINO的配置里“4scale”表示用了4个特征层级。以常见的ResNet50骨干为例从C3到C5stride分别为8、16、32以及C5经过额外卷积得到的C6层共同组成四层多尺度特征。多尺度特征输入给可变形注意力模块后每个查询会围绕锚点附近的参考点自适应采样不同特征层的若干个采样点这让模型天然具备跨尺度匹配目标的能力。但直接用这个基线跑棉田数据我在实验里发现了两个明显短板。第一棉桃棉蕾集中在中小尺度C3层级的分辨率还不够很多只有十几个像素的目标没有充分利用到浅层高分辨率特征。第二棉叶遮挡导致目标只露出一部分时模型预测的置信度普遍偏低容易漏检。此外还有类别混淆病害斑和棉蕾在颜色上接近仅仅靠视觉特征很容易错。2.2 改进点一增加P2浅层特征参与跨尺度融合针对小目标召回率不高的问题我做的第一个改动是增加P2层级也就是stride为4的浅层高分辨率特征图。骨干网络输出的C2特征图具有最丰富的空间细节但传统DINO-4scale里并不用它因为直接加进来会显著增加计算量而且浅层特征语义噪声也比较大。我的做法不是简单把P2粗暴塞进特征金字塔而是加了一个轻量级跨尺度特征融合模块。具体来说我对C2特征先做通道压缩把维度降到与C3一致然后和上采样后的C3语义特征做逐像素加权融合权重由一个轻量的注意力分支实时生成。公式上就是P2_out alpha * C2_down (1 - alpha) * up(C3_sem)其中的alpha由网络自适应学习训练初期偏小优先保证语义稳定性训练后期会逐渐加大对空间细节的依赖。这个模块很轻参数量增加不到5%但小目标召回率提升明显。我前后对比过直接加P2、使用普通FPN和带注意力融合三种方案带注意力融合那版在棉铃这个类上的AP提升是最可观的。2.3 改进点二正负查询对比去噪的农田适配DINO训练时有一个关键组件叫去噪训练做法是把真实目标框做不同程度的缩放和偏移扰动生成带噪声的正样本和负样本查询要求模型在解码器前几层把这些“被噪声污染”的查询还原到正确框。这种做法好处是训练早期就给模型很强的定位监督避免Transformer解码器冷启动。我在实际跑棉田数据时发现标准的去噪训练对“部分遮挡目标”不够友好。因为棉铃被叶子挡了一半真实框和可见区域差异很大如果扰动范围设置太死板模型会误把遮挡当作噪声学到错误的边界。所以我把去噪训练做了农田化适配对正样本查询的扰动范围从固定的0.4改为动态缩放遮挡比例估计高的目标采用更大的扰动尺度同时在后半段训练里额外引入了“软负样本”也就是只与真实框有部分重叠但并不完整的预测候选让模型学会区分“被遮挡但真实存在”和“底色背景”的边界。这个改进属于训练策略层面的调整完全不需要改变模型前向结构只在损失加权和样本构造上做文章。对比实验发现棉铃类别的准确率保持稳定召回率提高了两个多点。尤其对行间滴灌带阴影下的目标之前的模型经常漏改进后误检和漏检都明显减少。2.4 改进点三类别解耦头与细粒度分类分支原版DINO的分类分支是一个简单线性层负责输出类别概率。棉田里棉蕾、幼铃、病斑这三类外观上存在相似性但空间上下文差异很大棉蕾通常着生在果枝顶端幼铃紧贴着蕾柄病斑则集中在叶片中。为了利用这些上下文信息我重新设计了检测头把目标分类改为“粗类别细类别”解耦结构。粗类别判断是不是目标细类别判断到底是棉铃、棉蕾、病斑还是杂草。细类别分支输入不仅包括当前查询对应的ROI特征还包括了周围一个扩大区域的空间上下文特征。这么做的灵感来自一个很朴素的观察田间人眼判定棉铃时并不会只盯着一个点看而是会看周围果枝的分布、叶片颜色、是否有萼片包裹。模型也应当具备这种“周边视觉”。解耦头的代价是解码器输出维度增加了一点但收敛速度反而更快了因为粗分类任务把大量背景样本在前置分支消化掉了细分类分支只需要专注在真正有歧义的目标上做区分。2.5 损失函数和训练策略的调优模型配置确定后损失函数是整个训练最容易出细节问题的地方。DINO本身的损失包括分类损失Focal Loss、边界框回归损失L1 GIoU以及去噪损失。我在农业场景里做了一处调整把分类损失从标准Focal Loss改成带“实例困难度”加权的Focal Loss。困难度怎么算训练过程中维护每个锚点查询的历史最大IoUIoU长期处于中等区间0.3到0.6的目标就判定为困难样本加权系数调高。这实际上是借鉴了在线难例挖掘的思想让模型把注意力集中到棉田里那些边界模糊、遮挡严重的“老大难”目标上。另外我把去噪损失的权重按照训练轮次做了warm-up设置。前10个epoch权重从0.3线性升到0.8后面保持稳定这么做是为了避免训练初期损失过于集中在去噪分支上导致主损失信号被稀释。我在实验里对比过固定权重和动态权重动态权重的收敛损失曲线更平滑最终mAP高出约0.8个百分点。3. 数据是最大的成本棉田数据准备与标注实践3.1 数据采集方案与时空覆盖模型再强数据不行也一样白搭。棉田数据采集是整个项目里时间成本最高的一环。我采用的采集方案分三个层次第一层是无人机航拍飞行高度控制在15到25米使用正射相机地面分辨率控制在1.5到2.5厘米/像素覆盖整块棉田的大场景第二层是地面近景采集用自走式采集车沿棉行低速行驶镜头朝斜下方45度拍摄专门采集无人机看不到的叶片遮挡部位和底层棉铃第三层是手持设备补拍针对病害叶片、杂草这类需要近看的对象用手机或微单贴近拍摄。采集的时空覆盖一定要做够。时间维度上棉花从苗期、蕾期、花铃期到吐絮期每个阶段目标形态差异都非常大不能用同一个时期的照片训练完就指望全生育期可用。我这边按每半个月一个周期采集一轮完整覆盖了四个主生育阶段。空间维度上要覆盖不同品种、不同密度种植模式、不同土壤背景膜上种植、裸地、滴灌带分布。如果只在一两个地块采集模型换到别的棉田必然崩。3.2 标签体系设计类别与属性怎么定标签体系我前后改了三次最后定下来的方案是类别属性的两级结构。一级类别包括四类棉铃包含幼铃和成铃、棉蕾、病害叶片、主要杂草。二级属性是可选的不参与Loss计算但会在后处理里使用比如棉铃的“露白”“吐絮”状态、棉蕾的“展开/未展开”状态。属性标注工作量很大所以只对抽样帧标注。在标注边境标注规则上最核心的一条是“遮挡目标必须标”。一开始标注员会把被叶片遮挡超过一半的棉铃直接忽略结果训练出来的模型对遮挡目标天然盲区。后来改了规则只要目标主体轮廓可辨认哪怕只露30%也要标出来完全看不见的不标。同时增加一个属性字段标记遮挡程度可见比例大于50%记为030%到50%记为1小于30%记为2。这样既能教会模型识别遮挡目标也能在后处理时按遮挡程度分档统计农学上也有意义。3.3 数据增强模拟田间遮挡和光照变化棉田数据量有限依赖外部预训练权重的基础上数据增强就成了提高泛化能力的关键。我用的增强组合包括常用的Mosaic、MixUp、HSV抖动、随机旋转和尺度变换但真正影响大的是两类针对性增强。第一类是“模拟遮挡增强”。从训练集里随机裁剪真实棉花叶片作为遮挡块粘贴在任何目标的上方并以随机比例遮挡目标区域。相当于在训练时人为制造更多遮挡样本让模型不因为目标被部分覆盖就大幅掉置信度。第二类是不同地物背景混合增强。把棉田里的滴灌带、地膜、杂草背景块单独提取出来叠加在目标周围模拟杂草丛生和背景杂乱的情况。增强比例上模拟遮挡增强在后期训练的40个epoch里逐步加大最后控制在总体样本的30%左右。具体操作用到了开源框架里的自定义数据管线在YAML配置文件里就可以灵活组合不用动模型代码。需要特别提醒的是农业图像增强时不要盲目使用颜色反转或者强锐化这类增强会破坏叶片和棉铃的纹理真实性反而导致模型对真实田间图像的适应性下降。3.4 标注质量控制和半自动标注几千张图像、几万个实例全靠人工标注既慢又容易出错。我采用的流程是“自动预标注 人工精修”。先训练一个初版模型跑一遍全部影像生成带置信度的预标注框标注员在标注工具里只做确认、删减、移动边框和修改类别。但这里面有一个陷阱如果预标注模型的错误率偏高标注员会产生“锚定效应”会无意识地接受模型给出的错误边界。所以我在流程里加了反锚定机制把大约20%的预标注框做随机偏移和缩放强制标注员必须手动修正每个框不能只点“接受全部”。最终每张图都经过二次抽检抽检比例不低于15%并对两次标注不一致的地方做仲裁复盘形成标注规范文档的持续更新。4. 训练调参与评估的完整记录4.1 硬件环境与训练配置整个资源不算豪华两台拥有24G显存的GPU服务器训练数据总量约8000张图像四类目标标注实例总数四万多。训练框架选用PyTorch为基础实现的DINO工程在此基础上改网络结构。超参数方面我给出实际可复现的一组配置输入尺寸短边800、长边1333优化器AdamW初始学习率主网络1e-4骨干网络1e-5因为骨干用到了预训练权重学习率小了防止灾难性遗忘权重衰减0.05批次大小每卡4张两张卡共8批总共训练72个epoch前5个epoch做线性warm-up。骨干网络采用ImageNet预训练初始化。只做检测任务骨干没继续冻住而是低学习率参与训练。batch size这件事很重要DETR系模型对batch size不敏感但去噪训练依赖一定量的正样本统计8这个数字在对比实验里明显比4稳定。显存允许的话batch size不要太小。4.2 评估指标与结果分析模型评价不能只看一个mAP。我同时统计了四类目标的AP50、AP75、AR平均召回率以及小目标面积小于32×32像素的AP_small和遮挡目标子集的AP_occ。因为棉田更看重“有没有漏掉”所以召回率指标在这套系统里的权重要高于精确率。实测数据列一下改进后的模型在验证集上的总体AP50约为87.2%mAPCOCO指标IoU从0.5到0.95取平均约为72.5%。类别上棉蕾AP50最高达到91%棉铃因为遮挡问题AP50为84.6%病害叶片由于部分病斑早期非常小AP50只有78.9%。专门统计的遮挡目标子集上改进模型的AP50比基线DINO-4scale提升了将近7个百分点。这些数字是在固定地块划分的验证集上得到的整体符合田间使用预期。有一点必须说明验证集的划分方式我用了“按地块划分”而不是“按图像随机划分”。随机划分会把同一架次、同一地块的图像同时分到训练和验证集中看似指标很高实际上模型见过的场景已经泄露了换到新地块效果立刻跳水。按地块划分后的指标才真实反映跨地块泛化能力。4.3 训练过程中的典型问题与排查训练里遇到最头疼的问题是去噪训练分支导致Loss在前几个epoch剧烈震荡一度怀疑代码有bug。排查后发现是去噪查询生成时对目标的随机噪声尺度过大和当前学习率不匹配。我把噪声标准差从0.8下调到0.5并配合warm-up学习率震荡问题才缓解。第二个常见问题是内存爆炸。4scale多尺度特征加P2融合分支后Encoder输入token数量大幅增加24G显存在batch size为8时会出现OOM。解决思路是把P2融合分支里的高分辨率特征图做下采样后再输入Encoder只保留叠加信息而不是把原始P2完整喂给Transformer。这样既保住了小目标的细节响应又控制了显存占用。第三个是过拟合问题表现在验证集指标下降到某个点后不再提升训练损失继续下降。这个问题靠增强和早停只能缓解根本解法还是补充大量不同地块、不同光照下采集的新数据。我在第二轮迭代里增加了大约3000张跨地块图像验证集mAP立刻提升了2个百分点。5. 从模型到系统推理部署与现场修正5.1 大图切片推理策略田间图像是几千像素乘几千像素的无人机正射图直接缩放后送进模型会损失大量小目标细节。我的做法是切片推理把大图按固定尺寸切成瓦片瓦片之间保留重叠区域重叠率设置为15%到20%。重叠的目的是防止目标被切在瓦片边缘导致截断不完整推理时每个瓦片独立输出检测结果再根据目标框中心点做重叠区域的去重合并。切片尺寸的选择需要综合考虑显存和上下文信息。尺寸太小单个棉铃可能不到几个像素且缺少周围果枝的上下文尺寸太大小目标数量多容易卡显存。我最终使用1024×1024的切片尺寸在推理设备上单瓦片耗时约80毫秒一块标准棉田的整图大概切成400个瓦片并行处理后全图推理不超过30秒。5.2 模型导出与加速DETR系模型部署比CNN模型稍麻烦一些因为很多推理引擎对Transformer动态形状的支持不够友好。我先做了ONNX导出固定输入尺寸为1024×1024然后转成推理引擎专用的IR格式开启FP16精度做图优化。这里特别要注意的是ONNX导出时必须把DETR解码器里的循环结构转换成静态图或者在推理框架里用插件方式补上动态部分否则导出会报错或产出的引擎结果和PyTorch不一致。FP16精度在棉田场景里实测几乎没有掉点mAP降幅在0.3%以内推理速度提升接近一倍。如果边缘设备更弱还可以做进一步的模型蒸馏用大模型输出作为软标签训练一个轻量小模型但在我这套场景里FP16已经满足时效要求就没有继续压缩。5.3 目标计数与生长监测分析检测框出来后系统还要把“框”变成“农事结论”。棉田管理通常按取样点统计系统把检测结果投影到地理坐标上按田块网格聚合。比如每个网格统计棉铃密度、棉蕾数量、病害叶片比例输出一张棉田长势分级热力图。计数去重是关键。同一株棉花可能出现在相邻瓦片的重叠区如果直接累加就会重复计数。我用的是目标中心点去重结合多帧跟踪匹配对同一地块多次飞行的结果做空间对齐只统计新增的目标从而监测棉铃生长增量。这个功能在实际使用中非常有用棉农可以直观看到一周内哪些区域棉铃增长慢、哪些区域病害扩散快。这里的一个经验是计数结果一定要给出置信度区间不要输出精确到个位数的数字因为模型本身有漏检精确数反而误导决策。我在系统里同时输出“模型识别数”和“校正系数”让使用者自己判断。5.4 已知限制和对抗场景处理这套系统的限制也很明显只能在可见光条件下工作遇到阴天、雾天、正午强逆光检测效果会下滑。应对办法是在数据采集时加入不同天气时段样本同时对极端光照图像做预处理归一化。棉田行间杂草和棉苗在苗期形态非常相似再强的模型也会混淆。我的做法是引入地理先验棉苗通常排列在播种行线上杂草更多出现在行间或地头利用空间位置先验做二次过滤能纠正一部分类别误判。系统更新迭代时还有一个容易踩的坑新模型改进了某些类别但可能在旧模型擅长的类别上回退。上线前必须做回归测试就是固定一批覆盖各种场景的永久验证集确保新模型在所有核心场景上的关键指标不出现明显回退然后再灰度发布。6. 常见问题与排查速查6.1 问题速查表下面这组问题是我在实际训练和部署中反复遇到的整理成表格方便快速定位。问题现象可能原因对应解决方案训练Loss震荡严重去噪扰动尺度过大、学习率偏高降低噪声标准差、加强warm-up棉铃小目标几乎不检浅层特征缺失、输入分辨率不够增加P2融合、提高输入图像短边验证集高但换地块崩按图像随机划分导致数据泄露改成按地块/按航次划分遮挡目标置信度低训练样本中遮挡目标过少加入模拟遮挡增强、强制标注遮挡目标推理时内存溢出DETR解码器动态形状、显存不足固定输入尺寸、开启FP16、减小batch相邻瓦片重复计数瓦片重叠去重逻辑不完善按目标中心点去重、重叠区域IoU合并棉蕾和病斑混淆类别间视觉纹理接近增加上下文特征解耦头、扩大标注样本雾天/阴天效果下降可见光成像受天气影响采集多气象数据、图像增强归一化6.2 工程层面的避坑经验农业AI项目里算法只占一半另一半是工程和流程。第一文件命名和版本管理不能乱每轮数据采集都要记录地块编码、飞行高度、天气、日期模型训练时要把这些元信息一并记录到日志里否则后期排查数据问题根本无从下手。第二标注规范要前置最好在采集第一批数据时就同步定好不要边标边改规则否则之前标好的图全部要返工。第三模型训练要有一个固定的“不可变验证集”所有迭代版本都在这上面跑保证指标可对比。在模型迭代策略上我的体会是“小步快跑”优于“憋大招”。不要等所有数据收齐、所有模块都完美了再训练第一版而是先拿一批数据训练一个粗糙模型用来支撑数据质检和困难样本梳理。很多标注错误和采集盲区都是第一版模型的失败案例“逼”出来的越早看到这些失败数据闭环就越早转起来。6.3 从研究到落地的三个认知这个过程做下来我有几个认知层面的体会。第一用户永远不关心你的模型叫什么名字只关心你能不能数清棉铃、能不能告诉他哪块地生病了。所以在系统设计上算法模块和业务模块的接口要尽量简单业务侧只消费“框类别置信度空间坐标”这几个字段就够了。第二改进模型不要贪多。DINO本身已经很强我实际有效的改进也就是三点P2融合、去噪训练适配、类别解耦头。改太多模块会引入大量变量出了问题很难定位。第三数据策略比网络结构更影响最终效果。我后期几乎一半的时间在补数据和修标注模型结构基本冻结但每次数据层面的优化带来的提升都实实在在。按照这套流程我后来又把这个系统扩展到了其他作物上比如油菜花期的角果识别、果园幼果期的果径估测核心模型改动很小主要是重新采集数据、调整类别标签体系。这也说明改进DINO-4scale这类检测模型本身并不是终点把它变成一套能快速适配不同农业场景的“数据 模型 部署”流水线才是更有价值的事。如果正在读这篇博客的你也要做类似项目我建议先花两周时间把数据规范和验证集定好再动手改模型结构这样的顺序能少走很多弯路。