Cách huấn luyện YOLO TRÊN COCO JSON không cần chuyển đổi
Tại sao nên huấn luyện trực tiếp tại... COCO JSON
Chú thích trong COCO JSON định dạng này có thể được sử dụng trực tiếp cho Ultralytics YOLO đào tạo mà không cần chuyển đổi sang .txt các tập tin trước. Việc này được thực hiện bằng cách tạo lớp con. YOLODataset để phân tích COCO Xử lý JSON tức thời và tích hợp nó vào quy trình huấn luyện thông qua một trình huấn luyện tùy chỉnh.
Cách tiếp cận này giúp duy trì COCO JSON là nguồn thông tin duy nhất — không convert_coco() Gọi hàm, không cần sắp xếp lại thư mục, không cần tạo tệp nhãn trung gian. YOLO26 và tất cả những thứ khác Ultralytics YOLO Các mô hình phát hiện được hỗ trợ. Mô hình phân đoạn và tư thế yêu cầu các trường nhãn bổ sung (xem Câu hỏi thường gặp).
Bạn muốn chuyển đổi một lần duy nhất?
Xem COCO ĐẾN YOLO Hướng dẫn chuyển đổi đối với tiêu chuẩn convert_coco() quy trình làm việc.
Tổng quan về kiến trúc
Cần hai lớp học:
COCOJSONDataset— đọc COCO JSON và các công cụ chuyển đổi các hộp giới hạn ĐẾN YOLO định dạng trong bộ nhớ trong quá trình huấn luyệnCOCOJSONTrainer— ghi đèbuild_dataset()để sử dụngCOCOJSONDatasetthay vì mặc địnhYOLODataset
Việc triển khai tuân theo cùng một mô hình như chức năng tích hợp sẵn. GroundingDataset, đồng thời cũng đọc trực tiếp các chú thích JSON. Ba phương thức được ghi đè: get_img_files(), cache_labels(), và get_labels().
Xây dựng COCO Lớp tập dữ liệu JSON
Hàm COCOJSONDataset lớp kế thừa từ YOLODataset và ghi đè lên logic tải nhãn. Thay vì đọc .txt các tệp từ thư mục nhãn, nó sẽ mở COCO Tệp JSON này lặp lại các chú thích được nhóm theo hình ảnh và chuyển đổi từng hộp giới hạn từ COCO định dạng pixel [x_min, y_min, width, height] ĐẾN YOLO định dạng trung tâm chuẩn hóa [x_center, y_center, width, height]Chú thích đám đông (iscrowd: 1Các ô có diện tích bằng 0 sẽ tự động bị bỏ qua.
Hàm get_img_files() Phương thức này trả về một danh sách rỗng vì đường dẫn hình ảnh được xác định từ JSON. file_name cánh đồng bên trong cache_labels(). ID danh mục được sắp xếp và ánh xạ lại thành chỉ số lớp bắt đầu từ 0, do đó cả chỉ số bắt đầu từ 1 (tiêu chuẩn) đều được sử dụng. COCO Các lược đồ ID không liền kề hoạt động chính xác.
import json
from collections import defaultdict
from pathlib import Path
import numpy as np
from ultralytics.data.dataset import DATASET_CACHE_VERSION, YOLODataset
from ultralytics.data.utils import get_hash, load_dataset_cache_file, save_dataset_cache_file
from ultralytics.utils import TQDM
class COCOJSONDataset(YOLODataset):
"""Dataset that reads COCO JSON annotations directly without conversion to .txt files."""
def __init__(self, *args, json_file="", **kwargs):
self.json_file = json_file
super().__init__(*args, data={"channels": 3}, **kwargs)
def get_img_files(self, img_path):
"""Image paths are resolved from the JSON file, not from scanning a directory."""
return []
def cache_labels(self, path=Path("./labels.cache")):
"""Parse COCO JSON and convert annotations to YOLO format. Results are saved to a .cache file."""
x = {"labels": []}
with open(self.json_file) as f:
coco = json.load(f)
images = {img["id"]: img for img in coco["images"]}
# Sort categories by ID and map to 0-indexed classes
categories = {cat["id"]: i for i, cat in enumerate(sorted(coco["categories"], key=lambda c: c["id"]))}
img_to_anns = defaultdict(list)
for ann in coco["annotations"]:
img_to_anns[ann["image_id"]].append(ann)
for img_info in TQDM(coco["images"], desc="reading annotations"):
h, w = img_info["height"], img_info["width"]
im_file = Path(self.img_path) / img_info["file_name"]
if not im_file.exists():
continue
self.im_files.append(str(im_file))
bboxes = []
for ann in img_to_anns.get(img_info["id"], []):
if ann.get("iscrowd", False):
continue
# COCO: [x, y, w, h] top-left in pixels -> YOLO: [cx, cy, w, h] center normalized
box = np.array(ann["bbox"], dtype=np.float32)
box[:2] += box[2:] / 2 # top-left to center
box[[0, 2]] /= w # normalize x
box[[1, 3]] /= h # normalize y
if box[2] <= 0 or box[3] <= 0:
continue
cls = categories[ann["category_id"]]
bboxes.append([cls, *box.tolist()])
lb = np.array(bboxes, dtype=np.float32) if bboxes else np.zeros((0, 5), dtype=np.float32)
x["labels"].append(
{
"im_file": str(im_file),
"shape": (h, w),
"cls": lb[:, 0:1],
"bboxes": lb[:, 1:],
"segments": [],
"normalized": True,
"bbox_format": "xywh",
}
)
x["hash"] = get_hash([self.json_file, str(self.img_path)])
save_dataset_cache_file(self.prefix, path, x, DATASET_CACHE_VERSION)
return x
def get_labels(self):
"""Load labels from .cache file if available, otherwise parse JSON and create the cache."""
cache_path = Path(self.json_file).with_suffix(".cache")
try:
cache = load_dataset_cache_file(cache_path)
assert cache["version"] == DATASET_CACHE_VERSION
assert cache["hash"] == get_hash([self.json_file, str(self.img_path)])
self.im_files = [lb["im_file"] for lb in cache["labels"]]
except (FileNotFoundError, AssertionError, AttributeError, KeyError, ModuleNotFoundError):
cache = self.cache_labels(cache_path)
cache.pop("hash", None)
cache.pop("version", None)
return cache["labels"]
Các nhãn đã được phân tích cú pháp được lưu vào một .cache tệp tin nằm cạnh tệp JSON (ví dụ: instances_train.cacheTrong các lần chạy huấn luyện tiếp theo, bộ nhớ đệm được tải trực tiếp, bỏ qua bước phân tích cú pháp JSON. Nếu tệp JSON thay đổi, quá trình kiểm tra mã băm sẽ thất bại và bộ nhớ đệm sẽ được xây dựng lại tự động.
Kết nối tập dữ liệu với quy trình huấn luyện
Thay đổi duy nhất cần thực hiện trong trình huấn luyện là ghi đè lên. build_dataset(). Mặc định DetectionTrainer xây dựng một YOLODataset quét .txt các tập tin nhãn. Bằng cách thay thế nó bằng COCOJSONDataset, người huấn luyện đọc từ COCO Thay vào đó là JSON.
Đường dẫn đến tệp JSON được lấy từ một tệp tùy chỉnh. train_json / val_json field in the data config (see Step 3). During training, mode="train" quyết tâm train_json; trong quá trình xác thực, mode="val" quyết tâm val_json. Nếu như val_json nếu chưa được thiết lập, nó sẽ sử dụng phương án dự phòng. train_json.
from ultralytics.models.yolo.detect import DetectionTrainer
from ultralytics.utils import colorstr
class COCOJSONTrainer(DetectionTrainer):
"""Trainer that uses COCOJSONDataset for direct COCO JSON training."""
def build_dataset(self, img_path, mode="train", batch=None):
json_file = self.data["train_json"] if mode == "train" else self.data.get("val_json", self.data["train_json"])
return COCOJSONDataset(
img_path=img_path,
json_file=json_file,
imgsz=self.args.imgsz,
batch_size=batch,
augment=mode == "train",
hyp=self.args,
rect=self.args.rect or mode == "val",
cache=self.args.cache or None,
single_cls=self.args.single_cls or False,
stride=int(self.model.stride.max()) if hasattr(self, "model") and self.model else 32,
pad=0.0 if mode == "train" else 0.5,
prefix=colorstr(f"{mode}: "),
task=self.args.task,
classes=self.args.classes,
fraction=self.args.fraction if mode == "train" else 1.0,
)
Đang cấu hình tập dữ liệu. yaml vì COCO JSON
Hàm dataset.yaml sử dụng tiêu chuẩn path, train, và val Các trường để xác định vị trí thư mục hình ảnh. Hai trường bổ sung, train_json và val_json, chỉ định COCO các tệp chú thích COCOJSONTrainer đọc. Cái nc và names Các trường xác định số lượng lớp và tên của chúng, phù hợp với thứ tự đã được sắp xếp. categories trong JSON.
path: /path/to/images # root directory with train/ and val/ subfolders
train: train
val: val
# COCO JSON annotation files
train_json: /path/to/annotations/instances_train.json
val_json: /path/to/annotations/instances_val.json
nc: 80
names:
0: person
1: bicycle
# ... remaining class names
Cấu trúc thư mục dự kiến:
my_dataset/
images/
train/
img_001.jpg
...
val/
img_100.jpg
...
annotations/
instances_train.json
instances_val.json
dataset.yaml
Tập luyện chạy bộ COCO JSON
Sau khi đã thiết lập lớp tập dữ liệu, lớp huấn luyện và cấu hình YAML, quá trình huấn luyện sẽ diễn ra theo quy trình chuẩn. model.train() cuộc gọi. Điểm khác biệt duy nhất so với một buổi chạy luyện tập thông thường là... trainer=COCOJSONTrainer lập luận, điều này cho biết Ultralytics Sử dụng trình tải tập dữ liệu tùy chỉnh thay vì trình tải mặc định.
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
model.train(data="dataset.yaml", epochs=100, imgsz=640, trainer=COCOJSONTrainer)
Toàn bộ quy trình huấn luyện diễn ra như mong đợi, bao gồm xác thực , lưu điểm kiểm tra và ghi nhật ký số liệu.
Triển khai đầy đủ
Để thuận tiện, toàn bộ mã nguồn được cung cấp bên dưới dưới dạng một đoạn mã sao chép-dán duy nhất. Nó bao gồm tập dữ liệu tùy chỉnh, trình huấn luyện tùy chỉnh và lệnh gọi huấn luyện. Hãy lưu tập tin này cùng với tệp của bạn. dataset.yaml và chạy trực tiếp.
import json
from collections import defaultdict
from pathlib import Path
import numpy as np
from ultralytics import YOLO
from ultralytics.data.dataset import DATASET_CACHE_VERSION, YOLODataset
from ultralytics.data.utils import get_hash, load_dataset_cache_file, save_dataset_cache_file
from ultralytics.models.yolo.detect import DetectionTrainer
from ultralytics.utils import TQDM, colorstr
class COCOJSONDataset(YOLODataset):
"""Dataset that reads COCO JSON annotations directly without conversion to .txt files."""
def __init__(self, *args, json_file="", **kwargs):
self.json_file = json_file
super().__init__(*args, data={"channels": 3}, **kwargs)
def get_img_files(self, img_path):
return []
def cache_labels(self, path=Path("./labels.cache")):
x = {"labels": []}
with open(self.json_file) as f:
coco = json.load(f)
images = {img["id"]: img for img in coco["images"]}
categories = {cat["id"]: i for i, cat in enumerate(sorted(coco["categories"], key=lambda c: c["id"]))}
img_to_anns = defaultdict(list)
for ann in coco["annotations"]:
img_to_anns[ann["image_id"]].append(ann)
for img_info in TQDM(coco["images"], desc="reading annotations"):
h, w = img_info["height"], img_info["width"]
im_file = Path(self.img_path) / img_info["file_name"]
if not im_file.exists():
continue
self.im_files.append(str(im_file))
bboxes = []
for ann in img_to_anns.get(img_info["id"], []):
if ann.get("iscrowd", False):
continue
box = np.array(ann["bbox"], dtype=np.float32)
box[:2] += box[2:] / 2
box[[0, 2]] /= w
box[[1, 3]] /= h
if box[2] <= 0 or box[3] <= 0:
continue
cls = categories[ann["category_id"]]
bboxes.append([cls, *box.tolist()])
lb = np.array(bboxes, dtype=np.float32) if bboxes else np.zeros((0, 5), dtype=np.float32)
x["labels"].append(
{
"im_file": str(im_file),
"shape": (h, w),
"cls": lb[:, 0:1],
"bboxes": lb[:, 1:],
"segments": [],
"normalized": True,
"bbox_format": "xywh",
}
)
x["hash"] = get_hash([self.json_file, str(self.img_path)])
save_dataset_cache_file(self.prefix, path, x, DATASET_CACHE_VERSION)
return x
def get_labels(self):
cache_path = Path(self.json_file).with_suffix(".cache")
try:
cache = load_dataset_cache_file(cache_path)
assert cache["version"] == DATASET_CACHE_VERSION
assert cache["hash"] == get_hash([self.json_file, str(self.img_path)])
self.im_files = [lb["im_file"] for lb in cache["labels"]]
except (FileNotFoundError, AssertionError, AttributeError, KeyError, ModuleNotFoundError):
cache = self.cache_labels(cache_path)
cache.pop("hash", None)
cache.pop("version", None)
return cache["labels"]
class COCOJSONTrainer(DetectionTrainer):
"""Trainer that uses COCOJSONDataset for direct COCO JSON training."""
def build_dataset(self, img_path, mode="train", batch=None):
json_file = self.data["train_json"] if mode == "train" else self.data.get("val_json", self.data["train_json"])
return COCOJSONDataset(
img_path=img_path,
json_file=json_file,
imgsz=self.args.imgsz,
batch_size=batch,
augment=mode == "train",
hyp=self.args,
rect=self.args.rect or mode == "val",
cache=self.args.cache or None,
single_cls=self.args.single_cls or False,
stride=int(self.model.stride.max()) if hasattr(self, "model") and self.model else 32,
pad=0.0 if mode == "train" else 0.5,
prefix=colorstr(f"{mode}: "),
task=self.args.task,
classes=self.args.classes,
fraction=self.args.fraction if mode == "train" else 1.0,
)
model = YOLO("yolo26n.pt")
model.train(data="dataset.yaml", epochs=100, imgsz=640, trainer=COCOJSONTrainer)
Để biết các khuyến nghị về siêu tham số , hãy xem hướng dẫn Mẹo huấn luyện mô hình .
Câu hỏi thường gặp
Sự khác biệt giữa hàm này và convert_coco() là gì?
convert_coco() viết .txt Ghi nhãn các tập tin vào ổ đĩa dưới dạng chuyển đổi một lần. Phương pháp này phân tích cú pháp JSON ở đầu mỗi lần chạy huấn luyện và chuyển đổi các chú thích trong bộ nhớ. Sử dụng convert_coco() khi vĩnh viễn YOLO - Định dạng nhãn được ưu tiên; hãy sử dụng phương pháp này để giữ nguyên COCO JSON là nguồn thông tin duy nhất mà không cần tạo thêm tệp tin nào khác.
Có thể YOLO tàu hỏa trên COCO JSON không cần mã tùy chỉnh?
Không phải với tình hình hiện tại Ultralytics đường ống, dự kiến YOLO .txt Các nhãn được thiết lập mặc định. Hướng dẫn này cung cấp mã tùy chỉnh tối thiểu cần thiết — một lớp dữ liệu và một lớp huấn luyện. Sau khi được định nghĩa, quá trình huấn luyện chỉ cần một tệp tiêu chuẩn. model.train() gọi.
Liệu điều này có hỗ trợ phân đoạn và ước lượng tư thế không?
Hướng dẫn này bao gồm phát hiện đối tượngĐể thêm vào phân vùng thể hiện hỗ trợ, bao gồm segmentation dữ liệu đa giác từ COCO chú thích trong segments trường của mỗi từ điển nhãn. Ví dụ: ước tính tư thế, bao gồm keypoints. Các GroundingDataset mã nguồn Cung cấp một triển khai tham chiếu để xử lý các phân đoạn.
Liệu các kỹ thuật tăng cường dữ liệu có hoạt động với bộ dữ liệu tùy chỉnh này không?
Đúng. COCOJSONDataset mở rộng YOLODataset, vậy nên tất cả đều được tích hợp sẵn tăng cường dữ liệu — mosaic, mixup, copy-pastevà những ứng dụng khác — chạy mà không cần chỉnh sửa.
Mã định danh danh mục được ánh xạ tới chỉ số lớp như thế nào?
Các danh mục được sắp xếp theo id và được ánh xạ tới các chỉ số tuần tự bắt đầu từ 0. Điều này xử lý các ID dựa trên chỉ số 1 (tiêu chuẩn). COCO ), ID dựa trên chỉ số 0 và ID không liền kề. names từ điển trong dataset.yaml nên tuân theo cùng thứ tự sắp xếp như COCO categories mảng.
Liệu có sự hao phí hiệu năng nào so với việc sử dụng nhãn đã được chuyển đổi trước đó không?
Cái COCO Dữ liệu JSON được phân tích cú pháp một lần trong lần chạy huấn luyện đầu tiên. Các nhãn đã được phân tích cú pháp được lưu vào một tệp. .cache Tệp được lưu trữ, do đó các lần chạy tiếp theo sẽ tải ngay lập tức mà không cần phân tích cú pháp lại. Tốc độ huấn luyện tương đương với tiêu chuẩn. YOLO Quá trình huấn luyện diễn ra vì các chú thích được lưu trữ trong bộ nhớ. Bộ nhớ đệm được xây dựng lại tự động nếu tệp JSON thay đổi.