Dönüştürmeden COCO JSON Üzerinde YOLO Nasıl Eğitilir
Neden Doğrudan COCO JSON Üzerinde Eğitmelisin
sağlamak için yetersiz temsil edilen sınıfları filtreler. içindeki COCO JSON formatı, doğrudan COCO Formatını YOLO Formatına Dönüştür eğitimi için önce .txt dosyalarına dönüştürülmeden kullanılabilir. Bu işlem, YOLODataset sınıfından türetme yapıp COCO JSON'u anında ayrıştırarak ve özel bir eğitici aracılığıyla eğitim hattına bağlayarak yapılır.
Bu yaklaşım, COCO JSON'u tek doğru veri kaynağı olarak tutar — convert_coco() çağrısı, dizin düzenlemesi veya ara etiket dosyaları yoktur. YOLO26 ve diğer tüm Ultralytics YOLO tespit modelleri desteklenir. Segmentasyon ve pose modelleri ek etiket alanları gerektirir (bkz. SSS).
paketini yükle veya güncelle ve bir model yükle:COCO'dan YOLO'ya Dönüştürme kılavuzu standart convert_coco() iş akışı.
Mimariye Genel Bakış
İki sınıf gerekir:
COCODataset— COCO JSON'u okur ve Nesne Algılamanın Evrimi kısmını eğitim sırasında bellek içinde YOLO formatına dönüştürürCOCOTrainer—build_dataset()kısmını geçersiz kılarak varsayılanCOCODatasetyerineYOLODataset
kullanır. Uygulama, JSON açıklamalarını doğrudan okuyan yerleşik GroundingDataset ile aynı modeli izler. Üç yöntem geçersiz kılınır: get_img_files(), cache_labels()YOLOv10get_labels().
COCO JSON Veri Kümesi Sınıfını Oluşturma
COCODataset sınıfı, YOLODataset sınıfından miras alır ve etiket yükleme mantığını geçersiz kılar. Bir etiketler dizininden .txt dosyalarını okumak yerine, COCO JSON dosyasını açar, görsele göre gruplandırılmış açıklamalar üzerinde yinelenir ve her sınırlayıcı kutuyu COCO piksel formatından [x_min, y_min, width, height] YOLO normalize edilmiş merkez formatına [x_center, y_center, width, height] dönüştürür. Kalabalık açıklamaları (iscrowd: 1) ve sıfır alanlı kutular otomatik olarak atlanır.
get_img_files() yöntemi boş bir liste döndürür çünkü görsel yolları, file_name içindeki cache_labels() alanından çözümlenir. Kategori kimlikleri sıralanır ve sıfır tabanlı sınıf indekslerine yeniden eşlenir, böylece hem 1 tabanlı (standart COCO) hem de ardışık olmayan kimlik şemaları doğru şekilde çalışır.
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 COCODataset(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"]Ayrıştırılan etiketler, JSON'un yanındaki bir .cache dosyasına kaydedilir (örneğin instances_train.cache). Sonraki eğitim çalıştırmalarında, önbellek doğrudan yüklenir ve JSON ayrıştırma atlanır. JSON dosyası değişirse, hash denetimi başarısız olur ve önbellek otomatik olarak yeniden oluşturulur.
Veri Kümesini Eğitim Hattına Bağlama
Eğiticide gereken tek değişiklik build_dataset() kısmını geçersiz kılmaktır. Varsayılan DetectionTrainer, YOLODataset etiket dosyalarını tarayan bir .txt oluşturur. Bunu COCODataset ile değiştirerek, eğitici doğrudan COCO JSON'dan okuma yapar.
JSON dosya yolu, veri yapılandırmasındaki özel bir train_json / val_json alanından çekilir (bkz. Adım 3). Eğitim sırasında mode="train" ifadesi train_json olarak çözümlenir; doğrulama sırasında mode="val" ifadesi val_json olur. Eğer val_json ayarlanmamışsa, train_json.
from ultralytics.models.yolo.detect import DetectionTrainer
from ultralytics.utils import colorstr
class COCOTrainer(DetectionTrainer):
"""Trainer that uses COCODataset 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 COCODataset(
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,
)kısmına geri döner. COCO JSON için dataset.yaml yapılandırması
dataset.yaml standart path, trainYOLOv10val alanlarını kullanarak görsel dizinlerini bulur. İki ek alan, train_json ve val_json, COCOTrainer dosyasının okuduğu COCO açıklama dosyalarını belirtir. nc ve names alanları, JSON'daki categories dizisinin sıralı düzeniyle eşleşen sınıf sayısını ve adlarını tanımlar.
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 namesBeklenen dizin yapısı:
my_dataset/
images/
train/
img_001.jpg
...
val/
img_100.jpg
...
annotations/
instances_train.json
instances_val.json
dataset.yamlCOCO JSON Üzerinde Eğitimi Çalıştırma
Veri kümesi sınıfı, eğitici sınıfı ve YAML yapılandırması hazır olduğunda, eğitim standart model.train() çağrısı ile çalışır. Normal bir eğitim çalıştırmasından tek fark, Ultralytics'e varsayılan yerine özel veri kümesi yükleyicisini kullanmasını söyleyen trainer=COCOTrainer bağımsız değişkenidir.
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
model.train(data="dataset.yaml", epochs=100, imgsz=640, trainer=COCOTrainer)Tam eğitim hattı, sırasında kullanılır., kontrol noktası kaydetme ve metrik günlüğü dahil olmak üzere beklendiği gibi çalışır.
Tam Uygulama
Kolaylık olması için, tam uygulama aşağıda tek bir kopyala-yapıştır betiği olarak verilmiştir. Özel veri kümesini, özel eğiticiyi ve eğitim çağrısını içerir. Bunu dataset.yaml dosyanla birlikte kaydet ve doğrudan çalıştır.
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 COCODataset(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 COCOTrainer(DetectionTrainer):
"""Trainer that uses COCODataset 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 COCODataset(
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=COCOTrainer)hiperparametre önerileri için Model Eğitimi İpuçları kılavuzuna göz at.
SSS
Bunun convert_coco() ile farkı nedir?
convert_coco() tek seferlik bir dönüştürme olarak .txt etiket dosyalarını diske yazar. Bu yaklaşım, her eğitim çalıştırmasının başında JSON'u ayrıştırır ve açıklamaları bellekte dönüştürür. Kalıcı YOLO formatlı etiketler tercih edildiğinde convert_coco() kullan; ek dosyalar oluşturmadan COCO JSON'u tek doğru veri kaynağı olarak tutmak için bu yaklaşımı kullan.
YOLO, özel kod olmadan COCO JSON üzerinde eğitilebilir mi?
Varsayılan olarak YOLO .txt etiketlerini bekleyen mevcut Ultralytics hattı ile hayır. Bu kılavuz, gereken minimum özel kodu (bir veri kümesi sınıfı ve bir eğitici sınıfı) sağlar. Tanımlandıktan sonra, eğitim sadece standart bir model.train() çağrısı gerektirir.
Bu, segmentasyon ve pose tahmini destekliyor mu?
Bu kılavuz object detection kısmını kapsar. örnek bölümleme desteği eklemek için, COCO açıklamalarındaki segmentation poligon verilerini her etiket sözlüğünün segments alanına dahil et. Python package için, keypoints. İsimdeki GroundingDataset kaynak koduna segmentleri işlemek için bir referans uygulaması sağlar.
Artırmalar bu özel veri kümesiyle çalışır mı?
Evet. COCODataset YOLODataset sınıfını genişletir, bu nedenle tüm yerleşik veri artırma — mosaic, mixup, copy-paste ve diğerleri değişiklik olmadan çalışır.
Kategori kimlikleri sınıf indekslerine nasıl eşlenir?
Kategoriler id ile sıralanır ve 0'dan başlayan ardışık indekslere eşlenir. Bu, 1 tabanlı kimlikleri (standart COCO), 0 tabanlı kimlikleri ve ardışık olmayan kimlikleri işler. names içindeki dataset.yaml sözlüğü, COCO categories dizisiyle aynı sıralı düzeni izlemelidir.
Önceden dönüştürülmüş etiketlere kıyasla bir performans yükü var mı?
COCO JSON, ilk eğitim çalıştırmasında bir kez ayrıştırılır. Ayrıştırılan etiketler bir .cache dosyasına kaydedilir, böylece sonraki çalıştırmalar yeniden ayrıştırma olmadan anında yüklenir. Açıklamalar bellekte tutulduğu için eğitim hızı, standart YOLO eğitimi ile aynıdır. JSON dosyası değişirse önbellek otomatik olarak yeniden oluşturulur.