YOLO Dönüştürmeden COCO YOLO Nasıl Eğitilir
Neden Doğrudan COCO Üzerinde Eğitim Yapmalı?
Anotasyonlar içinde COCO bu biçim doğrudan şu amaçla kullanılabilir: Ultralytics YOLO dönüştürmeden eğitim .txt önce dosyalar. Bu, alt sınıf oluşturarak yapılır YOLODataset COCO anında ayrıştırmak ve bunları özel bir eğitici aracılığıyla eğitim sürecine entegre etmek.
Bu yaklaşım, COCO 'u tek doğru kaynak olarak korur — hayır convert_coco() çağrı, dizin yeniden düzenlemesi yok, ara etiket dosyaları yok. YOLO26 ve diğer tüm Ultralytics YOLO modelleri desteklenmektedir. Segmentasyon ve duruş modelleri için ek etiket alanları gereklidir (bkz. SSS).
Yoksa tek seferlik bir dönüştürme mi arıyorsunuz?
Şuna bakın: COCO YOLO COCO YOLO Kılavuzu standart için convert_coco() iş akışı.
Mimariye Genel Bakış
İki sınıf gereklidir:
COCOJSONDataset— COCO dosyasını okur ve dönüştürür sınırlayıcı kutular eğitim sırasında bellekte YOLOCOCOJSONTrainer— geçersiz kılarbuild_dataset()kullanmak içinCOCOJSONDatasetvarsayılan yerineYOLODataset
Bu uygulama, yerleşik olanla aynı şablonu izler GroundingDatasetve bu, JSON açıklamalarını da doğrudan okur. Üç yöntem yeniden tanımlanmıştır: get_img_files(), cache_labels()ve get_labels().
COCO Veri Kümesi Sınıfının Oluşturulması
COCOJSONDataset sınıf, şu sınıftan miras alır YOLODataset ve etiket yükleme mantığını geçersiz kılar. Şu şekilde okumak yerine .txt labels dizinindeki dosyaları alır, COCO dosyasını açar, görüntülere göre gruplandırılmış açıklamaları tek tek inceler ve her bir sınır kutusunu COCO formatından dönüştürür [x_min, y_min, width, height] YOLO merkez formatına [x_center, y_center, width, height]. Topluluk açıklamaları (iscrowd: 1) ve alanı sıfır olan kutular otomatik olarak atlanır.
get_img_files() Bu yöntem, resim yollarının JSON'dan çözümlendiği için boş bir liste döndürür file_name içindeki alan cache_labels(). Kategori kimlikleri sıralanır ve sıfır tabanlı sınıf indekslerine yeniden eşleştirilir; böylece hem 1 tabanlı (standart COCO) hem de ardışık olmayan kimlik şemaları düzgün bir ş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 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"]
Ayrıştırılan etiketler bir .cache JSON dosyasının yanındaki dosya (ör. instances_train.cache). Sonraki eğitim çalıştırmalarında önbellek, JSON ayrıştırma işlemi atlanarak doğrudan yüklenir. JSON dosyasında bir değişiklik olursa, hash kontrolü başarısız olur ve önbellek otomatik olarak yeniden oluşturulur.
Veri kümesini eğitim boru hattına bağlama
Eğitimcide yapılması gereken tek değişiklik, geçersiz kılmaktır build_dataset(). Varsayılan DetectionTrainer bir YOLODataset şunları tarayan .txt etiket dosyaları. Bunu şununla değiştirerek COCOJSONDataset, eğitmen bunun yerine COCO dosyasından okur.
JSON dosyasının yolu özel bir dosyadan alınır train_json / val_json field in the data config (see Step 3). During training, mode="train" karar verir train_json; doğrulama sırasında, mode="val" karar verir val_json. Eğer val_json ayarlanmamışsa, varsayılan olarak 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,
)
COCO yaml dataset.yaml dosyasını yapılandırma
dataset.yaml standart olanı kullanır path, trainve val görüntü dizinlerini bulmak için alanlar. İki ek alan, train_json ve val_json, COCO dosyalarını belirtin COCOJSONTrainer şöyle diyor. nc ve names alanlar, sınıfların sayısını ve adlarını tanımlar; bunlar, categories JSON'da.
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
Beklenen dizin yapısı:
my_dataset/
images/
train/
img_001.jpg
...
val/
img_100.jpg
...
annotations/
instances_train.json
instances_val.json
dataset.yaml
COCO Üzerinde Koşu Antrenmanı
Veri kümesi sınıfı, eğitici sınıfı ve YAML yapılandırması hazır olduğunda, eğitim standart prosedüre göre gerçekleştirilir model.train() koşu. Normal bir antrenman koşusundan tek farkı trainer=COCOJSONTrainer Bu argüman, Ultralytics varsayılan veri yükleyicisi yerine özel veri yükleyicisini Ultralytics söyler.
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
model.train(data="dataset.yaml", epochs=100, imgsz=640, trainer=COCOJSONTrainer)
Doğrulama, kontrol noktası kaydetme ve metrik günlüğü kaydetme dahil olmak üzere tüm eğitim süreci beklendiği gibi çalışıyor.
Tam Uygulama
Kolaylık olması açısından, tam uygulama aşağıda tek bir kopyala-yapıştır komut dosyası olarak sunulmuştur. Bu dosya, özel veri setini, özel eğiticiyi ve eğitim çağrısını içermektedir. Bunu dataset.yaml ve doğrudan çalıştırın.
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)
Hiperparametre önerileri için Model Eğitimi İpuçları kılavuzuna bakın.
SSS
Bununla convert_coco() arasındaki fark nedir?
convert_coco() yazar .txt etiket dosyalarını tek seferlik bir dönüştürme işlemiyle diske kaydedin. Bu yaklaşım, her eğitim çalışmasının başında JSON dosyasını ayrıştırır ve etiketleri bellekte dönüştürür. Kullanım convert_coco() Kalıcı YOLO etiketler tercih edildiğinde; ek dosyalar oluşturmadan COCO dosyasını tek geçerli kaynak olarak korumak için bu yöntemi kullanın.
YOLO , özel kod yazmadan COCO veriseti üzerinde YOLO mi?
YOLO öngören mevcut Ultralytics değil .txt varsayılan olarak etiketler. Bu kılavuz, gerekli olan en az düzeyde özel kodu sunar — bir veri kümesi sınıfı ve bir eğitici sınıfı. Bunlar tanımlandıktan sonra, eğitim için yalnızca standart bir model.train() arama.
Bu özellik, segmentasyon ve poz tahminini destekliyor mu?
Bu kılavuz şu konuları kapsamaktadır nesne tespiti. Eklemek için örnek segmentasyonu destek, şunları içerir: segmentation COCO elde edilen poligon verileri segments her etiket sözlüğünün alanı. İçin poz tahmini, şunları içerir keypoints. Şunu GroundingDataset kaynak kodu segmentlerin işlenmesi için bir referans uygulama sunar.
Bu özel veri kümesinde genişletme işlemleri işe yarıyor mu?
Evet. COCOJSONDataset genişletir YOLODataset, dolayısıyla tüm yerleşik veri genişletme — mozaik, mixup, kopyala-yapıştırve diğerleri — herhangi bir değişiklik yapılmadan çalıştırılabilir.
Kategori kimlikleri sınıf indekslerine nasıl eşleştirilir?
Kategoriler şu şekilde sıralanmıştır: id ve 0'dan başlayan sıralı dizinlere eşleştirilir. Bu, 1 tabanlı kimlikleri (standart COCO), 0 tabanlı kimlikleri ve ardışık olmayan kimlikleri destekler. names sözlükte dataset.yaml COCO ile aynı sıralama düzenini takip etmelidir categories dizi.
Önceden dönüştürülmüş etiketlere kıyasla bir performans kaybı var mı?
COCO dosyası ilk eğitim çalışmasında bir kez ayrıştırılır. Ayrıştırılan etiketler bir .cache dosyası, böylece sonraki çalıştırmalar yeniden ayrıştırma yapılmadan anında yüklenir. Etiketler bellekte tutulduğu için eğitim hızı standart YOLO ile aynıdır. JSON dosyasında değişiklik olursa önbellek otomatik olarak yeniden oluşturulur.