ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

YOLOv8实战:飞机、鸟类、无人机三分类检测与RK3588部署

YOLOv8实战:飞机、鸟类、无人机三分类检测与RK3588部署 简介本资源面向计算机视觉算法工程师、无人机反制与低空安防研究者及目标检测学习者提供一套可直接训练的YOLOv8细分类型飞机、鸟类、无人机检测模型与配套数据集解决细粒度目标识别中类别混淆、样本不足的问题。压缩包共约2000个文件以1984个txt标签文件为主另含13个md说明文档、2个pdf资料与1个yaml配置文件整体约867.2MB。数据集包含1万多张图像采用YOLO格式标注已划分train、val、test三个子集并附data.yamlyolov5、yolov7、yolov8等主流框架均可直接读取训练。目录结构清晰标签与图像一一对应可区分具体飞机型号便于快速复现与二次开发。目前已有443人学习下载适合需要细粒度检测方案、想省去数据清洗与划分环节的读者参考使用。1. 从一张混淆矩阵说起飞机、鸟类、无人机为什么要放在同一个检测头里去年帮一个做机场净空监测的团队看模型他们拿 COCO 预训练的 YOLOv8m 直接跑场区监控结果一张图里同时出现客机、海鸥和四旋翼模型把远处巡航的无人机标成了鸟把贴地飞的海鸥标成了无人机飞机倒是没漏但置信度忽高忽低。问题不在 YOLOv8 本身而在于 COCO 里bird、airplane是两个独立类drone压根没有对应类别模型只能把无人机往kite或bird上靠。这就是「细分类型飞机-鸟类-无人机检测」这个方向真正要解决的事把三类空中目标收进一个检测头让模型学会区分它们的轮廓、纹理和运动上下文而不是靠单帧颜色硬猜。这套方案适合三类人做低空安防、机场净空、电力巡检的工程团队手里有无人机航拍或塔台监控视频、想自己标数据训模型的人以及已经跑通 yolov8训练自己的数据集、想换一套更贴场景类别的开发者。它不解决「从零发明检测器」而是把 YOLOv8 这套成熟框架落到一个具体的三分类任务上顺带把数据集构建、训练参数、部署到 RK3588 这类边缘板的路径讲清楚。下面按「数据怎么来 → 模型怎么训 → 坑在哪 → 怎么验证」的顺序展开能抄的地方直接给命令和配置。2. 数据集构建飞机、鸟类、无人机三类的标注边界怎么划2.1 三类目标的视觉差异与标注粒度飞机、鸟类、无人机在单帧图像里的可分性其实比想象中弱。大型客机有固定翼和发动机短舱轮廓规整、长宽比稳定鸟类翅膀形态随扑翼相位剧烈变化同一只鸟在不同帧里可能是「一」字也可能是「V」字多旋翼无人机在远距离下就是一个带旋翼模糊的小十字和悬停的猛禽轮廓高度相似。标注时如果只框一个外接矩形模型学到的更多是背景和尺度先验而不是目标本身。我一般建议按「可见主体」标注飞机框住机身加机翼不把尾迹算进去鸟类框住躯干和展开的翼展翅膀收拢时按实际像素范围框无人机框住机体加旋翼盘面不把地面投影算进去。三类都只用一个类框不做部件级标注因为细分类型检测的落地场景要的是「是什么」不是「哪个部位」。如果后续要做机型细分再在飞机类里加子类那是另一个任务。标注工具用 LabelImg 或 CVAT 都行导出 YOLO 格式的 txt。每张图对应一个同名 txt每行class_id x_center y_center width height坐标归一化到 0-1。类别映射固定为0: airplane, 1: bird, 2: drone这个顺序一旦定下就不要在训练中途改否则标签和权重对不上损失曲线会直接起飞。2.2 数据来源与增强策略公开数据里飞机可以用 HRSC2016 或 DOTA 里的机场子集鸟类可以用 CUB-200 里带飞行姿态的图无人机可以找 UAVDT 或自己用消费级无人机拍。但直接拼凑会有严重的域偏移HRSC2016 是遥感俯视CUB 是近距离侧拍UAVDT 是车载视角三者混在一起训模型会先学「视角」而不是「类别」。我的做法是分域采样每个域至少占 20%再用强增强把视角差异抹平。增强用 YOLOv8 内置的mosaic、mixup、hsv_h/s/v、degrees、translate、scale、flipud/fliplr。针对这个任务degrees可以开到 15因为空中目标姿态多变flipud要慎用飞机倒飞和鸟倒飞在真实场景里极少开了反而引入噪声。mosaic概率保持默认 1.0但要注意它会把四张图拼成一张小目标被缩得更小如果数据里无人机本身就只有几十像素建议把mosaic降到 0.5 并配合copy_paste做小目标复制。数据划分按 8:1:1 走但不要随机分。同一段视频的连续帧必须落在同一个集合里否则训练集和验证集共享背景mAP 会虚高。我一般按视频源或拍摄批次划分保证验证集里的场景在训练集里没见过。划分脚本用 Python 写读 images 目录按文件名前缀分组再按组分配。import os, random, shutil from pathlib import Path random.seed(42) root Path(datasets/air_bird_drone) img_dir root / images lbl_dir root / labels # 按文件名前缀分组同组不拆散 groups {} for img in img_dir.glob(*.jpg): key img.stem.split(_)[0] # 假设命名如 airport_0001.jpg groups.setdefault(key, []).append(img.stem) keys list(groups.keys()) random.shuffle(keys) n len(keys) train_k keys[:int(n*0.8)] val_k keys[int(n*0.8):int(n*0.9)] test_k keys[int(n*0.9):] for split, ks in [(train, train_k), (val, val_k), (test, test_k)]: (root / split / images).mkdir(parentsTrue, exist_okTrue) (root / split / labels).mkdir(parentsTrue, exist_okTrue) for k in ks: for stem in groups[k]: shutil.copy(img_dir / f{stem}.jpg, root / split / images / f{stem}.jpg) shutil.copy(lbl_dir / f{stem}.txt, root / split / labels / f{stem}.txt) print(split done:, len(train_k), len(val_k), len(test_k))这段脚本的关键在key img.stem.split(_)[0]它把同一批次或同一视频的帧绑在一起。如果你的命名没有统一前缀就换成按目录名分组。random.seed(42)保证每次划分一致方便复现。跑完检查三个 split 的类别分布如果某一类在验证集里少于 5%说明采样不均要回去补数据。2.3 data.yaml 的写法与路径陷阱YOLOv8 靠一个 yaml 文件找数据和类别名。常见写法path: /home/user/datasets/air_bird_drone train: train/images val: val/images test: test/images nc: 3 names: 0: airplane 1: bird 2: dronepath用绝对路径最稳相对路径在yolo train从不同工作目录启动时会翻车。names的键必须是整数写成字符串0在某些版本里会报KeyError。如果训练时提示No labels found先确认 labels 目录和 images 目录同级且文件名一一对应再确认 txt 里没有空行和多余空格。YOLOv8 对空 txt 是容忍的但一行里多一个空格就会解析失败这个坑我踩过不止一次。3. 训练配置从 yolov8n 到 yolov8m 的选型与参数落点3.1 模型规模与输入分辨率怎么定YOLOv8 提供 n/s/m/l/x 五档。飞机-鸟类-无人机这个任务如果部署在 RK3588 或 GTX1660Ti 这类算力有限的设备上yolov8n和yolov8s是主力。n 的参数量约 3.2Ms 约 11.2Mm 约 25.9M。实测在 640 输入下n 在 1660Ti 上能跑到 100 FPSs 大概 60 FPSm 掉到 30 FPS 左右。如果场景里无人机目标普遍小于 32 像素优先提分辨率而不是换大模型imgsz960带来的小目标召回提升通常比 n 换 m 更明显。输入分辨率的选择要看目标像素分布。先统计训练集里三类目标的框面积算 sqrt(w*h) 的中位数。如果中位数在 20-40 像素imgsz640够用低于 20上 960 或 1280高于 80640 就够再大只是浪费算力。改分辨率时记得同步改batch显存不够就降 batch 或开amp。3.2 训练命令与关键参数最小可跑命令yolo detect train \ data/home/user/datasets/air_bird_drone/data.yaml \ modelyolov8s.pt \ imgsz640 \ epochs150 \ batch16 \ device0 \ workers8 \ projectruns/abd \ nameexp_s_640 \ pretrainedTrue \ optimizerSGD \ lr00.01 \ lrf0.01 \ momentum0.937 \ weight_decay0.0005 \ warmup_epochs3.0 \ cos_lrTrue \ close_mosaic10 \ patience30 \ seed0逐项说pretrainedTrue加载 COCO 权重三类任务微调必须开否则收敛慢且 mAP 低一截。optimizerSGD是 YOLOv8 官方默认AdamW在小数据集上容易过拟合除非数据量低于 2000 张再考虑。lr00.01配合cos_lrTrue做余弦退火lrf0.01是最终学习率系数即最低降到 0.0001。warmup_epochs3.0让前 3 个 epoch 学习率从低到高爬避免一开始就把预训练权重冲烂。close_mosaic10在最后 10 个 epoch 关掉 mosaic让模型在真实分布上收尾这个对 mAP 提升通常有 1-2 个点。patience30是早停30 轮验证 mAP 不涨就停省时间。如果显存不够把batch降到 8同时把lr0按比例降到 0.005因为 batch 变小梯度噪声变大学习率不降容易震荡。workers设成 CPU 核数的 0.75 左右设太大反而因为 IO 争抢变慢。3.3 损失曲线与指标怎么看训练启动后runs/abd/exp_s_640/下会生成results.csv和weights/。results.csv里关注train/box_loss、train/cls_loss、val/box_loss、val/cls_loss、metrics/mAP50、metrics/mAP50-95。正常情况 box_loss 和 cls_loss 都单调下降val 曲线略高于 train 但趋势一致。如果 train 降 val 不降甚至上升就是过拟合加数据或加dropoutYOLOv8 里通过dropout参数默认 0可设 0.1。如果两条都平着不降检查学习率是不是太小或标签有没有问题。画损失曲线用 pandas matplotlib读results.csv直接 plot。注意results.csv的列名带空格读的时候用skipinitialspaceTrue。这个脚本很短但能帮你快速判断训练是不是在正轨上比盯着终端刷屏有用。import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/abd/exp_s_640/results.csv, skipinitialspaceTrue) df.columns [c.strip() for c in df.columns] fig, ax plt.subplots(1, 2, figsize(12, 4)) ax[0].plot(df[epoch], df[train/box_loss], labeltrain_box) ax[0].plot(df[epoch], df[val/box_loss], labelval_box) ax[0].set_xlabel(epoch); ax[0].set_ylabel(box_loss); ax[0].legend() ax[1].plot(df[epoch], df[metrics/mAP50], labelmAP50) ax[1].plot(df[epoch], df[metrics/mAP50-95], labelmAP50-95) ax[1].set_xlabel(epoch); ax[1].set_ylabel(mAP); ax[1].legend() plt.tight_layout(); plt.savefig(loss_curve.png, dpi150)跑完看loss_curve.png如果 mAP50 在 0.85 以上、mAP50-95 在 0.55 以上三类任务基本可用。低于这个数先别急着换模型回去查标注质量和验证集分布。4. 避坑与排查三类混检最容易翻车的五个地方4.1 鸟类和无人机互相误检mAP 卡在 0.6 上不去现象验证集里鸟被标成 drone、无人机被标成 bird两类混淆矩阵对角线外数值很高。原因通常是训练集里这两类的背景高度相似都是天空且目标尺度接近模型只能靠纹理区分而远距离下纹理被压缩没了。解决在数据里加入「同背景不同类」的硬负样本比如同一片天空下既有鸟又有无人机的帧同时把imgsz提到 960让纹理信息保留更多如果还不行在names里把两类合并成aerial先训一版再在检测头上做二阶段细分。4.2 飞机类召回高但误检地面车辆现象机场场景里跑道上的摆渡车、加油车被标成 airplane。原因是飞机和车辆在俯视或侧视下都是长条形且训练集里飞机样本多、车辆样本少模型把「长条灰色」当成了飞机特征。解决在数据里显式加入车辆负样本标成背景不写进 txt 或单独加一个vehicle类再在推理时过滤同时开rectTrue做矩形推理减少 letterbox 带来的形变让长宽比特征更可靠。4.3 训练到一半 loss 变 NaN现象train/box_loss突然变成 nan训练中断。原因多半是学习率太大或某张图的标签坐标越界比如 x_center 写成 1.2。解决先检查所有 txt用脚本扫一遍坐标范围把越界的行修掉或删掉对应图然后把lr0降到 0.005开ampTrue默认开但把grad_clip设成 10.0。YOLOv8 默认有梯度裁剪但极端标签仍会炸。4.4 验证集 mAP 很高实际部署漏检严重现象results.csv里 mAP50 0.9但拿现场视频跑无人机漏检一半。原因是验证集和训练集同源背景、光照、拍摄角度都相似模型没学到泛化。解决重新按拍摄批次划分验证集确保验证集里的场景训练时没见过再补一版跨域测试比如用训练时没出现过的机型或天气。如果跨域掉点超过 20 个 mAP说明数据多样性不够回去补数据比调参有用。4.5 导出 RK3588 后精度掉一截现象PyTorch 权重 mAP50 0.88转 ONNX 再转 RKNN 后掉到 0.75。原因通常是量化校准集选得不好或者导出时opset和dynamic设置不对。解决导出 ONNX 用opset12、dynamicFalse、simplifyTrueRKNN 量化时校准集要从验证集里抽 200-500 张覆盖三类目标和不同光照不要只用一类。如果还掉点把mean_values和std_values对齐训练时的归一化参数YOLOv8 默认是 0-1 归一化RKNN 里不要重复除 255。5. 部署到 RK3588 与推理验证从 pt 到 rknn 的完整链路5.1 导出 ONNX 与 RKNN 转换RK3588 的 NPU 只吃 RKNN 格式链路是pt → onnx → rknn。先导出 ONNXyolo export \ modelruns/abd/exp_s_640/weights/best.pt \ formatonnx \ imgsz640 \ opset12 \ simplifyTrue \ dynamicFalsesimplifyTrue会调 onnx-simplifier 去掉冗余节点RKNN 转换时更稳。dynamicFalse固定输入尺寸NPU 对动态 shape 支持差。导出后用onnxruntime跑一张图确认输出和 PyTorch 一致再进 RKNN 工具链。RKNN 转换脚本from rknn.api import RKNN rknn RKNN(verboseTrue) rknn.config( mean_values[[0, 0, 0]], std_values[[255, 255, 255]], target_platformrk3588, quantized_dtypeasymmetric_quantized-8, ) rknn.load_onnx(modelbest.onnx) rknn.build(do_quantizationTrue, datasetcalib.txt) rknn.export_rknn(best.rknn) rknn.release()mean_values和std_values这里写0和255是因为 YOLOv8 训练时输入是 0-1RKNN 内部会做(x - mean) / std等价于除 255。如果你的训练用了别的归一化这里要对应改。calib.txt每行一张校准图路径抽 300 张左右三类目标都要有。quantized_dtype用默认的 8bit 非对称量化精度和速度平衡最好。5.2 板端推理与后处理对齐RK3588 上跑 RKNN 模型输出是三个尺度的特征图需要自己做 decode 和 NMS。常见做法是用 rknn_model_zoo 里的 YOLOv8 demo 改类别数和阈值。关键参数conf_thres0.25、iou_thres0.45、max_det300。如果板端漏检多先把conf_thres降到 0.15 看召回能不能上来再决定是调阈值还是回去补数据。验证方法在板端跑一段现场视频把检测结果和 PyTorch 同帧结果并排看。如果板端框偏移明显检查 letterbox 的 padding 是否在 decode 时正确还原如果类别错乱检查names顺序是否和训练时一致。我一般会在板端存 100 帧带框结果和 PC 端逐帧比对确认 mAP 掉点不超过 3 个点才算过关。5.3 一个容易被忽略的验证技巧部署完别只看 mAP拿一段「三类同框」的视频跑统计每类的漏检和误检。具体做法人工标 200 帧作为测试基准写脚本算每类的 precision/recall再画 PR 曲线。如果某一类 recall 低于 0.7优先查这一类在训练集里的样本量和标注质量而不是调模型。我自己的习惯是每次训完模型先跑一遍「三类同框」测试集再决定要不要上线。这个习惯帮我省过好几次返工——有一次飞机类 recall 只有 0.65查下来是标注时把尾迹也算进框里模型学偏了重新标了 300 张就好了。希望帮到你。本文还有配套的精品资源点击获取
返回列表