| """Train YOLOv8x on 100% of data (no validation split). For competition only.""" |
| import sys |
| import torch |
| from pathlib import Path |
| from ultralytics import YOLO |
| import json |
| import shutil |
|
|
| _orig = torch.load |
| def _safe(*a, **kw): kw["weights_only"] = False; return _orig(*a, **kw) |
| torch.load = _safe |
|
|
| SEED = int(sys.argv[1]) if len(sys.argv) > 1 else 42 |
| IMGSZ = int(sys.argv[2]) if len(sys.argv) > 2 else 1280 |
| EPOCHS = int(sys.argv[3]) if len(sys.argv) > 3 else 100 |
| OPTIMIZER = sys.argv[4] if len(sys.argv) > 4 else "AdamW" |
| LR = float(sys.argv[5]) if len(sys.argv) > 5 else 0.0005 |
|
|
| print(f"Training: seed={SEED} imgsz={IMGSZ} epochs={EPOCHS} opt={OPTIMIZER} lr={LR}") |
| print("MODE: 100% training data (NO validation split)") |
|
|
| work_dir = Path(f"train_full_s{SEED}_i{IMGSZ}_e{EPOCHS}") |
| work_dir.mkdir(exist_ok=True) |
|
|
| ann = json.load(open("input/train/annotations.json")) |
| categories = ann["categories"] |
| images = ann["images"] |
| annotations = ann["annotations"] |
|
|
| print(f"Total images: {len(images)} (ALL used for training)") |
|
|
| |
| train_img_dir = work_dir / "images" / "train" |
| val_img_dir = work_dir / "images" / "val" |
| train_lbl_dir = work_dir / "labels" / "train" |
| val_lbl_dir = work_dir / "labels" / "val" |
|
|
| for d in [train_img_dir, val_img_dir, train_lbl_dir, val_lbl_dir]: |
| d.mkdir(parents=True, exist_ok=True) |
|
|
| img_map = {img["id"]: img for img in images} |
| img_anns = {} |
| for a in annotations: |
| img_anns.setdefault(a["image_id"], []).append(a) |
|
|
| |
| for img in images: |
| src = Path("input/train/images") / img["file_name"] |
| if not src.exists(): |
| continue |
|
|
| |
| dst_train = train_img_dir / img["file_name"] |
| if not dst_train.exists(): |
| shutil.copy2(src, dst_train) |
|
|
| |
| |
|
|
| iw, ih = img["width"], img["height"] |
| label_lines = [] |
| for a in img_anns.get(img["id"], []): |
| x, y, w, h = a["bbox"] |
| cx = (x + w / 2) / iw |
| cy = (y + h / 2) / ih |
| nw = w / iw |
| nh = h / ih |
| cx = max(0, min(1, cx)) |
| cy = max(0, min(1, cy)) |
| nw = max(0, min(1, nw)) |
| nh = max(0, min(1, nh)) |
| label_lines.append(f"{a['category_id']} {cx} {cy} {nw} {nh}") |
|
|
| lbl_name = img["file_name"].rsplit(".", 1)[0] + ".txt" |
| (train_lbl_dir / lbl_name).write_text("\n".join(label_lines)) |
|
|
| |
| val_count = 0 |
| for img in images[:5]: |
| src = Path("input/train/images") / img["file_name"] |
| dst = val_img_dir / img["file_name"] |
| if src.exists() and not dst.exists(): |
| shutil.copy2(src, dst) |
| lbl_name = img["file_name"].rsplit(".", 1)[0] + ".txt" |
| lbl_src = train_lbl_dir / lbl_name |
| if lbl_src.exists(): |
| shutil.copy2(lbl_src, val_lbl_dir / lbl_name) |
| val_count += 1 |
|
|
| nc = len(categories) |
| cat_names = {c["id"]: c["name"] for c in categories} |
| names_list = [cat_names.get(i, f"class_{i}") for i in range(nc)] |
|
|
| data_yaml = work_dir / "data.yaml" |
| data_yaml.write_text( |
| f"path: {work_dir.resolve()}\n" |
| f"train: images/train\n" |
| f"val: images/val\n" |
| f"nc: {nc}\n" |
| f"names: {names_list}\n" |
| ) |
|
|
| print(f"Train images: {len(images)}, Val images: {val_count} (dummy)") |
| print(f"Categories: {nc}") |
|
|
| model = YOLO("yolov8x.pt") |
| model.train( |
| data=str(data_yaml), |
| epochs=EPOCHS, |
| imgsz=IMGSZ, |
| batch=2 if IMGSZ <= 1280 else 1, |
| workers=0, |
| device=0 if torch.cuda.is_available() else "cpu", |
| seed=SEED, |
| close_mosaic=10, |
| mosaic=1.0, |
| copy_paste=0.3, |
| mixup=0.2, |
| degrees=10, |
| translate=0.2, |
| scale=0.9, |
| fliplr=0.0, |
| optimizer=OPTIMIZER, |
| lr0=LR, |
| lrf=0.01, |
| warmup_epochs=5, |
| cls=4.0, |
| label_smoothing=0.1, |
| save=True, |
| save_period=25, |
| ) |
|
|
| print(f"Done! Best: {work_dir}/run/weights/best.pt") |
|
|