尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

VisDrone2019+YOLOv8小目标检测实战:格式转换、训练调参与部署全流程

VisDrone2019+YOLOv8小目标检测实战:格式转换、训练调参与部署全流程 做无人机视角目标检测VisDrone2019全称VisDrone2019-DET几乎是绕不开的公开数据集。无人机俯拍场景里的小目标、密集遮挡、类别不均衡问题在COCO、VOC上很难练出来而在VisDrone上练一遍很多工程问题都会暴露出来。用YOLOv8在这个数据集上训练是不少做毕设、算法对比、甚至工业预研的标配操作。整个过程说难不难说简单也不简单最坑人的地方其实不在训练本身而在数据格式转换、训练参数理解和针对小目标的调优策略上。这篇文章把我从环境搭建、数据集处理、训练调参、评估优化到模型导出部署的完整流程记录下来希望能帮正在折腾VisDrone的人少走点弯路。1. 项目概述VisDrone2019与YOLOv8的搭配逻辑1.1 为什么选择VisDrone2019做无人机视角检测VisDrone2019数据集是无人机视觉领域知名度很高的公开数据集主要采集自城市、郊区、乡村等多类场景视角是无人机高空俯拍画面里的人和车在整张图中往往只占几十个甚至十几个像素。数据集包含检测DET、单目标跟踪、多目标跟踪等子任务我们训练检测模型用的通常是VisDrone2019-DET子集。从数据规模上看VisDrone2019-DET的训练集有6471张图片验证集548张。类别上官方给了12类编号0到11第0类是ignored regions背景干扰区第1到第11类分别对应pedestrian、people、bicycle、car、van、truck、tricycle、awning-tricycle、bus、motor和others。实际训练时大部分人会忽略第0类和others类只保留10个有效类别。这就是为什么网上各种VisDrone的YOLO配置类别数量有写10的、有写9的本质区别在有没有合并pedestrian和people。这个数据集最大的特点就是难。不是难在标注质量而是难在目标尺度。无人机飞到几十米上百米高度一辆小汽车可能只有20×15像素一个行人可能只有8×12像素。在YOLOv8默认的640×640输入下这类目标经过下采样后几乎就剩一两个特征点非常容易漏检。也正因如此很多人拿VisDrone做小目标检测研究的基准数据集用它验证自己的改进模块是否有效比单纯在COCO上刷分更能说明问题。1.2 为什么用YOLOv8而不是老版YOLOYOLOv8是Ultralytics团队在2023年初推出的版本相比YOLOv5它把C3模块换成了C2f模块检测头改成了anchor-free的解耦头分类分支和回归分支各自独立损失函数也换成了DFL加CIoU的组合。这些改动带来的直接效果是收敛更快、精度更高、部署更方便。对VisDrone这种复杂的密集小目标场景YOLOv8的解耦头优势很明显。老版YOLO的检测头是把分类和回归放在同一个分支里做的两个任务会互相干扰YOLOv8把两个分支分开分类更专注类别判断回归更专注框的位置在拥挤密集的俯拍画面里框的定位质量会好不少。另外YOLOv8训练代码集成度高一条命令行就能跑训练、验证、导出对新手极其友好。从工程角度看YOLOv8还顺手解决了几个老版本很痛的点它支持AMP混合精度训练默认开启能省不少显存内置了Mosaic、MixUp、Copy-Paste等数据增强模型的ONNX导出也很干净后续转TensorRT或者RKNN都很方便。这些特性组合起来让YOLOv8成为我用过的YOLO系里最适合快速验证算法想法的版本。1.3 整体流程一览整个训练流程可以拆成五个阶段环境搭建、数据转换、模型训练、评估调优、导出部署。环境搭建主要是把PyTorch和ultralytics装了数据转换要把VisDrone的标注格式转成YOLO格式同时处理好类别映射训练阶段要写对yaml配置文件和训练参数评估阶段要会看mAP、PR曲线和混淆矩阵最后把训练好的权重导出成ONNX或TensorRT引擎用于实际部署。这个流程看着简单但每一步都有坑。数据转换时类别编号差一位训练出来mAP直接归零训练参数里imgsz对显存和速度的影响巨大验证集划分不对指标虚高到没法看。后面每一章我都会把具体的操作和排查经验写清楚。2. 环境搭建Ubuntu 20.04上的YOLOv8训练环境2.1 用conda隔离环境避免污染系统Python我个人的习惯是所有Python项目先建conda环境不直接往系统环境里装深度学习框架。尤其是Ubuntu 20.04系统自带Python 3.8很多系统工具依赖这个版本的库你要是往系统Python里装一堆新版依赖很容易把系统搞坏。wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh bash Miniconda3-latest-Linux-x86_64.sh安装完成并初始化后创建训练环境conda create -n yolov8 python3.8 conda activate yolov8Python版本选3.8或3.9都行YOLOv8官方要求Python在3.8到3.10之间。我习惯用3.8因为它兼容性最稳无论后面是装TensorRT还是RKNN工具链都不会遇到版本拒载的问题。conda创建环境的时候如果下载慢可以把channel源配置成国内的镜像源具体配置方法网上很多这里不展开说了。2.2 安装PyTorch与ultralytics创建好环境后先装PyTorch。这一步特别重要PyTorch的安装版本必须和你的显卡驱动、CUDA版本匹配。最简单的办法是去PyTorch官网的get-started页面选对应的安装命令我这里的场景一般用CUDA 11.8或者12.1pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118如果你是纯CPU环境同样去官网选CPU版本。这里我先说明一个事实CPU版本能跑YOLOv8但会慢到让人怀疑人生训练VisDrone这种几千张图的数据集一轮epoch可能都要半小时起步全量训练不现实。CPU环境更适合做的事情是快速跑通代码流程验证数据格式有没有问题或者做小样本的过拟合测试。安装完PyTorch再装ultralyticspip install ultralyticsultralytics这个包会连带把opencv-python、pandas、matplotlib、seaborn这些依赖都装好日常训练用到的功能基本都覆盖了。装完后可以验证一下版本python -c from ultralytics import YOLO; print(YOLO.__name__)如果输出正常说明安装成功。这里有个小坑pip默认源下载慢的话经常装到一半超时建议提前把pip源切到国内镜像比如清华源或阿里源。配置方法很简单在用户目录下创建~/.pip/pip.conf写入[global] index-url https://pypi.tuna.tsinghua.edu.cn/simple即可。2.3 快速验证环境是否可用环境装好后不要急着训练VisDrone先跑一次官方自带的coco8小数据集确认整条链路是通的。coco8是YOLOv8自带的一个8张图片的微型数据集几秒钟就能训完。yolo detect train datacoco8.yaml modelyolov8s.pt epochs3 imgsz640这条命令会自动从官方GitHub下载yolov8s.pt预训练权重。如果网络不好也可以提前把权重文件下载好放到当前目录下。跑完后看runs/detect/train目录下是否生成了权重文件和results.csv生成了就说明环境没问题。这一步还有两个额外作用一是验证GPU版本的PyTorch是否真的在用GPU。用nvidia-smi查看训练时的显存占用如果显卡利用率在40%以上说明GPU正常工作如果一直是CPU占用高说明torch装成了CPU版得重装。二是让你提前熟悉ultralytics的输出格式方便后面看VisDrone训练日志时心里有数。我手边一台GTX 1660Ti6GB显存的机器实测YOLOv8s在coco8上训3轮大概十几秒全流程验证很省时间。如果你的电脑配置不高完全可以用这个方式先把流程走通再考虑小模型在子集上测试。3. VisDrone2019数据集处理格式转换与划分3.1 VisDrone标注格式到底长什么样VisDrone2019-DET的标注文件是一行一个目标的txt文件每一行有8个字段用逗号分隔bbox_left, bbox_top, bbox_width, bbox_height, score, category, truncation, occlusion举个实际例子假设一张图里有一辆车标注看起来就是567, 234, 45, 32, -1, 4, 0, 0含义是目标框左上角x坐标567左上角y坐标234框宽45框高32检测任务中第5列score一般填-1第6列category是类别编号4对应car第7列是截断程度第8列是遮挡程度。后两列在检测训练里很少用到我们转换时主要取前六列。VisDrone的类别编号是从1开始的1对应pedestrian2对应people3对应bicycle4对应car5对应van6对应truck7对应tricycle8对应awning-tricycle9对应bus10对应motor11对应others。注意这里没有0吗其实是有的0专门留给ignored regions也就是被人为标记为“不用检测但影响判断”的背景区域比如被树挡住一半的人、极小到无法辨识的目标。这些区域在转换时必须丢掉否则会把大量背景噪声当成标注模型会被带偏。3.2 用Python脚本将VisDrone转成YOLO格式YOLO格式的标签文件和VisDrone完全不同。YOLO要求每行是class_id x_center y_center width height其中坐标全部做了归一化除以图片的宽和高值在0到1之间。class_id也必须从0开始。也就是说原VisDrone的category 1要写成0category 4要写成3。下面是我常用的转换脚本直接照抄就能用import os import cv2 import glob src_img_dir VisDrone2019-DET-train/images src_txt_dir VisDrone2019-DET-train/annotations dst_img_dir dataset/VisDrone-YOLO/images/train dst_txt_dir dataset/VisDrone-YOLO/labels/train os.makedirs(dst_img_dir, exist_okTrue) os.makedirs(dst_txt_dir, exist_okTrue) def visdrone2yolo(txt_path, img_w, img_h): boxes [] with open(txt_path, r, encodingutf-8, errorsignore) as f: lines f.readlines() for line in lines: data line.strip().split(,) if len(data) 6: continue left, top, w, h float(data[0]), float(data[1]), float(data[2]), float(data[3]) cat int(float(data[5])) if cat 0: continue x_center (left w / 2) / img_w y_center (top h / 2) / img_h w_norm w / img_w h_norm h / img_h # 坐标越界保护 x_center min(max(x_center, 0.0), 1.0) y_center min(max(y_center, 0.0), 1.0) w_norm min(max(w_norm, 0.0), 1.0) h_norm min(max(h_norm, 0.0), 1.0) if w_norm 0 or h_norm 0: continue boxes.append(f{cat - 1} {x_center:.6f} {y_center:.6f} {w_norm:.6f} {h_norm:.6f}) return boxes for img_path in glob.glob(os.path.join(src_img_dir, *.jpg)): img cv2.imread(img_path) if img is None: print(无法读取图片, img_path) continue h, w img.shape[:2] base_name os.path.splitext(os.path.basename(img_path))[0] txt_path os.path.join(src_txt_dir, base_name .txt) if not os.path.exists(txt_path): continue boxes visdrone2yolo(txt_path, w, h) if len(boxes) 0: continue # 拷贝图片到目标目录 dst_img os.path.join(dst_img_dir, os.path.basename(img_path)) cv2.imwrite(dst_img, img) dst_txt os.path.join(dst_txt_dir, base_name .txt) with open(dst_txt, w, encodingutf-8) as f: f.write(\n.join(boxes)) print(转换完成)这个脚本里有几个点值得单独说明。第一我用了cv2.imread读取图片获取宽高这样能保证归一化使用的图片尺寸和实际图片尺寸完全一致。第二我特意加了坐标越界保护因为VisDrone标注中偶尔会有边界框超出图片范围的情况如果不做限制归一化后会出现大于1的坐标训练时可能报错或者产生无效anchor。第三框的宽或高归一化后如果小于等于0说明原始标注就是无效的直接跳过。3.3 类别合并与数据检查的实战细节VisDrone里pedestrian和people这两个类别非常容易混淆。官方定义中pedestrian一般指站立的人people指行走或聚集的人。但从无人机视角看这个区分其实很主观标注不一致的情况大量存在。如果坚持用10个类别训练你会发现模型在区分这两个类别上浪费了大量能力而且验证指标也不好。很多人会把pedestrian和people合并成一个person类别这样类别数从10降为9。合并方式是在转换脚本里把category映射表改一下也就是把1和2都映射到0后面的类别依次后移。但注意这样处理之后就不能简单用cat - 1了需要写一个显式的映射字典。mapping { 1: 0, # pedestrian - person 2: 0, # people - person 3: 1, # bicycle 4: 2, # car 5: 3, # van 6: 4, # truck 7: 5, # tricycle 8: 6, # awning-tricycle 9: 7, # bus 10: 8, # motor 11: -1 # others丢弃 }这样最终分类是9类。具体合不合并要看你的业务需求如果只关心“画面里有人”这个事实合并肯定更好如果业务上需要区分行人和人群那就别合并接受指标略低的结果。转换完数据之后强烈建议做一次数据体检。最简单的方式是随机抽几张图片把YOLO格式的标签画回去看看对齐不对齐。写一个小脚本读label文件把归一化的坐标乘回图片宽高用opencv画矩形肉眼看标注是否贴合目标。这一步能发现大部分格式问题。我第一次转VisDrone的时候就是因为没做检查训练到一半才发现类别编号全部错位浪费了一天时间。另外VisDrone官方已经划分好了train和val训练集和验证集不要自己重新随机划分。官方的划分考虑了场景多样性自己乱分容易造成数据泄露导致验证指标虚高。把转换后的train放到dataset/VisDrone-YOLO/images/trainval放到images/val对应标签同理放好就行。3.4 数据增强与样本不均衡处理VisDrone的类别分布非常不平衡。car类别的样本数量远高于其他类别而awning-tricycle、motor这些类别样本稀少。如果直接训练模型会偏向样本多的类别少数类别的召回率会很低。YOLOv8内置的Mosaic增强对这类问题有缓解作用。Mosaic会把4张图拼成一张相当于变相增加了每张图的样本数量同时打乱了目标的空间分布。训练时默认开启Mosaic对VisDrone这种密集场景很有用。Copy-Paste增强也能缓解小目标样本不足的问题它会把一张图中的目标复制粘贴到另一张图中相当于数据重复使用。但这个增强在小目标上效果有限因为小目标复制过去后容易和背景融合。另外mixup增强会把两张图加权混合类别标签也跟着混合这对降低过拟合有帮助。我的建议是先用YOLOv8默认增强训一版基线之后再尝试关闭mosaic最后的10个epochYOLOv8默认会这么做叫close_mosaic这样能有效稳定最终指标。不要一上来就堆增强策略增强过多有时反而会让小目标更难学。4. 训练配置与实操从yaml到命令行4.1 数据配置文件visdrone.yaml怎么写YOLOv8不直接在命令行里写数据集的类别和路径而是统一通过一个yaml配置文件来声明。在项目目录下新建visdrone.yamlpath: /home/user/workspace/dataset/VisDrone-YOLO train: images/train val: images/val names: 0: pedestrian 1: people 2: bicycle 3: car 4: van 5: truck 6: tricycle 7: awning-tricycle 8: bus 9: motor如果你是合并类别后的9类版本names就相应改成9个。path字段指向数据集根目录train和val写相对于根目录的路径。注意不要在train里写绝对路径加文件具体名字YOLOv8会按目录递归扫描。有一个很多人踩过的坑names列表的索引必须和标签文件里第一个数字对应。标签里写的是0names第0个位置就必须是这个类别的名字如果names写乱了训练不会报错但mAP会莫名其妙很低。转换VisDrone时尤其要小心因为原始类别编号是1到11很容易在写names时把顺序搞混。4.2 关键训练参数的含义与推荐值训练命令本身不复杂yolo detect train datavisdrone.yaml modelyolov8s.pt epochs100 imgsz1280 batch8 device0但这条命令里每个参数背后都有讲究。我整理了一份针对VisDrone的参数清单参数推荐值说明modelyolov8n.pt / yolov8s.pt预训练权重的选择n最快s最均衡imgsz1280推荐输入图片尺寸对小目标影响极大batch显卡显存和模型决定不要一味求大稳定即可epochs100-300小数据集可以更长看验证集是否收敛optimizerAdamW或SGDYOLOv8默认SGD实测AdamW收敛更稳lr00.01SGD或0.001AdamW学习率过大容易震荡lrf0.01最终学习率是lr0*lrfpatience50验证指标50轮不升则提前停止ampTrue混合精度训练默认开启省显存cacheTrue把图片缓存到内存加快数据读取其中imgsz我个人认为是VisDrone训练中最重要的参数。同样的模型输入640和输入1280mAP差距可以达到5到10个点。原因很简单VisDrone的目标太小640输入下小目标可能只有4到6个像素特征提取器根本学不到有效信息提到1280后同样是20×15像素的目标变成了40×30特征信息丰富了一个量级。但imgsz不是越大越好。1280的显存占用是640的4倍GTX 1660Ti这种6GB显存的卡yolov8s配1280输入batch只能设到4甚至2。如果显存不够可以用yolov8n跑1280输入或者继续用640输入先跑通再用1280做精调。batch大小对训练的影响也很大。batch太小BN统计不稳定损失震荡batch太大显存爆掉。我实测用6GB显存的1660Tiyolov8s、imgsz640、batch8是比较稳定的组合。如果你用更高端的显卡比如24GB的RTX 3090batch可以调到16甚至32。4.3 训练过程监控与损失曲线绘制训练启动后ultralytics会在runs/detect/train目录下实时写入日志和指标。训练完成后同目录下会生成一个results.csv文件里面每一行是一个epoch的完整指标包括train/box_loss、train/cls_loss、train/dfl_loss、val/box_loss、val/cls_loss、val/dfl_loss以及metrics/precision、metrics/recall、metrics/mAP50、metrics/mAP50-95。很多人喜欢通过看损失曲线判断训练是否正常。这里我分享一个基于results.csv画曲线的脚本import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/detect/train/results.csv) loss_cols [c for c in df.columns if loss in c and val not in c] val_loss_cols [c for c in df.columns if loss in c and val in c] plt.figure(figsize(12, 5)) plt.subplot(1, 2, 1) for c in loss_cols: plt.plot(df[c], labelc) plt.xlabel(epoch) plt.ylabel(train loss) plt.legend() plt.grid(True) plt.subplot(1, 2, 2) for c in val_loss_cols: plt.plot(df[c], labelc) plt.xlabel(epoch) plt.ylabel(val loss) plt.legend() plt.grid(True) plt.tight_layout() plt.savefig(loss_curves.png, dpi150)怎么看这个图正常训练的train loss应该是平滑下降最后趋于平缓。val loss如果在下降后开始反弹上升说明过拟合了应该考虑提前停止或者加数据增强。如果loss全程震荡不降先别急着调参数优先检查标签文件是不是有问题比如框的位置是不是错的、类别是不是错位了。训练不收敛的问题绝大多数是数据问题而不是模型问题。额外提醒一句训练过程中不要频繁打开runs/detect/train目录下的图片去“看效果”中间epoch的模型往往还在收敛中看早了只会误导你。一切以最终的best.pt和mAP为准。5. 评估指标与针对性优化让小目标更容易被检测5.1 如何看懂mAP、PR曲线与混淆矩阵YOLOv8训练完成后会自动跑一遍验证集并输出precision、recall、mAP50和mAP50-95这几个指标。很多人只看mAP50这一个数其实在VisDrone这种数据集上mAP50-95和mAP50的差距本身就是重要信息。mAP50指的是IoU阈值在0.5时的平均精度mAP50-95则是把IoU阈值从0.5到0.95按0.05步长取平均后的平均精度。如果你的mAP50不低但mAP50-95明显低很多说明模型预测的框位置不够准。这在VisDrone小目标上很常见因为目标只有十几个像素IoU稍微偏一点就达不到0.75甚至0.5。pr_curve.png和confusion_matrix.png是验证目录下最值得反复看的两张图。PR曲线越靠近右上角说明precision和recall兼顾得越好。混淆矩阵能直接告诉你哪两个类别最容易互相误判。在VisDrone上最常见的现象就是pedestrian和people互混、tricycle和awning-tricycle互混。看到这种情况不用纠结模型能力这本质是标注本身就模棱两可考虑合并类别反而是更好的选择。5.2 针对VisDrone小目标场景的4个有效优化方向训练完基线后不要急着上各种“改进模块”先在工程层面做几个高性价比的优化效果通常比改网络结构更明显。第一个方向是提高输入分辨率这也是我反复强调的。用imgsz1280做训练甚至推理时用更大的尺寸是提升VisDrone小目标检测最简单粗暴的手段。代价是显存和推理速度。如果显存不够可以考虑“切图”策略把2000×1500的大图切成几个重叠的小块分别推理后再合并结果。切图推理在无人机巡检里是常规操作虽然代码量多一点但效果提升非常直接。第二个方向是调整置信度阈值。无人机视角下的小目标在检测头里得分普遍偏低默认的conf0.25会滤掉大量真目标。验证时可以用yolo detect val modelbest.pt conf0.05你会发现recall大幅提升。推理时也可以把conf调低到0.1甚至0.05配合NMS把重复框去掉。代价是误检变多但很多业务场景里误检可以通过后续跟踪或过滤逻辑处理。第三个方向是类别处理。如果刚才看混淆矩阵发现某些类别严重互混合并类别是最省事的解法。把pedestrian和people合并成person把tricycle和awning-tricycle合并成tricycle能显著降低类别间混淆mAP往往不降反升。第四个方向才是结构改进。常见做法是给YOLOv8加P2检测层专门保留高分辨率特征图来检测小目标或者用BiFPN替换PAN-FPN增强多尺度特征融合也可以在骨干网络里加注意力模块比如EMA、CBAM之类。但这里我要泼一盆冷水结构改进一定要基于基线先把baseline训好、指标记录清楚再一项一项改每次只改一个变量。很多人在VisDrone上乱加模块最后指标反而下降原因就是不知道哪个改动起了副作用。5.3 什么时候停止训练怎么防止过拟合YOLOv8自带early stopping机制patience参数默认是50。也就是说验证集的mAP如果连续50个epoch都没有提升训练会自动停止并用历史最好的权重作为best.pt。这个机制在VisDrone上很好用因为数据量不算大训练到80到120轮左右基本就收敛了继续硬训只会过拟合。判断是否过拟合最直观的信号就是训练损失还在降但验证损失开始回升。这种情况下即使验证mAP还在微涨也别继续训了后续epoch的模型泛化能力已经变差。我个人的习惯是设置patience30稍微激进一点节省时间。如果训练集表现很好但验证集很差过拟合严重优先考虑增强数据多样性。YOLOv8的Mosaic、MixUp、HSV随机增强等都可以开着。另一个容易被忽略的点是scale增强它控制了训练时对图像随机缩放的程度。VisDrone目标本来就不大scale设得太大反而会把目标缩得更小我一般保持默认0.5不调整。6. 模型导出与部署从PyTorch到ONNX再到板端推理6.1 导出ONNX与TensorRT模型训练完得到runs/detect/train/best.pt这个PyTorch权重适合训练和继续调优但不适合直接部署。部署时的标准做法是先导出成ONNX格式yolo export modelruns/detect/train/best.pt formatonnx imgsz1280 halfTrue这里的imgsz必须和训练时保持一致最好也和你后续推理时打算用的一致。如果训练时是1280导出也用1280。半精度halfTrue能让模型体积减半推理速度更快但需要目标平台支持FP16。导出完成后可以用Netron打开onnx文件查看网络结构。这一步很有用很多做算法移植的人会在这里确认模型输入输出节点的名字和维度后面写推理代码或者做模型转换时都需要这些信息。如果目标是NVIDIA平台可以进一步把ONNX转成TensorRT引擎trtexec --onnxbest.onnx --saveEnginebest.engine --fp16TensorRT的加速效果非常明显尤其在小目标检测这种计算密集的场景同一块显卡上通常能比ONNX Runtime快2到4倍。前提是TensorRT版本和你的ONNX算子兼容如果转换过程中报算子不支持可以尝试降低opset版本重新导出。6.2 RK3588与Orin平台的部署要点这两年边缘端部署YOLOv8的需求越来越大RK3588和NVIDIA Orin是两个代表性平台。RK3588是瑞芯微的旗舰SoC内置6 TOPS算力的NPU很多无人机机载边缘计算盒子用的就是它。在RK3588上部署YOLOv8核心工具是RKNN-Toolkit2流程大致是先用yolo export导出ONNX然后用RKNN-Toolkit2在PC上把ONNX转成RKNN格式最后在板端用rknn-toolkit-lite的Python接口加载rknn模型做推理。RK3588部署有几个常见坑一是ONNX里的某些算子NPU不支持需要手动替换或简化网络结构二是输入尺寸必须是固定的不能像ONNX Runtime那样动态变化三是量化精度损失如果用INT8量化VisDrone这种小目标场景精度掉得比较明显建议先用FP16验证精度可接受后再尝试INT8。NVIDIA Orin平台则简单一些直接用TensorRT推理即可。如果你用的是JetPack 5.0以上的系统镜像里面已经自带了TensorRT只需要把导出的engine文件拷贝过去再用Python C API加载。Orin上跑YOLOv8s、1280输入实时性也完全没问题。无论是RKNN还是TensorRT部署时都建议写一个类似下面的推理流程读图、resize到imgsz、归一化、前向推理、解析输出结果、NMS后处理、映射回原图坐标、画框保存。YOLOv8的输出是一个1×84×8400的张量以640输入、80类为例前4维是框坐标后面是各分类得分。如果是自定义的9类或10类输出通道数会相应变化。解析时稍微注意一下别直接用COCO的80类解析逻辑去读VisDrone的模型。7. 常见问题与排查技巧实录7.1 环境与训练阶段的高频报错我把实际训练VisDrone时频率最高的几个问题整理成了速查表方便对照排查问题现象常见原因排查与解决训练时提示CUDA out of memory显存不足降低batch、imgsz或者换更小的模型如yolov8n验证mAP为0且recall为0类别编号错位检查标签第一个数字是否和names索引一致损失值一直不下降标签坐标异常或学习率过大先随机画几张图检查标签降低lr0重新训练训练速度极慢CPU训练或数据加载瓶颈确认GPU可用设置cacheTrue增加workersval阶段报错找不到图片yaml路径配置错误检查path、train、val的相对路径是否正确训练到一半进程被杀内存不足降低workers数量避免cacheTrue占用过多内存这里特别说一下“验证mAP为0”的问题。我的一个朋友第一次转VisDrone时把原始的category编号直接当成了YOLO的class_id没有减1结果网络认为标签里有第10类但names里只有10个类名第10类索引直接越界。YOLOv8发现标签类别和模型输出类别对不上时不会直接报错而是训练出来一个mAP全是0的模型。排查思路就是打开一个label文件看第一列的数值范围如果出现大于等于类别数的数字肯定是映射出了问题。7.2 结果异常与调参排查经验除了报错更多时候是模型“能跑但效果不好”。我在VisDrone上踩过几个坑分享一下判断逻辑。如果训练出来的模型在训练集上表现很好在验证集上mAP很低那就是过拟合。VisDrone训练集6471张说多不多模型容量一大就记住了训练集。解决办法是换小模型、加增强、加正则。YOLOv8一般不需要单独设置weight_decay默认0.0005已经够用。如果所有类别mAP都不高先别急着改网络。回到数据的源头把训练集里每类目标的真实数量统计一下。如果发现某些类别只有几百个框其他类别有几十万框那么少数类别学不好是必然的。对这种类别不均衡可以考虑给少数类别做复制粘贴增强或者干脆在损失函数里提高少数类别的权重。YOLOv8默认没有直接的类别权重接口但可以修改数据增强让少数类别出现在更多训练样本里。如果只是个别类别mAP很低比如motor和others看混淆矩阵大概率是和其他类混淆了。这类问题靠结构调整很难解决合并类别或者减少该类别训练样本中的错误标注更有效。还有一个小技巧很多人不知道训练VisDrone时可以把训练过程中的一些中间检查点保留下来比如每个epoch结束时的weights。YOLOv8默认只保留last.pt和best.pt但有时候best是在训练早期产生的后面震荡之后的模型反而在特定场景下更好用。如果只是做算法预研可以关掉early stopping让模型训满epochs然后自己选中间态做测试。最后分享一个我自己总结的小经验。做VisDrone这类小目标数据集第一次训练总想一步到位直接上大模型大分辨率结果显存爆了、时间耗了、效果也不行。我现在习惯先用yolov8n、imgsz640、30个epoch跑通全流程检查数据转换没毛病之后再上yolov8s、imgsz1280跑正式训练。别小看这个先小后大的流程它能帮你把“代码问题”和“模型调参问题”分开省下来的折腾时间远比那几十分钟验证时间多。如果你也在搞无人机视角目标检测希望这份记录能让你少踩几个坑。
返回列表