Skip to main content

Cách chuyển đổi chú thích COCO sang định dạng YOLO

Huấn luyện Ultralytics YOLO các model yêu cầu chú thích ở định dạng YOLO, nhưng nhiều công cụ chú thích phổ biến lại xuất ra định dạng COCO JSON. Hướng dẫn này chỉ bạn cách chuyển đổi chú thích COCO sang định dạng YOLO và bắt đầu huấn luyện object detection, instance segmentation, và pose estimation đã được huấn luyện kỹ.

Tại sao cần chuyển từ COCO sang YOLO?

Định dạng COCO JSON lưu trữ tất cả chú thích trong một tệp duy nhất, trong khi YOLO sử dụng một tệp văn bản cho mỗi hình ảnh với tọa độ được chuẩn hóa. Việc chuyển đổi là cần thiết vì:

  • Các model YOLO yêu cầu .txt tệp nhãn với mỗi tệp cho một hình ảnh, chứa class x_center y_center width height trong tọa độ được chuẩn hóa.
  • COCO JSON sử dụng tọa độ pixel trong [x_min, y_min, width, height] định dạng với một tệp JSON duy nhất cho tất cả hình ảnh.
  • ID lớp khác biệt — COCO sử dụng các giá trị category_id tùy ý, trong khi YOLO yêu cầu ID lớp bắt đầu từ số 0.
Tính năngCOCO JSONYOLO TXT
Cấu trúcTệp JSON đơn cho tất cả hình ảnhMột .txt tệp cho mỗi hình ảnh
Định dạng Bbox[x_min, y_min, width, height] theo pixelclass x_center y_center width height được chuẩn hóa (0-1)
ID lớpcategory_id (có thể bắt đầu từ bất kỳ số nào)Bắt đầu từ số 0 (zero-indexed)
SegmentationMảng đa giác (polygon) trong segmentation trườngTọa độ đa giác sau ID lớp
Keypoints[x, y, visibility, ...] theo pixel[x, y, visibility, ...] được chuẩn hóa

Bắt đầu nhanh

Cách nhanh nhất để chuyển đổi chú thích COCO và bắt đầu huấn luyện:

from ultralytics.data.converter import convert_coco

convert_coco(
    labels_dir="path/to/annotations/",  # directory containing your JSON files
    save_dir="path/to/output/",  # where to save converted labels
    cls91to80=False,  # IMPORTANT: set False for custom datasets
)

Sau khi chuyển đổi, tổ chức cấu trúc thư mục của bạn, tạo một tệp dataset.yaml, và bắt đầu huấn luyện. Xem hướng dẫn từng bước chi tiết bên dưới.

Datasets tùy chỉnh: luôn sử dụng `cls91to80=False`

Phương thức cls91to80=True mặc định được thiết kế chỉ cho tiêu chuẩn tập dữ liệu COCO với 80 lớp đối tượng, ánh xạ 91 ID danh mục không liên tục sang 80 ID lớp liên tục. Đối với bất kỳ dataset tùy chỉnh nào, bạn phải thiết lập cls91to80=False — nếu không, ID lớp của bạn sẽ bị ánh xạ sai một cách âm thầm và model của bạn sẽ học các lớp sai.

Hướng dẫn chuyển đổi từng bước

1. Chuẩn bị dataset COCO của bạn

Một dataset định dạng COCO điển hình được xuất từ các công cụ chú thích có cấu trúc sau:

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

Mỗi tệp JSON tuân theo đặc tả COCO data format với ba trường bắt buộc — images, annotations, và categories:

{
    "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" }
    ]
}

2. Chuyển đổi chú thích

Sử dụng lệnh convert_coco() hàm để chuyển đổi chú thích COCO JSON của bạn sang định dạng YOLO .txt :

Chuyển đổi COCO sang định dạng YOLO
from ultralytics.data.converter import convert_coco

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

3. Tổ chức cấu trúc thư mục

Sau khi chuyển đổi, các tệp nhãn cần được đặt cùng với hình ảnh của bạn. YOLO mong đợi một labels/ thư mục phản chiếu thư mục images/ :

import shutil
from pathlib import Path

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

