Instructions to use camstack/camstack-trainer with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- ultralytics
How to use camstack/camstack-trainer with ultralytics:
from huggingface_hub import hf_hub_download from ultralytics import YOLO # pick the weights file from this repo's "Files and versions" tab weights = hf_hub_download("camstack/camstack-trainer", "<weights>.pt") model = YOLO(weights) source = 'http://images.cocodataset.org/val2017/000000039769.jpg' model.predict(source=source, save=True) - Notebooks
- Google Colab
- Kaggle
camstack-train 0.1.0: YOLOv9 root detector fine-tune (job.json in, result.json + bundle.tar out)
ebeed67 verified Download camstack_train/train_det.py from camstack/camstack-trainer: direct link, hf CLI and curl.
- Browser
- Download file 4.57 kB
-
https://huggingface.co/camstack/camstack-trainer/resolve/main/camstack_train/train_det.py
- Command line
-
hf download hf://camstack/camstack-trainer/camstack_train/train_det.py
-
curl -L -o train_det.py https://huggingface.co/camstack/camstack-trainer/resolve/main/camstack_train/train_det.py
4.57 kB
| """Fine-tune the YOLOv9 root detector with Ultralytics. | |
| This is the ONLY module that imports Ultralytics (AGPL-3.0), and only inside | |
| :func:`ultralytics_train`, so the rest of the package — and its tests — never | |
| load it. The hub never imports this package at all. | |
| """ | |
| from __future__ import annotations | |
| import time | |
| from dataclasses import dataclass | |
| from pathlib import Path | |
| from typing import Any, Callable, Optional, Protocol | |
| from .events import Emitter | |
| from .spec import JobSpec | |
| #: Where Ultralytics' base weights are cached between jobs (the cache volume). | |
| WEIGHTS_DIR = "weights" | |
| class TrainOutcome: | |
| best_pt: Path | |
| epochs_run: int | |
| best_epoch: int | |
| best_map50: float | |
| best_map50_95: float | |
| seconds: float | |
| class Trainer(Protocol): | |
| def __call__(self, job: JobSpec, data_yaml: Path, work: Path, cache: Path, emitter: Emitter) -> TrainOutcome: ... | |
| def write_data_yaml(root: Path, names: list[str], with_replay: bool, has_val: bool) -> Path: | |
| """The Ultralytics dataset file. Without a val split, val = train (stated).""" | |
| train = ["images/train"] + (["images/replay"] if with_replay else []) | |
| val = "images/val" if has_val else "images/train" | |
| lines = [f"path: {root.as_posix()}", "train:"] | |
| lines += [f" - {t}" for t in train] | |
| lines.append(f"val: {val}") | |
| lines.append("names:") | |
| lines += [f" {i}: {name!r}" for i, name in enumerate(names)] | |
| path = root / "data.yaml" | |
| path.write_text("\n".join(lines) + "\n", "utf-8") | |
| return path | |
| class EpochTracker: | |
| """Turns Ultralytics' per-epoch callback into ``epoch`` events + the best epoch.""" | |
| emitter: Emitter | |
| epochs: int | |
| started: float | |
| clock: Callable[[], float] = time.monotonic | |
| epochs_run: int = 0 | |
| best_epoch: int = 0 | |
| best_map50: float = 0.0 | |
| best_map50_95: float = 0.0 | |
| def on_epoch(self, epoch: int, box_loss: Optional[float], metrics: dict[str, Any]) -> None: | |
| map50 = _number(metrics.get("metrics/mAP50(B)")) | |
| map50_95 = _number(metrics.get("metrics/mAP50-95(B)")) | |
| self.epochs_run = epoch | |
| if map50_95 is not None and map50_95 >= self.best_map50_95: | |
| self.best_epoch, self.best_map50_95 = epoch, map50_95 | |
| self.best_map50 = map50 or 0.0 | |
| elapsed = self.clock() - self.started | |
| eta = elapsed / epoch * (self.epochs - epoch) if epoch > 0 else None | |
| self.emitter.epoch(epoch, self.epochs, box_loss, map50, map50_95, None if eta is None else round(eta, 1)) | |
| def _number(value: Any) -> Optional[float]: | |
| try: | |
| return None if value is None else round(float(value), 5) | |
| except (TypeError, ValueError): | |
| return None | |
| def base_weights(job: JobSpec, cache: Path) -> Path: | |
| """The base checkpoint, downloaded once into the cache volume.""" | |
| from ultralytics.utils.downloads import attempt_download_asset | |
| target = cache / WEIGHTS_DIR / job.base.weights | |
| target.parent.mkdir(parents=True, exist_ok=True) | |
| if not target.is_file(): | |
| attempt_download_asset(str(target)) | |
| return target | |
| def ultralytics_train(job: JobSpec, data_yaml: Path, work: Path, cache: Path, emitter: Emitter) -> TrainOutcome: | |
| import torch | |
| from ultralytics import YOLO | |
| model = YOLO(str(base_weights(job, cache))) | |
| tracker = EpochTracker(emitter, job.hyper.epochs, time.monotonic()) | |
| def on_fit_epoch_end(trainer: Any) -> None: | |
| loss = getattr(trainer, "tloss", None) | |
| box_loss = _number(loss[0]) if loss is not None and len(loss) > 0 else None | |
| tracker.on_epoch(int(trainer.epoch) + 1, box_loss, dict(getattr(trainer, "metrics", {}) or {})) | |
| model.add_callback("on_fit_epoch_end", on_fit_epoch_end) | |
| started = time.monotonic() | |
| model.train( | |
| data=str(data_yaml), | |
| epochs=job.hyper.epochs, | |
| batch=job.hyper.batch, | |
| lr0=job.hyper.lr0, | |
| freeze=job.hyper.freeze or None, | |
| patience=job.hyper.patience, | |
| seed=job.hyper.seed, | |
| deterministic=True, | |
| imgsz=job.base.imgsz, | |
| device=0 if torch.cuda.is_available() else "cpu", | |
| project=str(work / "runs"), | |
| name="train", | |
| exist_ok=True, | |
| plots=False, | |
| verbose=False, | |
| ) | |
| best = work / "runs" / "train" / "weights" / "best.pt" | |
| return TrainOutcome( | |
| best_pt=best, | |
| epochs_run=tracker.epochs_run, | |
| best_epoch=tracker.best_epoch, | |
| best_map50=tracker.best_map50, | |
| best_map50_95=tracker.best_map50_95, | |
| seconds=round(time.monotonic() - started, 1), | |
| ) | |