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/manifest.py from camstack/camstack-trainer: direct link, hf CLI and curl.
- Browser
- Download file 6.23 kB
-
https://huggingface.co/camstack/camstack-trainer/resolve/main/camstack_train/manifest.py
- Command line
-
hf download hf://camstack/camstack-trainer/camstack_train/manifest.py
-
curl -L -o manifest.py https://huggingface.co/camstack/camstack-trainer/resolve/main/camstack_train/manifest.py
6.23 kB
| """``result.json`` (schema ``camstack.training-result/v1``) and ``bundle.tar``. | |
| ``bundle.tar`` holds every artefact under its FLAT catalog name (a Core ML | |
| package as its directory), and ``files[]`` lists one row per regular file in it | |
| with its size and sha256, so the hub verifies what it fetched file by file. | |
| ``catalogDraft`` is a ``ModelCatalogEntry`` per variant whose format URLs are | |
| RELATIVE file names (the hub rewrites them to ``camstack-local://``), with the | |
| revision every format carries under D743/D744: the sha256 of its weight file | |
| (the ONNX itself, an IR's ``.bin``, a Core ML package's ``weight.bin``). | |
| """ | |
| from __future__ import annotations | |
| import hashlib | |
| import importlib.metadata | |
| import json | |
| import os | |
| import platform | |
| import tarfile | |
| from pathlib import Path | |
| from typing import Optional | |
| from . import __version__ | |
| from .dataset import sha256_file | |
| from .spec import JobSpec | |
| RESULT_SCHEMA = "camstack.training-result/v1" | |
| LICENCE = "AGPL-3.0 (Ultralytics derivative)" | |
| MLPACKAGE_FILES = ( | |
| "Manifest.json", | |
| "Data/com.apple.CoreML/model.mlmodel", | |
| "Data/com.apple.CoreML/weights/weight.bin", | |
| ) | |
| TOOLCHAIN_PACKAGES = ("torch", "ultralytics", "openvino", "nncf", "coremltools", "onnx") | |
| def toolchain_versions() -> dict[str, Optional[str]]: | |
| out: dict[str, Optional[str]] = {"python": platform.python_version()} | |
| for name in TOOLCHAIN_PACKAGES: | |
| try: | |
| out[name] = importlib.metadata.version(name) | |
| except importlib.metadata.PackageNotFoundError: | |
| out[name] = None | |
| return out | |
| def trainer_block() -> dict[str, str]: | |
| return {"version": __version__, "revision": os.environ.get("TRAINER_REVISION", "local")} | |
| def classify(rel: str, catalog_id: str) -> tuple[str, str]: | |
| """(format, variant) of a bundle file.""" | |
| if rel.startswith(f"{catalog_id}.mlpackage/"): | |
| return "coreml", "base" | |
| if rel.endswith(".pt"): | |
| return "pt", "base" | |
| if rel.endswith(".onnx"): | |
| return "onnx", "base" | |
| return "openvino", "int8" if rel.startswith(f"{catalog_id}-int8.") else "base" | |
| def file_rows(staging: Path, catalog_id: str) -> list[dict]: | |
| rows = [] | |
| for path in sorted(p for p in staging.rglob("*") if p.is_file()): | |
| rel = path.relative_to(staging).as_posix() | |
| fmt, variant = classify(rel, catalog_id) | |
| rows.append({"path": rel, "bytes": path.stat().st_size, "sha256": sha256_file(path), "format": fmt, "variant": variant}) | |
| return rows | |
| def write_bundle(staging: Path, rows: list[dict], out: Path) -> dict: | |
| """A plain, deterministic tar of exactly the listed files.""" | |
| out.parent.mkdir(parents=True, exist_ok=True) | |
| with tarfile.open(out, "w", format=tarfile.PAX_FORMAT) as tar: | |
| for row in rows: | |
| info = tar.gettarinfo(str(staging / row["path"]), arcname=row["path"]) | |
| info.mtime, info.uid, info.gid, info.uname, info.gname = 0, 0, 0, "", "" | |
| with (staging / row["path"]).open("rb") as handle: | |
| tar.addfile(info, handle) | |
| return {"path": out.name, "bytes": out.stat().st_size, "sha256": sha256_file(out)} | |
| def _row(rows: list[dict], path: str) -> Optional[dict]: | |
| return next((r for r in rows if r["path"] == path), None) | |
| def _mb(*rows: Optional[dict]) -> float: | |
| return round(sum(r["bytes"] for r in rows if r is not None) / 1e6, 2) | |
| def _openvino_format(rows: list[dict], stem: str) -> Optional[dict]: | |
| xml, weights = _row(rows, f"{stem}.xml"), _row(rows, f"{stem}.bin") | |
| if xml is None or weights is None: | |
| return None | |
| return {"url": xml["path"], "files": [weights["path"]], "runtimes": ["python"], "sizeMB": _mb(xml, weights), "revision": weights["sha256"]} | |
| def _formats_base(rows: list[dict], cid: str) -> dict: | |
| formats: dict = {} | |
| onnx = _row(rows, f"{cid}.onnx") | |
| if onnx is not None: | |
| formats["onnx"] = {"url": onnx["path"], "sizeMB": _mb(onnx), "revision": onnx["sha256"]} | |
| ov = _openvino_format(rows, f"{cid}-fp16") | |
| if ov is not None: | |
| formats["openvino"] = ov | |
| members = [_row(rows, f"{cid}.mlpackage/{m}") for m in MLPACKAGE_FILES] | |
| if all(m is not None for m in members): | |
| formats["coreml"] = { | |
| "url": f"{cid}.mlpackage", | |
| "isDirectory": True, | |
| "files": list(MLPACKAGE_FILES), | |
| "runtimes": ["python"], | |
| "sizeMB": _mb(*members), | |
| "revision": members[2]["sha256"], | |
| } | |
| return formats | |
| def _entry(job: JobSpec, entry_id: str, name: str, description: str, formats: dict, floors: dict) -> dict: | |
| return { | |
| "id": entry_id, | |
| "name": name, | |
| "description": description, | |
| "inputSize": {"width": job.base.imgsz, "height": job.base.imgsz}, | |
| "labels": [], | |
| "preprocessMode": "letterbox", | |
| "defaultClassFloors": floors, | |
| "formats": formats, | |
| } | |
| def catalog_draft(job: JobSpec, rows: list[dict], floors: dict) -> dict: | |
| cid = job.catalog.id | |
| origin = f"fine-tuned from {job.base.model_id} on dataset version {job.dataset.version_id}" | |
| base = _entry(job, cid, job.catalog.name, f"{job.catalog.name} — {origin}", _formats_base(rows, cid), floors["candidate"]) | |
| int8 = None | |
| int8_format = _openvino_format(rows, f"{cid}-int8") | |
| if int8_format is not None and floors.get("candidateInt8") is not None: | |
| int8 = _entry( | |
| job, f"{cid}-int8", f"{job.catalog.name} (INT8)", | |
| f"{job.catalog.name} — OpenVINO INT8 calibrated on the user's own frames; {origin}", | |
| {"openvino": int8_format}, floors["candidateInt8"], | |
| ) | |
| return {"base": base, "int8": int8} | |
| def result_sha256(path: Path) -> str: | |
| return hashlib.sha256(path.read_bytes()).hexdigest() | |
| def write_result(path: Path, result: dict) -> str: | |
| path.parent.mkdir(parents=True, exist_ok=True) | |
| path.write_text(json.dumps(result, indent=2, sort_keys=False) + "\n", "utf-8") | |
| return result_sha256(path) | |
| def failed_result(job_key: str, error: dict) -> dict: | |
| return { | |
| "schema": RESULT_SCHEMA, | |
| "jobKey": job_key, | |
| "status": "failed", | |
| "error": error, | |
| "trainer": trainer_block(), | |
| "toolchain": toolchain_versions(), | |
| "licence": LICENCE, | |
| } | |