# Move labels next to images for each split
for split in ["train", "val"]:
    src = converted_dir / split  # convert_coco strips "instances_" prefix from JSON filename
    dst = dataset_dir / "labels" / split
    dst.mkdir(parents=True, exist_ok=True)
    for f in src.glob("*.txt"):
        shutil.move(str(f), str(dst / f.name))

Cấu trúc cuối cùng của bạn cấu trúc tập dữ liệu sẽ trông như sau:

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

4. Tạo dataset.yaml

Tạo tệp dataset.yaml tệp cấu hình ánh xạ các danh mục COCO của bạn sang tên lớp YOLO. Tệp này cho YOLO biết dữ liệu của bạn nằm ở đâu và cần phát hiện những lớp nào:

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)

Tệp YAML kết quả:

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

Để biết thêm chi tiết về định dạng YAML của dataset, hãy xem hướng dẫn cấu hình dataset.

5. Huấn luyện model YOLO của bạn

Với dataset đã chuyển đổi của bạn, hãy huấn luyện model YOLO:

Huấn luyện trên dữ liệu COCO đã chuyển đổi
from ultralytics import YOLO

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

Để biết các mẹo huấn luyện và thực tiễn tốt nhất, hãy xem hướng dẫn huấn luyện model.

6. Xác minh quá trình chuyển đổi của bạn

Trước khi huấn luyện, hãy kiểm tra ngẫu nhiên một vài tệp nhãn để xác nhận ID lớp và tọa độ là chính xác:

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}"
Mẹo

Nếu bạn thấy ID lớp âm, có khả năng COCO JSON của bạn sử dụng category_id bắt đầu từ 0. Thêm 1 vào tất cả các giá trị category_id trong JSON của bạn trước khi chạy convert_coco(), vì nó ánh xạ ID lớp dưới dạng category_id - 1.

Khắc phục các vấn đề thường gặp

ID lớp sai sau khi chuyển đổi

Nếu model của bạn huấn luyện được nhưng phát hiện sai lớp đối tượng, có khả năng bạn đang sử dụng cls91to80=True (mặc định) trên một dataset tùy chỉnh. Điều này ánh xạ các giá trị category_id thông qua bảng tra cứu COCO 91-to-80, vốn chỉ đúng cho tiêu chuẩn tập dữ liệu COCO.

Giải pháp: Luôn sử dụng cls91to80=False cho dataset tùy chỉnh.

Không tìm thấy nhãn trong quá trình huấn luyện

Nếu quá trình huấn luyện hiển thị WARNING: No labels found hoặc 0 images, N backgrounds, các tệp nhãn của bạn không nằm trong thư mục mong đợi. convert_coco() lưu nhãn vào một thư mục đầu ra riêng biệt (ví dụ: save_dir/labels/train/), nhưng YOLO mong đợi labels/ song song với images/ bên trong thư mục dataset của bạn.

Giải pháp: Di chuyển các tệp nhãn để khớp với cấu trúc thư mục mong đợi. Đảm bảo labels/train/ là một phần tử đồng cấp của images/train/.

KeyError trong quá trình chuyển đổi

Nếu bạn gặp lỗi KeyError: 'bbox' hoặc các lỗi tương tự khi chạy convert_coco(), labels_dir của bạn có khả năng chứa các tệp JSON không phải dạng instance (ví dụ: captions_train2017.json) có cấu trúc chú thích khác biệt.

Giải pháp: Chỉ đặt các tệp JSON chú thích instance (ví dụ: instances_train2017.json) vào trong labels_dir.

Các tệp nhãn trống sau khi chuyển đổi

Nếu quá trình chuyển đổi hoàn tất nhưng các tệp .txt bị trống hoặc thiếu, có thể tất cả các chú thích đều có iscrowd: 1 (thường gặp với các mặt nạ do SAM tạo ra), hoặc bounding boxes có chiều rộng hoặc chiều cao bằng 0.

Giải pháp: Kiểm tra các chú thích JSON của bạn để tìm các giá trị iscrowd. Nếu sử dụng mặt nạ SAM, hãy tiền xử lý JSON để thiết lập iscrowd: 0.

