Meet YOLO26: next-gen vision AI.

Link to this section如何将 COCO 标注转换为 YOLO 格式#

训练 Ultralytics YOLO 模型需要 YOLO 格式的标注,但许多流行的 标注 工具导出的是 COCO JSON 格式。本指南将向你展示如何将 COCO 标注转换为 YOLO 格式,并开始训练 目标检测实例分割姿态估计 模型。

想要跳过转换步骤吗?

如需直接使用 COCO JSON 进行训练而无需生成 .txt 文件,请参阅 Train YOLO on COCO JSON Without Conversion

Link to this section为什么要从 COCO 转换为 YOLO?#

COCO JSON 格式将所有标注存储在单个文件中,而 YOLO 则为每张图像使用一个带有归一化坐标的文本文件。进行转换的原因如下:

  • YOLO 模型需要 .txt 标签文件,每张图像对应一个文件,包含归一化坐标格式的 class x_center y_center width height
  • COCO JSON 使用像素坐标,格式为 [x_min, y_min, width, height],并且所有图像共用一个 JSON 文件。
  • 类别 ID 不同 — COCO 使用任意的 category_id 值,而 YOLO 要求使用从零开始的类别 ID。
功能COCO JSONYOLO TXT
结构所有图像共用一个 JSON 文件每张图像一个 .txt 文件
BBox 格式[x_min, y_min, width, height](像素)class x_center y_center width height(归一化,0-1)
类别 IDcategory_id(可以是任意数字)从零开始的索引(从 0 开始)
分割segmentation 字段中的多边形数组类别 ID 后紧跟多边形坐标
关键点[x, y, visibility, ...](像素)[x, y, visibility, ...](归一化)

Link to this section快速入门#

转换 COCO 标注并开始训练的最快方法:

from ultralytics.data.converter import convert_coco

convert_coco(
    labels_dir="my_dataset/annotations/",  # directory containing your JSON files
    save_dir="my_dataset/converted/",  # where to save converted labels
    cls91to80=False,  # set False for custom datasets (see warning below)
)

转换完成后,组织目录结构创建 dataset.yaml开始训练。请查看下方的完整 分步指南

自定义数据集:始终使用 `cls91to80=False`

默认的 cls91to80=True 仅适用于具有 80 个对象类别的标准 COCO 数据集,它将 91 个不连续的类别 ID 映射到 80 个连续的类别 ID。对于任何自定义数据集,你 必须 设置 cls91to80=False,否则你的类别 ID 将被静默错误地映射,导致模型学习到错误的类别。

Link to this section分步转换指南#

Link to this section准备你的 COCO 数据集#

从标注工具导出的典型 COCO 格式数据集具有以下结构:

my_dataset/
├── images/
│   ├── train/
│   │   ├── img_001.jpg
│   │   ├── img_002.jpg
│   │   └── ...
│   └── val/
│       ├── img_100.jpg
│       └── ...
└── annotations/
    ├── instances_train.json
    └── instances_val.json

每个 JSON 文件均遵循 COCO 数据格式 规范,具有三个必需字段 — imagesannotationscategories

{
    "images": [{ "id": 1, "file_name": "img_001.jpg", "width": 640, "height": 480 }],
    "annotations": [
        {
            "id": 1,
            "image_id": 1,
            "category_id": 1,
            "bbox": [100, 50, 200, 150],
            "area": 30000,
            "iscrowd": 0
        }
    ],
    "categories": [
        { "id": 1, "name": "helmet" },
        { "id": 2, "name": "vest" }
    ]
}

Link to this section转换标注#

使用 convert_coco() 函数将你的 COCO JSON 标注转换为 YOLO .txt 格式:

将 COCO 转换为 YOLO 格式
from ultralytics.data.converter import convert_coco

convert_coco(
    labels_dir="my_dataset/annotations/",
    save_dir="my_dataset/converted/",
    cls91to80=False,
)

convert_coco() 会为每个已标注的图像生成一个 .txt 文件,存入以对应 JSON 文件命名的 labels/ 子目录中,并移除 instances_ 前缀(例如 instances_train.json 会生成 labels/train/)。没有标注的图像会被跳过,且不会生成对应的标签文件,因此 labels/ 目录结构可能无法与所有图像完全对应:

