File size: 10,052 Bytes
694fdc6 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | # Detect-crime Miner β Recipe to Beat the King
Target element: `manak0/Detect-crime` on subnet 423 (open-source / public track).
Read [ANALYSIS.md](ANALYSIS.md) first β it documents the king's model (the manak0 baseline)
and where the gap lives.
Current king of record (2026-05-04 leaderboard): hotkey `5CSeBYβ¦tv9f`, score **0.576**.
Crime is **uncontested**: there is no `Detect-crime-winner` HF repo, and the king's score
is within rounding of the published baseline's `overall_iou` (0.597). Anybody who lands a
modest improvement takes the throne.
## Layout
```
crime_miner/
βββ ANALYSIS.md β analysis of the king + scoring + constraints
βββ README.md β this file
βββ miner.py β deployable inference (multi-scale TTA + WBF + CLAHE)
βββ chute_config.yml β chute resource spec (16 GB GPU, matches king's)
βββ class_names.txt β target class order β DO NOT REORDER
βββ training/
βββ DATASET.md β dataset sources + pipeline (start here)
βββ build_dataset.py β end-to-end builder: manako + Roboflow + COCO bat
βββ poll_manako.py β background poller for in-domain frames + king's preds
βββ train.py β two-stage YOLOv11 training (silver β clean fine-tune)
βββ verify_dataset.py β QA over assembled YOLO dirs
βββ export_onnx.py β export with NMS baked in -> [1, 300, 6]
βββ requirements.txt
```
## What the miner does differently
`miner.py` keeps the king's I/O contract (single `weights.onnx` β `TVFrameResult`) but adds
six concrete improvements over the auto-generated `subnet_bridge` template the king ships:
1. **Letterboxed input at 1280** instead of stretch-resized 640. Small objects (balaclava
~30 px, glove ~25 px, spray paint can ~20 px) survive β the king's stretch resize
destroys them. This alone lifts recall on the four catastrophic classes.
2. **Per-class confidence floors**. King uses one global 0.25 across all six classes; we
set `balaclava=0.05, bat=0.10, glove=0.05, graffiti=0.20, hoodie=0.20, spray paint=0.10`.
Synthetic-benchmark recalls were 0.034 / 0.143 / 0.064 / 0.321 / 0.274 / 0.161 β the
bottleneck is recall, and the FFPI cap has plenty of headroom (~6.5 preds/img today).
3. **Multi-scale TTA** at `{1280, 1536} Γ {orig, hflip}` = 4 forward passes, collapsed to 2
when the ONNX export is static-shape. Pro_6000 has the budget (latency p95 = 10 s).
4. **Weighted Box Fusion** across TTA streams. WBF averages cluster boxes weighted by
score, which yields tighter localizations than always picking the highest-confidence
proposal β and tighter boxes mean more cases cross the IoUβ₯0.5 bar that the scorer uses.
5. **CLAHE on dark frames only** (luma gate). Crime CCTV is night-heavy. King applies no
preprocessing.
6. **Class-aware NMS at IoU=0.45**. King uses class-agnostic NMS, which suppresses
balaclava-on-hoodie or glove-near-bat overlaps. Class-aware keeps both.
Total ONNX inference cost on Pro_6000 with YOLOv11s + 2-scale TTA is well under 1 s/frame.
## How to deploy
You need: a `weights.onnx` exported in `[1, 300, 6]` layout (NMS baked in) β produced by
`training/export_onnx.py` after training, OR you can ship the king's raw ONNX directly to
test the inference improvements alone.
### Option 1 β drop-in test with the king's weights
Sanity-check that the inference improvements alone help, before training:
```bash
cp /root/turbovision_crime/king_models/Detect-crime/weights.onnx ./weights.onnx
python miner.py # smoke test on /tmp/crime_proof.png
```
Expected: with the king's weights but our miner.py, you should already see a noticeable lift
on the rare classes (recall driven up by the lower per-class conf floors and the 1280 input
that the dynamic-shape ONNX accepts). The king's published ONNX is **static** at 640Γ640,
so the dynamic letterbox path won't help unless you re-export β see below.
### Option 2 β train a real beating model
See [training/DATASET.md](training/DATASET.md) for full data-pipeline notes. Quick path:
```bash
cd training
pip install -r requirements.txt
# 1) Start the manako poller in the background to accumulate in-domain frames
# (each rotation surfaces a fresh challenge ~every few minutes during active scoring).
python poll_manako.py --out ../manako_pool --interval 120 --forever &
# 2) Build the silver dataset. Combine manako frames (king-labeled), Roboflow
# per-class detection sets, and (optional) COCO baseball bat. Roboflow needs
# ROBOFLOW_API_KEY in env.
python build_dataset.py \
--out ../data \
--king-onnx /root/turbovision_crime/king_models/Detect-crime/weights.onnx \
--manako --manako-polls 30 --manako-poll-delay 120 \
--roboflow balaclava=brainster/balaclava-detection-v3 \
--roboflow glove=ppe-detection/gloves-v1 \
--roboflow graffiti=graffiti-detection/graffiti-v3 \
--roboflow "spray paint=tools/spray-paint-can-v1" \
--coco-bat /path/to/coco/instances_train2017.json /path/to/coco/train2017 \
--extra-dir ../manako_pool/images \
--min-conf 0.10 --keep-empty --intra-threads 16
# 3) Verify the assembled dataset
python verify_dataset.py --data ../data/data.yaml --visualize 20
# 4) Stage A: silver pretrain
python train.py --data ../data/data.yaml --weights yolo11s.pt \
--imgsz 1280 --batch 16 --stage A --epochs 200 --name crime_a
# 5) Build a clean set: hand-verify (or LLM-verify) ~300 manako frames into
# ../data_clean/data.yaml with the same YOLO layout.
# 6) Stage B: clean fine-tune
python train.py --data ../data_clean/data.yaml \
--weights ../runs/detect/crime_a/weights/best.pt \
--imgsz 1280 --batch 16 --stage B --epochs 50 --name crime_b
# 7) Export with NMS baked in -> [1, 300, 6]
python export_onnx.py --weights ../runs/detect/crime_b/weights/best.pt \
--imgsz 1280 --out ../weights.onnx
```
### Option 3 β deploy via the turbovision CLI
```bash
cd /root/turbovision_crime
sv -vv deploy-os-miner --model-path scratch/crime_miner --element-id manak0/Detect-crime
```
The CLI uploads `miner.py`, `weights.onnx`, `class_names.txt`, `chute_config.yml` to your
HF repo, builds the chute, and commits the on-chain pointer.
## Tuning knobs (top of `miner.py`)
| Constant | Default | Effect of raising | Effect of lowering |
|---|---|---|---|
| `PER_CLASS_CONF[0]` (balaclava) | 0.05 | fewer FPs (good for FFPI) | more recall (better AP, better IoU) |
| `PER_CLASS_CONF[2]` (glove) | 0.05 | as above | as above |
| `PER_CLASS_CONF[4]` (hoodie) | 0.20 | fewer hoodie FPs | more boxes (may hurt precision) |
| `TTA_SIZES` | (1280, 1536) | better small-object recall | faster inference |
| `WBF_IOU` | 0.55 | more conservative fusion | tighter clusters |
| `NMS_IOU` | 0.45 | keeps more near-duplicates | stricter dedup |
| `MAX_DET` | 100 | more boxes survive ranking | tighter cap |
| `CLAHE_DARK_THRESHOLD` | 70 | CLAHE on more frames | only the very dark ones |
When tuning, validate against `runs/detect/crime_b/val_batch*.jpg` and the manako latest
challenge image β don't hill-climb on the synthetic benchmark alone (it's only 50 frames).
## Why these specific choices
- **The IoU pillar dominates the live score** (dashboard 0.576 β baseline `overall_iou`
0.597). IoU is the *label-agnostic* AUC-F1 placement metric β what matters most is
whether *any* well-placed box exists for each GT. So the optimal strategy is to flood
predictions for the rare classes; the FFPI cap (10 FP/image, currently ~6.5 preds/img
baseline) gives generous headroom.
- **mAP@50 matters too** because secondary pillars are likely weighted in. mAP@50 is
per-class-averaged with strict label match. Raising recall on the four near-zero classes
even modestly (0.03 β 0.20 on balaclava) lifts the per-class mean by ~0.03 alone.
- **WBF over hard NMS**: tighter localizations β more boxes clearing the IoUβ₯0.5 bar.
- **Class-aware NMS**: balaclava overlaps with hoodie geometry; bat overlaps with glove
on a held bat. Class-agnostic NMS would silently kill one of each pair.
- **CLAHE only on dark frames**: applying CLAHE to bright frames hurts hoodie/graffiti
texture. Luma gate keeps it surgical.
## Verifying you're actually beating the king
Before committing on-chain:
1. Pull the latest annotated challenge image+predictions:
```bash
curl -sL "https://console.scorevision.io/api/v2/elements/manak0%2FDetect-crime?lookback_days=7" \
| jq '.latestAnnotatedChallenge'
```
2. Run your `miner.py` on that image; visually verify your boxes β₯ king's, especially on
balaclava, glove, and spray paint.
3. Run `sv -vv run-once` (per `MINER.md`) to score yourself end-to-end on a real challenge
without committing β confirms the chute deploys correctly and your output format matches.
4. Only after the offline score is repeatedly above 0.62 (the king + a comfortable margin)
should you deploy and commit.
## Open questions / pending work
- **Live pillar weights for `Detect-crime`** β confirm by reading the active manifest with
`sv -vv elements list` once `.env` is configured. The recipe above assumes IoU-dominated
scoring; if mAP/precision/recall pillars are weighted higher, the per-class confidence
floors should be raised (less recall, more precision).
- **Real GT vs SAM3 PGT** β confirm whether `elements[].ground_truth = true` in the live
manifest. If real GT (Manako-internal), the synthetic_fixed dataset on HF is the closest
proxy and we should overfit it carefully. If SAM3 PGT, the live targets are whatever
SAM3 detects when prompted with the 6 class names β slightly fuzzier.
- **Manako data pull** β `poll_manako.py` is built but untested for `Detect-crime`. The
endpoint shape is the same as petrol-station's; if Manako gates the API for low-traffic
elements, fall back to using the king's ONNX as the silver labeler over Roboflow data.
|