Chris Leo commited on
Commit
2588d4e
Β·
verified Β·
1 Parent(s): 430c3a7

scorevision: push artifact

Browse files
Files changed (1) hide show
  1. training/DATASET.md +133 -0
training/DATASET.md ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Detect-crime β€” Dataset Sources & Pipeline
2
+
3
+ The king's training set is small and synthetic β€” that's why per-class recalls collapse on
4
+ balaclava (3.4%), glove (6.4%), and spray paint (16.1%). The single biggest score lever is
5
+ **more, real, in-domain data**, especially for the four catastrophic classes.
6
+
7
+ ## Target classes (target order β€” must match `class_names.txt`)
8
+
9
+ | id | name | king recall | priority |
10
+ |---:|---|---:|---|
11
+ | 0 | balaclava | 0.034 | **critical** |
12
+ | 1 | bat | 0.143 | high |
13
+ | 2 | glove | 0.064 | **critical** |
14
+ | 3 | graffiti | 0.321 | medium |
15
+ | 4 | hoodie | 0.274 | medium (carries the IoU mean alone) |
16
+ | 5 | spray paint | 0.161 | high |
17
+
18
+ ## Sources
19
+
20
+ ### Tier 1 β€” in-domain (gold)
21
+
22
+ **`manak0/Detect-crime` `latestAnnotatedChallenge` API.** Same pattern as petrol-station: the
23
+ console at `console.scorevision.io/api/v2/elements/manak0%2FDetect-crime?lookback_days=30`
24
+ returns one `latestAnnotatedChallenge` record at a time. The record rotates as the runner
25
+ emits fresh challenges, so polling at ~120s for several hours / days accumulates distinct
26
+ in-domain frames *with the king's predictions attached*. Use those predictions as silver
27
+ labels (king is 0.576, so they're noisy but in-domain).
28
+
29
+ Use `poll_manako.py` to collect; use `build_dataset.py --manako` to integrate.
30
+
31
+ ### Tier 2 β€” public detection datasets (silver / gold mix)
32
+
33
+ | class | dataset | notes |
34
+ |---|---|---|
35
+ | **balaclava** | Roboflow Universe `balaclava-detection` (multiple variants, ~1k–5k labeled imgs) | search "balaclava" on universe.roboflow.com; download YOLO format |
36
+ | balaclava | MAFA β€” masked-face dataset (35k labeled faces, occluded) | ~3k images contain ski-mask / balaclava-style coverage; relabel as "balaclava" only when the mouth+nose+ears are all occluded |
37
+ | **bat** | COCO 2017, class 35 "baseball bat" (~3.3k train + ~150 val instances) | already labeled YOLO-compatible after `pycocotools` re-export; map cls 35 -> our cls 1 |
38
+ | bat | Open Images V7, class `Baseball bat` | larger, but noisier labels |
39
+ | **glove** | Roboflow Universe `gloves-detection` / `ppe-detection` | ~5k–10k labeled; merges leather, latex, work gloves |
40
+ | glove | COCO 2017 has no "glove" class; ImageNet n02883344 "ski glove" / n03775546 "boxing glove" β€” classification only, but useful for crops |
41
+ | **graffiti** | Roboflow Universe `graffiti-detection` | several variants 500–3k imgs |
42
+ | graffiti | STORM-IRMA Graffiti Dataset (Bardienus et al., academic release) | annotated graffiti tags + region bboxes |
43
+ | **hoodie** | DeepFashion2 (item id `short_sleeve_top + long_sleeve_outwear`) | very large; relabel "hooded" subset only |
44
+ | hoodie | Roboflow Universe `clothing-detection` | hooded sweatshirt subset |
45
+ | **spray paint** | Roboflow Universe `spray-paint-can`/`graffiti-tools` | small, 200–800 imgs each |
46
+ | spray paint | ImageNet n04270147 "spray can" | classification only β€” useful as copy-paste source crops |
47
+
48
+ Roboflow Universe links rotate; the build script uses the public Roboflow REST API
49
+ (`https://universe.roboflow.com/...`) and falls back to anonymous downloads for permissive-
50
+ licensed datasets. **Always check each dataset's license before use** β€” if a dataset is
51
+ non-redistributable, paste it into `--extra-dir` from a local copy instead.
52
+
53
+ ### Tier 3 β€” synthetic & augmentation
54
+
55
+ - **Copy-paste augmentation** (built into ultralytics: `copy_paste=0.30`). Disproportionately
56
+ helps rare classes by pasting their crops into other training images.
57
+ - **Mosaic + mixup** (also built-in): standard for YOLOv11.
58
+ - **Photometric augmentation**: HSV jitter, brightness scaling. CCTV crime footage is
59
+ high-variance lighting (flashbang, IR night vision, daylight) β€” push `hsv_v` to 0.5.
60
+
61
+ ## Pipeline
62
+
63
+ ```
64
+ sources β†’ KingLabeler (silver) ──┐
65
+ β”œβ”€ manako_pool/ (poll_manako.py) king's preds attached β”‚
66
+ β”œβ”€ roboflow/ (download.py per-class) β”‚
67
+ β”œβ”€ coco_bat/ (subset extractor) β”œβ”€ build_dataset.py
68
+ β”œβ”€ openimages/ (`oidv6` CLI, optional) β”‚ β†’ YOLO data.yaml
69
+ └─ extra/ (manual / verified frames) β”‚
70
+ β”˜
71
+ ```
72
+
73
+ ## Stage A vs Stage B
74
+
75
+ - **Stage A β€” silver pretrain**: train on the **assembled silver corpus** (Roboflow + COCO
76
+ + king-labeled manako + ImageNet copy-paste source). Targets: `200 epochs` at `imgsz=1280`,
77
+ YOLOv11s. Use heavy augmentation. Save EMA. Expect val mAP@50 around 0.30–0.45 β€” well
78
+ above king's 0.14, but synthetic-eval-flattering.
79
+ - **Stage B β€” clean fine-tune**: hand-verify (or LLM-verify with Qwen2-VL) ~300 manako frames
80
+ drawn from the latest 7-day window. This is the small-but-clean set that aligns most
81
+ closely with the live evaluator. Train `50 epochs` at `imgsz=1280` on Stage A weights with
82
+ reduced augmentation. Expect val mAP@50 to recede slightly (cleaner GT, harder eval) but
83
+ live-element score to *rise*, because we've shifted the distribution toward what's actually
84
+ scored on subnet.
85
+
86
+ ## Class balancing
87
+
88
+ The king's set is heavily skewed toward hoodie (~half of GT boxes). Without rebalancing, our
89
+ model would inherit that. Two interventions:
90
+
91
+ 1. **Weighted sampling** in dataloader (`sampler=` weighted by 1/sqrt(class_count)).
92
+ 2. **Copy-paste augmentation** sourced from a curated rare-class crop bank
93
+ (`crime_miner/training/_rare_crops/{balaclava, glove, spray_paint}/`). The build script
94
+ produces this bank as a byproduct.
95
+
96
+ ## What the build script writes
97
+
98
+ ```
99
+ data/
100
+ β”œβ”€β”€ data.yaml # ultralytics-style; names + train/val paths
101
+ β”œβ”€β”€ images/
102
+ β”‚ β”œβ”€β”€ train/{src}_{sha}.jpg # one per source image
103
+ β”‚ └── val/...
104
+ └── labels/
105
+ β”œβ”€β”€ train/{src}_{sha}.txt # YOLO format: cls cx cy w h (normalized)
106
+ └── val/...
107
+ ```
108
+
109
+ Manako frames are forced into `val` so the held-out set lives in the real evaluation domain.
110
+
111
+ ## Hard-class strategy: balaclava
112
+
113
+ Balaclava is the lowest-recall class. Two failure modes from the king's perspective:
114
+
115
+ 1. **Box too small at 640 input** (king's stretch resize destroys 30 px head crops).
116
+ *Solved* by 1280 letterboxed input + multi-scale TTA. No retraining required.
117
+ 2. **Few training examples**. Mitigations:
118
+ - Pull MAFA (~3k masked-face images) and select the ~30% subset where the mask covers the
119
+ entire head (i.e., balaclava, not surgical mask).
120
+ - Roboflow `balaclava-detection-v3` has ~1.5k labeled.
121
+ - Synthesize via copy-paste of balaclava crops onto random `hoodie` GT boxes (we have many
122
+ hoodie images; pasting a balaclava crop on top is plausible-looking).
123
+
124
+ Target: **5,000 balaclava-positive training images** going into Stage A.
125
+
126
+ ## Notes on label vocabulary
127
+
128
+ Both the manak0 baseline and our model emit class names matching `class_names.txt` exactly.
129
+ **Do not rename or reorder** β€” class id is what's compared on-subnet.
130
+
131
+ If the live element uses SAM3 pseudo-GT (not real GT), SAM3 will be prompted with these
132
+ exact strings as text labels (`scorevision/vlm_pipeline/sam3/detect_objects.py:36`). So the
133
+ class names in `class_names.txt` *are* the SAM3 prompts.