my_dataset/converted/
└── labels/
    ├── train/   # from instances_train.json
    │   ├── img_001.txt
    │   └── ...
    └── val/     # from instances_val.json
        └── ...
重新运行会创建一个新的输出文件夹

convert_coco() 绝不会覆盖已有的 save_dir:如果 my_dataset/converted/ 已经存在,再次运行时会将文件写入 my_dataset/converted-2/。请在重新运行前删除之前的输出(或更改 save_dir),否则后续步骤将会读取到旧的标签。

Link to this section组织目录结构#

转换后,标签文件需要放置在图像文件旁边。YOLO 要求 labels/ 目录与 images/ 目录镜像对应:

import shutil
from pathlib import Path

converted_dir = Path("my_dataset/converted/labels")
dataset_dir = Path("my_dataset")

# convert_coco names each subdirectory after its JSON file (minus the "instances_" prefix),
# so iterate the actual subdirectories instead of assuming "train"/"val".
for src in converted_dir.iterdir():
    if not src.is_dir():
        continue
    dst = dataset_dir / "labels" / src.name
    dst.mkdir(parents=True, exist_ok=True)
    for f in src.glob("*.txt"):
        shutil.move(str(f), str(dst / f.name))

你的最终 数据集结构 应该如下所示:

my_dataset/
├── images/
│   ├── train/
│   │   ├── img_001.jpg
│   │   └── ...
│   └── val/
│       └── ...
├── labels/
│   ├── train/
│   │   ├── img_001.txt
│   │   └── ...
│   └── val/
│       └── ...
└── dataset.yaml

Link to this section创建 dataset.yaml#

创建一个 dataset.yaml 配置文件,将你的 COCO 类别映射到 YOLO 类名。此文件告知 YOLO 数据所在位置以及要检测的类别:

import json
from pathlib import Path

import yaml

# Read categories from your COCO JSON
with open("my_dataset/annotations/instances_train.json") as f:
    coco = json.load(f)

# Build class names matching convert_coco output (category_id - 1)
categories = sorted(coco["categories"], key=lambda x: x["id"])
names = {cat["id"] - 1: cat["name"] for cat in categories}
# NOTE: convert_coco maps class IDs as category_id - 1, so category_id must
# start from 1. If your categories start from 0, add 1 to each ID first.

# Create dataset.yaml
dataset = {
    "path": str(Path("my_dataset").resolve()),
    "train": "images/train",
    "val": "images/val",
    "names": names,
}

with open("my_dataset/dataset.yaml", "w") as f:
    yaml.dump(dataset, f, default_flow_style=False)

生成的 YAML 文件:

path: /absolute/path/to/my_dataset
train: images/train
val: images/val
names:
    0: helmet
    1: vest

有关数据集 YAML 格式的更多详细信息,请参阅 数据集配置指南

Link to this section训练你的 YOLO 模型#

准备好转换后的数据集后,训练 YOLO 模型:

在转换后的 COCO 数据上进行训练
from ultralytics import YOLO

model = YOLO("yolo26n.pt")  # load a pretrained model
results = model.train(data="my_dataset/dataset.yaml", epochs=100, imgsz=640)

有关训练技巧和最佳实践,请参阅 模型训练指南

Link to this section验证你的转换#

训练前,抽查几个标签文件以确认类别 ID 和坐标是否正确:

from pathlib import Path

label_file = Path("my_dataset/labels/train/img_001.txt")
for line in label_file.read_text().strip().splitlines():
    parts = line.split()
    cls_id = int(parts[0])
    coords = [float(v) for v in parts[1:5]]
    assert cls_id >= 0, f"Negative class ID {cls_id} — category_id in your JSON may start from 0"
    assert all(0 <= v <= 1 for v in coords), f"Coordinates out of [0, 1] range: {coords}"
提示

If you see negative class IDs, your COCO JSON likely uses category_id starting from 0. Add 1 to all category_id values in your JSON before running convert_coco(), since it maps class IDs as category_id - 1.

Link to this section常见问题排查#

Link to this section转换后类别 ID 错误#

如果你的模型可以训练但检测到的对象类别错误,你很可能在自定义数据集上使用了(默认的)cls91to80=True。这会通过 COCO 91 到 80 的查找表映射你的 category_id 值,该表仅适用于标准 COCO 数据集

解决方法:对于自定义数据集,始终使用 cls91to80=False

