NorgesGruppen-Data / scripts /train_fulldata.py
Henrikalvados's picture
Upload folder using huggingface_hub
9f7ad84 verified
Raw
History Blame Contribute Delete
4.02 kB
"""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)")
# Use ALL images for training - copy train as val too (ultralytics requires val)
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)
# ALL images go to train AND val (val is just a dummy to satisfy ultralytics)
for img in images:
src = Path("input/train/images") / img["file_name"]
if not src.exists():
continue
# Symlink to train
dst_train = train_img_dir / img["file_name"]
if not dst_train.exists():
shutil.copy2(src, dst_train)
# Also copy a small subset to val (just 5 images to satisfy ultralytics)
# We don't care about val metrics - just need it to not crash
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))
# Copy first 5 images to val (dummy)
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")