| """Exact training recipe for LibreYOLO9P2s-visdrone. |
| |
| Reproduces the released checkpoint: yolo9_p2-s, VisDrone2019-DET, 768 px, |
| 60 epochs, transfer init from stock LibreYOLO9s.pt. |
| |
| Prepare the dataset first with build_visdrone.py, then: |
| |
| python train_visdrone.py --data /abs/path/to/visdrone/visdrone.yaml |
| |
| Notes discovered the hard way: |
| - lr0=0.01 (the family default) DIVERGES on transfer init; 0.005 is stable. |
| - Mosaic/mixup HURT on VisDrone (tiling shrinks tiny objects below |
| detectability); mild hsv + horizontal flip help. |
| - max_labels must be raised: dense aerial frames exceed the default 100-box |
| cap, silently dropping ground truth. |
| - Pass the dataset yaml by ABSOLUTE path. |
| """ |
|
|
| import argparse |
|
|
| from libreyolo import LibreYOLO9P2 |
|
|
|
|
| def main() -> None: |
| parser = argparse.ArgumentParser(description=__doc__) |
| parser.add_argument("--data", required=True, help="Absolute path to visdrone.yaml") |
| parser.add_argument("--epochs", type=int, default=60) |
| parser.add_argument("--batch", type=int, default=2) |
| parser.add_argument("--imgsz", type=int, default=768) |
| parser.add_argument("--workers", type=int, default=2) |
| parser.add_argument("--name", default="visdrone_p2s_768") |
| args = parser.parse_args() |
|
|
| model = LibreYOLO9P2(None, size="s") |
| model.train( |
| data=args.data, |
| epochs=args.epochs, |
| batch=args.batch, |
| nbs=16, |
| imgsz=args.imgsz, |
| workers=args.workers, |
| lr0=0.005, |
| warmup_epochs=5, |
| mosaic_prob=0.0, |
| mixup_prob=0.0, |
| hsv_prob=1.0, |
| flip_prob=0.5, |
| max_labels=600, |
| pretrained="LibreYOLO9s.pt", |
| name=args.name, |
| exist_ok=True, |
| eval_interval=5, |
| save_period=5, |
| ) |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|