Link to this section训练期间未找到标签#

如果训练时显示 WARNING: No labels found0 images, N backgrounds,说明你的标签文件不在预期的目录下。convert_coco() 将标签保存到独立的输出目录(例如 save_dir/labels/train/),但 YOLO 要求 labels/ 目录与数据集中的 images/ 目录并列。

解决方法:移动标签文件以匹配预期的 目录结构。确保 labels/train/images/train/ 的兄弟目录。

Link to this section转换期间出现 KeyError#

If you get KeyError: 'bbox' or similar errors when running convert_coco(), your labels_dir likely contains non-instance JSON files (e.g., captions_train2017.json) that have a different annotation structure.

解决方法:仅将实例标注 JSON 文件(例如 instances_train2017.json)放入 labels_dir

Link to this section转换后标签文件为空#

如果转换完成但 .txt 文件为空或缺失,可能是所有标注都具有 iscrowd: 1(在使用 SAM 生成的掩码时很常见),或者 边界框 的宽度或高度为零。

Solution: Inspect your JSON annotations for iscrowd values. If using SAM masks, preprocess the JSON to set iscrowd: 0.

Link to this section转换后的标签中类别 ID 不连续#

如果标签文件中的类别 ID 不连续(例如 0、4、9 而不是 0、1、2),则说明你的标注工具使用了不连续的 category_id 值。

Solution: Verify the class IDs in your .txt files match the names dictionary in dataset.yaml. Remap IDs to contiguous values if needed.

有关完整的 API 详细信息和参数说明,请参阅 convert_coco API 参考

Link to this section常见问题解答#

Link to this section如何将 COCO JSON 标注转换为 YOLO 格式?#

使用 Ultralytics 的 convert_coco() 函数将 COCO JSON 标注转换为 YOLO .txt 格式。对于自定义数据集,请设置 cls91to80=False

from ultralytics.data.converter import convert_coco

convert_coco(labels_dir="path/to/annotations/", save_dir="output/", cls91to80=False)

转换后,重新组织你的标签文件,使 labels/images/ 目录镜像对应,然后创建一个 dataset.yaml 文件。请参阅 分步指南 以了解完整的工作流程。

Link to this section为什么 COCO 转换后 YOLO 训练显示 "No labels found"?#

这是因为 convert_coco() 将标签保存到 save_dir/labels/ 内的子目录中(例如 save_dir/labels/train/),而不是直接保存在数据集的 labels/train/ 中(与 images/train/ 平行)。YOLO 希望标签与图像位置平行——例如,images/train/img.jpg 需要对应的 labels/train/img.txt。请移动你的转换后的标签以匹配此结构。请参阅 修复目录结构

Link to this sectionWhat does cls91to80 do in convert_coco()?#

The cls91to80 parameter controls how COCO category_id values are mapped to YOLO class IDs. When True (default), it applies the coco91_to_coco80_class() lookup table designed for the standard COCO dataset, which has 80 classes with non-contiguous IDs (1-90). For custom datasets, always set cls91to80=False — this simply subtracts 1 from each category_id to create zero-indexed class IDs.

Link to this section我可以直接在 COCO JSON 上训练 YOLO 而无需转换吗?#

在当前的 YOLO 训练流程中不可以——标注必须采用 YOLO .txt 格式,且每张图像对应一个文件。请先使用 convert_coco() 转换你的 COCO JSON,然后按照此 指南 进行组织和训练。有关支持格式的更多信息,请参阅 数据集格式

Link to this section我可以将 COCO 分割标注转换为 YOLO 格式吗?#

Yes, use use_segments=True when calling convert_coco() to include polygon segmentation masks in the converted YOLO labels. This produces label files compatible with YOLO segmentation models:

from ultralytics.data.converter import convert_coco

convert_coco(labels_dir="annotations/", save_dir="output/", use_segments=True, cls91to80=False)

Link to this section如何将 COCO 关键点标注转换为 YOLO 格式?#

使用 use_keypoints=True 转换用于 姿态估计 训练的 COCO 关键点标注:

from ultralytics.data.converter import convert_coco

convert_coco(labels_dir="annotations/", save_dir="output/", use_keypoints=True, cls91to80=False)

请注意,如果同时设置 use_segmentsuse_keypointsTrue,则只有关键点会被写入标签文件 —— 分割部分将被静默忽略。

评论