Views
No views yet
Latest release:v0.3.0— pin this revision for reproducibility, or omitrevision=to always get the latest. All releases: the Files and versions tab.
model.zip, versioned by HuggingFace
revision/tag (v<version>). Each release bundles everything needed to run:| file | purpose |
|---|---|
manifest.yaml | version + provenance (train git SHA, backbone, detector) |
yolo_weights.pt | the companion YOLO detector |
classifier.ckpt | the temporal ViT classifier |
config.yaml | inference + decision config |
logistic_calibrator.json | the calibrated decision head |
temporal_model.core):pip install "git+https://github.com/pyronear/temporal-model.git#subdirectory=core"model.zip and run it on a temporally ordered sequence
of frames:1from pathlib import Path
2
3from huggingface_hub import hf_hub_download
4from temporal_model.core.model import BboxTubeTemporalModel
5
6# 1. Download a specific release (pin the revision).
7model_zip = hf_hub_download("pyronear/temporal-model", "model.zip", revision="v0.3.0")
8
9# 2. Temporally-ordered frames. Filenames carry timestamps
10# (<prefix>_<YYYY-MM-DDTHH-MM-SS>.jpg); the order is the time order.
11frame_paths = sorted(Path("my_sequence").glob("*.jpg"))
12
13# 3. Load (device=None → auto cuda → mps → cpu) and predict.
14# hf_hub_download returns a str, so wrap it in Path().
15model = BboxTubeTemporalModel.from_package(Path(model_zip), device=None)
16out = model.predict_sequence(frame_paths)
17
18# 1. Binary verdict — the alarm decision.
19print("is_smoke: ", out.is_positive)
20
21# 2. Calibrated smoke probability in [0, 1]: the strongest kept tube's calibrated
22# probability (0.0 when no tube was kept). Use is_positive for a yes/no alarm;
23# use the probability to rank/triage sequences or apply your own threshold.
24kept = out.details.get("tubes", {}).get("kept", [])
25probs = [t["probability"] for t in kept if t["probability"] is not None]
26smoke_probability = max(probs) if probs else 0.0
27print("smoke probability:", smoke_probability)
28print("kept tubes: ", len(kept))predict_sequence(frame_paths) returns a TemporalModelOutput:is_positive: bool — the smoke verdict. True iff at least one tube's
calibrated probability clears the packaged decision threshold.details: dict — per-tube logits, calibrated probabilities, bounding boxes, and
the decision (aggregation, threshold). The top-level smoke probability is
the maximum kept-tube probability (shown above).is_positive and the probability are consistent: a positive sequence always has a
kept tube whose probability is ≥ the threshold, so smoke_probability is ≥ the
threshold whenever is_smoke is True.model.zip baked in
(auto-uses the GPU with --gpus all):1docker run --gpus all -p 8000:8000 \
2 -e TEMPORAL_API_S3_BUCKET=<frames-bucket> \
3 -e TEMPORAL_API_S3_ENDPOINT_URL=<s3-endpoint> \
4 pyronear/temporal-model-api:0.3.0
5# POST /predict {"frames": ["<s3-key>", ...]} GET /healthPOST /predict returns { "is_smoke": bool, "probability": float | null, "model": {...} }, where probability is the calibrated max kept-tube probability (null
only for an uncalibrated model). Add ?verbose=true for a details block with the
per-tube breakdown and decision config.model.zip manifest records how it was built — the training git SHA, the
classifier backbone (vit_small_patch14_dinov2.lvd142m), and the exact companion
detector (e.g. pyronear/yolo11s_nimble-narwhal_v6.0.0, verified by SHA-256). So
a served model always traces back to its detector + training code.