首页 / 资讯中心 / 文章详情

YOLOv5遥感目标识别实战指南:从数据标注到模型部署

YOLOv5遥感目标识别实战指南:从数据标注到模型部署 ★ FEATURED ARTICLE
简介这是一份基于YOLOv5算法的遥感图像目标识别项目资源包面向计算机视觉方向学生、科研人员及企业开发者可支撑毕业设计、课程设计、作业演示或高分项目初期的快速搭建与效果验证。包内共156个文件以Python源码.py/.pyc、模型结构配置.yaml、训练权重.pt为核心辅以PNG/JPG结果图、Shell脚本、TensorBoard训练日志、Dockerfile及说明文档压缩包整体约242.81MB。项目内含可用于推理的预训练权重并配套完整训练、验证与预测脚本覆盖环境配置、数据准备、模型训练到结果可视化的主要环节yaml配置便于替换数据集和调整网络参数适合在此基础上继续扩展多类别、多场景遥感目标检测。已有42人学习下载建议先按默认权重复现检测效果再根据实际任务微调能够帮助学习者快速建立工程化视觉项目思路。1. YOLOv5算法在遥感图像目标识别中的应用项目资源包到底能解决什么问题拿到遥感影像做目标识别的人,大概率都经历过同一个场景:图上机场的飞机、港口的船舶、城区的车辆,人工一眼就能认出来,模型跑完一遍,大目标挺准,小目标一塌糊涂。我在多个项目里用 YOLOv5 做遥感图像目标检测,从油罐计数、车辆统计到工地安全帽识别,几乎都把它当成第一个基线来验证。原因很简单:YOLOv5 开源生态完整,训练“自己的数据集”门槛低,项目资源包通常已经把环境、权重、数据组织、训练脚本全部串好了,省去大量重复劳动。但遥感图像有自己的特殊性——俯瞰视角、目标尺度跨度大、背景复杂、标注成本高。所谓“项目资源包”,本质上就是把“环境配置 预训练权重 标注工具 训练流程 部署脚本”打包成一个可复现的工程。本文按实际工程路径来写,适合拿到资源包准备训练自己遥感数据集的人,也适合正在技术选型、想评估 YOLOv5 能否胜任遥感目标识别的人。2. 先看懂 YOLOv5:为什么这套网络结构适合遥感场景2.1 从 YOLOv5 网络结构图看遥感目标检测需要什么网络上搜“yolov5网络结构图”,最常看到的就是那张包含 Backbone、Neck、Head 三段式结构的图。YOLOv5 的模型定义在models/yolov5s.yaml里,几行 YAML 就能完整描述整个网络。我习惯先把结构图和各层输出尺寸对应起来看,因为遥感任务的很多问题,根源都在特征图分辨率上。Backbone 部分:CSPDarknet。核心模块是 C3,它借鉴了 CSPNet 的设计,把特征图沿通道分成两路,一路做残差堆叠,另一路直接拼接,最后再通过卷积融合。相比普通残差结构,C3 在保持精度的同时计算量更小,这对遥感大图推理很有意义——一张 640x640 的瓦片只是原始影像的一小块,推理瓦片数往往成百上千,单张快一点,整体能省不少时间。Neck 部分:SPPF 加 PANet。SPPF 把输入特征图分别做 5x5、9x9、13x13 感受野的空间金字塔池化,再把不同尺度的结果拼在一起。遥感目标尺寸分布极不均匀,同一张瓦片里可能出现几百米的建筑群和几个像素的汽车,SPPF 的多感受野融合天然适合这种多尺度场景。PANet 则负责把深层语义信息传回浅层,再接自顶向下的路径,这样小目标能同时拿到高分辨率的细节和丰富的语义特征。Head 部分:YOLOv5 在三个尺度上检测目标,分别对应 8 倍、16 倍、32 倍下采样。以输入 640x640 为例,输出特征图是 80x80、40x40、20x20。三个尺度的分工很明确:80x80 的特征图感受野小,负责小目标;20x20 负责大目标。遥感图像小目标居多,但目标再小也至少覆盖 4x4 像素才算可辨识,经过 8 倍下采样后 80x80 的网格大致能表达,这就是训练时一直强调输入尺寸不能随便缩小的原因。2.2 损失函数与锚框:为什么遥感小目标容易漏检YOLOv5 有三大损失:分类损失用 BCE,置信度损失也用 BCE,定位损失用 CIoU。CIoU 同时考虑交并比、中心点距离和长宽比,比普通 IoU 损失收敛更稳。但遥感场景下,小目标漏检往往不是损失函数选得不对,而是锚框和特征图网格根本没匹配上。YOLOv5 自带的锚框是从 COCO 数据集上聚类出来的,COCO 里的目标在整幅图中占比通常较大,而遥感小目标往往只有 20x20 像素甚至更小。如果直接套默认锚框,小目标的真实框和预设锚框的 IoU 很低,训练初期梯度就会有问题。好在 YOLOv5 训练时默认开启自动锚框计算,它会读取你的labels/*.txt,针对你的目标尺寸重新做 k-means 聚类,训练启动时的日志里会打印“Autoanchor: 9 anchors”的相关信息。我一般会在训练启动后专门看一眼这段输出,确认最小锚框尺寸和标注里的小目标尺寸处于同一量级。如果尺寸差太多,说明标注数据本身有问题,或者目标太小已经超出 YOLOv5 这三个检测头的能力边界。遥感数据还有一个特点:目标方向任意。飞机、舰船、车辆往往是斜着停的,而 YOLOv5 的检测框是轴对齐矩形,一个斜 45 度的目标,水平框里必然夹带大量背景。这个矛盾在第 3 章数据标注部分会详细展开,但你需要先记住一个结论:对于遥感旋转目标,水平框本身就是一种近似,训练数据里这种近似的“质量”直接决定模型上限。2.3 四档模型怎么选:s、m、l、x 在遥感任务上的取舍YOLOv5 官方提供了 s、m、l、x 四档预训练模型,差别主要在深度和宽度。很多新手直接用 yolov5s 开训,跑完发现小目标检测效果不行,第一反应是算法不行,其实是模型容量不够。模型参数量(约)推理速度适用场景yolov5s7.2M快快速验证流程、边缘端部署yolov5m21.2M中等遥感目标检测的入门最佳选择yolov5l46.5M较慢精度优先的离线批量推理yolov5x86.7M慢追求极致精度,显存充足以我的经验,遥感目标检测建议直接从 m 起步。s 的参数量在复杂背景、小目标密集的遥感任务上容易欠拟合;l 和 x 精度确实更高,但训练时间、显存占用和推理成本都翻倍,适合项目的中后期调优。如果是在树莓派这类边缘设备上部署,先从 s 跑通流程、再用 m 做精度验证,是比较务实的路径。此外,模型规格不同,对应的预训练权重也不同,资源包里如果已经放了对应.pt文件,我一般会先核对一下模型权重和配置文件的匹配关系,避免用 s 的权重去加载 m 的模型报尺寸不匹配的错。3. 把遥感影像变成训练集:标注格式、瓦片裁剪与项目资源包文件核对3.1 遥感图像标注:从旋转框到 YOLO 格式的转换遥感图像标注和普通自然图像标注最大的区别在于“方向”。常用标注工具里,LabelImg 只支持水平框,roLabelImg 支持旋转框,X-AnyLabeling 则兼具半自动辅助标注的能力。YOLOv5 官方只支持水平框的 YOLO 格式,标签是纯文本,每行对应一个目标:class_id x_center y_center width height其中坐标全部归一化到 0-1。例如一个“plane”类别、中心点在 (0.5, 0.5)、宽高分别占整图 20% 的目标,对应一行0 0.5 0.5 0.2 0.2。如果从 LabelImg 导出的是 VOC 格式的 XML,需要转成 YOLO txt。我通常用下面这个脚本处理:import xml.etree.ElementTree as ET def voc_to_yolo(xml_path, out_path, classes): classes: 类别列表,顺序必须与 data.yaml 中 names 一致 tree ET.parse(xml_path) root tree.getroot() size root.find(size) w int(size.find(width).text) h int(size.find(height).text) lines [] for obj in root.findall(object): name obj.find(name).text if name not in classes: continue box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) cx (xmin xmax) / 2.0 / w cy (ymin ymax) / 2.0 / h bw (xmax - xmin) / w bh (ymax - ymin) / h lines.append(f{classes.index(name)} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) with open(out_path, w) as f: f.write(\n.join(lines))这段代码的核心是按 XML 里解析出的归一化坐标来写 YOLO 格式。需要注意:类别列表classes的顺序必须和训练时的data.yaml完全一致,否则类别会对不上,这是资源包使用中最高频的翻车点之一。如果你用 roLabelImg 标注了旋转框,而 YOLOv5 需要水平框,常见的做法是取旋转框的最小外接水平矩形,而不是直接把旋转框四个点存进 txt,否则 YOLOv5 解析时会报坐标格式错误。标注质量直接影响模型上限。遥感图像负样本极多,同一类目标在不同影像中呈现的外观差异也大。我一般会在项目启动时定义清楚“目标判定标准”,比如一架飞机被建筑阴影遮住一半算不算正样本、车辆被树冠遮挡到什么程度才算漏标。标准不统一,标注人员各标各的,模型训练结果就成了黑匣子,很难定位问题。3.2 把大影像切成小瓦片:训练前最重要的一步遥感影像动辄上万像素,直接整图缩放成 640x640 训练,小目标全部变成像素点,检测无从谈起。常规做法是把大图裁成 640 或 1280 尺寸的瓦片,相邻瓦片留一定重叠,防止目标正好被切成两半。裁剪的同时,标注框的坐标也要同步换算。from PIL import Image import os def crop_tiles_with_labels(image_path, label_dir, out_img_dir, out_label_dir, tile_size640, overlap100): 裁剪遥感影像及对应的 YOLO 标签 label 文件与 image 同名,后缀 .txt img Image.open(image_path) img_w, img_h img.size step tile_size - overlap stem os.path.splitext(os.path.basename(image_path))[0] # 读取原始标签并转为绝对像素坐标 boxes [] with open(os.path.join(label_dir, stem .txt)) as f: for line in f: parts line.strip().split() if len(parts) ! 5: continue cls, cx, cy, bw, bh parts cx, cy, bw, bh float(cx), float(cy), float(bw), float(bh) x1 (cx - bw / 2) * img_w y1 (cy - bh / 2) * img_h x2 (cx bw / 2) * img_w y2 (cy bh / 2) * img_h boxes.append((int(cls), x1, y1, x2, y2)) idx 0 for y in range(0, img_h, step): for x in range(0, img_w, step): # 瓦片边界,边缘补齐到 tile_size box (x, y, min(x tile_size, img_w), min(y tile_size, img_h)) tile Image.new(RGB, (tile_size, tile_size), (0, 0, 0)) tile.paste(img.crop(box), (0, 0)) tile.save(os.path.join(out_img_dir, f{stem}_{idx:06d}.jpg)) # 换算标签:保留与瓦片有交集的框 new_lines [] for cls, x1, y1, x2, y2 in boxes: nx1, ny1 max(x1, x) - x, max(y1, y) - y nx2, ny2 min(x2, x tile_size) - x, min(y2, y tile_size) - y if nx2 - nx1 4 or ny2 - ny1 4: continue # 裁剪后目标太小,直接丢弃 ncxn (nx1 nx2) / 2 / tile_size ncyn (ny1 ny2) / 2 / tile_size nw (nx2 - nx1) / tile_size nh (ny2 - ny1) / tile_size new_lines.append(f{cls} {ncxn:.6f} {ncyn:.6f} {nw:.6f} {nh:.6f}) with open(os.path.join(out_label_dir, f{stem}_{idx:06d}.txt), w) as f: f.write(\n.join(new_lines)) idx 1这段代码里最关键的是两个边界处理:瓦片边缘不足 640 时用黑色补齐,避免模型学到不均匀的缩放;裁剪后宽度或高度小于 4 像素的目标直接丢弃。不要小看这个过滤操作,如果不做,模型会反复看到“只有两三像素的模糊目标”,严重干扰置信度学习,这也算是我交过学费的经验。瓦片尺寸的选择要在“小目标清晰度”和“GPU 显存”之间权衡。显存够大建议用 1280 训练,小目标保留的像素更多;普通消费级显卡用 640 也能跑,但要接受小目标漏检率的上升。重叠区一般取瓦片尺寸的 10%-20%,太小压不住切断问题,太大则同一个目标在多个瓦片里重复出现,浪费计算量。3.3 项目资源包文件核对清单拿到一个“YOLOv5 遥感目标识别项目资源包”,我不会急着开训,而是先花十分钟核对这些关键文件:project/ ├── data/ │ ├── remote.yaml # 数据集配置文件 │ ├── images/ # 瓦片或原始影像 │ └── labels/ # YOLO 格式标签 ├── models/ │ └── yolov5s.yaml # 网络结构定义 ├── weights/ │ ├── yolov5s.pt │ └── yolov5m.pt ├── scripts/ │ └── split_data.py # 数据切分脚本 ├── train.py ├── val.py ├── detect.py └── requirements.txt核心核对点有三个。第一,remote.yaml里的path是相对路径还是绝对路径,换机器后绝对路径会直接失效,相对路径也要先确认当前工作目录对不对;第二,classes列表的顺序与所有标签 txt 中的类别 ID 是否一致,这是最容易踩坑的地方——标注工具里类别顺序和训练配置不一致,模型训练时 loss 能降,但推理结果全错位;第三,预训练权重是否存在并能正常加载,资源包里如果放了.pt但配套代码版本不匹配,加载时大概率报结构错误。这些问题在新手手里的出现频率极高,先核对一遍能省去几小时的排错时间。3.4 数据切分:按“景”切,不按“张”切遥感数据切分跟自然图像切分有个巨大差别:同一架飞机,可能出现在连续多张相邻影像或多帧推扫数据里。按整图随机切分,训练集和验证集可能同时包含同一个目标的不同视角,验证 mAP 会虚高,部署到新区域后精度暴跌。代码上,我通常按文件名里的“景号”前缀分组,保证同一个景的瓦片只进训练集或验证集,不交叉。import os import random from collections import defaultdict def split_by_scene(image_dir, out_train_list, out_val_list, val_ratio0.2): 按文件名前缀(通常是景号)分组切分 scene_images defaultdict(list) for f in os.listdir(image_dir): if not f.endswith(.jpg): continue scene_id f.split(_)[0] # 假设文件名形如 S01_000000.jpg scene_images[scene_id].append(f) scenes list(scene_images.keys()) random.seed(42) random.shuffle(scenes) val_scene_count max(1, int(len(scenes) * val_ratio)) val_scenes set(scenes[:val_scene_count]) train_files, val_files [], [] for scene, files in scene_images.items(): for f in files: if scene in val_scenes: val_files.append(os.path.join(image_dir, f)) else: train_files.append(os.path.join(image_dir, f)) with open(out_train_list, w) as f: f.write(\n.join(train_files)) with open(out_val_list, w) as f: f.write(\n.join(val_files))这段脚本的价值在于从根源上杜绝数据泄漏。注意文件名前缀的规则要提前定好,裁剪瓦片时就应该在文件名里保留场景信息,否则跑到这一步才发现字段丢了,就只能靠人工归组,那才是真正的血泪经验。4. 用 YOLOv5 训练自己的遥感数据集:环境、命令与超参数调整4.1 yolo v5 环境配置:先解决 CUDA 版本匹配“yolov5环境配置”是出现频率极高的搜索词,绝大多数配置问题出在 PyTorch 和 CUDA 的版本匹配上。我的一般流程是先用 conda 建环境,再单独装 PyTorch,避免 requirements.txt 自动装一个和本机 CUDA 驱动不匹配的版本。conda create -n yolo python3.9 -y conda activate yolo pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 git clone https://github.com/ultralytics/yolov5.git cd yolov5 pip install -r requirements.txt装完后用两个命令确认环境:nvidia-smi python -c import torch; print(fCUDA available: {torch.cuda.is_available()}, PyTorch: {torch.__version__})nvidia-smi看的是显卡驱动支持的最高 CUDA 版本,而 PyTorch 实际使用的是自己指定的 CUDA runtime 版本,比如 cu118 对应 CUDA 11.8。这两个不严格等价,驱动版本只要不低于 PyTorch 需要的中间版本就行。很多人在这一步翻车,torch.cuda.is_available()返回 False,最后发现是 PyTorch 装成了 CPU 版本。项目资源包里的 requirements.txt 一般会把关键依赖固定住,建议先比对一下里面的 torch 版本和你本机 GPU 驱动再动手安装。4.2 训练自己的数据集:一条命令跑通遥感检测环境配好后,训练命令其实比较固定,核心长这样:python train.py \ --data data/remote.yaml \ --weights weights/yolov5m.pt \ --epochs 150 \ --batch-size 16 \ --img 640 \ --device 0 \ --workers 8 \ --cache ram各参数含义如下:参数常用值说明--datadata/remote.yaml数据集配置,里面写图像路径和类别名--weightsyolov5s/m/l.pt预训练权重,建议至少用 COCO 预训练模型起步--epochs100-300遥感任务收敛慢,100 轮只是基线--batch-size8-32受显存限制,640 输入下 16 比较稳妥--img640 / 1280输入尺寸,越大对小目标越友好--device0指定 GPU,CPU 训练则写cpu--workers8数据加载线程数,Windows 下建议 4 以内--cacheram / disk将图像缓存到内存或磁盘,显著加速小数据集迭代remote.yaml是训练入口,内容如下:path: data/remote # 数据集根目录 train: images/train # 训练图像目录 val: images/val # 验证图像目录 nc: 4 # 类别数 names: [plane, ship, vehicle, oil_tank]训练开始后,终端会先打印自动锚框计算的信息,然后输出每一轮的 box_loss、cls_loss、obj_loss、mAP0.5 和 mAP0.5:0.95。我不太会在前 20 轮频繁看 mAP,那是欠拟合的正常过程;重点观察 loss 是否稳定下降,以及是否存在剧烈震荡。4.3 遥感场景下的超参数调整:几个关键旋钮YOLOv5 的超参数文件在data/hyps/hyp.scratch-low.yaml,里面变量很多,但遥感场景下值得动的不多,改多了反而玄学。我平时只调这几个:lr0: 0.01 # 初始学习率 lrf: 0.01 # 最终学习率 lr0 * lrf mosaic: 1.0 # mosaic 增强概率 scale: 0.5 # 随机缩放范围 fliplr: 0.5 # 水平翻转概率 hsv_h: 0.0 # 色调增强 close_mosaic: 10 # 最后 10 轮关闭 mosaic遥感图像色彩相对稳定,不像自然照片那样光照变化大,所以我把hsv_h、hsv_s、hsv_v都调小甚至设为 0,避免模型学到不真实的色彩变化。fliplr要看目标语义:如果识别车辆方向不重要,0.5 没问题;如果方向和朝向是后续任务的一部分,建议降为 0,因为水平翻转会把左行车辆变成右行,和真实标注逻辑冲突。close_mosaic保持默认或调大到 15,作用是最后若干轮关掉 mosaic 增强,让模型在接近真实分布的数据上稳定收敛。训练时还有一个容易被忽略的参数是--multi-scale。开启后,每 10 轮会在 0.5 到 1.5 倍之间随机改变输入尺寸,等于免费做了尺度增强。遥感目标尺度差异本来就大,这个参数对泛化能力有明显帮助,代价是训练时间略有增加。超参数调整的原则是“一次只动一个变量”。我见过有人一次性改了 lr、mosaic、scale、fliplr,最后效果变差根本不知道是哪一个拖了后腿。先跑一版默认参数,再逐项调整,用同样的验证集对比 mAP,才是工程上可控的做法。4.4 中断恢复与训练过程观察训练到一半断掉是很常见的事,尤其是租用云 GPU 或处理长时间任务时。YOLOv5 支持断点恢复:python train.py --resume runs/train/expruns/train/exp里保存着last.pt,resume 后训练轮次、优化器状态、学习率调度都会接着来,不需要从头开始。这里有个习惯值得养成:每跑完一轮训练,我会写一个简单的标注和说明文件放在 exp 目录里,记录当时的输入尺寸、batch、超参数改了什么。否则一周后看exp3、exp5、exp7一堆目录,根本分不清哪个对应哪次实验。训练过程中的可视化输出也要会看。YOLOv5 默认在runs/train/exp下生成results.png,里面包含损失曲线、精确率、召回率和 mAP 曲线。和分类任务不同,目标检测的 loss 曲线不单调下降是正常的,但如果 mAP 在 50 轮后还在剧烈抖动,大概率是学习率过高或数据有问题,应该停下来检查标注文件,而不是继续加大训练轮次。5. 遥感目标识别常见问题与避坑:从漏检到过拟合的处置记录5.1 飞机漏检率居高不下:小目标在特征图里消失了现象:训练了 100 轮,mAP0.5 在 0.6 左右,看起来还行,但单独统计飞机的漏检率,发现大部分飞机根本没被召回。人工标注明明有,模型就是检测不到。原因:小目标经过 YOLOv5 检测头的下采样后,在 80x80 特征图上可能只占据 1 到 2 个像素,包含的语义信息太少。此外,遥感影像通常是灰度分布复杂、纹理细节多,模型很容易把注意力放在背景纹理上。还有一个常见原因是自动锚框计算出的最小锚框仍然偏大,小目标与锚框的 IoU 达不到正样本阈值。解决:我的操作顺序是——第一步,把输入尺寸从 640 提到 1280,小目标像素量变成原来的两倍;第二步,检查 anchors 是否匹配,可以在训练日志里找到锚框尺寸,再对比标注文件中的目标宽高分布,确认小锚框覆盖到位;第三步,如果还不行,降低推理时的置信度阈值,从默认的 0.25 降到 0.01,看看目标是否只是“置信度低”而不是完全没被检测到;最后,考虑在模型结构上加入 P2 检测层,将浅层高分辨率特征接入检测头,但这会显著增加计算量和显存占用。前两步能解决九成问题。5.2 训练 loss 很低但验证集 mAP 惨淡:数据泄漏在捣乱现象:训练集上 loss 降得又快又低,验证集上 mAP 也虚高,一度到 0.8 以上,但拿到另一景影像上测试,效果惨不忍睹。原因:数据泄漏。裁剪瓦片时,同一个目标可能出现在多张瓦片里,如果你把瓦片随机分进训练集和验证集,验证集里就混杂了大量与训练集高度相似甚至包含同一目标的图像。模型“见过”验证集的内容,评估结果自然好看,但换到新区域就露馅。解决:严格按“景”进行数据切分,先分组再分集,这个逻辑在第 3.4 节代码里已经写清楚了。另外要检查瓦片重叠率是否过高,overlap 超过 50% 时,同一目标的重复度太高,即使按景名分组,也要确认相邻瓦片不会被分配到不同集合中。做完整图切分后,单独抽出几景完全不参与训练的数据做最终评测,这个数据要像高考出题一样严格隔离,从训练开始就锁进保险柜。5.3 旋转目标检测不准:水平框的近似代价现象:舰船、飞机这类目标在遥感影像中方向任意,模型检测出的水平框要么漏掉船头船尾,要么把旁边的码头一起框进来。框的位置不精准,后续计数或识别任务全部受影响。原因:YOLOv5 的输出只有中心点、宽高和类别,没有角度参数,本质上是水平框检测器。把旋转目标当水平框做,标注时就已经夹带了背景噪声,目标越斜,噪声越大。解决:如果项目允许,先用旋转框标注工具标好,再转成水平外接矩形,这样至少定位更贴近目标;如果必须用旋转框检测,官方 YOLOv5 没有支持,需要换成带角度输出的模型仓库,同时对资源包中的训练脚本做相应替换。不要尝试在官方 YOLOv5 的结构里硬加角度头,尾期的调参和大规模验证成本非常高。遥感目标检测里“旋转框”算是一个门槛型需求,一开始就要想清楚:水平框的近似到底能不能满足业务精度,不能的话,换个支持旋转框的模型比后期补救更划算。5.4 CUDA out of memory 与数据加载瓶颈并存现象:训练启动后第一轮就报CUDA out of memory,或者 GPU 利用率不高但 CPU 已经满载,训练速度全靠 CPU 硬扛。原因:显存溢出通常是输入尺寸过大、batch 过大或模型规格过高共同造成的;而 CPU 满载 GPU 吃不满,则多是数据加载链路的问题。解决:显存方面,先减小 batch-size 到 4 或 8,如果仍然 OOM,就降低输入尺寸,或者换小一档的模型。这里有一个反直觉的教训:batch 减小到一定程度后,模型收敛会变慢,可以用梯度累积来平衡。数据加载方面,增加--workers到 8-16,把--cache ram打开,如果数据集太大,至少把验证集单独缓存;另一个容易忽略的点是数据集必须放在本地 NVMe SSD 上,放在机械硬盘或网络存储里,训练全程都会受 IO 拖累。最后检查pin_memory默认开启状态,内存充足时保持开启能减少数据从 CPU 到 GPU 的拷贝时间。6. 把模型用起来:推理验证、导出部署与落地小技巧6.1 用 val.py 评估:别只盯着 mAP0.5训练完成后,评估命令是:python val.py \ --data data/remote.yaml \ --weights runs/train/exp/best.pt \ --img 640 \ --conf-thres 0.001 \ --iou-thres 0.5 \ --task val遥感小目标检测场景,我特别建议把--conf-thres调到 0.001,这个阈值下能看清楚“模型是否真的找到了目标”。如果放宽阈值后召回率明显提升,说明目标都能检测出来,只是在工程阈值下被过滤掉了;如果放宽后召回率依然低,问题在模型本身,去调数据比调阈值更有用。mAP0.5:0.95比mAP0.5更能反映框的位置精度,旋转目标场景下这个指标会非常难看,但它恰恰是提醒你“水平框解决问题已经到了天花板”的信号。6.2 导出 ONNX 与部署:从训练机到边缘设备模型验证通过后,导出成部署格式:python export.py --weights runs/train/exp/best.pt --include onnx导出后可以用 ONNX Runtime 本地推理,也可以继续转成 TensorRT engine(需要本机有 TensorRT 环境),或者转成一个简单的 TorchScript 用于树莓派这类边缘设备。边缘设备部署要注意,遥感场景输入的瓦片往往还是 640 甚至更大,树莓派算力有限,建议先控制推理帧率,再逐步调整置信度阈值。部署不只是“能跑就行”,要提前想清楚误报和漏报哪个代价更高:无人机巡检时漏掉一个目标可能比多框一个更严重,那就把阈值调低,让模型更“激进”,宁可多几个误报再人工复核。6.3 用混淆矩阵找出压死部署的最后一根稻草val.py 会输出confusion_matrix.png,这是我最先看的部署指导文件。遥感数据集里常见的混淆目标很有规律:车辆与集装箱、树林与阴影、油罐与圆形建筑。如果混淆矩阵显示某两个类别经常互相误判,优先补充这两个类别的新样本,比盲目调参数有效得多。另一个习惯是,每次结束训练后,我都会从验证集里肉眼抽查 20 张模型的预测可视化图,单看 mAP 你永远不知道模型到底是在“认真检测”还是在“猜规律”。我现在的固定流程是:先跑一轮 50 轮的小规模训练验证数据自洽,再上全量 150 轮正式训练,这个习惯帮我避免了至少三次隔夜全量训练后才发现标签错位的返工。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站