換格式直接用 Ultralytics YOLO 在 COCO JSON 標(biāo)注上訓(xùn)練)
如何不轉(zhuǎn)換格式直接用 Ultralytics YOLO 在 COCO JSON 標(biāo)注上訓(xùn)練【免費(fèi)下載鏈接】ultralyticsUltralytics YOLO26, YOLO11, YOLOv8 — object detection, instance segmentation, semantic segmentation, image classification, pose estimation, object tracking項(xiàng)目地址: https://gitcode.com/GitHub_Trending/ul/ultralytics如果你的數(shù)據(jù)集標(biāo)注以 COCO JSON 格式存在如 Labelme、COCO 官方工具或 SAM 導(dǎo)出的instances_train.json而 Ultralytics YOLO 默認(rèn)訓(xùn)練管線只識別 YOLO.txt標(biāo)簽常規(guī)做法是先跑一次convert_coco()把標(biāo)注轉(zhuǎn)成.txt文件再訓(xùn)練。項(xiàng)目文檔提供了一條不轉(zhuǎn)換的路徑通過一個自定義數(shù)據(jù)集類在訓(xùn)練時直接解析 COCO JSON并用一個自定義 trainer 把它接入標(biāo)準(zhǔn)訓(xùn)練流程。完成本文后你可以用一個標(biāo)準(zhǔn)的model.train()調(diào)用直接在自己的 COCO JSON 標(biāo)注上訓(xùn)練檢測模型文檔以 YOLO26 為例其他 Ultralytics YOLO 檢測模型同樣適用標(biāo)注文件保持為唯一的真值來源不產(chǎn)生任何中間標(biāo)簽文件。這條路徑適用于對象檢測任務(wù)實(shí)例分割和姿態(tài)估計(jì)需要在cache_labels()中額外寫入segments或keypoints字段本文最后會說明擴(kuò)展方向。方案原理兩個類替換默認(rèn)數(shù)據(jù)加載Ultralytics 的訓(xùn)練管線默認(rèn)構(gòu)建YOLODataset它會掃描標(biāo)簽?zāi)夸浿械?txt文件。直接讀 COCO JSON 的做法是替換這條數(shù)據(jù)通路只需要兩個類COCODataset— 繼承YOLODataset重寫標(biāo)簽加載邏輯打開 COCO JSON把每個邊界框從 COCO 像素格式[x_min, y_min, width, height]轉(zhuǎn)換為 YOLO 歸一化中心點(diǎn)格式[x_center, y_center, width, height]全部在內(nèi)存中完成。iscrowd: 1的眾包標(biāo)注和零面積框會被自動跳過。COCOTrainer— 繼承DetectionTrainer只重寫build_dataset()方法讓訓(xùn)練器構(gòu)建COCODataset而不是默認(rèn)的YOLODataset。這個實(shí)現(xiàn)是內(nèi)置GroundingDataset的簡化版——GroundingDataset同樣直接讀取 JSON 標(biāo)注可參考其 源碼實(shí)現(xiàn) 處理 segments 等更復(fù)雜的場景。COCODataset重寫了三個方法get_img_files()、cache_labels()和get_labels()。其中g(shù)et_img_files()返回空列表因?yàn)閳D片路徑從 JSON 的file_name字段解析而不是掃描目錄category_id會按 ID 排序后重映射為從 0 開始的類別索引所以 1-based標(biāo)準(zhǔn) COCO、0-based 或非連續(xù) ID 體系都能正確處理。與一次性轉(zhuǎn)換convert_coco() 工作流的區(qū)別convert_coco()把.txt標(biāo)簽寫入磁盤適合需要永久保留 YOLO 格式標(biāo)簽的場景本文方案在訓(xùn)練時解析 JSON、內(nèi)存中轉(zhuǎn)換適合希望以 COCO JSON 為唯一真值來源、不生成額外文件的場景。準(zhǔn)備數(shù)據(jù)集目錄結(jié)構(gòu)按如下方式組織images/下按 train/val 分開放圖片JSON 標(biāo)注文件單獨(dú)存放my_dataset/ images/ train/ img_001.jpg ... val/ img_100.jpg ... annotations/ instances_train.json instances_val.json dataset.yamlJSON 文件需符合 COCO 數(shù)據(jù)格式包含images、annotations、categories三個字段其中images中每條記錄的file_name是相對于圖片根目錄的文件名解析時通過Path(self.img_path) / img_info[file_name]定位圖片找不到的圖片會被跳過。編寫訓(xùn)練腳本下面是項(xiàng)目文檔提供的完整腳本包含數(shù)據(jù)集類、訓(xùn)練器和訓(xùn)練調(diào)用。把它保存在dataset.yaml同目錄并直接運(yù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 COCODataset(YOLODataset): Dataset that reads COCO JSON annotations directly without conversion to .txt files. def __init__(self, *args, json_file, **kwargs): Initialize the dataset with a COCO JSON annotation file. 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. self.fraction 1.0 # fraction is applied while scanning a directory, which this dataset skips return [] def cache_labels(self, pathPath(./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) categories {cat[id]: i for i, cat in enumerate(sorted(coco[categories], keylambda 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], descreading 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], dtypenp.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, dtypenp.float32) if bboxes else np.zeros((0, 5), dtypenp.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, } ) if not x[labels]: raise RuntimeError(fNo images listed in {self.json_file} were found in {self.img_path}) 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] class COCOTrainer(DetectionTrainer): Trainer that uses COCODataset for direct COCO JSON training. def build_dataset(self, img_path, modetrain, batchNone): Build a COCODataset for the given split using the JSON file from the data config. json_file self.data[train_json] if mode train else self.data[val_json] return COCODataset( img_pathimg_path, json_filejson_file, imgszself.args.imgsz, batch_sizebatch, augmentmode train, hypself.args, rectself.args.rect or mode val, cacheself.args.cache or None, single_clsself.args.single_cls or False, strideint(self.model.stride.max()) if hasattr(self, model) and self.model else 32, pad0.0 if mode train else 0.5, prefixcolorstr(f{mode}: ), taskself.args.task, classesself.args.classes, fractionself.args.fraction if mode train else 1.0, ) model YOLO(yolo26n.pt) model.train(datadataset.yaml, epochs100, imgsz640, trainerCOCOTrainer)代碼中的兩個關(guān)鍵點(diǎn)build_dataset()只改一件事訓(xùn)練時用train_json、驗(yàn)證時用val_json取 JSON 路徑。這兩個鍵在 data 配置中都是必填的——訓(xùn)練和驗(yàn)證讀取不同的圖片目錄訓(xùn)練 JSON 不能代替缺失的val_json。解析結(jié)果會寫緩存標(biāo)簽解析完成后保存到 JSON 同目錄的.cache文件例如instances_train.cache后續(xù)訓(xùn)練直接加載緩存跳過 JSON 解析。在 Windows 上以腳本方式啟動訓(xùn)練時需要在訓(xùn)練調(diào)用前加if __name__ __main__:代碼塊否則會觸發(fā)RuntimeError這是 Ultralytics 訓(xùn)練腳本的通用要求。配置 dataset.yamldataset.yaml使用標(biāo)準(zhǔn)的path、train、val字段定位圖片目錄再新增train_json、val_json兩個字段指向 COCO 標(biāo)注文件。注意與 轉(zhuǎn)換指南 中的寫法不同這里的path指向圖片根目錄所以train、val是裸的分片名而兩個 JSON 路徑字段不與path拼接必須寫絕對路徑。下例中的/path/to/my_dataset需替換為你數(shù)據(jù)集的實(shí)際絕對路徑path: /path/to/my_dataset/images # root with train/ and val/ image subfolders train: train val: val # COCO JSON annotation files (use absolute paths; these custom keys are not resolved against path) train_json: /path/to/my_dataset/annotations/instances_train.json val_json: /path/to/my_dataset/annotations/instances_val.json names: 0: person 1: bicycle # ... remaining class namesnames必須按 JSONcategories數(shù)組按 ID 排序后的順序列出類別名與代碼中categories的重映射邏輯一致類別數(shù)量從names推導(dǎo)不需要單獨(dú)設(shè)置nc。啟動訓(xùn)練運(yùn)行上面保存的腳本即可。與普通訓(xùn)練相比唯一的區(qū)別是model.train()中的trainerCOCOTrainer參數(shù)它告訴 Ultralytics 使用自定義數(shù)據(jù)集加載器。epochs100和imgsz640是文檔示例中的取值可按需調(diào)整完整訓(xùn)練管線按標(biāo)準(zhǔn)流程運(yùn)行包括訓(xùn)練中的驗(yàn)證、checkpoint 保存和指標(biāo)記錄詳見 訓(xùn)練模式文檔。驗(yàn)證結(jié)果與常見失敗現(xiàn)象檢查緩存文件。首次運(yùn)行時JSON 同目錄會生成instances_train.cache/instances_val.cache。后續(xù)運(yùn)行直接加載該緩存說明解析結(jié)果已被復(fù)用。確認(rèn)訓(xùn)練與驗(yàn)證都在正常跑指標(biāo)。訓(xùn)練中的驗(yàn)證會走COCOTrainer.build_datasetmodeval解析val_json所以驗(yàn)證階段能讀到標(biāo)簽、正常計(jì)算指標(biāo)。訓(xùn)練結(jié)束后按 訓(xùn)練文檔 中描述的方式查看保存的 checkpoint 和記錄的訓(xùn)練/驗(yàn)證指標(biāo)即可。兩個文檔明確給出的失敗現(xiàn)象如果 JSON 里列出的圖片在img_path下一個都找不到cache_labels()會拋出RuntimeError: No images listed in json were found in img_path。此時檢查path是否指向了包含train/、val/的圖片根目錄以及 JSON 中file_name的相對路徑是否與該目錄一致。獨(dú)立的model.val()不走自定義 trainer只有訓(xùn)練中的驗(yàn)證經(jīng)過COCOTrainer.build_dataset單獨(dú)調(diào)用model.val()會構(gòu)建標(biāo)準(zhǔn)YOLODataset掃描圖片旁的.txt標(biāo)簽而找不到——它不會報(bào)錯而是把圖片全部計(jì)為背景驗(yàn)證跑完但所有指標(biāo)為0并給出No labels found in ...和no labels found in detect set, cannot compute metrics without labels警告。如果你在訓(xùn)練之外單獨(dú)驗(yàn)證模型需要按同樣的build_dataset覆蓋方式子類化 validator并通過model.val(validator...)傳入。緩存陳舊陷阱。緩存的哈?;?JSON 的文件大小和路徑而不是內(nèi)容。任何保持字節(jié)數(shù)不變的編輯——微調(diào)坐標(biāo)、翻轉(zhuǎn)iscrowd、替換兩個等長類別名——都會讓陳舊緩存原樣保留訓(xùn)練會靜默使用舊標(biāo)注且無警告原地替換某張圖片同理不可見。編輯標(biāo)注或原地替換圖片后刪除對應(yīng)的.cache文件。限制與擴(kuò)展僅覆蓋對象檢測。需要實(shí)例分割時把 COCO 標(biāo)注中的segmentation多邊形數(shù)據(jù)寫入每個標(biāo)簽字典的segments字段姿態(tài)估計(jì)則寫入keypoints。處理 segments 的參考實(shí)現(xiàn)見內(nèi)置GroundingDataset的 源碼。fraction參數(shù)不生效。fraction在掃描圖片目錄時才應(yīng)用COCODataset跳過了這一步代碼里把它重置為1.0即該數(shù)據(jù)集只接受完整數(shù)據(jù)集不能按比例采樣。無額外性能開銷。JSON 只在首次訓(xùn)練時解析一次之后從.cache文件加載標(biāo)注駐留內(nèi)存訓(xùn)練速度與標(biāo)準(zhǔn) YOLO 訓(xùn)練一致。如果之后需要永久性的 YOLO 格式標(biāo)簽例如換用其他框架改走 COCO to YOLO 轉(zhuǎn)換指南中的convert_coco()一次性轉(zhuǎn)換流程即可自定義數(shù)據(jù)集代碼不再需要。下一步給cache_labels()擴(kuò)展segments或keypoints以支持分割與姿態(tài)任務(wù)調(diào)參方面參考 Model Training Tips 中的超參數(shù)建議更多訓(xùn)練參數(shù)與多 GPU 配置見 訓(xùn)練模式文檔數(shù)據(jù)集 API 細(xì)節(jié)見 YOLODataset 參考。【免費(fèi)下載鏈接】ultralyticsUltralytics YOLO26, YOLO11, YOLOv8 — object detection, instance segmentation, semantic segmentation, image classification, pose estimation, object tracking項(xiàng)目地址: https://gitcode.com/GitHub_Trending/ul/ultralytics創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考