MMDetection3.0自定义数据集训练全流程实战指南
发布时间:2026/9/16 19:19:49来源:尧图网络
说实话很多人在接触 MMDetection3.0 时第一反应是去翻文档、配环境、跑官方 demo结果折腾两三天模型是跑起来了一换到自己的数据就各种报错。我见过太多人卡在这条线上不是框架难用而是中间缺了一段如何把一堆散乱的图片变成框架能吃的数据集的经验。这篇内容就是把我自己从零搭建自定义数据集、跑通完整训练流程的过程捋一遍包括数据格式怎么转、配置怎么改、训练时哪些报错是高频的、哪些参数值得调希望能让你少走几趟弯路。这套流程适配的目标人群很明确有基础 Python 语法概念了解目标检测大概是怎么回事但还没有系统用过 MMDetection3.0 的开发者。我会尽量把每一步的为什么也讲清楚而不是只丢给你一段能跑的代码。1. 训练目标检测模型的完整链路先看清全局地图1.1 从图片文件夹到 mAP 指标中间到底发生了什么很多教程上来就让你 pip install 一堆东西然后跑一个训练命令看到 loss 在降就宣布成功。但这样跳过太多环节了导致后面稍微换个数据集、换个模型就完全抓瞎。一次完整的目标检测训练链条大概是这样准备训练图片整理成规范目录给图片画框标注导出成标注文件比如 XML、JSON把标注转换成 MMDetection 能读的 COCO 格式安装 MMDetection3.0 及对应版本依赖根据你的任务修改模型配置文件启动训练监控 loss、lr、显存等指标评估模型效果导出推理结果根据失败案例迭代数据和参数这中间任何一个环节出错训练都跑不起来而很多人恰恰卡在最容易被忽略的第一环数据。1.2 MMDetection3.0 相比 2.x 到底改了什么MMDetection3.0 是一次大版本重构并不是在 2.x 基础上加几个模型那么简单。它废弃了老版的Cascade R-CNN那套以config里写死整个模型结构的方式改用了一种更模块化的注册机制。所有组件都通过MODELS.register_module()注册然后在配置里像搭积木一样组合。更直白的变化是3.0 的配置写法更工程化。以前你改个 backbone 要理解它内部很多隐藏的传递逻辑现在则必须显式写清楚每个组件怎么连接。这对初学者来说前期学习曲线反而更陡峭但一旦理解了它的设计思路之后写复杂模型会轻松很多。还有一点值得注意3.0 把许多原本散落在各文件里的工具函数统一收进了mmengine这意味着训练流程的底层逻辑也被重构了。你会遇到一些跟老版本完全不同的工作方式比如 runner 机制、自定义 hook 挂载方式。1.3 为什么说数据格式是第一个分水岭MMDetection3.0 支持两种标注格式COCO 格式和 VOC 格式。更准确地说它通过dataset_type来区分然后在内部把标注信息统一转成一种中间结构再送入模型。实际项目里我强烈建议直接转 COCO 格式不用犹豫。原因有三第一COCO 格式的社区支持最完善无论可视化脚本还是后续做数据增强都有现成工具第二MMDetection 内部对于 COCO 结构处理得更流畅出问题也更容易排查第三COCO 是跨框架通用的今天你用 MMDetection明天要迁移到 Detectron2 或者自己写 Dataset成本最低。所以接下来最核心的准备工作就是把自己的标注数据变成 COCO JSON。2. 数据准备把原始图片和标注改造成 COCO 格式2.1 数据集目录如何组织动手写转换脚本之前先把目录结构定好。我看过不少人的数据集目录杂乱图片散落各处最后训练时 index 对不上排查半天才发现是路径错了。一个清晰且通用的目录结构长这样data/ ├── custom_dataset/ │ ├── annotations/ │ │ ├── train.json │ │ └── val.json │ ├── images/ │ │ ├── train/ │ │ │ ├── 000001.jpg │ │ │ └── ... │ │ └── val/ │ │ └── ... │ └── (可选) test/简单说就是 images 和 annotations 分开。MMDetection 的 CocoDataset 在读取时会拿data_root拼接ann_file和data_prefix目录不对训练直接报错找不到图片。等到报错再去改目录不如一开始就按规范来。2.2 COCO JSON 标注文件的字段拆解COCO 格式看起来是一堆嵌套字典但核心就四个字段images、annotations、categories以及可有可无的info。images一个列表每个元素是一张图的信息至少要包含id、file_name、width、height。annotations一个列表每个元素是一个检测框标注核心字段是id、image_id、category_id、bbox、area、iscrowd。categories一个列表每个元素包含id和name注意这里的id要跟annotations里的category_id对应。有个特别容易搞错的地方COCO 格式里bbox是[x, y, width, height]不是[x1, y1, x2, y2]坐标是左上角加宽高。而很多标注工具导出的是[x_min, y_min, x_max, y_max]。如果你拿到的是后者转的时候必须算一下width x_max - x_minheight y_max - y_min。我见过不下十个人因为没有做这个换算训练出来的框全往右下角偏移还以为是模型问题。实际上就是数据格式错了。2.3 手写一个轻量标注转换脚本假设你用的是 Labelme 标注它默认导出的 JSON 里包含shapes列表每个 shape 是[{label: cat, points: [[x1,y1],[x2,y2]]}]且points记录的是多边形顶点需要先算出最小外接矩形。这里给出一个经过我实际测试的转换脚本能把 Labelme 格式转成 COCO 格式import json import os from glob import glob from PIL import Image def convert_labelme_to_coco(img_dir, json_dir, output_path, categories): cat_name_to_id {name: i 1 for i, name in enumerate(categories)} images [] annotations [] annotation_id 1 # 统一按文件名排序保证多次执行结果一致 label_files sorted(glob(os.path.join(json_dir, *.json))) for img_id, label_file in enumerate(label_files, start1): with open(label_file, r, encodingutf-8) as f: label_data json.load(f) img_path os.path.join(img_dir, label_data[imagePath]) # 如果 imagePath 不存在尝试用文件名去匹配 if not os.path.exists(img_path): base_name os.path.splitext(os.path.basename(label_data[imagePath]))[0] candidates glob(os.path.join(img_dir, base_name .*)) if candidates: img_path candidates[0] else: print(fwarning: image not found for {label_file}) continue with Image.open(img_path) as img: width, height img.size images.append({ id: img_id, file_name: os.path.basename(img_path), width: width, height: height, }) for shape in label_data[shapes]: label shape[label] if label not in cat_name_to_id: continue points shape[points] xs [p[0] for p in points] ys [p[1] for p in points] x_min, x_max min(xs), max(xs) y_min, y_max min(ys), max(ys) w x_max - x_min h y_max - y_min # 过滤掉异常框 if w 0 or h 0: print(fwarning: invalid bbox in {label_file}, skip) continue annotations.append({ id: annotation_id, image_id: img_id, category_id: cat_name_to_id[label], bbox: [x_min, y_min, w, h], area: w * h, iscrowd: 0, }) annotation_id 1 out_dict { images: images, annotations: annotations, categories: [ {id: i 1, name: name} for i, name in enumerate(categories) ], } with open(output_path, w, encodingutf-8) as f: json.dump(out_dict, f, ensure_asciiFalse, indent2) print(fsaved {len(images)} images, {len(annotations)} annotations to {output_path}) # 用法示例 if __name__ __main__: convert_labelme_to_coco( img_dirdata/custom_dataset/images/train, json_dirdata/custom_dataset/labelmes/train, output_pathdata/custom_dataset/annotations/train.json, categories[cat, dog, bird] )这段脚本的亮点在于处理了三个常见问题一是imagePath字段可能指向相对路径导致找不到图片二是 Labelme 画框时可能画出 w 或 h 为 0 的退化框三是标注类别不在预设列表里的情况。这三个问题如果不提前兜住后面训练时会在不知名的地方爆出奇怪异常。2.4 转换之后必须做的一步真正看一眼标注转换完千万没着急开训练。我强烈建议你写个几行的可视化脚本把标注框画到原图上随机抽几十张看看。很多人觉得标注文件生成了就万事大吉实际上我在这一步里抓到过的奇奇怪怪问题比训练阶段还要多坐标漂浮到图片外、类别错位、图片文件名对不上、宽高被自动旋转了等。一个最简单的检查方法import json import cv2 import os import random with open(data/custom_dataset/annotations/train.json, r) as f: data json.load(f) cat_id_to_name {c[id]: c[name] for c in data[categories]} samples random.sample(data[images], 20) for img_info in samples: img_path os.path.join(data/custom_dataset/images/train, img_info[file_name]) img cv2.imread(img_path) if img is None: print(ferror: cannot read {img_path}) continue for ann in data[annotations]: if ann[image_id] ! img_info[id]: continue x, y, w, h [int(v) for v in ann[bbox]] cv2.rectangle(img, (x, y), (x w, y h), (0, 255, 0), 2) cv2.putText(img, cat_id_to_name[ann[category_id]], (x, y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1) cv2.imshow(check, img) cv2.waitKey(0)这里有个实战经验如果图片数量大不要逐张看按类别的分布去抽样看更有意义。因为个别类别的标注错误可能隐藏很深全局随机抽可能一直抽不到。3. 环境安装与验证版本匹配的细节决定成败3.1 用 mim 而不是直接 pip installMMDetection3.0 的依赖是个无底洞直接pip install mmdet经常会遇到依赖版本冲突。官方推荐的安装方式是先装 OpenMMLab 的包管理器 mim让 mim 帮你处理环境依赖pip install -U openmim mim install mmengine mim install mmcv mim install mmdet但这里有个关键点必须强调mim 在安装 mmcv 时会去下载与你的 CUDA 和 PyTorch 版本匹配的预编译包。如果你机器上有多个 conda 环境务必先激活目标环境再执行安装命令否则装错环境的概率极大。有一次我在服务器上排查了一个下午发现训练时总是在某个操作上卡死最后定位到原因是 mmcv 装进了 base 环境而当前 conda 环境里 import 到的 mmcv 是旧版。这种低级错误最浪费生命。3.2 PyTorch、CUDA、mmcv 三者的匹配关系这是个经典大坑。mmcv 分两个版本mmcv和mmcv-lite。MMDetection3.0 要求使用完整版。完整版需要用mim install mmcv来安装它会检测你当前的 PyTorch 和 CUDA 版本然后选择合适的预编译 wheel。但如果你用的 PyTorch 是 conda 安装的 CPU 版或者 CUDA 版本比较新而 mmcv 还没跟上mim 可能装到一半报找不到匹配的编译包。我自己比较稳妥的做法是先创建 conda 环境并安装指定版本的 PyTorch比如torch1.13.1cu117然后mim install mmcv2.1.0最后pip install mmdet3.2.0三个版本锁定好跑起来基本不会出问题。如果你想省事用最新版建议先查一下 mmdet 官方 README 里的版本对照表不要盲目追求新。3.3 跑一个官方 demo 作为环境验收环境装完直接训练是挺冒险的因为训练报错的信息量太大容易混淆环境问题还是代码问题。我建议先用官方预训练权重跑一次推理验证环境基础功能正常。mim download mmdet --config faster-rcnn_r50_fpn_1x_coco --dest ./checkpoints python demo/image_demo.py demo/demo.jpg faster-rcnn_r50_fpn_1x_coco.py checkpoints/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth --device cuda:0如果这一步能顺利输出带框图片说明 mmcv、mmdet、PyTorch、CUDA 四者之间基本打通了。如果这一步就报错先不要碰自己的数据集优先把环境问题搞定。4. 配置文件修改像改参数一样改模型结构4.1 MMDetection3.0 的配置继承机制MMDetection 的配置文件不是一份孤立文件而是通过_base_字段继承多个基础配置。你可能最终只需要写一个 30 行的子配置它会从基础配置里继承模型结构、训练策略、数据管线等。初学者最容易犯的错是拿到一份配置文件从头到尾全部改一遍改到最后自己都不知道改了哪里。正确姿势是先用configs目录下的现成配置做模板找到你想用的模型配置然后新建一个只包含差异项的子配置。比如我想用 Faster R-CNN 训练自己的数据集可以基于configs/faster_rcnn/faster-rcnn_r50_fpn_1x_coco.py新建/configs/my_config/rtmdet_tiny_custom.py。4.2 数据配置到底要改哪几项关键配置片段如下_base_ ../faster_rcnn/faster-rcnn_r50_fpn_1x_coco.py data_root data/custom_dataset/ metainfo { classes: (cat, dog, bird), palette: [(220, 20, 60), (119, 11, 32), (0, 0, 142)] } train_dataloader dict( batch_size4, datasetdict( data_rootdata_root, metainfometainfo, ann_fileannotations/train.json, data_prefixdict(imgimages/train/) ) ) val_dataloader dict( datasetdict( data_rootdata_root, metainfometainfo, ann_fileannotations/val.json, data_prefixdict(imgimages/val/) ) ) val_evaluator dict(ann_filedata_root annotations/val.json)注意看metainfo里定义了类别名称顺序就是模型输出的顺序。这个顺序必须跟训练数据里categories的id对应上。比如你标注文件里category_id1对应cat那么在metainfo的classes元组的第一个位置必须是cat。对不上的话训练不报错但 mAP 会全面崩溃因为模型学到了类别 A评估器却拿类别 B去对。data_prefix里img字段用的是相对于data_root的路径ann_file同理。这里的坑是很隐蔽的如果之前目录里images/train写成了images/train/某些版本下会拼接出双斜杠路径不同系统下表现还不一样。4.3 采样与工人进程别让数据加载拖垮训练数据加载是很多人的盲区。训练慢的第一元凶往往不是 GPU 算力不够而是数据加载速度跟不上 GPU。配置里有几个关键参数train_dataloader dict( batch_size4, num_workers4, samplerdict(typeDefaultSampler, shuffleTrue), datasetdict(...) )batch_size需要根据你的显存来调num_workers是每个 GPU 上用于数据加载的子进程数shuffle在训练时必须为 True否则模型学不到泛化特征当你的标注图片分辨率较大比如 4000x3000转成模型输入 1333x800 时需要大量 CPU 算力做缩放和增强。如果num_workers设置太小GPU 经常会空转等待数据。我的经验是num_workers 4 * 显卡数是一个比较合理的起点如果 CPU 核心足够可以往上加。4.4 模型输出类别数怎么改MMDetection3.0 的模型结构配置不再像老版本那样需要你手动算通道数而是通过num_classes直接注入。以 Faster R-CNN 为例你需要把roi_head里的bbox_head的num_classes改成自己的类别数。如果你是拿 COCO 预训练权重做微调还要注意一个机制load_from加载权重时如果类别数不同它会把分类头参数忽略掉并在日志里输出一条 warning。很多人看到 warning 以为出了 bug其实这是正常现象。如果你希望冻结 backbone 的前几层不参与训练也可以设置frozen_stages。5. 启动训练从启动命令到日志解读5.1 训练命令的两种启动姿势MMDetection3.0 提供了两个入口一个是传统train.py脚本另一个是更简洁的mim trainpython tools/train.py configs/my_config/rtmdet_tiny_custom.py --work-dir ./work_dirs/rtmdet_tiny_custom或者用 mim 命令mim train mmdet configs/my_config/rtmdet_tiny_custom.py --work-dir ./work_dirs/rtmdet_tiny_custom两种方式差别不大建议直接用python tools/train.py。--work-dir指定了日志和权重的输出目录这是一个值得单独为每个实验创建的路径否则不同实验的日志混在一起后面分析会非常痛苦。如果你的机器有多个 GPU可以用CUDA_VISIBLE_DEVICES0,1,2,3 python tools/train.py ...来指定用哪些卡。注意这里的编号跟nvidia-smi里的编号通常一致。5.2 训练日志里哪些指标是关键MMDetection3.0 通过 mmengine 输出训练日志默认每隔一定迭代次数打印一行。主要关注的字段有loss总损失值loss_cls、loss_bbox分类和回归损失lr当前学习率data_time数据加载耗时time单次迭代总耗时这里有一个容易误导新手的现象训练第一个 epoch 时 loss 可能不降反升这是正常的因为学习率从一个较小的值 warmup 到比较大的值损失波动是预期行为。但如果连续两三个 epoch 后 loss 还没有明显下降就得检查学习率是不是太大、数据预处理是否有 bug。data_time如果长期显著高于time的一半说明数据加载是瓶颈了。这时候优先调整num_workers和persistent_workers配置而不是盲目换更好的 GPU。5.3 高频报错与排查链路我把自定义数据集训练时出现频率最高的几个报错整理一下都带排查思路。第一个是KeyError: gt_labels。这个报错的根因通常是配置文件里的test_dataloader或val_dataloader还在用原来 COCO 的类别设置导致数据集读取时拿不到类别标签。排查链路很简单打开你的数据配置文件看metainfo是否同时写入train_dataloader、val_dataloader、test_dataloader三个部分。只改 train 不管 val 是新手常犯的错。第二个是RuntimeError: CUDA out of memory。显存溢出时不要第一反应去换小的 backbone先看当前的batch_size。把batch_size从 8 降到 4还溢出就降到 2同时注意输入图片尺寸img_scale越大显存占用越高。还有一个技巧optimizer里把typeSGD换成typeAdamW会略微增加显存但收敛更快取舍要看你的业务场景。第三个是训练中途报FileNotFoundError。这个往往不是训练代码的问题而是你的数据加载管线里写死了某个图片路径但实际图片不存在。建议转换标注时就把路径拼接逻辑梳理清楚同时在启动训练前先单独跑一遍数据加载的测试脚本确认所有图片路径都真实存在。第四个是class imbalance导致的 loss 变成 NaN。如果你的数据里某个类别样本极少幸存的让我冷静下来想想——其实就是学习率太大或者梯度爆炸。可以先调低学习率从 0.001 降到 0.0001 试试。如果还不行检查标注中有没有area0的退化框或者标签 id 是否从 0 开始。COCO 数据集的 category_id 默认从 1 开始如果你从 0 开始模型训练时会认为存在一个背景类作为第 0 类导致维度错位。5.4 训练中断之后如何接着跑训练可能因为各种原因中断服务器重启、显存不够被 kill、内存溢出。这时候重新从 epoch 0 开始跑会浪费大量时间。MMDetection3.0 提供了断点续训能力只要你在训练命令中指定--resumepython tools/train.py configs/my_config/rtmdet_tiny_custom.py --work-dir ./work_dirs/rtmdet_tiny_custom --resume它会自动读取work_dirs下最新的权重文件从最近的 epoch 继续训练。有一个细节要注意--resume完全依赖 checkpoint 文件如果你的--work-dir下同时存在多个.pth文件它会自动选择最新一个。如果因为某些原因续训后 loss 波动异常可以删掉最近的 checkpoint退到上一个 epoch 的权重重新开始。6. 模训完之后的评估与推理验证模型真的学到了东西6.1 测试指令与指标含义训练结束后你手上会有epoch_10.pth、epoch_20.pth这样的权重文件。评估模型在验证集上的效果用下面的命令python tools/test.py configs/my_config/rtmdet_tiny_custom.py work_dirs/rtmdet_tiny_custom/epoch_20.pth --work-dir work_dirs/rtmdet_tiny_custom/val_results输出会包含 COCO 风格的评估指标这里面最常看的几个APIoU0.50:0.95综合指标最严格也是论文里最常报的AP50IoU0.50阈值宽松单看位置是否预测到AP75IoU0.75更精细的定位能力AR平均召回率反映模型找到目标的能力对于自定义数据集如果你的标注框本身比较小AP 偏低是正常的因为小目标在 IoU 计算时更敏感一点儿偏差就掉到阈值以下。6.2 用训练的模型跑自己的图片测试完成后用demo/image_demo.py做推理python demo/image_demo.py demo/custom_test.jpg configs/my_config/rtmdet_tiny_custom.py work_dirs/rtmdet_tiny_custom/epoch_20.pth --device cuda:0如果你不想每次都在命令行传一堆参数可以写一个简短的 Python 推理脚本。这里分享一个我常用的模板from mmdet.apis import init_detector, inference_detector import mmcv config_file configs/my_config/rtmdet_tiny_custom.py checkpoint_file work_dirs/rtmdet_tiny_custom/epoch_20.pth model init_detector(config_file, checkpoint_file, devicecuda:0) result inference_detector(model, demo/custom_test.jpg) model.show_result(demo/custom_test.jpg, result, out_fileoutput/res.jpg)注意init_detector的第二个参数也可以传一个权重文件路径。如果你最终要部署到服务端可以用model.to_onnx()或者直接用 mmdeploy 转成 TensorRT但这已经是后话了。6.3 针对失败样本做数据迭代而非疯狂调参模型训完之后你的工作还没结束甚至可以说真正的工作才刚刚开始。拿验证集里预测失败的样本做一个错误分析。把模型漏检的图片、误检的图片、框偏差大的图片分别收集起来问自己几个问题漏检是因为目标太小那么你需要考虑加入多尺度训练或者使用更大的输入尺寸误检是因为背景跟目标太像可能需要增加难负样本挖掘或者收集更多背景图作为负样本框偏差大是因为边界标注本身不够精细那要回头修正标注质量我个人体会在标注数据质量控制上的投入回报率永远高于调参。你花三个小时优化学习率策略可能 AP 提升不到 1 个点但花三个小时把数据里明显的错误标注修掉AP 涨三五个点都不稀奇。所以每轮实验结束后我都会花一部分时间抽看标注质量而不是只盯训练日志。6.4 多类别与小数据集的两个实战技巧如果你的类别数量比较多比如二三十个类类别之间的样本数量往往不均衡。这时候有个好用的配置项是class_weight可以在损失函数里为少数类别增加权重。但这个值需要基于你的数据统计来设置不要想当然给一个很大的数否则模型会过分关注少数类导致多数类掉点。如果你的数据量很小比如每个类别只有几十张图建议直接用 COCO 预训练权重做迁移学习同时把 backbone 的frozen_stages设大一点先只训练检测头等模型稳定了再解冻 backbone 微调。我甚至在只有两百张图的项目里跑出过能用的模型核心就是不要从头训一定用预训练。7. 顺手补充几个容易忽略但很实用的细节7.1 随机种子与可复现性训练开始前设置randomness dict(seed0, deterministicFalse)在配置里。deterministicFalse的语义很微妙它允许某些算子在非确定性模式下运行速度稍快但会牺牲一点点可复现性。如果你做对比实验需要严格可复现把它设为 True如果只是跑业务模型保持 False 即可。7.2 学习率与 batch size 的换算逻辑MMDetection 默认的配置文件里batch size 通常对应 8 卡配置。如果你只有单卡且 batch size 是 2那学习率不能直接沿用默认值。经验公式就是线性缩放new_lr base_lr * new_bs / base_bs。比如默认lr0.01对应bs16你单卡bs4那学习率大致取0.0025。这个经验公式虽然没有理论上的严格证明但在绝大多数目标检测任务里都适用。7.3 类别顺序变更后必须重新评估如果你中途修改了metainfo里classes的顺序但加载的还是旧权重模型的分类头输出维度不变但其实每个类别对应的通道已经错乱了。这种情况下模型不会报错但 mAP 会惨不忍睹。所以改类别顺序后我建议从头开始训练或者只加载 backbone 权重而不加载整个 checkpoint。7.4 多卡训练时 transformers 相关参数的坑如果你用 DDP 多卡训练配置里train_dataloader的batch_size是每张卡的批大小而不是全局批大小。也就是说4 卡每卡 batch_size4全局 batch_size16。学习率设置要以全局 batch size 为基准计算否则等效学习率会跟你预期的差 4 倍导致收敛不稳定。我在一次 4 卡训练中发现 loss 震荡得厉害后来排查到原因就是拿着单卡实验的学习率直接跑多卡学习率被放大了 4 倍。调完之后 loss 瞬间稳定下来。7.5 日志可视化tools/train.py默认会输出到终端同时保存到work_dirs下的 tf_logs 目录。你可以用 TensorBoard 查看tensorboard --logdir work_dirs/rtmdet_tiny_custom如果比较习惯用曲线展示也可以在配置里挂接 wandb。配置里加入visualizer dict( typeDetLocalVisualizer, vis_backends[dict(typeTensorboardVisBackend), dict(typeWandbVisBackend)] )不过 wandb 会把数据传云端注意你的数据是否允许外传。内网环境或者保密数据建议只用 TensorBoard。8. 一些踩坑后的个人心得在这些天的实战里最深的一个体会是MMDetection3.0 的坑大多数不在框架本身而在工程化配套环节。数据格式没转好、环境版本没锁对、配置项层次搞混这三类问题占了所有报错的大头。如果你能从项目最开始就把数据目录和标注格式规范化后面简直一路绿灯。另一个想分享的经验是把每次实验的配置、数据版本、训练时长、指标结果记录下来。很多人训练完一个模型过了两周就忘了当时用的什么超参数、数据是怎么处理的。这个信息的价值不亚于模型权重本身。我自己现在每个实验都会在work_dirs下放一个README.md记录当次实验的背景、改动、结论后面排查问题或者写报告时效率翻倍。最后再分享一个数据处理上的小技巧如果你的标注工具有自动保存功能记得在转换标注前做一次全量校验过滤掉那些没有标注物的图片否则 COCO 格式中annotations为空可能会在训练时报错而这个报错的提示常常很隐晦。我在实际项目里就遇到过训练到一半迭代器报了个奇怪的异常查了很久才发现是有几张空标注图混进去了。模型训练这条路方法对了之后剩下的都是重复劳动和时间积累。希望这篇内容能帮你把前期的坑填平把精力留给真正有价值的调优和迭代。
网站建设高端定制企业官网