1876张鼠标数据集YOLO训练全流程:格式转换、避坑与调优
简介面向目标检测与计算机视觉研究的鼠标检测数据集共包含1876张真实场景图片统一标注为单一类别mouse涵盖2261个矩形标注框适用于训练YOLO系列、Faster R-CNN等主流检测模型也可用于VOC格式与YOLO格式数据转换教学。压缩包共2000个文件以XML标注文件和YOLO格式TXT标注文件为主要内容整体大小约219.91MB便于快速下载与解压使用。数据由labelImg工具人工标注画框规则统一保证了标注质量的可用性同时特别声明仅提供精确合理标注不保证模型精度适合作为算法效果验证与对照试验的基准数据。目前已有296人学习下载适合刚接触目标检测的开发者学习数据标注规范也适合有经验的工程师在自定义数据集中补充鼠标类样本、调试检测模型。1. 拿到1876张鼠标数据集先别急着训练做目标检测的人都知道鼠标这种小目标不算冷门但也不像行人、车辆那样有现成大把公开数据。有人要办公场景的鼠标检测有人做行为分析要识别桌上有没有鼠标还有人要把鼠标从键盘、触控板、水杯一堆杂物里分出来。这时候手里有一份鼠标数据集1876张VOCYOLO格式就意味着图片和标注都齐了省去找图、打标签的时间直接可以做训练和评估。1876张这个量级说多不多说少不少——够用但不够你挥霍训练策略和划分方式稍有不当模型就能给你表演什么叫欠拟合。这份数据本质上是双格式交付VOC那套xml标注适合你用LabelImg继续改、适合转成其它框架要的格式YOLO那套txt标注适合直接喂给YOLO系列训练连转换都省了。但别高兴太早两种格式并存也意味着你要先搞明白两者的换算关系、类别编号规则以及小数据集的训练边界。这篇就按一条完整链路来写格式怎么读、怎么转、怎么训、坑在哪里、训完怎么验收。2. 鼠标数据集的VOC和YOLO格式怎么理解从文件结构到坐标换算2.1 拿到手先看目录结构两份标注差在哪一份同时给VOC和YOLO格式的数据集常见做法是分成两个目录或者一个目录里既有xml又有txt。不管哪种第一步永远是先摸清文件组织方式别上来就写训练脚本。常见结构是这样mouse_dataset/ ├── images/ │ ├── mouse_0001.jpg │ ├── mouse_0002.jpg │ └── ... ├── voc_annotations/ │ ├── mouse_0001.xml │ ├── mouse_0002.xml │ └── ... └── yolo_labels/ ├── mouse_0001.txt ├── mouse_0002.txt └── ...先随便挑一张图把它的xml打开看一眼。VOC格式里每张图一个xml文件filename对应图片名size记录宽高object标签下有name、bndbox四个角点坐标。这里要注意VOC的xmin、ymin、xmax、ymax是绝对像素值左上角为原点x向右增大、y向下增大。你做坐标换算或者后续数据增强时这个原点方向搞反了出来的框全部上下颠倒。YOLO格式的txt每一行对应一个目标一行五个数class_id center_x center_y width height读到这里就得意识到VOC存的是左上角和右下角YOLO存的是中心点和宽高而且YOLO的四个数值全部归一化到0到1之间除以的是图片宽高。这个差异就是两份标注之间互相转换的根基。数据集的类别定义也很关键。1876张图里标注对象纯鼠标那一类ID就是0如果里面混杂了键盘、显示器之类的类别txt每行第一个数字的含义就完全不同。动手训练前建议写一行命令把txt里的类别号拉出来看分布awk {print $1} yolo_labels/*.txt | sort | uniq -c输出里如果只有一个0号类别说明是单类别检测如果有多个数字你要去对照数据集的类别映射表确认第0类到底是什么。很多人训练完发现鼠标全检不出来回头一查是txt里类别ID 0代表的是“电子产品”大类而默认类别名表里0是person——这种错位问题下文避坑章还会再展开。2.2 坐标换算VOC和YOLO互转的三个公式和边界检查转换的核心就是三个公式。设图片宽为W、高为HVOC角点为xmin, ymin, xmax, ymax转YOLO格式时center_x (xmin xmax) / 2.0 / W center_y (ymin ymax) / 2.0 / H width (xmax - xmin) / W height (ymax - ymin) / H反转换回来则是xmin int((center_x - width / 2) * W) ymin int((center_y - height / 2) * H) xmax int((center_x width / 2) * W) ymax int((center_y height / 2) * H)公式本身不难真正容易翻车的是边界检查。标注时手一抖框画出去一格xmax大于图片宽度、或者ymin小于0这类脏标注在1876张这种小数据集里一两张就能让训练损失曲线出现异常毛刺。所以转换脚本里一定要夹带检查逻辑超界的坐标要么截断、要么直接跳过这条样本并打印警告。下面是我常用的转换脚本核心逻辑xml和jpg放在同一个根目录下输出到自己指定目录转换时顺带做边界清洗import os import xml.etree.ElementTree as ET import cv2 def voc_to_yolo(xml_path, out_dir, image_root): 转换单个VOC xml为YOLO txt 边转换边检查坐标系是否越界越界就clip并告警 tree ET.parse(xml_path) root tree.getroot() img_name root.find(filename).text img_path os.path.join(image_root, img_name) h, w cv2.imread(img_path).shape[:2] # 用真实尺寸别信xml里size字段 lines [] for obj in root.iter(object): name obj.find(name).text cls_id 0 # 单类别数据集直接给0多类别要查映射表 bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 边界检查越界坐标截断到图片范围内 xmin, xmax max(0, xmin), min(w, xmax) ymin, ymax max(0, ymin), min(h, ymax) if xmax xmin or ymax ymin: print(f[warn] {img_name} has invalid bbox, skip) continue cx (xmin xmax) / 2.0 / w cy (ymin ymax) / 2.0 / h bw (xmax - xmin) / w bh (ymax - ymin) / h lines.append(f{cls_id} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) out_path os.path.join(out_dir, img_name.replace(.jpg, .txt)) with open(out_path, w) as f: f.write(\n.join(lines)) return len(lines)这段逻辑里有两个值得注意的细节。第一我用cv2.imread读取图片实际尺寸来算归一化而不是直接信xml里的size字段——因为遇到过标注工具写出来的size和图片真实分辨率不一致数据搬家过程中图片被压缩过。第二坐标为负或超过图像宽高时没有直接丢数据而是clip到边缘。鼠标贴边出现时框出去半截是很常见的直接丢反而损失了难样本clip之后边界框退化成贴边框信息量还在。多类别情况下cls_id那里不能写死0而要做一层类别名到ID的字典映射class_map {mouse: 0, keyboard: 1, monitor: 2} try: cls_id class_map[name] except KeyError: print(f[warn] unknown class {name}, skip) continue2.3 为什么同时给VOC和YOLO两份只留一份行不行有人拿到双格式数据集会想VOC这份是不是多余直接把txt拿去训练不就完了。实际不是。双格式存在的原因是不同工具链的输入要求不一样。你要用YOLOv8训练txt是原生格式没错但如果你想换mmdetection跑一轮对比实验它默认要吃COCO或VOC的json/xml如果你想可视化标注质量、手动修掉一两张脏框LabelImg直接打开的就是VOC的xml。预留一份VOC标注等于给自己留了一条退路——模型训练效果离谱时你可以随时回退到VOC侧去检查标注本身而不是面对一堆不知道哪张图对应哪个txt的裸数据。对1876张这个规模而言我更建议你直接以YOLO格式为主力训练格式VOC当作校验和编辑的辅助副本。接下来讲训练时所有脚本默认你用的是YOLO那套txt。3. 1876张怎么训出能用的鼠标检测模型数据划分与YOLO训练链路3.1 小数据集的划分原则验证集别按比例死搬1876张图片按默认8:1:1或者8:2划分验证集就分走两三百张。看起来合理未必。鼠标检测的难点集中在几种场景鼠标在纯色桌面上、鼠标半藏在键盘旁边、鼠标被手握住只露半边。如果验证集里恰好堆满了难样本而你训练集里全是那种放在白板前的大号鼠标特写训练出来的模型验证时mAP会非常难看。反过来说如果验证集全是简单样本评估结果一片繁荣部署到真实场景立刻现原形。我一般会对这种规模的数据做分层划分先按图片场景或难度做个粗略分组再每组内按比例抽取进训练集和验证集。没有场景标签时退一步的做法是纯随机划分但要把随机种子固定下来方便复现对比实验。下面这个脚本在划完分后直接生成YOLO训练需要的目录结构把图片和标签按train/val两个子集归好import os import random import shutil random.seed(42) # 固定种子方便实验复现 image_dir images label_dir yolo_labels train_img_dir dataset/images/train val_img_dir dataset/images/val train_lbl_dir dataset/labels/train val_lbl_dir dataset/labels/val os.makedirs(train_img_dir, exist_okTrue) os.makedirs(val_img_dir, exist_okTrue) os.makedirs(train_lbl_dir, exist_okTrue) os.makedirs(val_lbl_dir, exist_okTrue) all_imgs sorted([f for f in os.listdir(image_dir) if f.endswith(.jpg)]) random.shuffle(all_imgs) val_count int(len(all_imgs) * 0.15) # 1876张约281张做验证 val_imgs set(all_imgs[:val_count]) for img in all_imgs: lbl img.replace(.jpg, .txt) src_img os.path.join(image_dir, img) src_lbl os.path.join(label_dir, lbl) if not os.path.exists(src_lbl): print(f[skip] {img} has no label file) continue # 标注缺失的图片直接排除别硬塞进训练集 if img in val_imgs: shutil.copy(src_img, train_img_dir) if False else shutil.copy(src_img, val_img_dir) shutil.copy(src_lbl, val_lbl_dir) else: shutil.copy(src_img, train_img_dir) shutil.copy(src_lbl, train_lbl_dir)这段逻辑里有个地方要特别说shutil.copy(src_img, train_img_dir) if False else shutil.copy(src_img, val_img_dir)这个写法是我故意留下的三层表达式看着绕实际想表达的意图是——验证集图片只能进验证目录训练集图片只能进训练目录两者不能混淆。代码里用if False是提醒你复用脚本时最常犯的错误就是把验证集和训练集路径写反。写完后检查一下两个目录的资源数验证集大约在250到300张之间浮动不够就要检查是不是有图片缺标签被跳过了。小数据集还有一个容易被忽视的点训练集数量只有1500多张图片分辨率如果又高单卡训练时每轮很快但模型很容易在20个epoch左右就开始过拟合。这不是你的错是数据量的物理规律。应对策略分两步一是用预训练权重而不是从零训练二是控制训练轮次和早停参数别让它傻跑200轮。3.2 环境准备Anaconda里装YOLO的最小步骤无论用YOLOv5、YOLOv8还是最新的版本环境套路都差不多。用Anaconda建一个独立环境是值得的免得和已有项目互相污染依赖。这里以ultralytics的yolo命令行为例装好之后训练、验证、导出一条龙。conda create -n mouse_yolo python3.10 -y conda activate mouse_yolo pip install ultralytics装完ultralytics后建议顺手验证一下CUDA是否可用这一步用Python跑一行代码import torch print(torch.cuda.is_available(), torch.cuda.get_device_name(0) if torch.cuda.is_available() else cpu)输出True和显卡型号说明GPU环境正常。如果输出False有可能是PyTorch装成了CPU版这在最新版本里是个高频问题——你需要根据自己机器的CUDA版本从PyTorch官网装对应CUDA轮的torch版本再装ultralytics顺序不要反。顺序反了的常见翻车现场是先装ultralytics把CPU版torch拉进来了后续再怎么pip install也没法自动给你换掉只能手动重装torch。数据准备好之后写一个data.yaml文件指明训练验证路径和类别信息# mouse_data.yaml path: ./dataset train: images/train val: images/val names: 0: mouse注意names是0到N-1的列表顺序和txt里的类别ID严格对应。只有一类就只写一个mouse。文件编码不要带BOMYAML解析器遇上BOM头会报诡异错误这个坑我帮读者排除过不止一次。3.3 训练命令和三个关键参数batch、epochs、早停训练命令本身不复杂就一行yolo detect train datamouse_data.yaml modelyolov8s.pt epochs150 batch16 imgsz640 patience30 device0逐项解释参数选择。modelyolov8s.pt表示从官方预训练权重开始而不是yolov8s.yaml——用.pt文件可以继承在COCO上学到的通用特征这对小数据集极其重要。从零训练一个检测头在1876张数据上基本是灾难收敛慢且精度上限低。选s不是n是因为鼠标属于小目标特征细节比大目标更依赖网络的表达能力s在速度和精度上比n更平衡。batch16是常规显存下的起点值。你的显卡如果是8G显存imgsz640时batch16基本是安全线如果训练中途报CUDA out of memory果断把batch降到8或4不要硬扛。patience30表示30个epoch内验证集指标没有提升就提前终止这项对小数据集非常友好——你不需要手动判断什么时候过拟合了训练脚本帮你踩刹车。还有一个容易被忽略但能直接改善小数据集效果的参数是mosaic和hsv_h这些增强项。默认增强对小数据集过度反而把鼠标形状破坏掉。更合适的做法是适当降低增强强度yolo detect train datamouse_data.yaml modelyolov8s.pt epochs150 batch16 imgsz640 patience30 hsv_h0.01 hsv_s0.3 hsv_v0.3 mosaic0.8hsv_h色相增强改成0.01避免鼠标颜色被人为偏移太多因为鼠标颜色本身就是重要的判别特征。mosaic0.8表示80%的批次样本做mosaic拼接保留一部分原始完整图像让模型看到正常布局这在目标稀疏的数据集里能显著降低误检。3.4 训练过程盯四个指标不是只看loss训练跑起来之后终端会滚动输出各种数值。非从业人员容易只盯box_loss见它往下降就觉得万事大吉。实践里我盯的是四个指标的变化方向box_loss持续下降是底线但降到一定程度开始反弹时早停就会触发这是正常的。cls_loss关注的是分类分支有没有学起来鼠标这个类别如果和目标背景混在一起不好分这个值会偏高。看验证集mAP50和mAP50-95时前者到0.9以上说明“能找到鼠标”后者到0.6左右说明“框得还算准”。小数据集上mAP50-95别追求0.8以上那个精度需要一个几千张级的数据量才撑得起来。训练结束后跑一下验证集评估yolo detect val modelruns/detect/train/weights/best.pt datamouse_data.yaml评估输出会给出各类别平均精度和召回率单类别数据集的p和r都该在0.85以上才说得过去。如果召回率明显低于精确率说明漏检多后期需要考虑补样本或调低置信度门限。如果精确率低、召回率高说明误检多要么调高门限要么去看是不是背景样本不够、模型把什么东西都当成鼠标了。4. 鼠标数据集训练避坑5个跑不通或效果差的原因记录4.1 标签文件存在但训练时一个目标都读不到现象训练日志显示训练集图片载入了但每轮loss都是0或者接近0验证集精度全程为0。原因标签文件路径不对或者标签文件夹内的txt名字和图片名对不上。YOLO默认在图片同目录找同名txt或者根据data.yaml里train和val路径推算标签路径。常见做法是images和labels在同一个父目录下且训练集图片路径写成dataset/images/train那么标签会被自动定位到dataset/labels/train。一旦你把标签放到了dataset/labels/train/source/这种多套一层的目录里训练循环里读到的标签列表就是空的。解决先确认images/train下图片数量和labels/train下txt数量一致再随便打开一个txt看内容是否非空。最容易出问题的反而是txt文件内容为0字节——标注软件导出时某些样本没写进去但文件还在。用下面这行命令扫一遍空标签find dataset/labels/train -name *.txt -size 0 -delete把空标签删掉再回头看对应图片还在不在如果图片还在这些样本不会被当成没有标注的目标参与训练避免模型学到“有图无框”的错误信号。当然更好的做法是把对应图片也从训练集挪走。4.2 归一化坐标越界训练时警告刷屏现象训练日志里频繁出现WARNING: invalid box一类的输出且验证集AP始终上不去。原因前面转换章节说的边界问题在源标注里就存在。有人在LabelImg里画框时拖过了图片边缘导出成xml时坐标值大于了图片宽高转换脚本又没有做clip直接写进txt导致归一化后的坐标出现大于1的小数或者宽高为负数。解决写一个独立的检查脚本扫遍所有txt找出坐标小于0或大于1的行import glob bad_files [] for txt_path in glob.glob(dataset/labels/*/*.txt): with open(txt_path) as f: for i, line in enumerate(f, 1): parts line.strip().split() if len(parts) ! 5: bad_files.append((txt_path, i, not 5 cols)) continue _, cx, cy, bw, bh map(float, parts) if not (0 cx 1 and 0 cy 1 and 0 bw 1 and 0 bh 1): bad_files.append((txt_path, i, f{cx},{cy},{bw},{bh})) break print(bad_files if bad_files else all labels ok)跑完如果列出问题文件回VOC那侧修正xml再重新走转换流程。不要直接在txt里手改因为VOC原始标注才是唯一来源改txt改完又被人用VOC转换覆盖一次就白做了。4.3 训练到一半显存溢出中断之后权重全丢现象训练跑到第86个epoch突然报CUDA out of memory进程退出runs/detect/train里只有last.pt果冻态。恢复继续训练时只能从头再来前面80多个epoch白跑。原因显卡显存不够batch设大了。1876张的训练集单个batch的显存占用波动很大mosaic增强会一次性拼4张图实际显存开销接近batch的1.5倍。中间如果显卡被别的程序占了几百MB就可能中途爆掉。解决batch从16降到8imgsz从640降到512。鼠标不是那种需要超高分辨率才能检出的目标512的输入尺寸损失很小但显存占用几乎减半。另外进程中断后可以显式指定从断点续训yolo detect train datamouse_data.yaml modelruns/detect/train/weights/last.pt epochs150 batch8 imgsz512 resumeTrue注意续训时epoch数是总轮数不是剩余轮数。把150写上去训练脚本会自动从头计算已经跑过的轮数。不过这招只能救回最近一次的last.pt如果连last.pt都没有就老老实实重来。养成每50轮把权重复制一份的习惯比什么都强。4.4 验证集精度高、实际用起来乱框问题出在置信度门限现象训练评估mAP50到了0.93信心满满接入业务结果在真实桌面上框出一堆奇奇怪怪的矩形鼠标反而漏掉几个。原因训练时验证集和训练集来自同一个分布背景也类似。部署时换了个办公场景桌面纹理、光线角度全变了模型对“像鼠标”的误检目标给出了高分。这不是过拟合是域偏移。评估时默认置信度门限是0.25业务场景可能该设0.5以上。解决重新推理时手动调高门限使用conf参数yolo detect predict modelruns/detect/train/weights/best.pt sourcetest_samples/ conf0.5如果0.5门限下漏检变多先别急着回调门限去看漏检的那几张图大概率是鼠标被手遮住一半或逆光导致对比度极低。这种情况要么补样本要么接受漏检——提高门限压误检和降低门限找回漏检是一个跷跷板得按你的业务容忍度来定。4.5 数据集里图片尺寸参差、EXIF旋转把标注带偏现象部分图片训练时正常推理时同一张图怎么转都不出框或者框出来位置明显偏移。原因手机或相机拍的图片带EXIF方向信息有些标注工具画框时读取的不是像素排列方向导致标注坐标和实际视觉方向错位。YOLO读取时如果图像被解码成了正向但标注还是按旋转前的方向写的就全歪了。解决进训练前统一做一次图片标准化用Python批量转正并覆盖保存同时用OpenCV重写图片丢掉EXIF信息import os import cv2 from PIL import Image def normalize_images(image_dir): for name in os.listdir(image_dir): path os.path.join(image_dir, name) img Image.open(path) img ImageOps.exif_transpose(img) # 按EXIF转正 rgb cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR) cv2.imwrite(path, rgb) # OpenCV保存时不会写EXIF转正之后原标注的坐标才不会因为方向变化而错位。如果数据集中图片原本方向就五花八门建议转正后再肉眼抽检20张确认鼠标在框内。5. 训练后验收与调优怎么把模型推到能用的状态5.1 从PR曲线和混淆矩阵判断模型瓶颈训练结束后的results.png里画了PR曲线和混淆矩阵很多人扫一眼就关了。实际上这两个图能直接告诉你下一步该做什么。PR曲线右下角会标all classes 0.93这类汇总数字鼠标单类别下就是这个数字本身。如果曲线在召回率0.85处突然掉头向下说明有一撮鼠标样本怎么调阈值都检不出这是难样本的具体信号。这时候把验证集里漏检的图片挑出来按视觉特征做个简单归类。最常见的三种鼠标黑色、深色桌面、逆光鼠标在画面中占比极小小于原图面积的1%鼠标与背景纹理高度相似比如白色鼠标放在白色文档旁边。归类之后你会发现训练集里对应的样本量本身就少。任务就变成了有目的的补数据而不是盲目追求更大的随机数据集。验证指标只能告诉你“有没有问题”不能告诉你“哪里有问题”。用可视化推理找到漏检图片把损失函数的注意力引到难样本上——常见做法是把这些漏检图复制几份并做轻微抖动增强塞回训练集比你把训练轮数从150加到300有用得多。5.2 小数据集涨点的三个操作假样本、拷贝粘贴、多尺度1876张数据要榨出更多价值业界最常用的是目标级拷贝粘贴增强。把鼠标从一张图里crop出来随机粘贴到没有鼠标的背景图上生成合成样本。鼠标很少有姿态变化不涉及复杂的形变所以这种朴素增强在这个任务上特别有效。实现用Python配合标注读取并不复杂import cv2 import random def paste_object(bg_img, obj_img, label, out_img_path): h, w bg_img.shape[:2] oh, ow obj_img.shape[:2] # 随机缩放目标到原尺寸的0.8-1.0倍避免模型依赖特定大小 scale random.uniform(0.8, 1.0) nh, nw int(oh * scale), int(ow * scale) obj_resized cv2.resize(obj_img, (nw, nh)) x random.randint(0, max(w - nw, 0)) y random.randint(0, max(h - nh, 0)) bg_img[y:y nh, x:x nw] obj_resized label[...] f0 {((x nw / 2) / w):.6f} {((y nh / 2) / h):.6f} {(nw / w):.6f} {(nh / h):.6f} cv2.imwrite(out_img_path, bg_img)粘贴时要注意两个细节。一是目标边缘别生硬剪切粘贴后可以做轻微的高斯羽化否则模型会学到“鼠标周围有锋利边缘”的假信号部署到真实场景边缘不锐利就检不出来。二是粘贴位置要避开图像中间区域——训练集里鼠标通常不会出现在画面正中央合成样本如果大量居中模型对居中目标的响应会过强。多尺度方面YOLO训练时imgsz640会把所有输入图resize到这个尺寸。意味着原图里大的鼠标被缩小、小的鼠标被放大。训练集里两种尺度都要有如果你发现原数据集里的鼠标普遍偏大合成样本时用0.5倍缩放多搞一批小的模型对小目标的识别会明显改善。5.3 把训练产物导出成ONNX做部署验证很多人训完在验证集里看效果不错就收工了。真到部署阶段推理速度、模型大小和框架兼容性才是硬指标。用YOLO自带导出命令把权重转成ONNX格式yolo export modelruns/detect/train/weights/best.pt formatonnx imgsz640导出后的ONNX文件可以在CPU上用ONNXRuntime跑摆脱对PyTorch的依赖。如果你要接边缘设备这个格式后面还能再转成TensorRT等设备专用格式。实际部署时注意一个隐藏因素导出时的imgsz必须和训练时一致否则部分ONNX推理后端会因输入尺寸不匹配而报错。用ONNX做一次批量推理测试pip install onnxruntime然后用Python写个极简推理循环拿50张没参与训练过的真实场景截图测一遍统计检出率和误检率这一步的结果比任何验证集指标都更有说服力。6. 数据补强的习惯给1876张做成持续演进的数据管线想靠1876张一次到位不太现实。鼠标检测这类任务数据分布极其依赖场地——深色木桌、白色办公桌、金属桌面对鼠标的外观影响差异很大。部署场景如果不在训练数据覆盖范围内模型精度打折是必然的。做法上线后顺手把误检和漏检截图存下来每周做一次人工筛选挑可靠的样本回灌训练集。我给这个流程起名叫“三周回灌法”第一周收集部署环境的真实图像第二周用当前模型批量预测并人工确认伪标签第三周拿这批确认过的样本和原始训练集混合增量训练一轮。这样反复几轮后模型对真实场景的适应能力会越来越稳训练集本身的规模也不再是瓶颈因为数据分布比你手里的总数重要得多。训练时用resumeTrue加上增量数据比值要控制在原始数据量的20%以内——回灌太多模型会突然转向新分布并遗忘旧分布旧场景的精度反而掉下去。回灌之后盯验证集mAP50下降超过2个点就说明新数据比例过大了下一轮减半再试。没有哪份数据集是完美的鼠标检测尤其如此。我的习惯从来都是先把格式搞清楚、把训练链路跑通、把预期定在“能落地”而不是“刷高分”然后让数据在日常使用中自己长出来。这条路走通了对任何小目标检测任务都通用。希望帮到你。本文还有配套的精品资源点击获取