CVPR 2020的Workshop清单刚公布那几天,我所在的小组就盯上了Anti-UAV这一场。反无人机检测与跟踪挑战赛,主办方还拉了澎思科技等企业一起组织,说白了就是拿真实监控视频,让大家用计算机视觉去锁定画面里那些小得几乎看不清的无人机。这类比赛前几年少见,因为“无人机目标”和常规行人、车辆目标差异太大,很多在白天数据上跑得飞快的检测器,到了无人机视频里直接失效。所以这次挑战赛既有算法比拼意义,也逼着参赛者重新审视小目标检测和长时跟踪的基础问题。
我当时第一时间下载了比赛的说明和数据集,拉着两个师弟组了队,前后折腾了快一个月。这篇文章就把我们踩过的坑、试过的方法和最后提交的套路整理一下。如果你正准备参加类似的反无人机比赛,或者想入坑小目标检测、单目标跟踪,这篇内容应该能给你省下不少试错时间。需要注意,比赛和Workshop征稿其实是一体的,算法成绩是“硬通货”,但把方案写成技术报告同样有价值,这一点很多队伍忽略了。
1. 背景:为什么“反无人机”成了CVPR的正式考题
1.1 无人机目标为什么让常规检测器“失灵”
先看目标本身。无人机在监控画面里的成像尺寸非常小,很多帧只有十几个到几十个像素,长宽比也不固定。四旋翼在悬停时像一个十字形亮点,在飞行时又常常糊成一小团,颜色和天空、楼房边缘、云层接近。常规的目标检测模型,像Faster R-CNN、SSD,训练数据里主要是行人、车辆、常见物体,对这类极小而缺乏纹理的目标天然不敏感。小目标在特征金字塔里往往下采样几次后就剩几个像素,特征被背景淹没。
这里还有物理层面的原因。监控摄像机为了覆盖大场景,通常用广角镜头,远处无人机的实际物理尺寸可能只有几十厘米,投影到传感器上就是几个像素。再加上运动模糊、镜头散焦、H.264压缩带来的块效应,目标的边缘早就模糊掉了。我们当时把几段视频逐帧放大看,很多帧里无人机就是一团灰色噪点,人眼都要仔细辨别,模型就更难学了。
另外,真实监控视频里的环境变化极大。有逆光、有雾、有夜晚,无人机飞过树丛时会短暂遮挡,背景里有鸟、风筝、无人机玩具,甚至飞虫。这类干扰物和目标之间的区别,在单帧静态图像上看几乎无法判断。所以比赛才把“检测”和“跟踪”合在一起,逼着参赛者利用时序信息。动态场景下的目标外观变化剧烈,同一台无人机在画面里一会儿正面、一会儿侧面、一会儿又只剩个轮廓,仅靠模板匹配根本无法稳定跟住。
1.2 Anti-UAV挑战赛的任务定义与评测逻辑
需要先弄清比赛到底考什么。Anti-UAV挑战赛的核心任务可以拆成两条线:一是无人机检测,给定一段视频,预测包含无人机的空间和时间范围,也就是“什么时候出现、在哪出现”;二是无人机跟踪,在第一帧给定目标框后,持续输出后续每一帧的目标位置。两条线共用同一套真实场景数据,评测时会把检测结果和跟踪结果放在一起看。这种方式实际上借鉴了视频目标检测和单目标跟踪两大方向,对算法在“检测召回”和“跟踪稳定”之间做平衡。
从主办方公布的材料看,数据采集来自城市、郊区、海面等不同场景,无人机大小和飞行距离各有差异,还有大量“只有一帧能看见,下一秒就飞出画面”的片段。评测逻辑和常规检测有所区别,对检测任务来说,只要框的位置基本对上就算命中;对跟踪任务来说,则要求整个序列上的成功率,出现漂移后即使能重新找回,中间帧也会被判为失败。这一点和我们熟悉的OTB/UAV123这类benchmark一致,但反无人机场景里目标尺寸更小,失败恢复更难。
除了挑战赛,Workshop本身还有一个征稿环节。主办方鼓励参赛队伍把技术方案、数据集分析、失败案例写成短论文投稿。这个设置很聪明,因为比赛分数只能反映“结果”,而论文可以讲清楚“为什么这个设计有效”。很多在检测任务里刷高分的队伍,最终通过技术报告把工程经验转化成了可引用的研究结论。所以参加这个比赛,既要盯着排行榜,也要留出时间准备论文材料。
2. 核心技术点与参赛方案设计
2.1 检测器选型:精度与速度的平衡
选检测器之前,先看两个硬约束:一是目标太小,二是视频分辨率高。比赛的验证集是1080p甚至更高分辨率的监控视频,直接整图输入到通用检测器,等于把目标压到十几个像素,效果不会好。我们最初试过YOLOv5s,单帧速度确实快,但小目标召回低得可怜。后来换成YOLOv5x加高分辨率输入,配合TTA(测试时增强),效果提升明显,但训练和推理时间也涨了很多。
这里有个通用思路:如果目标是微小目标,优先做“图像分块”而不是简单缩放。把一帧图像切成有重叠的4块或9块,分别送进检测器,把结果按坐标合并,能够显著提升小目标的检测率。代价是计算量成倍增加。比赛里对单帧时间没有特别严格的限制,所以我们采用了分块加多尺度融合的方案,最终在检测任务里的召回比整图推理高出不少。
我当时做了一张简单的候选方案对比表,帮助团队快速决策:
| 方案 | 小目标召回 | 推理速度 | 显存占用 | 我们的结论 |
|---|---|---|---|---|
| YOLOv5s 640输入 | 低 | 快 | 低 | 只用于快速验证pipeline |
| YOLOv5x 1280输入 | 中 | 中 | 高 | 适合作为主检测器 |
| YOLOv5x + 四块切图 | 高 | 慢 | 很高 | 最终提交的主方案 |
| Faster R-CNN + FPN | 中高 | 很慢 | 高 | 只做候选框融合 |
| 更重的Transformer检测器 | 取决于权重 | 慢 | 很高 | 当时条件不支持,留给后续尝试 |
这个表格背后是一个取舍逻辑:在比赛场景下,准确率优先于实时性,因为我们的目标不是部署到嵌入式设备,而是拿到尽可能高的评测分数。如果你的需求是在无人机反制设备上实时运行,那肯定要换轻量网络加剪枝,这是另一个话题了。当时我们也在想,如果选择带DETR结构的新框架,小目标能力或许更强,但训练成本和不确定性实在太高,比赛周期不允许,所以最终还是用了成熟方案。
2.2 跟踪器选型:长时跟踪与在线更新
检测处理的是“有没有无人机”,跟踪处理的是“这一只无人机到底在哪”。我们试过两个流派:基于相关滤波的,和基于孪生网络的。相关滤波类的KCF算得快,但目标一变形就漂移,对无人机这种外观剧烈变化的目标不靠谱。后来换成SiamRPN++和SiamMask,准确度上去了,但速度慢不少。SiamRPN++在目标超过画面一定比例时表现最好,无人机这种小目标依然容易丢。
放弃纯跟踪器后,我们转向“检测+跟踪”双头方案:检测器每帧输出候选框,跟踪器在上一帧附近做局部搜索,两边结果用IoU做关联。一旦检测连续若干帧都认为某个位置有目标,就刷新跟踪模板。如果跟踪器在一段时间内没有找到可靠目标,就用检测器全图找人,找到后再重新初始化。这个逻辑听上去简单,但实际代码里要处理很多状态切换,比如目标暂时离场、出现多个候选框、检测器误检等。
我们参考了UAVDT竞赛里一些开源的baseline,把状态机画清楚后,跑出来的稳定度明显高于只依赖单一跟踪器。状态机大概分四档:Confirmed表示当前有高置信度检测框且跟踪器匹配稳定;Tentative表示检测到了相邻几帧候选框,但还没有足够证据;Lost表示已经连续丢了若干帧;Recovered表示在Lost状态下被检测器重新找回。每一帧执行流程都是从跟踪器预测出发,再用检测器结果修正,最后更新状态。状态切换条件一定要写清楚,否则多线程调参会把人折磨疯。
2.3 融合策略:检测与跟踪如何互相兜底
融合的核心是“双阈值决策”。把检测器输出的置信度分成两档:高置信度框直接作为跟踪的观测,低置信度框只用来提醒“疑似目标”,不立即更新模板。跟踪器给出的轨迹如果和检测框重叠度高,就采纳跟踪结果;如果长时间没有检测框支持,就把跟踪状态标为lost,不输出不可靠的结果。这个策略能有效减少误检,代价是会漏掉一些只出现一两帧的目标,但对最终成功率影响不大。
另一个容易被忽视的细节是去重。监控画面中可能出现两个或多个无人机,也可能出现飞机、鸟群。我们加入了基于外观特征的简单分类器,把检测框内的图像裁剪出来,用一个小网络判断“无人机/鸟类/背景”。实际操作中不用训练复杂的网络,用预训练分类网络提取特征,再加一个逻辑回归,效果就不错。把鸟类误检压下去之后,跟踪漂移率明显下降。
我画了一下整个流程的决策顺序:对每一帧视频,先用YOLOv5x分块推理得到大量候选框,置信度高于0.7的框进入跟踪关联;低于0.3的直接丢弃,中间档保留为“疑似”,并裁剪外观特征送给小分类器。分类器如果再给出较高置信度,就提升为观测;否则忽略。跟踪器在上一帧预测位置附近做局部区域搜索,与观测框计算IoU后形成匹配矩阵,用匈牙利算法做数据关联。最后根据状态机更新目标框并输出结果。这个流程写起来复杂,但每一步都有明确的输入输出,方便单独调bug。
3. 实操过程:从数据集到提交结果
3.1 数据集分析:先看再练
拿到数据后不要急着训练,先做一轮全量可视化。我们写脚本把所有视频抽帧,按目标框大小画直方图,发现绝大部分标注框的宽高都不超过40像素,甚至在20像素以下的占比超过一半。这说明无论检测器还是跟踪器,都要面向极小目标调优。我们还统计了目标出现帧的比例,有些序列目标一直存在,有些序列前一半是空背景后一半才出现目标,这对检测器的时域后处理很有影响。
可视化里还有一个重要发现:很多无人机在画面中飞行的轨迹并不平滑,因为无人机可能悬停、急转、瞬间拉升,不像行人那样有稳定的运动模型。这导致我们不能依赖卡尔曼滤波做强预测,只能把它当成位置平滑工具,主要靠视觉匹配来关联目标。建议大家在自己做项目时也先做这一步,哪怕只是写个简单脚本把目标框叠加到视频上,也能避免后面的无效调参。
数据标注格式通常是一份JSON或txt文件,记录每帧的目标框坐标、置信度、出现状态。我们搭建了一套数据管线,把原始标注转成检测器训练用的格式,同时保留原始视频的时间戳,便于跟踪任务使用。如果主办方提供的是不同格式的验证集标注,提前写好转换脚本可以省下大量时间。更细节的是,标注坐标系统到底基于原图还是基于抽帧后的图像,有些数据集给的坐标会相对于降采样后的帧,如果不转换直接训练,模型输出的位置会系统性偏移。
3.2 数据增强与样本处理
数据增强是这次比赛的关键突破点之一。标准的随机翻转、颜色抖动对无人机这种小目标帮助有限,更有效的是把同一帧中的目标复制粘贴到背景视频帧上。我们做了两种增强:一是随机位置粘贴无人机小目标,二是把目标放大缩小后贴到远处,模拟不同拍摄距离。使用这类“target-in-background”增强后,检测器的召回率提高了不少,尤其在目标极小的区间内明显更稳。
马赛克(Mosaic)增强也是推荐使用的。把四张图拼在一起,一张大图里目标密度变大,模型能学到更多背景上下文。使用马赛克时需要注意目标框可能会被截断,代码里要把被截断的目标过滤掉,否则训练时会出现大量不完整目标,干扰模型收敛。此外,我们还尝试了MixUp,但发现对检测框回归的帮助不如直接粘贴目标,所以最终没有使用它。
小目标检测还有一个惯用技巧:在训练时将输入分辨率提高到原始视频的0.5到1倍,而不是缩到640x640。如果显存不够,可以先切图再拼batch。切图会造成目标分布不均匀,部分分支没有目标,所以要设置合理的batch大小,保证每个batch内至少有部分图存在目标。这个细节很多人忽略,结果模型容易学到“输出空框”。
剪裁粘贴的伪代码思路大致是这样的:从训练样本中随机挑一个真实目标框,分割出目标图像;在另一张背景图随机选一个位置,把目标图像按随机尺度缩放后贴上去;更新标注框坐标,并限制在图像范围内;如果某一帧同时粘贴多个目标,还要保证目标之间不互相重叠。这个做法很像实例分割里的复制粘贴增强,但针对无人机小目标,我们会把目标缩得很小,让模型适应“一小团像素”的目标形态。
3.3 训练细节与调参心得
我们的训练分成两个阶段。第一阶段用COCO预训练模型,在自己的数据集上固定骨干网络,只训练检测头和FPN层,学习率设为0.001,跑大概30个epoch。第二阶段解除骨干冻结,学习率降到原来的十分之一,再训练20个epoch。这个策略比一来就全量微调稳定得多,不会把预训练特征破坏掉。反无人机数据量不大,直接全量微调容易过拟合。
评估时不要只看mAP,要看不同目标尺寸下的AP。我们按标注框面积把目标分成小、中、大三档,观察模型在什么尺寸范围最弱。如果小目标AP低,就回去调增强策略或加高分辨率分块。如果中等目标AP低,可能是标注质量问题,要检查数据转换脚本是否把坐标归一化错了。每个团队成员可以在不同模型配置上并行跑,用统一脚本输出报告,能极大提高调参效率。
训练时我们还用到了混合精度和梯度累加。混合精度在V100上能省一半显存,batch size可以翻倍,但要注意loss出现NaN时要关闭自动混合精度检查。梯度累加适合小显存环境,不过会拉长训练时间。比赛周期一般只有几周,建议先把一个完整流程跑通,再考虑优化训练时长,别把时间耗在刷分上。
下面是我们最终常用的一组训练参数,供参考:
| 参数 | 数值 | 说明 |
|---|---|---|
| 输入尺寸 | 1280x1280 | 靠近原始视频分辨率 |
| 初始学习率 | 0.001 | 使用余弦衰减 |
| batch size | 8 | 两张卡各4,配合混合精度 |
| 优化器 | SGD动量0.9 | 比Adam收敛更稳 |
| 总epoch数 | 50 | 早停阈值设为5个epoch |
| NMS阈值 | 0.7 | 减小框抖动 |
| 置信度阈值 | 0.3 | 候选框过滤 |
| TTA | 多尺度+翻转 | 测试时开启,在线提交前跑一次 |
这个配置不是万能的。如果数据集目标尺寸分布完全不同,一定要调整输入尺寸和锚点。YOLO系列需要根据目标大小重新聚类anchor,我们就把anchor从默认的COCO聚类结果换成了以20像素为中心的小尺寸分布,这一步对召回率影响非常大。很多人漏掉这个细节,拿着默认anchor硬跑,小目标自然效果差。
4. 评测指标与提交陷阱
4.1 关键指标:成功率、精确度、召回率怎么算
反无人机挑战赛的官方评测通常沿用单目标跟踪的指标:成功率(Success Rate)和精确度(Precision)。成功率计算的是预测框和真实框之间的IoU超过某个阈值(通常是0.5)的概率曲线,目标框越大,达到0.5 IoU越容易,因此小目标序列的得分天然偏低。精确度一般是中心位置误差小于20像素的帧占比,对无人机这种小目标更友好,但也更容易被孤立的正确点拉高。
这就造成一个矛盾:用成功率衡量,算法会倾向于输出大框来增加IoU,因为稍微重叠一点就能过阈值;用精确度衡量,则倾向于集中预测中心点,框的大小反而没那么重要。我们实际调试时发现,跟踪器在目标快速移动时经常出现“预测框大小正确但中心偏了”的情况,导致精确度掉得厉害。最后在输出阶段专门加了一个坐标平滑项,用前后帧中心点的加权平均替代单帧原始输出,效果立竿见影。
检测任务方面,主要看召回率(Recall)和误检率(False Alarm Rate)。反无人机背景下,目标是“确保不漏检”比“确保不误检”更重要,因为漏检会让跟踪器失去目标。但也不能忽视误检,如果算法把云层边缘和飞鸟都当成无人机,跟踪状态机就会频繁重置。我们在提交前专门统计过各类误检来源,把阈值调到一个平衡点,而不是单纯追求验证集最高分。
很多第一次参赛的队伍会忽略时序一致性。单帧检测结果即使准确率很高,也会存在某一帧漏检、下一帧又出现的情况。评测跟踪任务时,这种“闪烁”会让成功率变得很难看。我们加入了最少存活帧数的后处理:如果一个目标只连续出现了不到3帧,就直接忽略。这能有效压制检测器在低置信度区域的随机跳变,但也会把真正只停留一两帧的目标丢掉。在反无人机场景里,目标通常会出现一小段时间,所以这个折中总体划算。
4.2 提交格式与时间戳上的坑
这类比赛的提交接口对格式非常严格,稍微差一个字段就会导致部分序列判零分。我们第一次提交时,提交文件的帧索引从0开始,而官方要求从1开始,结果一大半序列失败,才发现问题。建议大家提交前写一个校验脚本,把预测框按视频时间戳重排,检查是否有越界坐标,是否出现负宽高,以及是否漏掉某些帧。程序化的校验远比肉眼查看靠谱。
时间戳问题是另一个隐蔽坑。官方数据集的视频帧率不统一,有的序列30fps,有的15fps,模型输出时如果不按原始时间戳对齐,后续的跟踪轨迹就会出现偏移。我们的做法是直接从视频文件读取帧序号,不依赖文件名里的数字,因为有些序列文件名带有相机编号。处理完后再随机抽几个序列可视化,确认“目标框跟着无人机走”再提交。
我写校验脚本的思路很简单,就是用opencv读取视频,得到总帧数,然后遍历自己的预测文件,把越界帧或坐标越界的行打印出来。这个脚本不复杂,但能在提交前拦截90%的格式问题。我们当时还发现,有些预测框坐标是浮点数可能被四舍五入丢失了精度,但官方允许带小数,所以一定要保持浮点输出而不是转成int再保存。
4.3 常见问题速查表
我把这次比赛遇到的高频问题整理成一个表:
| 问题 | 可能原因 | 解决办法 |
|---|---|---|
| 小目标检测全部漏掉 | 输入分辨率太低 | 切图/高分辨率输入/多尺度推理 |
| 预训练模型权重下载失败 | 网络环境受限 | 提前下载并本地备份 |
| 跟踪目标突然丢失 | 目标遮挡或背景相似 | 检测器全图搜索重新初始化 |
| 高频误检飞鸟 | 分类器不够强 | 加入外观分类网络/时域一致性判断 |
| 提交后部分序列零分 | 帧索引或字段格式错误 | 写校验脚本逐序列检查 |
| 训练loss下降但AP不涨 | 数据增强过度或过拟合 | 降低增强强度/早停 |
| 检测框抖动严重 | 模型对极低置信度框敏感 | 提高阈值/非极大抑制参数调整 |
逐条说一下:预训练模型的问题看似小事,但在比赛现场很致命,如果网不好,提前一天下载好所有权重;跟踪丢失的恢复问题要专门调试,建议记录目标消失前的位置和速度,当作下一次搜索的先验;检测框抖动方面,我们发现把NMS的IoU阈值从0.5调到0.7能有效抑制抖动,代价是可能把前后两个相邻的候选框合并掉。另一个经验是,如果发现验证集分数比训练的最后一个epoch高出很多,通常不是模型突变了,而是TTA起了作用,这种分数要谨慎参考,因为提交环境不一定允许开TTA。
5. 除了比赛,Workshop投稿也该重视
5.1 技术报告和论文的含金量
很多人以为参加比赛就是提交结果拿名次,忽略了Workshop本身还有征稿环节。CVPR的Workshop通常会有正式的论文通道,主题涵盖无人机检测、小目标跟踪、对抗样本等,虽然没有主会议论文那么顶,但对刚入行的同学来说是很好的学术训练。如果队伍在实践中摸索出了有效的数据增强方法、跟踪状态机设计,或者发现了一个现有数据集的评价偏差,都可以整理成短论文投稿。竞赛的技术报告还能作为论文的支撑材料。
具体到Anti-UAV Workshop,征稿内容往往包括研究论文、挑战赛参赛队伍的技术报告,以及数据集描述。投稿格式一般会沿用CVPR模板,页数限制较短,但审稿周期比主会短很多。如果你的算法在评测集上能排到前列,写报告时要突出“为什么有效”,而不是单纯描述“我们用了YOLO”。我们在报告里详细写了状态机切换策略和分块推理的取舍,审稿人给出的意见对我们后续研究帮助很大。
5.2 如何把比赛经验变成一篇能讲清楚的技术报告
写技术报告别急着堆结果,先把问题定义缩小。与其泛泛写“反无人机检测”,不如聚焦某一个难点,比如极小目标下的召回率提升。然后配上充分的对比实验,证明你提出的某个设计确实有效。对比实验不需要很多模型,但一定要控制变量,比如同样训练参数下,有无分块推理的差距是多少。这个数字比任何话术都有说服力。
还有一点,技术报告要说明失败案例。我们当时写了一段“为什么SiamRPN++在部分序列失效”,分析是因为目标过早丢失,模板无法更新。这个分析反而成了报告里最容易被引用的部分。如果能把失败原因总结成一个规律,比如“目标外观变化速度超过模板更新频率”,就更有价值。Workshop评审通常更看重洞察,而不是单纯的分数。
投稿时的图表也很关键。可以把状态机的流转图画出来,但这里的图不是mermaid,而是用绘图工具画的状态转移框图。其他常用的图包括:目标尺寸分布直方图、不同分辨率下的召回率曲线、典型失败帧截图。截图比任何文字都直观,尤其是展示“无人机只有十几个像素”的时候,读者一下子就能理解问题难度。排版用LaTeX模板即可,图表字体尽量和正文一致,别出现看不清坐标轴的情况。
6. 一些可持续复用的经验
训练和调试过程中,我们逐渐沉淀出几条通用经验,放到其它小目标检测项目里也一样好用。第一,数据可视化和误差分析是第一步,不要跳过;第二,检测器做召回,跟踪器做精度,两者一定要解耦,不能指望一个模型解决所有问题;第三,保存好每次实验的配置和输出,哪怕只是改了一个NMS阈值,也要记录,否则到后期完全不知道哪个版本最好。
关于硬件,我们用的是两片GTX 1080Ti,训练YOLOv5x需要把batch size压到8,然后用混合精度勉强跑动。如果有V100或3090会轻松很多,但小显存也能通过切图和梯度累加完成训练。推理阶段我们单独用一个带显卡的机器跑验证集,把检测和跟踪分开部署,避免显存互相挤占。这类比赛时间紧,建议优先保证实验可重复,而不是追求一次性刷出最高分。
实际操作中还有一个容易忽略的点:保存模型时不要只保存最后的epoch权重,要保存验证集指标最好的几个epoch权重。我们在第三周才发现验证集分数最高点出现在第18个epoch,而训练脚本默认只保存了最后一个epoch结果,重新用了好几天补跑。这属于典型的“教训型经验”,希望后来的队伍少走弯路。
最后再分享一个小技巧:验证集上如果发现某一类序列表现特别差,可以单独拿出来做针对性调试,而不是把整个模型推倒重来。比如有些低照度序列,我们把图像做一次CLAHE增强再送进检测器,这类序列的召回率就明显提升;有些背景杂乱的序列,则更适合关闭切图模式,因为切图后目标可能被切到块边界,反而增加漏检。这种按“场景心态”而非“模型心态”去调参,和平时在通用数据集上刷分很不一样。
收个尾吧,Anti-UAV这种挑战赛的价值不在于它叫CVPR Workshop,而在于它真正逼着人面对小目标、遮挡、类间干扰这些现实问题。即使不参加比赛,把数据下载下来跑一遍检测和跟踪,也能学到很多在常规公开数据集上学不到的东西。我后来在做智慧城市相关项目时,小目标检测模块就是直接从这次比赛方案里摘出来的,省了不少时间。后面如果主办方发布新一年度的任务,我大概率还会再报名,毕竟这类数据集越来越稀缺,能人肉调一调“几乎看不见的无人机”,本身就是一件挺有意思的事。