Khoảng trống ID lớp trong các nhãn đã chuyển đổi

Nếu ID lớp trong các tệp nhãn không liên tục (ví dụ: 0, 4, 9 thay vì 0, 1, 2), công cụ chú thích của bạn đang sử dụng các giá trị category_id không liên tục.

Giải pháp: Xác minh rằng các ID lớp trong tệp .txt của bạn khớp với từ điển names trong dataset.yaml. Ánh xạ lại các ID sang các giá trị liên tục nếu cần.

Để biết chi tiết đầy đủ về API và mô tả tham số, hãy xem convert_coco tài liệu tham khảo API.

Câu hỏi thường gặp (FAQ)

Làm cách nào để chuyển đổi chú thích COCO JSON sang định dạng YOLO?

Sử dụng lệnh convert_coco() hàm từ Ultralytics để chuyển đổi các chú thích COCO JSON sang định dạng YOLO .txt. Thiết lập cls91to80=False cho các tập dữ liệu tùy chỉnh:

from ultralytics.data.converter import convert_coco

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

Sau khi chuyển đổi, hãy sắp xếp lại các tệp nhãn của bạn để labels/ phản chiếu thư mục images/, sau đó tạo một tệp dataset.yaml. Xem từng bước chi tiết để biết quy trình hoàn chỉnh.

Tại sao huấn luyện YOLO lại hiển thị "No labels found" sau khi chuyển đổi từ COCO?

Điều này xảy ra do convert_coco() lưu các nhãn vào một thư mục con bên trong save_dir/labels/ (ví dụ: save_dir/labels/train/) thay vì trực tiếp vào labels/train/ cùng với các thư mục images/train/ của tập dữ liệu của bạn. YOLO yêu cầu các nhãn phải nằm song song với hình ảnh — ví dụ: images/train/img.jpg cần có labels/train/img.txt. Di chuyển các nhãn đã chuyển đổi của bạn để khớp với cấu trúc này. Xem sửa cấu trúc thư mục.

Tham số cls91to80 làm gì trong convert_coco()?

Phương thức cls91to80 tham số điều khiển cách các giá trị category_id của COCO được ánh xạ tới các ID lớp YOLO. Khi True (mặc định), nó sử dụng bảng tra cứu được thiết kế cho tập dữ liệu COCO tiêu chuẩn, vốn có 80 lớp với các ID không liên tục (1-90). Đối với custom datasets, luôn đặt cls91to80=False — điều này chỉ đơn giản là trừ đi 1 từ mỗi category_id để tạo ra các ID lớp bắt đầu từ 0.

Tôi có thể huấn luyện YOLO trực tiếp trên COCO JSON mà không cần chuyển đổi không?

Không thể với quy trình huấn luyện YOLO hiện tại — các chú thích phải ở định dạng YOLO .txt với một tệp cho mỗi hình ảnh. Sử dụng convert_coco() để chuyển đổi COCO JSON của bạn trước, sau đó làm theo hướng dẫn này để tổ chức và huấn luyện. Để biết thêm về các định dạng được hỗ trợ, hãy xem các định dạng tập dữ liệu.

Tôi có thể chuyển đổi chú thích phân đoạn COCO sang định dạng YOLO không?

Có, sử dụng use_segments=True khi gọi convert_coco() để bao gồm các mặt nạ phân đoạn đa giác trong các nhãn YOLO đã chuyển đổi. Điều này tạo ra các tệp nhãn tương thích với các mô hình phân đoạn YOLO:

from ultralytics.data.converter import convert_coco

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

Làm cách nào để chuyển đổi chú thích điểm mấu chốt (keypoint) COCO sang định dạng YOLO?

Sử dụng use_keypoints=True để chuyển đổi chú thích điểm mấu chốt COCO cho pose estimation huấn luyện:

from ultralytics.data.converter import convert_coco

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

Lưu ý rằng nếu cả use_segmentsuse_keypoints đều được thiết lập là True, chỉ các điểm mấu chốt mới được ghi vào các tệp nhãn — các phân đoạn sẽ bị bỏ qua một cách âm thầm.

Bình luận