无人机在露天矿上空转一圈,真正有价值的不只是“拍到画面”,而是能认出画面里每一台设备是谁、正在干什么、从哪条路往哪里开。矿区里几十台矿卡长得几乎一个样,从俯视角度往下看更是难以分辨,单纯做目标检测只能告诉你“这里有一辆车”,下一帧它换了个位置,你就不知道是不是原来那一辆了。所以露天矿巡检的刚需,不是检测模型,而是“检测+跟踪一体化”的轻量化模型。标题里那个4.39M参数、8.3W功耗的方案,恰好就是这种需求的典型解:一个模型同时输出边界框、类别和用于跨帧关联的特征,机载边缘端实时跑,无人机在空中就把“谁在哪、轨迹如何、有没有异常”一次搞清楚。这篇分享不打算讲虚的,直接拆解这个方案背后的设计思路、数据准备、部署流程和我踩过的坑。
1. 为什么露天矿巡检必须走“检测+跟踪一体化”的路
1.1 露天矿场景和普通安防监控根本不是一回事
我们平时在园区、停车场做的监控,摄像头固定,视野固定,目标从远到近、从近到远,变化是相对平稳的。露天矿的无人机巡检完全不是这个逻辑:飞手或航线程序控制飞机沿着采场台阶、坡道、排土场边缘飞行,相机一会俯视、一会斜视,画面里的目标小、速度快、互相遮挡严重。更重要的是,矿卡和挖掘机是流水作业的,一辆车刚从装载区出来,下一刻可能就被另一台车挡住,或者开进扬尘里看不见了。这个时候只输出一帧一帧的检测框,对调度和安全人员来说基本没用,他们真正要的是“这条轨迹是哪台车”,是要看清设备行为趋势的。
我在这类项目里最深的体会是:检测是单帧能力,跟踪是时序能力。露天矿巡检的安全价值恰恰在时序上。比如某辆矿卡疑似驶入危险区域,或者某人员长时间停留在设备盲区,这些都需要连续几帧甚至几十帧的轨迹才能判断。只靠检测模型逐帧跑,输出是碎片化的,地面站那边要再做一次跨帧匹配,等于把复杂度往后端推。而无人机机载算力有限、链路回传也不稳定,最合理的做法就是把检测和跟踪全部放到机载端,直接输出结构化轨迹。
1.2 传统“检测+单独跟踪”方案为什么在机载端跑不动
很多人第一反应是:检测用轻量模型,跟踪用经典的多目标跟踪框架,比如检测后接卡尔曼滤波加匈牙利匹配,再不行加一个单独的重识别特征提取网络。这套方案在服务器上确实能跑,但上了无人机就出问题。核心原因是算力和功耗账算不过来。
可以简单算一下:假设检测模型一次前向约30ms,单独的重识别特征提取网络跑一次约25ms,两步加起来单帧至少55ms。无人机机载平台本身就是低功耗设备,主流边缘AI盒子的整机功耗预算通常在10到25W之间。检测和跟踪分开跑,不仅算力翻倍,功耗也会明显上升,而且两套模型在嵌入式平台上就是内存带宽和NPU调度上的双重开销。机载平台本身还要处理飞控、图传、云台增稳,你要是把NPU跑满,航向指令的响应延迟都可能受影响。
更麻烦的是,传统方案里的“重识别”网络通常是在行人数据集上训练的,它提取出来的特征在俯视航拍场景下,对同型号同颜色的矿卡区分度很差。你花了一倍的算力去提特征,结果发现两辆紧挨着的同款矿卡依然分不清,这就很尴尬。所以一体化模型不是炫技,是被功耗和场景逼出来的务实选择。
2. “检测+跟踪一体化”模型内部到底长什么样
2.1 共享骨干网络:一个前向同时输出框、类别和特征
所谓“检测+跟踪一体化”,核心思想是让特征提取骨干网络被检测分支和跟踪分支共用。输入一帧图像,经过骨干网络提取特征,再经过特征融合结构得到多尺度特征,后面分出两个头:一个头输出检测框和类别,另一个头输出每个目标的嵌入特征,也就是一小段向量,用来描述这个目标长什么样。跟踪器拿到当前帧的检测框和嵌入特征后,和历史轨迹进行匹配,实现跨帧关联。
这种结构最直接的好处是计算量只比纯检测多一点点。因为嵌入特征是在检测框对应的特征点上提取的,通常只是加了一个很小的卷积头,参数量增加有限,推理时间几乎可以忽略。我们最终拿到的模型参数量4.39M,就是一个很典型的共享骨干实现。
我给当时的模型拆过参数,大致分布如下:
| 模块 | 参数量 | 占比 | 作用 |
|---|---|---|---|
| 轻量化骨干网络 | 约2.1M | 48% | 提取基础视觉特征 |
| 轻量化特征融合结构 | 约1.2M | 27% | 融合多尺度信息,兼顾大小目标 |
| 检测头 | 约0.6M | 14% | 分类与回归,输出目标框 |
| 嵌入特征头 | 约0.5M | 11% | 输出128维目标嵌入特征 |
这里有个很容易忽略的细节:4.39M参数听起来不大,但它是整个网络的完整参数量,不是主干网络的参数量。不少人对比模型大小只看主干,结果部署时发现完整模型比自己预期的大一倍。我建议评估模型时一定要以“端侧可运行格式”的工程文件大小为准,包括预处理和输出后处理这些环节都算进去。
2.2 带嵌入特征分支,还是纯检测加关联匹配
在做一体化方案的时候,实际有两条技术路线可以选:一条是像JDE、FairMOT这类经典做法,在检测网络里同时训练一个嵌入特征分支,用嵌入特征做跨帧外观匹配;另一条是学习ByteTrack这类纯检测关联思想,只用检测框的IoU和置信度做匹配,不额外提取任何特征。
两者在露天矿场景下的取舍很微妙。ByteTrack的优点是零额外计算,实现也简单,它靠“先高分框匹配、再低分框二次匹配”的策略,把遮挡和漏检的情况处理得相当好。但它有一个软肋:如果两台矿卡擦肩而过,或者一前一后非常接近,IoU匹配很容易认错,因为矿卡从俯视看几乎就是同一个长方形。而带嵌入特征分支的方案多花了一点算力,换来的是外观上的区分能力,对同款车型密集出现的矿区来说,这个付出是值得的。
| 对比维度 | 仅检测+关联(ByteTrack思路) | 检测+嵌入特征联合训练 |
|---|---|---|
| 额外算力开销 | 几乎为零 | 每目标多一次特征比对,开销很小 |
| 同款车辆区分能力 | 弱 | 较强 |
| 实现复杂度 | 低 | 中 |
| 典型适用场景 | 人员稀疏、目标间距大 | 车辆密集、外观相似度高 |
实际项目里我们做的是折中:模型输出带嵌入特征,跟踪匹配时先用嵌入特征的余弦相似度做第一轮匹配,匹配不上的再退到IoU匹配兜底。这样既不会在目标外观相似时频繁切错ID,也不会因为个别帧特征质量差就把轨迹丢掉。
3. 数据是露天矿巡检真正的门槛
3.1 跟踪数据标注,比想象中费劲得多
模型结构定下来后,最折磨人的不是调参,而是跟踪数据的准备。检测任务只需要每帧画框,跟踪任务则要求在每一帧里保持同一个目标的全局ID一致:这一帧右上角的矿卡和上一帧左边那辆是同一个人,必须给同一个ID。这样标注起来工作量成倍上升,因为标注员不仅要看当前帧,还要回看历史帧,判断每一辆车是不是之前出现过的那辆。
我们当时做了个折中方案,效果很好:采用“缩时标注”策略。不是每一帧都标,而是每隔5帧标一次,中间4帧的目标位置用线性插值先算出来,生成一批粗糙轨迹,然后标注员只需要核对和修正明显不对的框,不用从零开始画。这样效率大约提升了三倍,而且跟踪ID的连续性完全没受影响。对帧率30fps的视频,只标其中20%的帧,跟踪器训练时再按整段视频连续样本去训练,实测指标和全帧标注差异在可接受范围内。
另外一个关键点:要对轨迹走向做覆盖性控制。无人机巡检航线通常覆盖采场、排土场、运输主干道、破碎站等多个区域,数据不能全集中在某一两个好拍的机位。我们在采集时给飞手定了个约束:每个区域至少飞两种高度、两种角度。俯视高度能看到全貌,低空斜视能看到车身侧面特征,这两种视角对训练外观嵌入特征至关重要。只拍俯视,模型永远学不会区分车头和车尾。
3.2 粉尘、逆光、小目标:数据增强不能省
露天矿的环境特征是扬尘多、逆光强、阴影重、目标小。如果只用干净图像训练,模型一上飞机就会发现现实世界的图像质量和训练集差太多。我自己采集的数据里,扬尘严重时边缘的车辆像蒙了一层纱,轮廓都看不清;正午逆光时车身亮成一团,细节全没了。光靠常规的随机翻转、颜色抖动完全不够。
| 增强方式 | 模拟的真实环境 | 参考参数 |
|---|---|---|
| 高斯噪声/模糊 | 扬尘、低能见度 | 噪声标准差5到15,模糊核2到5像素 |
| 随机亮度/对比度 | 逆光、阴影 | 亮度变化系数0.7到1.3 |
| 运动模糊 | 无人机飞行振动 | 模糊长度3到8像素,角度随机 |
| 随机遮挡 | 设备交错、电塔遮挡 | 遮挡块面积5%到15% |
| 多尺度缩放 | 不同飞行高度 | 缩放比例0.5到1.5 |
其中扬尘是最有价值的一项增强。因为矿山粉尘是持续存在的,不是偶发现象,模型如果对模糊和低对比度不敏感,到了现场基本就是睁眼瞎。我们甚至专门合成了带粉尘干扰的夜间光晕图像,用于夜间巡检测试。实际效果上,没做过粉尘增强的模型在真实扬尘工况下小目标漏检率高出一倍多。
小目标问题也要单独说。矿卡在离地100米的俯视画面里,目标尺寸可能只有32×32像素左右,多尺度特征融合对这类目标很关键。模型输入分辨率选768×448而不是更小的VGA级别,也是出于小目标召回率的考虑。分辨率提高,整图计算量上升,但换来的是小目标漏检明显下降。功耗和精度之间总要找一个平衡点,我们的平衡点就落在768×448加上INT8量化。
4. 边缘终端部署:8.3W到底是怎么跑出来的
4.1 机载边缘AI盒子与功耗预算
标题里那个8.3W,指的是一块典型的边缘AI核心板在跑这个模型时的整板功耗。这类板子的算力规模大概在6到10TOPs之间,可以理解为一台小型的嵌入式AI计算机,体积跟扑克牌差不多,重量轻、散热要求相对低,适合无人机挂载。
一块算力约6TOPs的机载板,空载功耗通常在3W左右,加载跑满模型后功耗会升到8到10W。我们实测推理时的平均功耗在8.3W,峰值也就11W多一点。这个数字对无人机平台非常重要。拿一块典型的多旋翼电池算账,容量约100Wh,全机悬停加飞行功耗大概90W,原本能飞50多分钟;挂上这个检测+跟踪的盒子,整机功耗增加约8.3W,续航缩短大约7%,也就是三四分钟。假如换成桌面级功耗的嵌入式设备,功耗直接上到50W甚至100W,无人机根本带不动,或者是飞十几分钟就得换电池,巡检效率完全没法看。
4.2 从训练框架到端侧模型的剪枝、蒸馏与量化
模型训练完之后,直接拿浮点模型上板是不现实的。我们做了一套“训练后优化”流水线,顺序固定:先裁剪,再蒸馏,最后量化。
先说剪枝。主干网络里很多通道对最终精度的贡献很小,可以通过分析批归一化层的缩放因子来判断哪些通道是“弱通道”。我们把缩放因子数值接近0的通道剪掉,网络变瘦,推理速度提升,精度损失很小。这一步能让模型在板子上的推理从约40ms降到约35ms。
再说蒸馏。用一个大模型当老师,让小模型去学习老师输出层的软标签和中间层特征。大模型不必太大,准确率比小模型高几个点就行。蒸馏要特别注意训练策略的稳定,别急着一次到位,先用老师模型软标签训20轮,再正常微调10轮。这块当时没做好的时候,小模型虽然参数剪下去了,但检测精度掉了近两个点,后来加入蒸馏才稳住。
最后是INT8量化。浮点模型4.39M参数,直接算下来一张768×448的图,浮点计算量不小,板子的NPU跑INT8比FP16快很多。量化校准集要覆盖不同时段、不同天气的数据,至少要准备1000张代表性图片,只拿白天晴天图去校准,夜间或扬尘数据就会掉精度。
# 伪代码:模型导出为端侧静态图的典型流程 import onnx # 1. 保存训练好的模型并导出ONNX torch_model = load_trained_model("det_reid_final.pt") torch_model.eval() torch_model.to("cpu") dummy_input = torch.randn(1, 3, 448, 768) torch.onnx.export( torch_model, dummy_input, "det_reid.onnx", opset_version=11, input_names=["input"], output_names=["dets", "reid_embedding"], dynamic_axes=None, ) # 2. 检查ONNX模型结构 model_onnx = onnx.load("det_reid.onnx") onnx.checker.check_model(model_onnx)动态输入轴这里我们直接禁用,固定成448×768。动态分辨率很灵活,但会让端侧推理性能打折,也会让后处理逻辑复杂化。巡检航线高度相对固定,目标尺度变化不大,固定分辨率是最稳妥的选择。
4.3 机载推理主循环与结果回传
在机载端,检测和跟踪都在板子上跑完,地面站收到的不是视频流里的一帧帧原始画面,而是结构化的轨迹数据。这个设计有一个非常大的好处:无人机和地面站之间的无线链路只要还在,那么即使图像传输卡顿或花屏,所有目标轨迹和报警信息都不受影响,因为轨迹数据非常小,一帧十几个目标也才几KB,普通无线链路完全可以承载。
# 伪代码:机载推理主循环 class TrackerNode: def __init__(self, runtime, max_tracks=64): self.runtime = runtime self.tracks = {} def process(self, frame, timestamp): # 一次前向,同时得到检测框和嵌入特征 dets, embeddings = self.runtime.run(frame) # 使用检测框 + 嵌入特征更新全局轨迹 tracks = self.update_tracks(dets, embeddings, timestamp) # 输出结构化轨迹 return [ { "frame_ts": timestamp, "track_id": t.id, "category": t.category, "bbox": t.bbox, "confidence": t.score, } for t in tracks ]地面上报的轨迹数据长这样,和传统的目标JSON结构基本一致,后面需要接大屏或者告警系统的团队可以直接对接。
{ "frame_ts": 1720000000.125, "track_id": "T-042", "category": "heavy_truck", "bbox": [812, 445, 1010, 610], "confidence": 0.92, "speed_px": 4.1 }这里速度用的是像素速度,如果要换算成真实速度,需要结合无人机高度和相机内参做像素到米的比例换算。我们当时在机载端不做这个换算,地面站根据航线高度动态计算,因为无人机飞行高度一直在变,固定像素比例会算错速度。
5. 实测效果与指标怎么解读
5.1 MOTA、IDSW和FPS一个都不能少
评估这类一体化模型,不能只看检测准确率。我见过很多人拿一个mAP很高的模型直接部署,结果一上机跟踪轨迹乱跳,因为mAP考察的是单帧识别能力,完全不管跨帧ID稳定性。跟踪任务要重点看三个指标:MOTA、MOTP和IDSW。
MOTA全称是多目标跟踪准确率,综合了漏检率、误检率和ID切换率,一句话说就是衡量“轨迹整体对没对”。MOTP是多目标跟踪精确率,衡量跟踪框和真实框重叠度,直观讲就是框贴得紧不紧。IDSW是ID切换次数,就是同一个目标在跟踪过程中ID被错误改掉的次数,这个指标在巡检场景里直接影响业务判断,ID切来切去,地面大屏上的轨迹线会断掉,安全分析根本没法做。
我们在某矿区的实测数据大致是这样:
| 指标 | 数值 |
|---|---|
| 参数量 | 4.39M |
| 输入分辨率 | 768×448 |
| 平均推理帧率 | 约27 FPS |
| 整板功耗 | 平均8.3W |
| AP50(检测) | 0.921 |
| 小目标AP | 0.834 |
| MOTA | 0.836 |
| IDSW(每100帧) | 1.7次 |
| 端到端延迟 | 约120ms至170ms |
这组数据是某一时点的快照,不同的光线、扬尘程度和航线高度会有波动。但从趋势上讲,轻量化到4.39M参数并没有把精度拖垮,原因就在于骨干网络足够轻,检测头和嵌入头共享特征后,整体计算量下降的同时,特征利用率反而更高了。
5.2 端到端延迟到底怎么测
很多项目只测模型推理耗时,然后宣称“实时”。但无人机巡检里的实时是端到端的:从相机传感器曝光那一刻起,到地面站大屏上看到轨迹更新,中间隔了多少毫秒,这才是用户真正感受到的延迟。
我们当时把延迟拆成了五段:
| 环节 | 典型耗时 |
|---|---|
| 相机采集与ISP处理 | 5到10ms |
| 模型推理 | 35ms左右 |
| 跟踪匹配与轨迹编码 | 2ms左右 |
| 无线链路传输 | 40到80ms |
| 地面站解码与渲染 | 5到10ms |
加起来机载端约40ms左右,但链路的波动才是大头。实测在矿区环境下,无线链路平均延迟40ms到80ms,遇到遮挡或者距离远,会跳到150ms。所以我们在产品里不做“逐帧实时展示全部原始画面”这种压测,而是“轨迹和告警优先展示、原始视频低延迟补帧”,用户体验反而更稳。
端到端延迟的测试方法也有讲究:拿一块秒表,同时被地面站画面和无人机机载时钟拍到,对时间戳。记录从秒表读数变化到画面中同一个变化出现的时间差。多测几组取中位数才可靠,不能只看一组想当然。
6. 踩过的坑和排查手册
6.1 目标ID频繁跳变,同款矿卡互相认错
这是做露天矿跟踪时最坑的问题。两辆同型号矿卡一前一后行驶,距离只有几米,俯视视角下就是两个几乎一模一样的长方块,嵌入特征区分度很低。一开始我们的MOTA看着不错,但IDSW高得吓人,大屏上轨迹线经常突然换车头。
排查下来发现三个原因:嵌入特征头输出维度太低、训练数据里缺少同款车同时出现的样本、匹配逻辑里IoU权重大于外观权重。解决方案也对应三板斧:把嵌入特征维度从64提到128,大幅增加同款车同时出现在相邻帧的训练样本,匹配策略改成“外观特征优先、IoU兜底”。改完之后IDSW降了一半还不止。
6.2 机载画面振动模糊,小目标直接消失
无人机电机和桨叶带来的振动不可避免,尤其是硬挂载时,画面轻微抖动会被放大,表现在模型输出上就是小目标时有时无。一开始我以为是模型检测能力不行,后来在机上挂了记录仪对比才确认,是图像已经模糊了。
后来做了三件事:优先用云台增稳,镜头姿态稳住;算法侧对输入帧做轻量级电子稳像,其实只是把相邻两帧的全局平移量算出来做对齐;训练时增加运动模糊数据增强。这套组合下来,振动对检测的影响基本压到了可忽略的范围。如果你也遇到“一上机精度就下降”的情况,先试试看原始图像是不是都糊了,别急着调模型。
6.3 模型换一个矿区就掉点
在项目A训练好的模型,拿到项目B的矿场直接测,检测精度掉了两点多。原因很现实:不同矿区的岩土颜色、道路颜色、车辆涂装都不一样,模型学的是项目A的风格,跨域自然不适应。
没有捷径,只有补数据。我们当时把模型回到项目B的现场做了一轮快速采集和半自动标注,只补齐了3000帧关键场景,然后对模型做低学习率微调,精度很快回到正常。这也说明轻量化模型的微调成本很低,4.39M参数的全量微调在单卡上一小时之内就能跑完,这是小模型在生产落地中的一个巨大优势。
6.4 功耗上去了,但帧率反而掉下来
有一天实测发现盒子功耗从8.3W蹿到了12W,帧率却掉了三分之一。一开始以为是模型出了问题,查了半天最后发现是散热风扇堵了,核心板热降频,NPU被限了频。机载设备最容易被忽视的就是散热,无人机振动大、空间小,散热片容易松,风道容易被粉尘堵住。
建议在长期巡检项目里加一个简单的温控监控,机载端每10秒上报一次核心温度,温度超过阈值就告警。这看起来不是模型的事情,但工程落地就是综合问题,只能蹲在现场一点点排。
6.5 漏检小目标,查了半天竟然是前处理尺寸不对
一次迁移部署到新平台,检测小目标的能力明显变弱,模型没动过、权重没换过,最后定位到问题出在图像缩放算法的差异上。新平台的图像前处理用的是最近邻插值做缩放,矿卡边缘出现锯齿,小目标的细节被破坏了。换成双线性插值后问题立刻解决。
这类“坑”最常见的原因其实是端侧推理框架对图像预处理和后处理有差异,不同平台之间实现细节各有不同。迁移部署时不要默认“同一个模型在哪儿输出都一样”,每一步的数值精度都要对。
最后几点实在话
我个人做了几个类似项目后的体会是:检测+跟踪一体化,并不是把两个模型强行塞进一个网络里,而是把算力预算、数据标注、无人机平台三者重新对齐。机载端没有无限算力,所以参数必须小;露天矿目标高度相似,所以嵌入特征必须区分度足够;无人机对功耗敏感,所以INT8量化和推理优化是标配。这四个条件缺一个,项目大概率要中道崩殂。
最后再分享一个小技巧:评价这类模型,别只盯着mAP或者单帧FPS,多花时间看MOTA和IDSW,尤其是IDSW,它才是影响业务判断的核心指标。模型参数再小、帧率再高,如果ID老切换,调度员根本没法用。轻量化的尽头不是单纯把数变小,而是在小前提下保持整个系统的实用度。