Instructions to use aseylys/Outflock with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- ultralytics
How to use aseylys/Outflock with ultralytics:
from ultralytics import YOLOvv8 model = YOLOvv8.from_pretrained("aseylys/Outflock") source = 'http://images.cocodataset.org/val2017/000000039769.jpg' model.predict(source=source, save=True) - Notebooks
- Google Colab
- Kaggle
| import argparse | |
| import random | |
| import shutil | |
| from pathlib import Path | |
| import torch | |
| import yaml | |
| from ultralytics import YOLO | |
| classes = { | |
| 0: "Body", | |
| 1: "Lens", | |
| 2: "System", | |
| } | |
| # ~/Outflock | |
| REPO_DIR = Path(__file__).parent.parent | |
| IMAGES_DIR = REPO_DIR / "train/data/images" | |
| LABELS_DIR = REPO_DIR / "train/data/labels" | |
| DATASET_DIR = REPO_DIR / "train/datasets/camera_obb" | |
| RUNS_DIR = REPO_DIR / "train/runs" | |
| ONNX_DIR = REPO_DIR / "model" | |
| valRatio = 0.2 | |
| seed = 42 | |
| def hasValidLabel(imagePath: Path) -> bool: | |
| labelPath = LABELS_DIR / f"{imagePath.stem}.txt" | |
| if not labelPath.exists(): | |
| return False | |
| lines = labelPath.read_text().strip().splitlines() | |
| if not lines: | |
| return False | |
| for line in lines: | |
| parts = line.split() | |
| if len(parts) != 9: | |
| return False | |
| classId = int(parts[0]) | |
| if classId not in classes: | |
| return False | |
| coords = [float(value) for value in parts[1:]] | |
| if any(value < 0 or value > 1 for value in coords): | |
| return False | |
| return True | |
| def copyExample(imagePath: Path, split: str) -> None: | |
| labelPath = LABELS_DIR / f"{imagePath.stem}.txt" | |
| imageOut = DATASET_DIR / "images" / split / imagePath.name | |
| labelOut = DATASET_DIR / "labels" / split / labelPath.name | |
| imageOut.parent.mkdir(parents=True, exist_ok=True) | |
| labelOut.parent.mkdir(parents=True, exist_ok=True) | |
| shutil.copy2(imagePath, imageOut) | |
| shutil.copy2(labelPath, labelOut) | |
| def prepareDataset() -> Path: | |
| if DATASET_DIR.exists(): | |
| shutil.rmtree(DATASET_DIR) | |
| imagePaths = sorted( | |
| path | |
| for path in IMAGES_DIR.iterdir() | |
| if path.suffix.lower() in {".jpg", ".jpeg", ".png", ".webp"} | |
| and hasValidLabel(path) | |
| ) | |
| random.Random(seed).shuffle(imagePaths) | |
| valCount = max(1, int(len(imagePaths) * valRatio)) | |
| valImages = set(imagePaths[:valCount]) | |
| trainImages = imagePaths[valCount:] | |
| for imagePath in trainImages: | |
| copyExample(imagePath, "train") | |
| for imagePath in valImages: | |
| copyExample(imagePath, "val") | |
| dataYaml = DATASET_DIR / "data.yaml" | |
| dataYaml.write_text( | |
| yaml.safe_dump( | |
| { | |
| "path": str(DATASET_DIR.resolve()), | |
| "train": "images/train", | |
| "val": "images/val", | |
| "names": classes, | |
| }, | |
| sort_keys=False, | |
| ) | |
| ) | |
| print(f"Prepared {len(trainImages)} train and {len(valImages)} val images") | |
| return dataYaml | |
| def trainModel(dataYaml: Path, onnx: bool = False) -> None: | |
| print(f"CUDA available: {torch.cuda.is_available()}") | |
| if torch.cuda.is_available(): | |
| print(f"GPU: {torch.cuda.get_device_name(0)}") | |
| model = YOLO("yolov8m-obb.pt") | |
| model.train( | |
| data=str(dataYaml), | |
| epochs=50, | |
| imgsz=960, | |
| project=str(RUNS_DIR), | |
| name="flockOBB", | |
| task="obb", | |
| batch=16, | |
| device=0, | |
| workers=8, | |
| patience=20, | |
| pretrained=True, | |
| optimizer="auto", | |
| amp=True, | |
| # Detection-specific defaults worth making explicit. | |
| single_cls=False, | |
| rect=False, | |
| cache=False, | |
| # Augmentation. Conservative for real camera detection. | |
| degrees=5, | |
| translate=0.08, | |
| scale=0.4, | |
| shear=0.0, | |
| perspective=0.0005, | |
| flipud=0.0, | |
| fliplr=0.5, | |
| mosaic=0.7, | |
| mixup=0.05, | |
| copy_paste=0.0, | |
| ) | |
| if not onnx: | |
| return | |
| # Optional: export to ONNX and weights for OpenCV later. | |
| bestWeights = Path(model.trainer.best) | |
| if not bestWeights.exists(): | |
| saveDir = Path(model.trainer.save_dir) | |
| bestWeights = saveDir / "weights" / "best.pt" | |
| if not bestWeights.exists(): | |
| raise FileNotFoundError(f"Could not find trained best weights at {bestWeights}") | |
| print(f"Best weights saved to: {bestWeights}") | |
| exportModel = YOLO(str(bestWeights)) | |
| onnxPath = Path( | |
| exportModel.export( | |
| format="onnx", | |
| imgsz=960, | |
| opset=12, | |
| simplify=True, | |
| dynamic=False, | |
| ) | |
| ) | |
| ONNX_DIR.mkdir(parents=True, exist_ok=True) | |
| targetPath = ONNX_DIR / onnxPath.name | |
| shutil.copy2(onnxPath, targetPath) | |
| print(f"ONNX model copied to: {targetPath}") | |
| def parseArgs() -> argparse.Namespace: | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument( | |
| "--onnx", | |
| action="store_true", | |
| help="Export the trained best weights to ONNX after training.", | |
| ) | |
| parser.add_argument( | |
| "--clean", | |
| action="store_true", | |
| help="Clean Non-ONNX model directories.", | |
| ) | |
| return parser.parse_args() | |
| if __name__ == "__main__": | |
| args = parseArgs() | |
| dataYaml = prepareDataset() | |
| trainModel(dataYaml, onnx=args.onnx) | |
| if args.clean: | |
| shutil.rmtree(RUNS_DIR) | |
| print(f"Removed Non-ONNX model directory: {RUNS_DIR}") | |