CharlesCNorton commited on
Commit ·
f5498f9
0
Parent(s):
Image-level person classification on EUPE-ViT-B features with a single free parameter
Browse files- .gitattributes +35 -0
- .gitignore +7 -0
- Makefile +20 -0
- README.md +184 -0
- calibrate.py +107 -0
- circuit.json +64 -0
- classifier.json +19 -0
- classifier.safetensors +3 -0
- classifier_tight_fpr.json +121 -0
- classifier_tight_fpr.safetensors +3 -0
- common/__init__.py +22 -0
- common/artifacts.py +72 -0
- common/data.py +77 -0
- common/features.py +52 -0
- common/metrics.py +47 -0
- common/models.py +32 -0
- common/paths.py +25 -0
- common/pool.py +72 -0
- common/pools.py +36 -0
- discovery/dim48_characterization.json +546 -0
- discovery/dim_selection.json +504 -0
- discovery/prop_image_manifest.json +1 -0
- discovery/prop_specificity.json +710 -0
- discovery/variant_leaderboard.json +232 -0
- eval.json +20 -0
- eval_tight_fpr.json +21 -0
- head.py +81 -0
- infer.py +85 -0
- per_dim_thresholds.json +348 -0
- pyproject.toml +29 -0
- rtl/popcount.v +39 -0
- rtl/popcount_folded.v +46 -0
- rtl/sum.v +32 -0
- rtl/sum_folded.v +33 -0
- rtl_gen.py +183 -0
- synth.py +86 -0
- tests/conftest.py +29 -0
- tests/test_artifacts.py +68 -0
- tests/test_dims.py +64 -0
- tests/test_head.py +38 -0
- tests/test_rtl.py +245 -0
- verify.py +66 -0
.gitattributes
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
*.7z filter=lfs diff=lfs merge=lfs -text
|
| 2 |
+
*.arrow filter=lfs diff=lfs merge=lfs -text
|
| 3 |
+
*.bin filter=lfs diff=lfs merge=lfs -text
|
| 4 |
+
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
| 5 |
+
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
| 6 |
+
*.ftz filter=lfs diff=lfs merge=lfs -text
|
| 7 |
+
*.gz filter=lfs diff=lfs merge=lfs -text
|
| 8 |
+
*.h5 filter=lfs diff=lfs merge=lfs -text
|
| 9 |
+
*.joblib filter=lfs diff=lfs merge=lfs -text
|
| 10 |
+
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
| 11 |
+
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
| 12 |
+
*.model filter=lfs diff=lfs merge=lfs -text
|
| 13 |
+
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
| 14 |
+
*.npy filter=lfs diff=lfs merge=lfs -text
|
| 15 |
+
*.npz filter=lfs diff=lfs merge=lfs -text
|
| 16 |
+
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 17 |
+
*.ot filter=lfs diff=lfs merge=lfs -text
|
| 18 |
+
*.parquet filter=lfs diff=lfs merge=lfs -text
|
| 19 |
+
*.pb filter=lfs diff=lfs merge=lfs -text
|
| 20 |
+
*.pickle filter=lfs diff=lfs merge=lfs -text
|
| 21 |
+
*.pkl filter=lfs diff=lfs merge=lfs -text
|
| 22 |
+
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 23 |
+
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 24 |
+
*.rar filter=lfs diff=lfs merge=lfs -text
|
| 25 |
+
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 26 |
+
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
| 27 |
+
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
| 28 |
+
*.tar filter=lfs diff=lfs merge=lfs -text
|
| 29 |
+
*.tflite filter=lfs diff=lfs merge=lfs -text
|
| 30 |
+
*.tgz filter=lfs diff=lfs merge=lfs -text
|
| 31 |
+
*.wasm filter=lfs diff=lfs merge=lfs -text
|
| 32 |
+
*.xz filter=lfs diff=lfs merge=lfs -text
|
| 33 |
+
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
+
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
+
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
.gitignore
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
__pycache__/
|
| 2 |
+
*.py[cod]
|
| 3 |
+
.pytest_cache/
|
| 4 |
+
*.egg-info/
|
| 5 |
+
|
| 6 |
+
# Synthesis build products; regenerate with `make synth`.
|
| 7 |
+
build/
|
Makefile
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# make test run the backbone-free consistency suite
|
| 2 |
+
# make rtl regenerate rtl/ from per_dim_thresholds.json
|
| 3 |
+
# make synth synthesize every decision variant with nosis
|
| 4 |
+
# make clean
|
| 5 |
+
|
| 6 |
+
PYTHON ?= python
|
| 7 |
+
|
| 8 |
+
test:
|
| 9 |
+
$(PYTHON) -m pytest -q
|
| 10 |
+
|
| 11 |
+
rtl:
|
| 12 |
+
$(PYTHON) rtl_gen.py
|
| 13 |
+
|
| 14 |
+
synth: rtl
|
| 15 |
+
$(PYTHON) synth.py
|
| 16 |
+
|
| 17 |
+
clean:
|
| 18 |
+
rm -rf build
|
| 19 |
+
|
| 20 |
+
.PHONY: test rtl synth clean
|
README.md
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: other
|
| 3 |
+
license_name: fair-research-license
|
| 4 |
+
license_link: https://huggingface.co/facebook/EUPE-ViT-B/blob/main/LICENSE
|
| 5 |
+
base_model: facebook/EUPE-ViT-B
|
| 6 |
+
tags:
|
| 7 |
+
- image-classification
|
| 8 |
+
- binary-classification
|
| 9 |
+
- minimal-models
|
| 10 |
+
- interpretability
|
| 11 |
+
- vision-transformer
|
| 12 |
+
- circuit-synthesis
|
| 13 |
+
library_name: pytorch
|
| 14 |
+
datasets:
|
| 15 |
+
- detection-datasets/coco
|
| 16 |
+
pipeline_tag: image-classification
|
| 17 |
+
---
|
| 18 |
+
|
| 19 |
+
# 1-Parameter Classifier
|
| 20 |
+
|
| 21 |
+
Image-level person classification on EUPE-ViT-B features. A 768 pixel image
|
| 22 |
+
gives 2304 patch tokens at the final layer; layernorm across the 768 channels
|
| 23 |
+
and max-pool across patches gives one 768-D vector. The classifier reads 40 of
|
| 24 |
+
its dimensions, 20 person-positive and 20 person-negative, sums the positives,
|
| 25 |
+
subtracts the negatives, and compares the result to one threshold. The dimension
|
| 26 |
+
indices and their signs are fixed structure; the threshold, 25.284, is the only
|
| 27 |
+
value fitted to data.
|
| 28 |
+
|
| 29 |
+
```python
|
| 30 |
+
patches = backbone(image)["x_norm_patchtokens"] # (2304, 768)
|
| 31 |
+
pooled = layernorm(patches, 768).max(dim=0) # (768,)
|
| 32 |
+
score = pooled[pos_dims].sum() - pooled[neg_dims].sum()
|
| 33 |
+
present = score > threshold # the only free parameter
|
| 34 |
+
```
|
| 35 |
+
|
| 36 |
+
```python
|
| 37 |
+
from infer import PersonDetector
|
| 38 |
+
det = PersonDetector.load('baseline')
|
| 39 |
+
score, present = det.predict('image.jpg')
|
| 40 |
+
```
|
| 41 |
+
|
| 42 |
+
## Variants
|
| 43 |
+
|
| 44 |
+
| variant | dims | F1 | precision | recall | prop-FPR |
|
| 45 |
+
|---|---:|---:|---:|---:|---:|
|
| 46 |
+
| `baseline` | 40 | 0.8886 | 0.9011 | 0.8763 | 5.93 % |
|
| 47 |
+
| `tight_fpr` | 55 | 0.8527 | 0.8967 | 0.8127 | 2.72 % |
|
| 48 |
+
|
| 49 |
+
`baseline` is measured on all 5000 images of COCO val2017 through a backbone
|
| 50 |
+
forward at 768 px. `tight_fpr` keeps the same 20 positive dimensions and extends
|
| 51 |
+
the negative set with 15 mined from person-associated objects photographed
|
| 52 |
+
without people; it trades 0.036 F1 for a prop false-positive rate of 2.72 %. Its
|
| 53 |
+
row is measured by `discovery/prop_specificity.json` at `extra_neg_k` 15, which
|
| 54 |
+
recorded no pool, and is not comparable with the `VAL5000` figure.
|
| 55 |
+
|
| 56 |
+
## Dimension selection
|
| 57 |
+
|
| 58 |
+
`discovery/dim_selection.json`: 100,000 random 92-dimension subsets of the 768-D
|
| 59 |
+
space, a ridge classifier per subset, the top 1 % kept, dimension occurrence
|
| 60 |
+
counted across that cohort. Dimension 48 appears in 100 % of the top 1000
|
| 61 |
+
subsets; the next strongest, 525, appears in 31 %.
|
| 62 |
+
|
| 63 |
+
`discovery/dim48_characterization.json`: five analyses on dimension 48. F1
|
| 64 |
+
against K. Activation distributions for person-positive and person-negative
|
| 65 |
+
images, Cohen's d 1.98. Per-class activation delta across all 80 COCO
|
| 66 |
+
categories. Pairwise correlation among the ten most frequent dimensions, maximum
|
| 67 |
+
absolute value 0.57. Spatial IoU of peak activations against ground-truth person
|
| 68 |
+
boxes, mean 0.17.
|
| 69 |
+
|
| 70 |
+
`discovery/variant_leaderboard.json`: 20 classifier forms from 1 to 769
|
| 71 |
+
parameters. Ternary ±1 over 50 positive and 50 negative dimensions leads at F1
|
| 72 |
+
0.893.
|
| 73 |
+
|
| 74 |
+
Dimension 48 responds to people and to person-associated objects and is
|
| 75 |
+
suppressed on non-human animals and on non-anthropogenic structures. Alone it
|
| 76 |
+
reaches F1 0.83 as a 2-parameter classifier. The other 39 dimensions carry
|
| 77 |
+
largely orthogonal axes and reach 0.89 at one free parameter.
|
| 78 |
+
|
| 79 |
+
## Prop specificity
|
| 80 |
+
|
| 81 |
+
`discovery/prop_specificity.json` and `prop_image_manifest.json` measure
|
| 82 |
+
separation between "person present" and "person-associated object present, no
|
| 83 |
+
person". 8,479 ImageNet training images across 20 such synsets were filtered
|
| 84 |
+
with YOLO26l at confidence 0.25 to keep only frames with no detected person.
|
| 85 |
+
`baseline` fires on 5.9 % of them. Adding prop-specific negative dimensions
|
| 86 |
+
takes that to 2.7 % at K=15, which is the knee and what
|
| 87 |
+
`classifier_tight_fpr.json` carries.
|
| 88 |
+
|
| 89 |
+
## Circuit
|
| 90 |
+
|
| 91 |
+
Inputs are the 40 selected channels as signed INT8, post-layernorm,
|
| 92 |
+
post-max-pool and indexed. Output is one bit, combinational, with no multipliers
|
| 93 |
+
and no memory. Two forms, each synthesized with thresholds as runtime inputs and
|
| 94 |
+
with them baked in.
|
| 95 |
+
|
| 96 |
+
| variant | thresholds | slices | LUT4 | CCU2C | bound | ns |
|
| 97 |
+
|---|---|---:|---:|---:|---|---:|
|
| 98 |
+
| `sum` | runtime | 312 | 31 | 312 | carry | 10.40 |
|
| 99 |
+
| `sum_folded` | baked | 312 | 21 | 312 | carry | 10.40 |
|
| 100 |
+
| `popcount` | runtime | 146 | 291 | 118 | lut | 10.80 |
|
| 101 |
+
| `popcount_folded` | baked | 118 | 109 | 118 | carry | 10.80 |
|
| 102 |
+
|
| 103 |
+
```
|
| 104 |
+
additive score = sum(pos) - sum(neg) 40 x 8-bit adder tree
|
| 105 |
+
out = score > T 16-bit signed comparator
|
| 106 |
+
|
| 107 |
+
popcount b_i = f_i > t_i 40 x 8-bit comparators
|
| 108 |
+
out = popcount(b_0..b_19)
|
| 109 |
+
- popcount(b_20..b_39) > K two 20->5 bit counts, small compare
|
| 110 |
+
```
|
| 111 |
+
|
| 112 |
+
The popcount form replaces the signed adder tree with 40 independent one-bit
|
| 113 |
+
decisions, taking the carry chain from 312 cells to 118. Each channel retains
|
| 114 |
+
only which side of its threshold it fell on.
|
| 115 |
+
|
| 116 |
+
```
|
| 117 |
+
form F1
|
| 118 |
+
additive, float 0.884
|
| 119 |
+
popcount, K=13 0.876 -0.008
|
| 120 |
+
```
|
| 121 |
+
|
| 122 |
+
Measured on `BALANCED_VAL`, where the additive figure is 0.884 against the 0.889
|
| 123 |
+
measured on `VAL5000`. Both come from the same measurement.
|
| 124 |
+
|
| 125 |
+
Synthesis is [nosis](https://github.com/CharlesCNorton/nosis) targeting a
|
| 126 |
+
Lattice ECP5 LFE5U-25F. Counts are LUT4s, carry cells and slices on that device.
|
| 127 |
+
`calibrate.py` selects the 40 per-dimension thresholds and the integer K and
|
| 128 |
+
writes `per_dim_thresholds.json`; `rtl_gen.py` emits all four modules from that
|
| 129 |
+
file. INT8 constants are the calibrated float values scaled by 8.
|
| 130 |
+
|
| 131 |
+
## Layout
|
| 132 |
+
|
| 133 |
+
```
|
| 134 |
+
common/ pooled features, ternary scoring, metrics, named pools
|
| 135 |
+
classifier.json, .safetensors dimensions, signs and the threshold
|
| 136 |
+
classifier_tight_fpr.json, .safetensors the low-false-fire variant
|
| 137 |
+
head.py the decision as a fused Linear with ternary weights
|
| 138 |
+
verify.py scores a config over a named pool, writes eval.json
|
| 139 |
+
calibrate.py per-dimension calibration, writes per_dim_thresholds.json
|
| 140 |
+
rtl_gen.py Verilog generation from per_dim_thresholds.json
|
| 141 |
+
synth.py nosis synthesis, writes circuit.json
|
| 142 |
+
infer.py loader for both variants
|
| 143 |
+
discovery/ how the 40 dimensions were chosen
|
| 144 |
+
rtl/ the four decision modules, all generated
|
| 145 |
+
tests/ consistency suite, no backbone or dataset required
|
| 146 |
+
```
|
| 147 |
+
|
| 148 |
+
Each measured JSON opens with a provenance block naming its generating script,
|
| 149 |
+
the classifier config it read and that config's hash, and the pool.
|
| 150 |
+
`tests/test_artifacts.py` enforces the pairing. The five files under
|
| 151 |
+
`discovery/` record a null generator; their sweeps are not committed.
|
| 152 |
+
|
| 153 |
+
## Running
|
| 154 |
+
|
| 155 |
+
```
|
| 156 |
+
pip install -e .
|
| 157 |
+
make test # consistency suite
|
| 158 |
+
python verify.py # baseline on VAL5000
|
| 159 |
+
python calibrate.py # thresholds, then all four modules
|
| 160 |
+
make synth # synthesize with nosis
|
| 161 |
+
```
|
| 162 |
+
|
| 163 |
+
`COCO_ROOT` is the dataset root. `BACKBONE` is the backbone repo id or a local
|
| 164 |
+
path. `BACKBONE_SRC` supplies `argus.py` from a local directory; otherwise it is
|
| 165 |
+
fetched from the backbone repo.
|
| 166 |
+
|
| 167 |
+
## Evaluation pools
|
| 168 |
+
|
| 169 |
+
Declared in `common/pools.py` and named in each artifact's provenance block.
|
| 170 |
+
Figures are comparable only within a pool.
|
| 171 |
+
|
| 172 |
+
| pool | images |
|
| 173 |
+
|---|---|
|
| 174 |
+
| `VAL5000` | all 5000 of COCO val2017 |
|
| 175 |
+
| `CALIB1000` | first 1000 val2017 ids |
|
| 176 |
+
| `VAL500` | first 500 val2017 ids |
|
| 177 |
+
| `BALANCED_VAL` | val2017 subsampled to equal classes |
|
| 178 |
+
|
| 179 |
+
## Source backbone
|
| 180 |
+
|
| 181 |
+
EUPE-ViT-B from Meta FAIR ([arXiv:2603.22387](https://arxiv.org/abs/2603.22387),
|
| 182 |
+
Zhu et al., March 2026), distilled from PEcore-G + PElang-G + DINOv3-H+ via a
|
| 183 |
+
1.9B proxy teacher. License: FAIR Research License, non-commercial. This
|
| 184 |
+
classifier is an artifact derived from that backbone's feature geometry.
|
calibrate.py
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Calibrate the popcount reformulation and regenerate the RTL.
|
| 2 |
+
|
| 3 |
+
Per-dim thresholds are chosen on a balanced COCO val subsample: for a
|
| 4 |
+
person-positive dim the split maximizing F1 under `value > t`, for a
|
| 5 |
+
person-negative dim under `value < t`. Either way the split point is the same
|
| 6 |
+
cut, and at inference every channel uses `>` because the negative count is
|
| 7 |
+
subtracted.
|
| 8 |
+
|
| 9 |
+
Writes per_dim_thresholds.json, then calls rtl_gen so the baked constants cannot
|
| 10 |
+
drift from the calibration that produced them.
|
| 11 |
+
"""
|
| 12 |
+
import argparse
|
| 13 |
+
import json
|
| 14 |
+
import sys
|
| 15 |
+
from pathlib import Path
|
| 16 |
+
|
| 17 |
+
import torch
|
| 18 |
+
|
| 19 |
+
sys.path.insert(0, str(Path(__file__).resolve().parent)) # repo root, for `common`
|
| 20 |
+
from common import (COCO_ROOT, D, balanced_indices, coco_split, device, # noqa: E402
|
| 21 |
+
f1_sweep, person_labels, pool, prf1, write_artifact)
|
| 22 |
+
from common.pools import BALANCED_VAL # noqa: E402
|
| 23 |
+
|
| 24 |
+
import rtl_gen # noqa: E402
|
| 25 |
+
|
| 26 |
+
HERE = Path(__file__).resolve().parent
|
| 27 |
+
CLASSIFIER = HERE / 'classifier.json'
|
| 28 |
+
QUANT_SCALE = 8 # INT8 fixed-point scale for the layernormed feature values
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
def main():
|
| 32 |
+
ap = argparse.ArgumentParser(description=__doc__)
|
| 33 |
+
ap.add_argument('--cache', type=Path,
|
| 34 |
+
default=COCO_ROOT / 'val_feature_cache_768' / 'val.pt')
|
| 35 |
+
ap.add_argument('--seed', type=int, default=0)
|
| 36 |
+
args = ap.parse_args()
|
| 37 |
+
|
| 38 |
+
dev = device()
|
| 39 |
+
c = json.loads(CLASSIFIER.read_text())
|
| 40 |
+
pos_dims, neg_dims = c['pos_dims'], c['neg_dims']
|
| 41 |
+
all_dims = pos_dims + neg_dims
|
| 42 |
+
n_pos = len(pos_dims)
|
| 43 |
+
|
| 44 |
+
print('[load] val features and person labels', flush=True)
|
| 45 |
+
val = torch.load(args.cache, map_location='cpu', weights_only=False)
|
| 46 |
+
coco, _ = coco_split('val2017')
|
| 47 |
+
ids = [int(e['img_id']) for e in val]
|
| 48 |
+
feats = torch.stack([pool(e['spatial'].float().permute(1, 2, 0).reshape(-1, D))
|
| 49 |
+
for e in val]).to(dev)[:, all_dims]
|
| 50 |
+
y = person_labels(coco, ids, dev)
|
| 51 |
+
print(f' N={feats.shape[0]} person_rate={y.float().mean():.3f}', flush=True)
|
| 52 |
+
|
| 53 |
+
sel = balanced_indices(y, args.seed)
|
| 54 |
+
X, yb = feats[sel.to(dev)], y[sel.to(dev)]
|
| 55 |
+
print(f'[balanced] N={len(sel)} person_rate={yb.float().mean():.3f}', flush=True)
|
| 56 |
+
|
| 57 |
+
per_dim = []
|
| 58 |
+
for local, global_dim in enumerate(all_dims):
|
| 59 |
+
vals = X[:, local]
|
| 60 |
+
is_pos = local < n_pos
|
| 61 |
+
candidates = torch.quantile(vals, torch.linspace(0.05, 0.95, 19, device=dev))
|
| 62 |
+
best = (0.0, 0.0)
|
| 63 |
+
for t in candidates.tolist():
|
| 64 |
+
m = prf1(vals > t if is_pos else vals < t, yb)
|
| 65 |
+
if m.f1 > best[0]:
|
| 66 |
+
best = (m.f1, t)
|
| 67 |
+
per_dim.append({'dim_index_in_40': local, 'dim_global': int(global_dim),
|
| 68 |
+
'is_pos': is_pos, 'threshold': best[1],
|
| 69 |
+
'threshold_int8': int(round(best[1] * QUANT_SCALE)),
|
| 70 |
+
'per_dim_F1': best[0]})
|
| 71 |
+
lo = min(p['per_dim_F1'] for p in per_dim)
|
| 72 |
+
hi = max(p['per_dim_F1'] for p in per_dim)
|
| 73 |
+
print(f'[per-dim] calibrated, standalone F1 range {lo:.3f} - {hi:.3f}', flush=True)
|
| 74 |
+
|
| 75 |
+
bits = torch.stack([X[:, p['dim_index_in_40']] > p['threshold'] for p in per_dim], 1)
|
| 76 |
+
diff = (bits[:, :n_pos].sum(1) - bits[:, n_pos:].sum(1)).float()
|
| 77 |
+
best_k, best_m = 0, prf1(diff > 0, yb)
|
| 78 |
+
for t in range(-20, 21):
|
| 79 |
+
m = prf1(diff > t, yb)
|
| 80 |
+
if m.f1 > best_m.f1:
|
| 81 |
+
best_k, best_m = t, m
|
| 82 |
+
print(f'[popcount] F1={best_m.f1:.4f} P={best_m.precision:.4f} '
|
| 83 |
+
f'R={best_m.recall:.4f} K={best_k}', flush=True)
|
| 84 |
+
|
| 85 |
+
sums = X[:, :n_pos].sum(1) - X[:, n_pos:].sum(1)
|
| 86 |
+
add = f1_sweep(sums, yb)
|
| 87 |
+
print(f'[additive] F1={add.f1:.4f} P={add.precision:.4f} R={add.recall:.4f} '
|
| 88 |
+
f't={add.threshold:.3f}', flush=True)
|
| 89 |
+
|
| 90 |
+
write_artifact(HERE / 'per_dim_thresholds.json', {
|
| 91 |
+
'quant_scale': QUANT_SCALE,
|
| 92 |
+
'per_dim_thresholds': per_dim,
|
| 93 |
+
'popcount': {'final_threshold': int(best_k), **best_m.asdict()},
|
| 94 |
+
'additive': add.asdict(),
|
| 95 |
+
'F1_delta_popcount_vs_additive': best_m.f1 - add.f1,
|
| 96 |
+
}, generator='calibrate.py', classifier=CLASSIFIER,
|
| 97 |
+
pool=BALANCED_VAL.name, split=BALANCED_VAL.split, n_images=int(len(sel)),
|
| 98 |
+
positive_rate=round(yb.float().mean().item(), 4),
|
| 99 |
+
selection=BALANCED_VAL.selection, seed=args.seed)
|
| 100 |
+
|
| 101 |
+
for path in rtl_gen.generate():
|
| 102 |
+
print(f'[rtl] wrote {path}', flush=True)
|
| 103 |
+
print('[done]', flush=True)
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
if __name__ == '__main__':
|
| 107 |
+
main()
|
circuit.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"provenance": {
|
| 3 |
+
"generator": "synth.py",
|
| 4 |
+
"tool": "nosis",
|
| 5 |
+
"target": {
|
| 6 |
+
"family": "ecp5",
|
| 7 |
+
"device": "LFE5U-25F"
|
| 8 |
+
},
|
| 9 |
+
"inputs": "40 signed INT8 feature channels at the classifier dims",
|
| 10 |
+
"note": "LUT4, carry and slice counts on an ECP5, not abstract gates"
|
| 11 |
+
},
|
| 12 |
+
"variants": {
|
| 13 |
+
"sum": {
|
| 14 |
+
"slices": 312,
|
| 15 |
+
"lut4": 31,
|
| 16 |
+
"ccu2c": 312,
|
| 17 |
+
"ffs": 0,
|
| 18 |
+
"bound": "carry",
|
| 19 |
+
"critical_path_ns": 10.4,
|
| 20 |
+
"device": "LFE5U-25F",
|
| 21 |
+
"rtl": "rtl/sum.v",
|
| 22 |
+
"thresholds": "runtime input"
|
| 23 |
+
},
|
| 24 |
+
"sum_folded": {
|
| 25 |
+
"slices": 312,
|
| 26 |
+
"lut4": 21,
|
| 27 |
+
"ccu2c": 312,
|
| 28 |
+
"ffs": 0,
|
| 29 |
+
"bound": "carry",
|
| 30 |
+
"critical_path_ns": 10.4,
|
| 31 |
+
"device": "LFE5U-25F",
|
| 32 |
+
"rtl": "rtl/sum_folded.v",
|
| 33 |
+
"thresholds": "baked"
|
| 34 |
+
},
|
| 35 |
+
"popcount": {
|
| 36 |
+
"slices": 146,
|
| 37 |
+
"lut4": 291,
|
| 38 |
+
"ccu2c": 118,
|
| 39 |
+
"ffs": 0,
|
| 40 |
+
"bound": "lut",
|
| 41 |
+
"critical_path_ns": 10.8,
|
| 42 |
+
"device": "LFE5U-25F",
|
| 43 |
+
"rtl": "rtl/popcount.v",
|
| 44 |
+
"thresholds": "runtime inputs"
|
| 45 |
+
},
|
| 46 |
+
"popcount_folded": {
|
| 47 |
+
"slices": 118,
|
| 48 |
+
"lut4": 109,
|
| 49 |
+
"ccu2c": 118,
|
| 50 |
+
"ffs": 0,
|
| 51 |
+
"bound": "carry",
|
| 52 |
+
"critical_path_ns": 10.8,
|
| 53 |
+
"device": "LFE5U-25F",
|
| 54 |
+
"rtl": "rtl/popcount_folded.v",
|
| 55 |
+
"thresholds": "baked"
|
| 56 |
+
}
|
| 57 |
+
},
|
| 58 |
+
"accuracy": {
|
| 59 |
+
"protocol": "balanced COCO val subsample, see calibrate.py",
|
| 60 |
+
"additive_F1": 0.8843,
|
| 61 |
+
"popcount_F1": 0.8764,
|
| 62 |
+
"delta": -0.0079
|
| 63 |
+
}
|
| 64 |
+
}
|
classifier.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"backbone": "facebook/EUPE-ViT-B",
|
| 3 |
+
"feature_dim": 768,
|
| 4 |
+
"input_resolution": 768,
|
| 5 |
+
"patch_size": 16,
|
| 6 |
+
"patch_grid": [48, 48],
|
| 7 |
+
"preprocessing": "layernorm over 768 channels then max-pool over 2304 patches",
|
| 8 |
+
"pos_dims": [48, 525, 475, 645, 273, 292, 158, 510, 506, 337, 8, 309, 267, 217, 79, 13, 657, 207, 722, 311],
|
| 9 |
+
"neg_dims": [642, 224, 113, 565, 49, 637, 45, 520, 219, 290, 529, 617, 269, 745, 576, 701, 105, 694, 82, 283],
|
| 10 |
+
"pos_weight": 1.0,
|
| 11 |
+
"neg_weight": -1.0,
|
| 12 |
+
"threshold": 25.284494400024414,
|
| 13 |
+
"decision": "sum(feat[pos_dims]) - sum(feat[neg_dims]) > threshold",
|
| 14 |
+
"free_parameters": 1,
|
| 15 |
+
"fixed_parameters": {
|
| 16 |
+
"dim_indices": 40,
|
| 17 |
+
"signs": 40
|
| 18 |
+
}
|
| 19 |
+
}
|
classifier.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:8bc146ba921a879f159952375ff485ebe5d6ef97af02b33a7699f629775e0392
|
| 3 |
+
size 676
|
classifier_tight_fpr.json
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"variant": "stage_0_tight_fpr",
|
| 3 |
+
"parent": "classifier.json",
|
| 4 |
+
"description": "Extended-negative-dims classifier tuned for low prop-FPR. Positive dims unchanged; negative dims extended with 15 prop-correlated dims discovered via YOLO-filtered ImageNet prop-only images. See discovery/prop_specificity.json.",
|
| 5 |
+
"backbone": "facebook/EUPE-ViT-B",
|
| 6 |
+
"feature_dim": 768,
|
| 7 |
+
"input_resolution": 768,
|
| 8 |
+
"patch_size": 16,
|
| 9 |
+
"patch_grid": [
|
| 10 |
+
48,
|
| 11 |
+
48
|
| 12 |
+
],
|
| 13 |
+
"preprocessing": "layernorm over 768 channels then max-pool over 2304 patches",
|
| 14 |
+
"pos_dims": [
|
| 15 |
+
48,
|
| 16 |
+
525,
|
| 17 |
+
475,
|
| 18 |
+
645,
|
| 19 |
+
273,
|
| 20 |
+
292,
|
| 21 |
+
158,
|
| 22 |
+
510,
|
| 23 |
+
506,
|
| 24 |
+
337,
|
| 25 |
+
8,
|
| 26 |
+
309,
|
| 27 |
+
267,
|
| 28 |
+
217,
|
| 29 |
+
79,
|
| 30 |
+
13,
|
| 31 |
+
657,
|
| 32 |
+
207,
|
| 33 |
+
722,
|
| 34 |
+
311
|
| 35 |
+
],
|
| 36 |
+
"neg_dims_original": [
|
| 37 |
+
642,
|
| 38 |
+
224,
|
| 39 |
+
113,
|
| 40 |
+
565,
|
| 41 |
+
49,
|
| 42 |
+
637,
|
| 43 |
+
45,
|
| 44 |
+
520,
|
| 45 |
+
219,
|
| 46 |
+
290,
|
| 47 |
+
529,
|
| 48 |
+
617,
|
| 49 |
+
269,
|
| 50 |
+
745,
|
| 51 |
+
576,
|
| 52 |
+
701,
|
| 53 |
+
105,
|
| 54 |
+
694,
|
| 55 |
+
82,
|
| 56 |
+
283
|
| 57 |
+
],
|
| 58 |
+
"neg_dims_extra": [
|
| 59 |
+
11,
|
| 60 |
+
697,
|
| 61 |
+
572,
|
| 62 |
+
671,
|
| 63 |
+
51,
|
| 64 |
+
186,
|
| 65 |
+
752,
|
| 66 |
+
90,
|
| 67 |
+
161,
|
| 68 |
+
310,
|
| 69 |
+
88,
|
| 70 |
+
189,
|
| 71 |
+
613,
|
| 72 |
+
201,
|
| 73 |
+
360
|
| 74 |
+
],
|
| 75 |
+
"neg_dims": [
|
| 76 |
+
642,
|
| 77 |
+
224,
|
| 78 |
+
113,
|
| 79 |
+
565,
|
| 80 |
+
49,
|
| 81 |
+
637,
|
| 82 |
+
45,
|
| 83 |
+
520,
|
| 84 |
+
219,
|
| 85 |
+
290,
|
| 86 |
+
529,
|
| 87 |
+
617,
|
| 88 |
+
269,
|
| 89 |
+
745,
|
| 90 |
+
576,
|
| 91 |
+
701,
|
| 92 |
+
105,
|
| 93 |
+
694,
|
| 94 |
+
82,
|
| 95 |
+
283,
|
| 96 |
+
11,
|
| 97 |
+
697,
|
| 98 |
+
572,
|
| 99 |
+
671,
|
| 100 |
+
51,
|
| 101 |
+
186,
|
| 102 |
+
752,
|
| 103 |
+
90,
|
| 104 |
+
161,
|
| 105 |
+
310,
|
| 106 |
+
88,
|
| 107 |
+
189,
|
| 108 |
+
613,
|
| 109 |
+
201,
|
| 110 |
+
360
|
| 111 |
+
],
|
| 112 |
+
"pos_weight": 1.0,
|
| 113 |
+
"neg_weight": -1.0,
|
| 114 |
+
"threshold": 10.094175338745117,
|
| 115 |
+
"decision": "sum(feat[pos_dims]) - sum(feat[neg_dims]) > threshold",
|
| 116 |
+
"free_parameters": 1,
|
| 117 |
+
"fixed_parameters": {
|
| 118 |
+
"dim_indices": 55,
|
| 119 |
+
"signs": 55
|
| 120 |
+
}
|
| 121 |
+
}
|
classifier_tight_fpr.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:477e75cd66877cb2066c1e7e9d858f6a598f65d75c387a16f9f5fd78feae7d7d
|
| 3 |
+
size 796
|
common/__init__.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Pooled features, ternary scoring, metrics, named pools, artifact contract."""
|
| 2 |
+
from .paths import BACKBONE, BACKBONE_SRC, COCO_ROOT, REPO, UPSTREAM_BACKBONE, device
|
| 3 |
+
from .data import (MEAN, STD, coco_split, image_paths, load_image, normalize,
|
| 4 |
+
person_labels)
|
| 5 |
+
from .features import D, RES, backbone_pooled, pool, score, score_pool
|
| 6 |
+
from .metrics import Metrics, f1_at, f1_sweep, prf1
|
| 7 |
+
from .pools import BALANCED_VAL, CALIB1000, POOLS, VAL500, VAL5000, Pool, by_name
|
| 8 |
+
from .pool import LoadedPool, balanced_indices, load_pool
|
| 9 |
+
from .artifacts import (REGISTRY, ArtifactSpec, provenance, read_artifact,
|
| 10 |
+
sha256_of, write_artifact)
|
| 11 |
+
|
| 12 |
+
__all__ = [
|
| 13 |
+
'BACKBONE', 'BACKBONE_SRC', 'COCO_ROOT', 'REPO', 'UPSTREAM_BACKBONE', 'device',
|
| 14 |
+
'MEAN', 'STD', 'coco_split', 'image_paths', 'load_image', 'normalize',
|
| 15 |
+
'person_labels',
|
| 16 |
+
'D', 'RES', 'backbone_pooled', 'pool', 'score', 'score_pool',
|
| 17 |
+
'Metrics', 'f1_at', 'f1_sweep', 'prf1',
|
| 18 |
+
'BALANCED_VAL', 'CALIB1000', 'POOLS', 'VAL500', 'VAL5000', 'Pool', 'by_name',
|
| 19 |
+
'LoadedPool', 'balanced_indices', 'load_pool',
|
| 20 |
+
'REGISTRY', 'ArtifactSpec', 'provenance', 'read_artifact', 'sha256_of',
|
| 21 |
+
'write_artifact',
|
| 22 |
+
]
|
common/artifacts.py
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Artifact provenance stamping and the generator/artifact registry."""
|
| 2 |
+
import hashlib
|
| 3 |
+
import json
|
| 4 |
+
from dataclasses import dataclass
|
| 5 |
+
from pathlib import Path
|
| 6 |
+
from typing import Optional, Tuple
|
| 7 |
+
|
| 8 |
+
from .paths import REPO
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
@dataclass(frozen=True)
|
| 12 |
+
class ArtifactSpec:
|
| 13 |
+
"""Owning script, source pool, and required top-level payload keys."""
|
| 14 |
+
|
| 15 |
+
generator: Optional[str]
|
| 16 |
+
pool: Optional[str]
|
| 17 |
+
payload_keys: Tuple[str, ...]
|
| 18 |
+
note: str = ''
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
NO_GENERATOR = 'discovery sweep not committed; no producer for this file in the repo'
|
| 22 |
+
|
| 23 |
+
REGISTRY = {
|
| 24 |
+
'eval.json': ArtifactSpec('verify.py', 'VAL5000', ('metrics',)),
|
| 25 |
+
'eval_tight_fpr.json': ArtifactSpec(
|
| 26 |
+
'verify.py', None,
|
| 27 |
+
('metrics', 'prop_false_positive_rate', 'baseline')),
|
| 28 |
+
'discovery/dim_selection.json': ArtifactSpec(None, None, (), NO_GENERATOR),
|
| 29 |
+
'discovery/dim48_characterization.json': ArtifactSpec(None, None, (), NO_GENERATOR),
|
| 30 |
+
'discovery/prop_specificity.json': ArtifactSpec(None, None, (), NO_GENERATOR),
|
| 31 |
+
'discovery/prop_image_manifest.json': ArtifactSpec(None, None, (), NO_GENERATOR),
|
| 32 |
+
'discovery/variant_leaderboard.json': ArtifactSpec(None, None, (), NO_GENERATOR),
|
| 33 |
+
'per_dim_thresholds.json': ArtifactSpec(
|
| 34 |
+
'calibrate.py', 'BALANCED_VAL',
|
| 35 |
+
('quant_scale', 'per_dim_thresholds', 'popcount', 'additive',
|
| 36 |
+
'F1_delta_popcount_vs_additive')),
|
| 37 |
+
'circuit.json': ArtifactSpec('synth.py', None, ('variants', 'accuracy')),
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
def sha256_of(path) -> str:
|
| 42 |
+
"""Content hash of a file."""
|
| 43 |
+
return hashlib.sha256(Path(path).read_bytes()).hexdigest()
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
def provenance(generator: str, classifier=None, pool_info: Optional[dict] = None,
|
| 47 |
+
**extra) -> dict:
|
| 48 |
+
"""Assemble a provenance block from repository-recoverable fields only."""
|
| 49 |
+
block = {'generator': generator}
|
| 50 |
+
if classifier is not None:
|
| 51 |
+
path = Path(classifier)
|
| 52 |
+
block['classifier'] = str(path.resolve().relative_to(REPO)).replace('\\', '/')
|
| 53 |
+
block['classifier_sha256'] = sha256_of(path)
|
| 54 |
+
if pool_info:
|
| 55 |
+
block.update(pool_info)
|
| 56 |
+
block.update(extra)
|
| 57 |
+
return block
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
def write_artifact(path, payload: dict, *, generator: str, classifier=None,
|
| 61 |
+
pool_info: Optional[dict] = None, compact: bool = False, **extra):
|
| 62 |
+
"""Write `payload` beneath a provenance block and return the document."""
|
| 63 |
+
doc = {'provenance': provenance(generator, classifier, pool_info, **extra)}
|
| 64 |
+
doc.update(payload)
|
| 65 |
+
sep = (',', ':') if compact else None
|
| 66 |
+
text = json.dumps(doc, indent=None if compact else 2, separators=sep)
|
| 67 |
+
Path(path).write_text(text + ('' if compact else '\n'), encoding='utf-8')
|
| 68 |
+
return doc
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
def read_artifact(path) -> dict:
|
| 72 |
+
return json.loads(Path(path).read_text(encoding='utf-8'))
|
common/data.py
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""COCO loading and input normalization.
|
| 2 |
+
|
| 3 |
+
Images are resized to a square `resolution` with bilinear interpolation and
|
| 4 |
+
normalized with ImageNet statistics, matching the protocol every stage was
|
| 5 |
+
measured under.
|
| 6 |
+
"""
|
| 7 |
+
from pathlib import Path
|
| 8 |
+
from typing import Iterable, List, Sequence, Tuple, Union
|
| 9 |
+
|
| 10 |
+
import numpy as np
|
| 11 |
+
import torch
|
| 12 |
+
from PIL import Image
|
| 13 |
+
|
| 14 |
+
from .paths import COCO_ROOT
|
| 15 |
+
|
| 16 |
+
MEAN = (0.485, 0.456, 0.406)
|
| 17 |
+
STD = (0.229, 0.224, 0.225)
|
| 18 |
+
PERSON_CATEGORY_ID = 1
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def _stats(device: str) -> Tuple[torch.Tensor, torch.Tensor]:
|
| 22 |
+
mean = torch.tensor(MEAN).view(1, 3, 1, 1).to(device)
|
| 23 |
+
std = torch.tensor(STD).view(1, 3, 1, 1).to(device)
|
| 24 |
+
return mean, std
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def normalize(img: Image.Image, resolution: int, device: str) -> torch.Tensor:
|
| 28 |
+
"""PIL image -> (1, 3, R, R) normalized float tensor."""
|
| 29 |
+
img = img.convert('RGB').resize((resolution, resolution), Image.BILINEAR)
|
| 30 |
+
arr = np.asarray(img, dtype=np.uint8).copy()
|
| 31 |
+
x = torch.from_numpy(arr).permute(2, 0, 1).unsqueeze(0).to(device).float() / 255.0
|
| 32 |
+
mean, std = _stats(device)
|
| 33 |
+
return (x - mean) / std
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def load_image(image: Union[str, Path, Image.Image, np.ndarray, torch.Tensor],
|
| 37 |
+
resolution: int, device: str) -> torch.Tensor:
|
| 38 |
+
"""Accept a path, PIL image, HWC array, or CHW tensor; return a batch of 1."""
|
| 39 |
+
if isinstance(image, (str, Path)):
|
| 40 |
+
img = Image.open(image)
|
| 41 |
+
elif isinstance(image, Image.Image):
|
| 42 |
+
img = image
|
| 43 |
+
elif isinstance(image, np.ndarray):
|
| 44 |
+
img = Image.fromarray(image)
|
| 45 |
+
elif isinstance(image, torch.Tensor):
|
| 46 |
+
arr = image.cpu().numpy() if image.ndim == 3 else image[0].cpu().numpy()
|
| 47 |
+
if arr.shape[0] == 3:
|
| 48 |
+
arr = arr.transpose(1, 2, 0)
|
| 49 |
+
img = Image.fromarray((arr * 255).astype('uint8'))
|
| 50 |
+
else:
|
| 51 |
+
raise TypeError(f'unsupported image type: {type(image)}')
|
| 52 |
+
return normalize(img, resolution, device)
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
def coco_split(split: str = 'val2017'):
|
| 56 |
+
"""Return (COCO handle, image-file lookup) for a COCO split."""
|
| 57 |
+
from pycocotools.coco import COCO
|
| 58 |
+
coco = COCO(str(COCO_ROOT / 'annotations' / f'instances_{split}.json'))
|
| 59 |
+
id_to_file = {i['id']: i['file_name'] for i in coco.loadImgs(coco.getImgIds())}
|
| 60 |
+
return coco, id_to_file
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
def person_labels(coco, img_ids: Sequence[int], device: str = 'cpu') -> torch.Tensor:
|
| 64 |
+
"""Image-level person presence for each id, as a bool tensor."""
|
| 65 |
+
labels = [
|
| 66 |
+
any(a['category_id'] == PERSON_CATEGORY_ID
|
| 67 |
+
for a in coco.loadAnns(coco.getAnnIds(imgIds=i, iscrowd=False)))
|
| 68 |
+
for i in img_ids
|
| 69 |
+
]
|
| 70 |
+
return torch.tensor(labels, dtype=torch.bool, device=device)
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
def image_paths(id_to_file: dict, img_ids: Iterable[int],
|
| 74 |
+
split: str = 'val2017') -> List[Path]:
|
| 75 |
+
"""Absolute paths for a sequence of image ids within a split."""
|
| 76 |
+
root = COCO_ROOT / split
|
| 77 |
+
return [root / id_to_file[i] for i in img_ids]
|
common/features.py
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Pooled feature extraction and the ternary scoring rule.
|
| 2 |
+
|
| 3 |
+
The classifier reads one 768-D vector per image: layernorm across the 768
|
| 4 |
+
channels of every patch token, then max-pool across the 2304 patches. Score is
|
| 5 |
+
the sum of the person-positive dims minus the sum of the person-negative dims.
|
| 6 |
+
"""
|
| 7 |
+
from typing import Optional, Sequence
|
| 8 |
+
|
| 9 |
+
import torch
|
| 10 |
+
import torch.nn.functional as F
|
| 11 |
+
|
| 12 |
+
D = 768
|
| 13 |
+
RES = 768
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def pool(patch_tokens: torch.Tensor) -> torch.Tensor:
|
| 17 |
+
"""(N, D) or (B, N, D) patch tokens -> (D,) or (B, D) pooled vector."""
|
| 18 |
+
ln = F.layer_norm(patch_tokens.float(), [D])
|
| 19 |
+
return ln.max(dim=-2).values
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
@torch.inference_mode()
|
| 23 |
+
def backbone_pooled(backbone, x: torch.Tensor, autocast: bool = True) -> torch.Tensor:
|
| 24 |
+
"""Forward a normalized batch through the backbone and pool it."""
|
| 25 |
+
if autocast:
|
| 26 |
+
dev = 'cuda' if x.is_cuda else 'cpu'
|
| 27 |
+
with torch.autocast(dev, dtype=torch.bfloat16):
|
| 28 |
+
out = backbone.forward_features(x)
|
| 29 |
+
else:
|
| 30 |
+
out = backbone.forward_features(x)
|
| 31 |
+
return pool(out['x_norm_patchtokens'].float())
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def score(pooled: torch.Tensor, pos: Sequence[int], neg: Sequence[int]) -> torch.Tensor:
|
| 35 |
+
"""sum(pooled[pos]) - sum(pooled[neg]), over the last axis."""
|
| 36 |
+
if not torch.is_tensor(pos):
|
| 37 |
+
pos = torch.tensor(list(pos), dtype=torch.long, device=pooled.device)
|
| 38 |
+
if not torch.is_tensor(neg):
|
| 39 |
+
neg = torch.tensor(list(neg), dtype=torch.long, device=pooled.device)
|
| 40 |
+
return pooled.index_select(-1, pos).sum(-1) - pooled.index_select(-1, neg).sum(-1)
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
def score_pool(backbone, loaded, pos, neg, target_dims: Optional[torch.Tensor] = None):
|
| 44 |
+
"""Score a pool; with `target_dims`, also return the pooled activations there."""
|
| 45 |
+
scores, targets = [], []
|
| 46 |
+
for x in loaded:
|
| 47 |
+
pooled = backbone_pooled(backbone, x)[0]
|
| 48 |
+
scores.append(score(pooled, pos, neg))
|
| 49 |
+
if target_dims is not None:
|
| 50 |
+
targets.append(pooled[target_dims])
|
| 51 |
+
stacked = torch.stack(scores)
|
| 52 |
+
return (stacked, torch.stack(targets)) if target_dims is not None else (stacked, None)
|
common/metrics.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Binary classification metrics, single-sourced so every stage scores identically."""
|
| 2 |
+
from typing import NamedTuple
|
| 3 |
+
|
| 4 |
+
import torch
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
class Metrics(NamedTuple):
|
| 8 |
+
"""F1, precision, recall, and the threshold they were measured at."""
|
| 9 |
+
|
| 10 |
+
f1: float
|
| 11 |
+
precision: float
|
| 12 |
+
recall: float
|
| 13 |
+
threshold: float = float('nan')
|
| 14 |
+
|
| 15 |
+
def asdict(self) -> dict:
|
| 16 |
+
d = {'F1': self.f1, 'precision': self.precision, 'recall': self.recall}
|
| 17 |
+
if self.threshold == self.threshold: # excludes NaN
|
| 18 |
+
d['threshold'] = self.threshold
|
| 19 |
+
return d
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def prf1(pred: torch.Tensor, labels: torch.Tensor) -> Metrics:
|
| 23 |
+
"""Metrics for boolean prediction and label tensors."""
|
| 24 |
+
tp = (pred & labels).sum().float()
|
| 25 |
+
fp = (pred & ~labels).sum().float()
|
| 26 |
+
fn = (~pred & labels).sum().float()
|
| 27 |
+
precision = tp / (tp + fp).clamp(min=1)
|
| 28 |
+
recall = tp / (tp + fn).clamp(min=1)
|
| 29 |
+
f1 = 2 * precision * recall / (precision + recall).clamp(min=1e-9)
|
| 30 |
+
return Metrics(float(f1), float(precision), float(recall))
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def f1_at(scores: torch.Tensor, labels: torch.Tensor, threshold: float) -> Metrics:
|
| 34 |
+
"""Metrics at a fixed threshold."""
|
| 35 |
+
return prf1(scores > threshold, labels)._replace(threshold=float(threshold))
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def f1_sweep(scores: torch.Tensor, labels: torch.Tensor, n_candidates: int = 500) -> Metrics:
|
| 39 |
+
"""Best metrics over candidate thresholds drawn evenly from the sorted unique scores."""
|
| 40 |
+
uniq = torch.unique(scores).sort().values
|
| 41 |
+
stride = max(1, len(uniq) // n_candidates)
|
| 42 |
+
best = Metrics(0.0, 0.0, 0.0, 0.0)
|
| 43 |
+
for t in uniq.tolist()[::stride]:
|
| 44 |
+
m = prf1(scores > t, labels)
|
| 45 |
+
if m.f1 > best.f1:
|
| 46 |
+
best = m._replace(threshold=float(t))
|
| 47 |
+
return best
|
common/models.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Backbone loading."""
|
| 2 |
+
import sys
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
from typing import Optional
|
| 5 |
+
|
| 6 |
+
from .paths import BACKBONE, BACKBONE_SRC
|
| 7 |
+
|
| 8 |
+
_argus = None
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
def argus_module():
|
| 12 |
+
"""Import argus.py from the environment, BACKBONE_SRC, or the backbone repo."""
|
| 13 |
+
global _argus
|
| 14 |
+
if _argus is not None:
|
| 15 |
+
return _argus
|
| 16 |
+
try:
|
| 17 |
+
import argus
|
| 18 |
+
except ImportError:
|
| 19 |
+
if BACKBONE_SRC:
|
| 20 |
+
sys.path.insert(0, str(BACKBONE_SRC))
|
| 21 |
+
else:
|
| 22 |
+
from huggingface_hub import hf_hub_download
|
| 23 |
+
sys.path.insert(0, str(Path(hf_hub_download(BACKBONE, 'argus.py')).parent))
|
| 24 |
+
import argus
|
| 25 |
+
_argus = argus
|
| 26 |
+
return argus
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def load_backbone(repo: Optional[str] = None):
|
| 30 |
+
"""Load the stock backbone in eval mode."""
|
| 31 |
+
from transformers import AutoModel
|
| 32 |
+
return AutoModel.from_pretrained(repo or BACKBONE, trust_remote_code=True).eval().backbone
|
common/paths.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Filesystem and repository locations, overridable by environment.
|
| 2 |
+
|
| 3 |
+
BACKBONE HF repo id or local path for the backbone wrapper (alias: ARGUS_PATH)
|
| 4 |
+
BACKBONE_SRC local directory supplying argus.py (alias: ARGUS_SRC)
|
| 5 |
+
COCO_ROOT dataset root holding annotations/, train2017/, val2017/
|
| 6 |
+
DEVICE torch device string
|
| 7 |
+
"""
|
| 8 |
+
import os
|
| 9 |
+
from pathlib import Path
|
| 10 |
+
|
| 11 |
+
REPO = Path(__file__).resolve().parent.parent
|
| 12 |
+
|
| 13 |
+
UPSTREAM_BACKBONE = 'facebook/EUPE-ViT-B'
|
| 14 |
+
BACKBONE = os.environ.get('BACKBONE') or os.environ.get('ARGUS_PATH') or 'phanerozoic/argus'
|
| 15 |
+
BACKBONE_SRC = os.environ.get('BACKBONE_SRC') or os.environ.get('ARGUS_SRC') or None
|
| 16 |
+
COCO_ROOT = Path(os.environ.get('COCO_ROOT', '/home/zootest/datasets/coco'))
|
| 17 |
+
|
| 18 |
+
ARGUS = BACKBONE
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def device() -> str:
|
| 22 |
+
if 'DEVICE' in os.environ:
|
| 23 |
+
return os.environ['DEVICE']
|
| 24 |
+
import torch
|
| 25 |
+
return 'cuda' if torch.cuda.is_available() else 'cpu'
|
common/pool.py
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Evaluation-pool loading."""
|
| 2 |
+
from dataclasses import dataclass
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
from typing import Iterator, List, Optional
|
| 5 |
+
|
| 6 |
+
import torch
|
| 7 |
+
from PIL import Image
|
| 8 |
+
|
| 9 |
+
from .data import coco_split, image_paths, normalize, person_labels
|
| 10 |
+
from .features import RES
|
| 11 |
+
from .pools import Pool
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
@dataclass
|
| 15 |
+
class LoadedPool:
|
| 16 |
+
"""Image ids, paths and labels for one named pool, images optionally resident."""
|
| 17 |
+
|
| 18 |
+
pool: Pool
|
| 19 |
+
img_ids: List[int]
|
| 20 |
+
paths: List[Path]
|
| 21 |
+
labels: torch.Tensor
|
| 22 |
+
device: str
|
| 23 |
+
images: Optional[List[torch.Tensor]] = None
|
| 24 |
+
|
| 25 |
+
def __len__(self) -> int:
|
| 26 |
+
return len(self.img_ids)
|
| 27 |
+
|
| 28 |
+
def __iter__(self) -> Iterator[torch.Tensor]:
|
| 29 |
+
"""Yield each image as a normalized (1, 3, RES, RES) tensor."""
|
| 30 |
+
if self.images is not None:
|
| 31 |
+
yield from self.images
|
| 32 |
+
return
|
| 33 |
+
for path in self.paths:
|
| 34 |
+
yield normalize(Image.open(path), RES, self.device)
|
| 35 |
+
|
| 36 |
+
@property
|
| 37 |
+
def positive_rate(self) -> float:
|
| 38 |
+
return round(self.labels.float().mean().item(), 4)
|
| 39 |
+
|
| 40 |
+
def provenance(self) -> dict:
|
| 41 |
+
"""Pool fields recorded in an artifact's provenance block."""
|
| 42 |
+
return {'pool': self.pool.name, 'split': self.pool.split,
|
| 43 |
+
'n_images': len(self), 'positive_rate': self.positive_rate,
|
| 44 |
+
'selection': self.pool.selection}
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
def balanced_indices(labels: torch.Tensor, seed: int = 0) -> torch.Tensor:
|
| 48 |
+
"""Indices subsampling `labels` to equal positive and negative counts, seeded."""
|
| 49 |
+
generator = torch.Generator(device='cpu').manual_seed(seed)
|
| 50 |
+
cpu = labels.cpu()
|
| 51 |
+
pos = cpu.nonzero(as_tuple=True)[0]
|
| 52 |
+
neg = (~cpu).nonzero(as_tuple=True)[0]
|
| 53 |
+
n = min(len(pos), len(neg))
|
| 54 |
+
sel = torch.cat([pos[torch.randperm(len(pos), generator=generator)[:n]],
|
| 55 |
+
neg[torch.randperm(len(neg), generator=generator)[:n]]])
|
| 56 |
+
return sel[torch.randperm(len(sel), generator=generator)]
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
def load_pool(pool: Pool, device: str, preload: bool = False, seed: int = 0) -> LoadedPool:
|
| 60 |
+
"""Resolve a named pool to ids, paths and labels; `preload` holds images in memory."""
|
| 61 |
+
coco, id_to_file = coco_split(pool.split)
|
| 62 |
+
img_ids = sorted(coco.getImgIds())
|
| 63 |
+
if pool.n is not None:
|
| 64 |
+
img_ids = img_ids[:pool.n]
|
| 65 |
+
labels = person_labels(coco, img_ids, device)
|
| 66 |
+
if pool.balanced:
|
| 67 |
+
sel = balanced_indices(labels, seed)
|
| 68 |
+
img_ids = [img_ids[i] for i in sel.tolist()]
|
| 69 |
+
labels = labels[sel.to(labels.device)]
|
| 70 |
+
paths = image_paths(id_to_file, img_ids, pool.split)
|
| 71 |
+
images = [normalize(Image.open(p), RES, device) for p in paths] if preload else None
|
| 72 |
+
return LoadedPool(pool, img_ids, paths, labels, device, images)
|
common/pools.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Named evaluation pools, cited by name in every artifact's provenance block."""
|
| 2 |
+
from typing import NamedTuple, Optional
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
class Pool(NamedTuple):
|
| 6 |
+
name: str
|
| 7 |
+
split: str
|
| 8 |
+
n: Optional[int]
|
| 9 |
+
balanced: bool
|
| 10 |
+
selection: str
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
VAL5000 = Pool(
|
| 14 |
+
'VAL5000', 'val2017', 5000, False,
|
| 15 |
+
'the first 5000 val2017 image ids in sorted order, which is the whole split')
|
| 16 |
+
|
| 17 |
+
CALIB1000 = Pool(
|
| 18 |
+
'CALIB1000', 'val2017', 1000, False,
|
| 19 |
+
'the first 1000 val2017 image ids in sorted order')
|
| 20 |
+
|
| 21 |
+
VAL500 = Pool(
|
| 22 |
+
'VAL500', 'val2017', 500, False,
|
| 23 |
+
'the first 500 val2017 image ids in sorted order')
|
| 24 |
+
|
| 25 |
+
BALANCED_VAL = Pool(
|
| 26 |
+
'BALANCED_VAL', 'val2017', None, True,
|
| 27 |
+
'val2017 subsampled without replacement to equal person-positive and '
|
| 28 |
+
'person-negative counts')
|
| 29 |
+
|
| 30 |
+
POOLS = {p.name: p for p in (VAL5000, CALIB1000, VAL500, BALANCED_VAL)}
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def by_name(name: str) -> Pool:
|
| 34 |
+
if name not in POOLS:
|
| 35 |
+
raise ValueError(f'unknown pool {name!r}; expected one of {sorted(POOLS)}')
|
| 36 |
+
return POOLS[name]
|
discovery/dim48_characterization.json
ADDED
|
@@ -0,0 +1,546 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"provenance": {
|
| 3 |
+
"generator": null,
|
| 4 |
+
"note": "discovery sweep not committed; no producer in the repo"
|
| 5 |
+
},
|
| 6 |
+
"target_dim": 48,
|
| 7 |
+
"A_f1_vs_k": [
|
| 8 |
+
{
|
| 9 |
+
"K": 1,
|
| 10 |
+
"F1": 0.8285356163978577,
|
| 11 |
+
"precision": 0.7985524535179138,
|
| 12 |
+
"recall": 0.8608582615852356,
|
| 13 |
+
"dims": [
|
| 14 |
+
48
|
| 15 |
+
]
|
| 16 |
+
},
|
| 17 |
+
{
|
| 18 |
+
"K": 2,
|
| 19 |
+
"F1": 0.8562204241752625,
|
| 20 |
+
"precision": 0.8503633737564087,
|
| 21 |
+
"recall": 0.8621586561203003,
|
| 22 |
+
"dims": [
|
| 23 |
+
48,
|
| 24 |
+
525
|
| 25 |
+
]
|
| 26 |
+
},
|
| 27 |
+
{
|
| 28 |
+
"K": 3,
|
| 29 |
+
"F1": 0.8652572631835938,
|
| 30 |
+
"precision": 0.8526936173439026,
|
| 31 |
+
"recall": 0.8781967759132385,
|
| 32 |
+
"dims": [
|
| 33 |
+
48,
|
| 34 |
+
525,
|
| 35 |
+
475
|
| 36 |
+
]
|
| 37 |
+
},
|
| 38 |
+
{
|
| 39 |
+
"K": 5,
|
| 40 |
+
"F1": 0.8649698495864868,
|
| 41 |
+
"precision": 0.8608844876289368,
|
| 42 |
+
"recall": 0.8690940737724304,
|
| 43 |
+
"dims": [
|
| 44 |
+
48,
|
| 45 |
+
525,
|
| 46 |
+
475,
|
| 47 |
+
323,
|
| 48 |
+
240
|
| 49 |
+
]
|
| 50 |
+
},
|
| 51 |
+
{
|
| 52 |
+
"K": 10,
|
| 53 |
+
"F1": 0.9092138409614563,
|
| 54 |
+
"precision": 0.9465290904045105,
|
| 55 |
+
"recall": 0.8747290968894958,
|
| 56 |
+
"dims": [
|
| 57 |
+
48,
|
| 58 |
+
525,
|
| 59 |
+
475,
|
| 60 |
+
323,
|
| 61 |
+
240,
|
| 62 |
+
"..."
|
| 63 |
+
]
|
| 64 |
+
},
|
| 65 |
+
{
|
| 66 |
+
"K": 20,
|
| 67 |
+
"F1": 0.9288457632064819,
|
| 68 |
+
"precision": 0.9698113203048706,
|
| 69 |
+
"recall": 0.8912007212638855,
|
| 70 |
+
"dims": [
|
| 71 |
+
48,
|
| 72 |
+
525,
|
| 73 |
+
475,
|
| 74 |
+
323,
|
| 75 |
+
240,
|
| 76 |
+
"..."
|
| 77 |
+
]
|
| 78 |
+
},
|
| 79 |
+
{
|
| 80 |
+
"K": 30,
|
| 81 |
+
"F1": 0.9349648356437683,
|
| 82 |
+
"precision": 0.9795821309089661,
|
| 83 |
+
"recall": 0.8942349553108215,
|
| 84 |
+
"dims": [
|
| 85 |
+
48,
|
| 86 |
+
525,
|
| 87 |
+
475,
|
| 88 |
+
323,
|
| 89 |
+
240,
|
| 90 |
+
"..."
|
| 91 |
+
]
|
| 92 |
+
},
|
| 93 |
+
{
|
| 94 |
+
"K": 50,
|
| 95 |
+
"F1": 0.9407240152359009,
|
| 96 |
+
"precision": 0.9839091300964355,
|
| 97 |
+
"recall": 0.9011703729629517,
|
| 98 |
+
"dims": [
|
| 99 |
+
48,
|
| 100 |
+
525,
|
| 101 |
+
475,
|
| 102 |
+
323,
|
| 103 |
+
240,
|
| 104 |
+
"..."
|
| 105 |
+
]
|
| 106 |
+
},
|
| 107 |
+
{
|
| 108 |
+
"K": 92,
|
| 109 |
+
"F1": 0.9444695711135864,
|
| 110 |
+
"precision": 0.98539799451828,
|
| 111 |
+
"recall": 0.9068053960800171,
|
| 112 |
+
"dims": [
|
| 113 |
+
48,
|
| 114 |
+
525,
|
| 115 |
+
475,
|
| 116 |
+
323,
|
| 117 |
+
240,
|
| 118 |
+
"..."
|
| 119 |
+
]
|
| 120 |
+
},
|
| 121 |
+
{
|
| 122 |
+
"K": 184,
|
| 123 |
+
"F1": 0.9485046863555908,
|
| 124 |
+
"precision": 0.9855140447616577,
|
| 125 |
+
"recall": 0.9141742587089539,
|
| 126 |
+
"dims": [
|
| 127 |
+
48,
|
| 128 |
+
525,
|
| 129 |
+
475,
|
| 130 |
+
323,
|
| 131 |
+
240,
|
| 132 |
+
"..."
|
| 133 |
+
]
|
| 134 |
+
}
|
| 135 |
+
],
|
| 136 |
+
"B_dim48_distribution": {
|
| 137 |
+
"person_pos": {
|
| 138 |
+
"n": 2693,
|
| 139 |
+
"mean": 8.113646507263184,
|
| 140 |
+
"std": 2.3924715518951416,
|
| 141 |
+
"min": -1.2812166213989258,
|
| 142 |
+
"p25": 7.193147659301758,
|
| 143 |
+
"p50": 8.808687210083008,
|
| 144 |
+
"p75": 9.730491638183594,
|
| 145 |
+
"max": 12.061566352844238
|
| 146 |
+
},
|
| 147 |
+
"person_neg": {
|
| 148 |
+
"n": 2307,
|
| 149 |
+
"mean": 2.982386589050293,
|
| 150 |
+
"std": 2.7675836086273193,
|
| 151 |
+
"min": -3.072082042694092,
|
| 152 |
+
"p25": 0.5744761228561401,
|
| 153 |
+
"p50": 3.059739589691162,
|
| 154 |
+
"p75": 5.2233123779296875,
|
| 155 |
+
"max": 11.300838470458984
|
| 156 |
+
},
|
| 157 |
+
"separation_cohen_d": 1.983604907989502
|
| 158 |
+
},
|
| 159 |
+
"C_per_class_top15": [
|
| 160 |
+
{
|
| 161 |
+
"class": "person",
|
| 162 |
+
"cat_id": 1,
|
| 163 |
+
"n_imgs": 2693,
|
| 164 |
+
"dim48_mean_inclass": 8.1136474609375,
|
| 165 |
+
"dim48_mean_outclass": 2.982386350631714,
|
| 166 |
+
"delta": 5.131261110305786
|
| 167 |
+
},
|
| 168 |
+
{
|
| 169 |
+
"class": "tennis racket",
|
| 170 |
+
"cat_id": 43,
|
| 171 |
+
"n_imgs": 167,
|
| 172 |
+
"dim48_mean_inclass": 9.163715362548828,
|
| 173 |
+
"dim48_mean_outclass": 5.627990245819092,
|
| 174 |
+
"delta": 3.5357251167297363
|
| 175 |
+
},
|
| 176 |
+
{
|
| 177 |
+
"class": "tie",
|
| 178 |
+
"cat_id": 32,
|
| 179 |
+
"n_imgs": 145,
|
| 180 |
+
"dim48_mean_inclass": 8.980120658874512,
|
| 181 |
+
"dim48_mean_outclass": 5.6494951248168945,
|
| 182 |
+
"delta": 3.330625534057617
|
| 183 |
+
},
|
| 184 |
+
{
|
| 185 |
+
"class": "baseball glove",
|
| 186 |
+
"cat_id": 40,
|
| 187 |
+
"n_imgs": 100,
|
| 188 |
+
"dim48_mean_inclass": 8.982823371887207,
|
| 189 |
+
"dim48_mean_outclass": 5.680027008056641,
|
| 190 |
+
"delta": 3.3027963638305664
|
| 191 |
+
},
|
| 192 |
+
{
|
| 193 |
+
"class": "skateboard",
|
| 194 |
+
"cat_id": 41,
|
| 195 |
+
"n_imgs": 127,
|
| 196 |
+
"dim48_mean_inclass": 8.923754692077637,
|
| 197 |
+
"dim48_mean_outclass": 5.663267135620117,
|
| 198 |
+
"delta": 3.2604875564575195
|
| 199 |
+
},
|
| 200 |
+
{
|
| 201 |
+
"class": "baseball bat",
|
| 202 |
+
"cat_id": 39,
|
| 203 |
+
"n_imgs": 97,
|
| 204 |
+
"dim48_mean_inclass": 8.886703491210938,
|
| 205 |
+
"dim48_mean_outclass": 5.683949947357178,
|
| 206 |
+
"delta": 3.2027535438537598
|
| 207 |
+
},
|
| 208 |
+
{
|
| 209 |
+
"class": "backpack",
|
| 210 |
+
"cat_id": 27,
|
| 211 |
+
"n_imgs": 228,
|
| 212 |
+
"dim48_mean_inclass": 8.655838012695312,
|
| 213 |
+
"dim48_mean_outclass": 5.607059001922607,
|
| 214 |
+
"delta": 3.048779010772705
|
| 215 |
+
},
|
| 216 |
+
{
|
| 217 |
+
"class": "remote",
|
| 218 |
+
"cat_id": 75,
|
| 219 |
+
"n_imgs": 145,
|
| 220 |
+
"dim48_mean_inclass": 8.703699111938477,
|
| 221 |
+
"dim48_mean_outclass": 5.657751083374023,
|
| 222 |
+
"delta": 3.045948028564453
|
| 223 |
+
},
|
| 224 |
+
{
|
| 225 |
+
"class": "toothbrush",
|
| 226 |
+
"cat_id": 90,
|
| 227 |
+
"n_imgs": 34,
|
| 228 |
+
"dim48_mean_inclass": 8.746152877807617,
|
| 229 |
+
"dim48_mean_outclass": 5.725543022155762,
|
| 230 |
+
"delta": 3.0206098556518555
|
| 231 |
+
},
|
| 232 |
+
{
|
| 233 |
+
"class": "handbag",
|
| 234 |
+
"cat_id": 31,
|
| 235 |
+
"n_imgs": 292,
|
| 236 |
+
"dim48_mean_inclass": 8.576542854309082,
|
| 237 |
+
"dim48_mean_outclass": 5.570532321929932,
|
| 238 |
+
"delta": 3.0060105323791504
|
| 239 |
+
},
|
| 240 |
+
{
|
| 241 |
+
"class": "sports ball",
|
| 242 |
+
"cat_id": 37,
|
| 243 |
+
"n_imgs": 169,
|
| 244 |
+
"dim48_mean_inclass": 8.645074844360352,
|
| 245 |
+
"dim48_mean_outclass": 5.644669532775879,
|
| 246 |
+
"delta": 3.0004053115844727
|
| 247 |
+
},
|
| 248 |
+
{
|
| 249 |
+
"class": "hair drier",
|
| 250 |
+
"cat_id": 89,
|
| 251 |
+
"n_imgs": 9,
|
| 252 |
+
"dim48_mean_inclass": 8.637924194335938,
|
| 253 |
+
"dim48_mean_outclass": 5.74086856842041,
|
| 254 |
+
"delta": 2.8970556259155273
|
| 255 |
+
},
|
| 256 |
+
{
|
| 257 |
+
"class": "skis",
|
| 258 |
+
"cat_id": 35,
|
| 259 |
+
"n_imgs": 120,
|
| 260 |
+
"dim48_mean_inclass": 8.562700271606445,
|
| 261 |
+
"dim48_mean_outclass": 5.676822185516357,
|
| 262 |
+
"delta": 2.885878086090088
|
| 263 |
+
},
|
| 264 |
+
{
|
| 265 |
+
"class": "cell phone",
|
| 266 |
+
"cat_id": 77,
|
| 267 |
+
"n_imgs": 214,
|
| 268 |
+
"dim48_mean_inclass": 8.483532905578613,
|
| 269 |
+
"dim48_mean_outclass": 5.623681545257568,
|
| 270 |
+
"delta": 2.859851360321045
|
| 271 |
+
},
|
| 272 |
+
{
|
| 273 |
+
"class": "snowboard",
|
| 274 |
+
"cat_id": 36,
|
| 275 |
+
"n_imgs": 49,
|
| 276 |
+
"dim48_mean_inclass": 8.451048851013184,
|
| 277 |
+
"dim48_mean_outclass": 5.71931266784668,
|
| 278 |
+
"delta": 2.731736183166504
|
| 279 |
+
}
|
| 280 |
+
],
|
| 281 |
+
"C_per_class_bottom15": [
|
| 282 |
+
{
|
| 283 |
+
"class": "traffic light",
|
| 284 |
+
"cat_id": 10,
|
| 285 |
+
"n_imgs": 191,
|
| 286 |
+
"dim48_mean_inclass": 4.146858215332031,
|
| 287 |
+
"dim48_mean_outclass": 5.809599876403809,
|
| 288 |
+
"delta": -1.6627416610717773
|
| 289 |
+
},
|
| 290 |
+
{
|
| 291 |
+
"class": "boat",
|
| 292 |
+
"cat_id": 9,
|
| 293 |
+
"n_imgs": 121,
|
| 294 |
+
"dim48_mean_inclass": 4.040976047515869,
|
| 295 |
+
"dim48_mean_outclass": 5.788370132446289,
|
| 296 |
+
"delta": -1.74739408493042
|
| 297 |
+
},
|
| 298 |
+
{
|
| 299 |
+
"class": "fire hydrant",
|
| 300 |
+
"cat_id": 11,
|
| 301 |
+
"n_imgs": 86,
|
| 302 |
+
"dim48_mean_inclass": 3.6824471950531006,
|
| 303 |
+
"dim48_mean_outclass": 5.782199382781982,
|
| 304 |
+
"delta": -2.099752187728882
|
| 305 |
+
},
|
| 306 |
+
{
|
| 307 |
+
"class": "clock",
|
| 308 |
+
"cat_id": 85,
|
| 309 |
+
"n_imgs": 204,
|
| 310 |
+
"dim48_mean_inclass": 3.664764642715454,
|
| 311 |
+
"dim48_mean_outclass": 5.83461332321167,
|
| 312 |
+
"delta": -2.169848680496216
|
| 313 |
+
},
|
| 314 |
+
{
|
| 315 |
+
"class": "train",
|
| 316 |
+
"cat_id": 7,
|
| 317 |
+
"n_imgs": 157,
|
| 318 |
+
"dim48_mean_inclass": 3.4102745056152344,
|
| 319 |
+
"dim48_mean_outclass": 5.821805477142334,
|
| 320 |
+
"delta": -2.4115309715270996
|
| 321 |
+
},
|
| 322 |
+
{
|
| 323 |
+
"class": "sheep",
|
| 324 |
+
"cat_id": 20,
|
| 325 |
+
"n_imgs": 65,
|
| 326 |
+
"dim48_mean_inclass": 3.174736261367798,
|
| 327 |
+
"dim48_mean_outclass": 5.779951095581055,
|
| 328 |
+
"delta": -2.605214834213257
|
| 329 |
+
},
|
| 330 |
+
{
|
| 331 |
+
"class": "elephant",
|
| 332 |
+
"cat_id": 22,
|
| 333 |
+
"n_imgs": 89,
|
| 334 |
+
"dim48_mean_inclass": 3.023428201675415,
|
| 335 |
+
"dim48_mean_outclass": 5.795424938201904,
|
| 336 |
+
"delta": -2.7719967365264893
|
| 337 |
+
},
|
| 338 |
+
{
|
| 339 |
+
"class": "parking meter",
|
| 340 |
+
"cat_id": 14,
|
| 341 |
+
"n_imgs": 37,
|
| 342 |
+
"dim48_mean_inclass": 2.688075065612793,
|
| 343 |
+
"dim48_mean_outclass": 5.768880844116211,
|
| 344 |
+
"delta": -3.080805778503418
|
| 345 |
+
},
|
| 346 |
+
{
|
| 347 |
+
"class": "airplane",
|
| 348 |
+
"cat_id": 5,
|
| 349 |
+
"n_imgs": 97,
|
| 350 |
+
"dim48_mean_inclass": 2.6694958209991455,
|
| 351 |
+
"dim48_mean_outclass": 5.806950092315674,
|
| 352 |
+
"delta": -3.1374542713165283
|
| 353 |
+
},
|
| 354 |
+
{
|
| 355 |
+
"class": "stop sign",
|
| 356 |
+
"cat_id": 13,
|
| 357 |
+
"n_imgs": 69,
|
| 358 |
+
"dim48_mean_inclass": 2.509443998336792,
|
| 359 |
+
"dim48_mean_outclass": 5.7913737297058105,
|
| 360 |
+
"delta": -3.2819297313690186
|
| 361 |
+
},
|
| 362 |
+
{
|
| 363 |
+
"class": "cow",
|
| 364 |
+
"cat_id": 21,
|
| 365 |
+
"n_imgs": 87,
|
| 366 |
+
"dim48_mean_inclass": 2.1573596000671387,
|
| 367 |
+
"dim48_mean_outclass": 5.809632778167725,
|
| 368 |
+
"delta": -3.652273178100586
|
| 369 |
+
},
|
| 370 |
+
{
|
| 371 |
+
"class": "bird",
|
| 372 |
+
"cat_id": 16,
|
| 373 |
+
"n_imgs": 125,
|
| 374 |
+
"dim48_mean_inclass": 1.5200526714324951,
|
| 375 |
+
"dim48_mean_outclass": 5.854443073272705,
|
| 376 |
+
"delta": -4.33439040184021
|
| 377 |
+
},
|
| 378 |
+
{
|
| 379 |
+
"class": "giraffe",
|
| 380 |
+
"cat_id": 25,
|
| 381 |
+
"n_imgs": 101,
|
| 382 |
+
"dim48_mean_inclass": 0.5355944633483887,
|
| 383 |
+
"dim48_mean_outclass": 5.8535051345825195,
|
| 384 |
+
"delta": -5.317910671234131
|
| 385 |
+
},
|
| 386 |
+
{
|
| 387 |
+
"class": "zebra",
|
| 388 |
+
"cat_id": 24,
|
| 389 |
+
"n_imgs": 85,
|
| 390 |
+
"dim48_mean_inclass": 0.19826489686965942,
|
| 391 |
+
"dim48_mean_outclass": 5.842027187347412,
|
| 392 |
+
"delta": -5.643762290477753
|
| 393 |
+
},
|
| 394 |
+
{
|
| 395 |
+
"class": "bear",
|
| 396 |
+
"cat_id": 23,
|
| 397 |
+
"n_imgs": 49,
|
| 398 |
+
"dim48_mean_inclass": -0.3452981412410736,
|
| 399 |
+
"dim48_mean_outclass": 5.806369781494141,
|
| 400 |
+
"delta": -6.151667922735214
|
| 401 |
+
}
|
| 402 |
+
],
|
| 403 |
+
"D_top10_correlation": {
|
| 404 |
+
"dims": [
|
| 405 |
+
48,
|
| 406 |
+
525,
|
| 407 |
+
475,
|
| 408 |
+
323,
|
| 409 |
+
240,
|
| 410 |
+
637,
|
| 411 |
+
318,
|
| 412 |
+
472,
|
| 413 |
+
719,
|
| 414 |
+
251
|
| 415 |
+
],
|
| 416 |
+
"corr_matrix": [
|
| 417 |
+
[
|
| 418 |
+
1.000000238418579,
|
| 419 |
+
0.28202927112579346,
|
| 420 |
+
-0.03376583009958267,
|
| 421 |
+
0.24143743515014648,
|
| 422 |
+
-0.013180982321500778,
|
| 423 |
+
0.1519388109445572,
|
| 424 |
+
0.21512284874916077,
|
| 425 |
+
0.12231583148241043,
|
| 426 |
+
0.15586860477924347,
|
| 427 |
+
0.14881354570388794
|
| 428 |
+
],
|
| 429 |
+
[
|
| 430 |
+
0.28202927112579346,
|
| 431 |
+
0.9999998211860657,
|
| 432 |
+
0.2280241698026657,
|
| 433 |
+
0.08577030897140503,
|
| 434 |
+
0.20908223092556,
|
| 435 |
+
-0.09965874999761581,
|
| 436 |
+
0.2280401587486267,
|
| 437 |
+
0.08895031362771988,
|
| 438 |
+
0.2658396065235138,
|
| 439 |
+
-0.15059183537960052
|
| 440 |
+
],
|
| 441 |
+
[
|
| 442 |
+
-0.03376583009958267,
|
| 443 |
+
0.2280241698026657,
|
| 444 |
+
1.0000001192092896,
|
| 445 |
+
0.061812229454517365,
|
| 446 |
+
0.570030927658081,
|
| 447 |
+
-0.011771553196012974,
|
| 448 |
+
0.07696891576051712,
|
| 449 |
+
-0.10601639002561569,
|
| 450 |
+
0.06801445037126541,
|
| 451 |
+
-0.23264755308628082
|
| 452 |
+
],
|
| 453 |
+
[
|
| 454 |
+
0.24143743515014648,
|
| 455 |
+
0.08577030897140503,
|
| 456 |
+
0.061812229454517365,
|
| 457 |
+
0.9999997615814209,
|
| 458 |
+
0.0030930074863135815,
|
| 459 |
+
0.18994615972042084,
|
| 460 |
+
0.15969695150852203,
|
| 461 |
+
0.21833136677742004,
|
| 462 |
+
0.26542553305625916,
|
| 463 |
+
-0.039861708879470825
|
| 464 |
+
],
|
| 465 |
+
[
|
| 466 |
+
-0.013180982321500778,
|
| 467 |
+
0.20908223092556,
|
| 468 |
+
0.570030927658081,
|
| 469 |
+
0.0030930074863135815,
|
| 470 |
+
1.0000003576278687,
|
| 471 |
+
-0.09009360522031784,
|
| 472 |
+
0.003698738757520914,
|
| 473 |
+
-0.08297917991876602,
|
| 474 |
+
0.01635875552892685,
|
| 475 |
+
-0.21284666657447815
|
| 476 |
+
],
|
| 477 |
+
[
|
| 478 |
+
0.1519388109445572,
|
| 479 |
+
-0.09965874999761581,
|
| 480 |
+
-0.011771553196012974,
|
| 481 |
+
0.18994615972042084,
|
| 482 |
+
-0.09009360522031784,
|
| 483 |
+
0.9999999403953552,
|
| 484 |
+
0.13532496988773346,
|
| 485 |
+
0.04327913001179695,
|
| 486 |
+
-0.03058011643588543,
|
| 487 |
+
0.22757190465927124
|
| 488 |
+
],
|
| 489 |
+
[
|
| 490 |
+
0.21512284874916077,
|
| 491 |
+
0.2280401587486267,
|
| 492 |
+
0.07696891576051712,
|
| 493 |
+
0.15969695150852203,
|
| 494 |
+
0.003698738757520914,
|
| 495 |
+
0.13532496988773346,
|
| 496 |
+
0.9999998807907104,
|
| 497 |
+
0.030232839286327362,
|
| 498 |
+
0.23005540668964386,
|
| 499 |
+
0.025300158187747
|
| 500 |
+
],
|
| 501 |
+
[
|
| 502 |
+
0.12231583148241043,
|
| 503 |
+
0.08895031362771988,
|
| 504 |
+
-0.10601639002561569,
|
| 505 |
+
0.21833136677742004,
|
| 506 |
+
-0.08297917991876602,
|
| 507 |
+
0.04327913001179695,
|
| 508 |
+
0.030232839286327362,
|
| 509 |
+
1.000000238418579,
|
| 510 |
+
0.21879234910011292,
|
| 511 |
+
0.020776957273483276
|
| 512 |
+
],
|
| 513 |
+
[
|
| 514 |
+
0.15586860477924347,
|
| 515 |
+
0.2658396065235138,
|
| 516 |
+
0.06801445037126541,
|
| 517 |
+
0.26542553305625916,
|
| 518 |
+
0.01635875552892685,
|
| 519 |
+
-0.03058011643588543,
|
| 520 |
+
0.23005540668964386,
|
| 521 |
+
0.21879234910011292,
|
| 522 |
+
0.9999998807907104,
|
| 523 |
+
-0.015971055254340172
|
| 524 |
+
],
|
| 525 |
+
[
|
| 526 |
+
0.14881354570388794,
|
| 527 |
+
-0.15059183537960052,
|
| 528 |
+
-0.23264755308628082,
|
| 529 |
+
-0.039861708879470825,
|
| 530 |
+
-0.21284666657447815,
|
| 531 |
+
0.22757190465927124,
|
| 532 |
+
0.025300158187747,
|
| 533 |
+
0.020776957273483276,
|
| 534 |
+
-0.015971055254340172,
|
| 535 |
+
1.0000001192092896
|
| 536 |
+
]
|
| 537 |
+
],
|
| 538 |
+
"max_abs_offdiag": 0.570030927658081
|
| 539 |
+
},
|
| 540 |
+
"E_spatial_localization": {
|
| 541 |
+
"n_sampled_images": 500,
|
| 542 |
+
"mean_iou": 0.16534487868892028,
|
| 543 |
+
"median_iou": 0.15606729686260223,
|
| 544 |
+
"p95_iou": 0.35281437188386916
|
| 545 |
+
}
|
| 546 |
+
}
|
discovery/dim_selection.json
ADDED
|
@@ -0,0 +1,504 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"provenance": {
|
| 3 |
+
"generator": null,
|
| 4 |
+
"note": "discovery sweep not committed; no producer in the repo"
|
| 5 |
+
},
|
| 6 |
+
"n_sampled": 100000,
|
| 7 |
+
"K": 92,
|
| 8 |
+
"n_kept": 1000,
|
| 9 |
+
"f1_distribution": {
|
| 10 |
+
"min": 0.7833036780357361,
|
| 11 |
+
"p50": 0.8676828145980835,
|
| 12 |
+
"p95": 0.9258173704147339,
|
| 13 |
+
"p99": 0.9300636053085327,
|
| 14 |
+
"max": 0.9373591542243958
|
| 15 |
+
},
|
| 16 |
+
"top_kept_f1_range": [
|
| 17 |
+
0.9300652146339417,
|
| 18 |
+
0.9373591542243958
|
| 19 |
+
],
|
| 20 |
+
"best_single_genome_f1": 0.9373591542243958,
|
| 21 |
+
"best_single_genome_sorted": [
|
| 22 |
+
2,
|
| 23 |
+
4,
|
| 24 |
+
8,
|
| 25 |
+
21,
|
| 26 |
+
29,
|
| 27 |
+
39,
|
| 28 |
+
48,
|
| 29 |
+
67,
|
| 30 |
+
69,
|
| 31 |
+
75,
|
| 32 |
+
91,
|
| 33 |
+
119,
|
| 34 |
+
124,
|
| 35 |
+
141,
|
| 36 |
+
149,
|
| 37 |
+
157,
|
| 38 |
+
158,
|
| 39 |
+
168,
|
| 40 |
+
177,
|
| 41 |
+
181,
|
| 42 |
+
192,
|
| 43 |
+
198,
|
| 44 |
+
200,
|
| 45 |
+
218,
|
| 46 |
+
220,
|
| 47 |
+
240,
|
| 48 |
+
249,
|
| 49 |
+
250,
|
| 50 |
+
259,
|
| 51 |
+
267,
|
| 52 |
+
269,
|
| 53 |
+
272,
|
| 54 |
+
273,
|
| 55 |
+
275,
|
| 56 |
+
285,
|
| 57 |
+
286,
|
| 58 |
+
297,
|
| 59 |
+
300,
|
| 60 |
+
304,
|
| 61 |
+
318,
|
| 62 |
+
319,
|
| 63 |
+
323,
|
| 64 |
+
328,
|
| 65 |
+
330,
|
| 66 |
+
340,
|
| 67 |
+
373,
|
| 68 |
+
374,
|
| 69 |
+
377,
|
| 70 |
+
379,
|
| 71 |
+
391,
|
| 72 |
+
393,
|
| 73 |
+
403,
|
| 74 |
+
419,
|
| 75 |
+
429,
|
| 76 |
+
433,
|
| 77 |
+
436,
|
| 78 |
+
454,
|
| 79 |
+
463,
|
| 80 |
+
476,
|
| 81 |
+
520,
|
| 82 |
+
524,
|
| 83 |
+
530,
|
| 84 |
+
537,
|
| 85 |
+
548,
|
| 86 |
+
550,
|
| 87 |
+
558,
|
| 88 |
+
560,
|
| 89 |
+
570,
|
| 90 |
+
574,
|
| 91 |
+
582,
|
| 92 |
+
590,
|
| 93 |
+
594,
|
| 94 |
+
605,
|
| 95 |
+
606,
|
| 96 |
+
609,
|
| 97 |
+
612,
|
| 98 |
+
617,
|
| 99 |
+
624,
|
| 100 |
+
630,
|
| 101 |
+
646,
|
| 102 |
+
649,
|
| 103 |
+
657,
|
| 104 |
+
660,
|
| 105 |
+
673,
|
| 106 |
+
680,
|
| 107 |
+
700,
|
| 108 |
+
715,
|
| 109 |
+
716,
|
| 110 |
+
737,
|
| 111 |
+
740,
|
| 112 |
+
754,
|
| 113 |
+
755
|
| 114 |
+
],
|
| 115 |
+
"dim_frequency_top_25": {
|
| 116 |
+
"48": 1.0,
|
| 117 |
+
"525": 0.3140000104904175,
|
| 118 |
+
"475": 0.3110000193119049,
|
| 119 |
+
"323": 0.23400001227855682,
|
| 120 |
+
"240": 0.21700000762939453,
|
| 121 |
+
"637": 0.2120000123977661,
|
| 122 |
+
"318": 0.20600001513957977,
|
| 123 |
+
"472": 0.20200000703334808,
|
| 124 |
+
"719": 0.20100000500679016,
|
| 125 |
+
"251": 0.19700001180171967,
|
| 126 |
+
"506": 0.19500000774860382,
|
| 127 |
+
"13": 0.1940000057220459,
|
| 128 |
+
"281": 0.1900000125169754,
|
| 129 |
+
"113": 0.1860000044107437,
|
| 130 |
+
"331": 0.1860000044107437,
|
| 131 |
+
"224": 0.18200001120567322,
|
| 132 |
+
"382": 0.1810000091791153,
|
| 133 |
+
"767": 0.18000000715255737,
|
| 134 |
+
"605": 0.1770000010728836,
|
| 135 |
+
"642": 0.17500001192092896,
|
| 136 |
+
"157": 0.17400000989437103,
|
| 137 |
+
"155": 0.1680000126361847,
|
| 138 |
+
"273": 0.16700001060962677,
|
| 139 |
+
"207": 0.16500000655651093,
|
| 140 |
+
"510": 0.16500000655651093
|
| 141 |
+
},
|
| 142 |
+
"union_classifier": {
|
| 143 |
+
"n_dims": 768,
|
| 144 |
+
"F1": 0.9616926908493042,
|
| 145 |
+
"precision": 0.989005982875824,
|
| 146 |
+
"recall": 0.9358474016189575
|
| 147 |
+
},
|
| 148 |
+
"cores": {
|
| 149 |
+
"23": [
|
| 150 |
+
48,
|
| 151 |
+
525,
|
| 152 |
+
475,
|
| 153 |
+
323,
|
| 154 |
+
240,
|
| 155 |
+
637,
|
| 156 |
+
318,
|
| 157 |
+
472,
|
| 158 |
+
719,
|
| 159 |
+
251,
|
| 160 |
+
506,
|
| 161 |
+
13,
|
| 162 |
+
281,
|
| 163 |
+
113,
|
| 164 |
+
331,
|
| 165 |
+
224,
|
| 166 |
+
382,
|
| 167 |
+
767,
|
| 168 |
+
605,
|
| 169 |
+
642,
|
| 170 |
+
157,
|
| 171 |
+
155,
|
| 172 |
+
273
|
| 173 |
+
],
|
| 174 |
+
"46": [
|
| 175 |
+
48,
|
| 176 |
+
525,
|
| 177 |
+
475,
|
| 178 |
+
323,
|
| 179 |
+
240,
|
| 180 |
+
637,
|
| 181 |
+
318,
|
| 182 |
+
472,
|
| 183 |
+
719,
|
| 184 |
+
251,
|
| 185 |
+
506,
|
| 186 |
+
13,
|
| 187 |
+
281,
|
| 188 |
+
113,
|
| 189 |
+
331,
|
| 190 |
+
224,
|
| 191 |
+
382,
|
| 192 |
+
767,
|
| 193 |
+
605,
|
| 194 |
+
642,
|
| 195 |
+
157,
|
| 196 |
+
155,
|
| 197 |
+
273,
|
| 198 |
+
207,
|
| 199 |
+
510,
|
| 200 |
+
127,
|
| 201 |
+
245,
|
| 202 |
+
759,
|
| 203 |
+
292,
|
| 204 |
+
531,
|
| 205 |
+
617,
|
| 206 |
+
333,
|
| 207 |
+
527,
|
| 208 |
+
45,
|
| 209 |
+
332,
|
| 210 |
+
574,
|
| 211 |
+
595,
|
| 212 |
+
269,
|
| 213 |
+
158,
|
| 214 |
+
432,
|
| 215 |
+
0,
|
| 216 |
+
119,
|
| 217 |
+
310,
|
| 218 |
+
490,
|
| 219 |
+
557,
|
| 220 |
+
528
|
| 221 |
+
],
|
| 222 |
+
"92": [
|
| 223 |
+
48,
|
| 224 |
+
525,
|
| 225 |
+
475,
|
| 226 |
+
323,
|
| 227 |
+
240,
|
| 228 |
+
637,
|
| 229 |
+
318,
|
| 230 |
+
472,
|
| 231 |
+
719,
|
| 232 |
+
251,
|
| 233 |
+
506,
|
| 234 |
+
13,
|
| 235 |
+
281,
|
| 236 |
+
113,
|
| 237 |
+
331,
|
| 238 |
+
224,
|
| 239 |
+
382,
|
| 240 |
+
767,
|
| 241 |
+
605,
|
| 242 |
+
642,
|
| 243 |
+
157,
|
| 244 |
+
155,
|
| 245 |
+
273,
|
| 246 |
+
207,
|
| 247 |
+
510,
|
| 248 |
+
127,
|
| 249 |
+
245,
|
| 250 |
+
759,
|
| 251 |
+
292,
|
| 252 |
+
531,
|
| 253 |
+
617,
|
| 254 |
+
333,
|
| 255 |
+
527,
|
| 256 |
+
45,
|
| 257 |
+
332,
|
| 258 |
+
574,
|
| 259 |
+
595,
|
| 260 |
+
269,
|
| 261 |
+
158,
|
| 262 |
+
432,
|
| 263 |
+
0,
|
| 264 |
+
119,
|
| 265 |
+
310,
|
| 266 |
+
490,
|
| 267 |
+
557,
|
| 268 |
+
528,
|
| 269 |
+
545,
|
| 270 |
+
558,
|
| 271 |
+
597,
|
| 272 |
+
645,
|
| 273 |
+
28,
|
| 274 |
+
51,
|
| 275 |
+
79,
|
| 276 |
+
82,
|
| 277 |
+
301,
|
| 278 |
+
126,
|
| 279 |
+
542,
|
| 280 |
+
173,
|
| 281 |
+
90,
|
| 282 |
+
380,
|
| 283 |
+
71,
|
| 284 |
+
384,
|
| 285 |
+
514,
|
| 286 |
+
620,
|
| 287 |
+
630,
|
| 288 |
+
713,
|
| 289 |
+
223,
|
| 290 |
+
516,
|
| 291 |
+
520,
|
| 292 |
+
606,
|
| 293 |
+
17,
|
| 294 |
+
172,
|
| 295 |
+
355,
|
| 296 |
+
393,
|
| 297 |
+
421,
|
| 298 |
+
745,
|
| 299 |
+
68,
|
| 300 |
+
252,
|
| 301 |
+
280,
|
| 302 |
+
334,
|
| 303 |
+
657,
|
| 304 |
+
95,
|
| 305 |
+
111,
|
| 306 |
+
151,
|
| 307 |
+
244,
|
| 308 |
+
543,
|
| 309 |
+
748,
|
| 310 |
+
290,
|
| 311 |
+
363,
|
| 312 |
+
469,
|
| 313 |
+
561,
|
| 314 |
+
591
|
| 315 |
+
],
|
| 316 |
+
"184": [
|
| 317 |
+
48,
|
| 318 |
+
525,
|
| 319 |
+
475,
|
| 320 |
+
323,
|
| 321 |
+
240,
|
| 322 |
+
637,
|
| 323 |
+
318,
|
| 324 |
+
472,
|
| 325 |
+
719,
|
| 326 |
+
251,
|
| 327 |
+
506,
|
| 328 |
+
13,
|
| 329 |
+
281,
|
| 330 |
+
113,
|
| 331 |
+
331,
|
| 332 |
+
224,
|
| 333 |
+
382,
|
| 334 |
+
767,
|
| 335 |
+
605,
|
| 336 |
+
642,
|
| 337 |
+
157,
|
| 338 |
+
155,
|
| 339 |
+
273,
|
| 340 |
+
207,
|
| 341 |
+
510,
|
| 342 |
+
127,
|
| 343 |
+
245,
|
| 344 |
+
759,
|
| 345 |
+
292,
|
| 346 |
+
531,
|
| 347 |
+
617,
|
| 348 |
+
333,
|
| 349 |
+
527,
|
| 350 |
+
45,
|
| 351 |
+
332,
|
| 352 |
+
574,
|
| 353 |
+
595,
|
| 354 |
+
269,
|
| 355 |
+
158,
|
| 356 |
+
432,
|
| 357 |
+
0,
|
| 358 |
+
119,
|
| 359 |
+
310,
|
| 360 |
+
490,
|
| 361 |
+
557,
|
| 362 |
+
528,
|
| 363 |
+
545,
|
| 364 |
+
558,
|
| 365 |
+
597,
|
| 366 |
+
645,
|
| 367 |
+
28,
|
| 368 |
+
51,
|
| 369 |
+
79,
|
| 370 |
+
82,
|
| 371 |
+
301,
|
| 372 |
+
126,
|
| 373 |
+
542,
|
| 374 |
+
173,
|
| 375 |
+
90,
|
| 376 |
+
380,
|
| 377 |
+
71,
|
| 378 |
+
384,
|
| 379 |
+
514,
|
| 380 |
+
620,
|
| 381 |
+
630,
|
| 382 |
+
713,
|
| 383 |
+
223,
|
| 384 |
+
516,
|
| 385 |
+
520,
|
| 386 |
+
606,
|
| 387 |
+
17,
|
| 388 |
+
172,
|
| 389 |
+
355,
|
| 390 |
+
393,
|
| 391 |
+
421,
|
| 392 |
+
745,
|
| 393 |
+
68,
|
| 394 |
+
252,
|
| 395 |
+
280,
|
| 396 |
+
334,
|
| 397 |
+
657,
|
| 398 |
+
95,
|
| 399 |
+
111,
|
| 400 |
+
151,
|
| 401 |
+
244,
|
| 402 |
+
543,
|
| 403 |
+
748,
|
| 404 |
+
290,
|
| 405 |
+
363,
|
| 406 |
+
469,
|
| 407 |
+
561,
|
| 408 |
+
591,
|
| 409 |
+
96,
|
| 410 |
+
397,
|
| 411 |
+
419,
|
| 412 |
+
425,
|
| 413 |
+
523,
|
| 414 |
+
627,
|
| 415 |
+
734,
|
| 416 |
+
124,
|
| 417 |
+
236,
|
| 418 |
+
454,
|
| 419 |
+
9,
|
| 420 |
+
345,
|
| 421 |
+
358,
|
| 422 |
+
480,
|
| 423 |
+
575,
|
| 424 |
+
736,
|
| 425 |
+
26,
|
| 426 |
+
34,
|
| 427 |
+
65,
|
| 428 |
+
141,
|
| 429 |
+
152,
|
| 430 |
+
176,
|
| 431 |
+
204,
|
| 432 |
+
293,
|
| 433 |
+
305,
|
| 434 |
+
445,
|
| 435 |
+
282,
|
| 436 |
+
389,
|
| 437 |
+
437,
|
| 438 |
+
619,
|
| 439 |
+
162,
|
| 440 |
+
178,
|
| 441 |
+
311,
|
| 442 |
+
394,
|
| 443 |
+
409,
|
| 444 |
+
483,
|
| 445 |
+
496,
|
| 446 |
+
613,
|
| 447 |
+
717,
|
| 448 |
+
50,
|
| 449 |
+
188,
|
| 450 |
+
216,
|
| 451 |
+
325,
|
| 452 |
+
602,
|
| 453 |
+
699,
|
| 454 |
+
740,
|
| 455 |
+
254,
|
| 456 |
+
258,
|
| 457 |
+
299,
|
| 458 |
+
403,
|
| 459 |
+
495,
|
| 460 |
+
603,
|
| 461 |
+
622,
|
| 462 |
+
40,
|
| 463 |
+
83,
|
| 464 |
+
146,
|
| 465 |
+
150,
|
| 466 |
+
232,
|
| 467 |
+
259,
|
| 468 |
+
341,
|
| 469 |
+
392,
|
| 470 |
+
444,
|
| 471 |
+
522,
|
| 472 |
+
567,
|
| 473 |
+
629,
|
| 474 |
+
647,
|
| 475 |
+
25,
|
| 476 |
+
170,
|
| 477 |
+
205,
|
| 478 |
+
267,
|
| 479 |
+
274,
|
| 480 |
+
307,
|
| 481 |
+
411,
|
| 482 |
+
549,
|
| 483 |
+
576,
|
| 484 |
+
618,
|
| 485 |
+
686,
|
| 486 |
+
760,
|
| 487 |
+
8,
|
| 488 |
+
200,
|
| 489 |
+
255,
|
| 490 |
+
353,
|
| 491 |
+
354,
|
| 492 |
+
413,
|
| 493 |
+
455,
|
| 494 |
+
463,
|
| 495 |
+
544,
|
| 496 |
+
721,
|
| 497 |
+
93,
|
| 498 |
+
171,
|
| 499 |
+
225,
|
| 500 |
+
234
|
| 501 |
+
]
|
| 502 |
+
},
|
| 503 |
+
"runtime_s": 4.635331869125366
|
| 504 |
+
}
|
discovery/prop_image_manifest.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{"provenance":{"generator":null,"note":"discovery sweep not committed; no producer in the repo"},"source":"imagenet-1k train","filter":"YOLO26l, no person detected","person_conf_threshold":0.25,"total_kept":8479,"synsets":{"n04039381":"racket","n04591713":"Windsor_tie","n02883205":"bow_tie","n04254680":"soccer_ball","n04118538":"rugby_ball","n04228054":"ski","n02769748":"backpack","n03127747":"crash_helmet","n03124170":"cowboy_hat","n04259630":"sombrero","n03680355":"loafer","n03124043":"cowboy_boot","n03838899":"oboe","n03249569":"drum","n04074963":"remote_control","n02676566":"acoustic_guitar","n03272010":"electric_guitar","n04152593":"screen","n04590129":"window_shade","n04418357":"theater_curtain"},"stats":{"racket":{"inspected":1300,"kept":357},"Windsor_tie":{"inspected":551,"kept":500},"bow_tie":{"inspected":1300,"kept":242},"soccer_ball":{"inspected":1134,"kept":500},"rugby_ball":{"inspected":1300,"kept":149},"ski":{"inspected":1300,"kept":225},"backpack":{"inspected":587,"kept":500},"crash_helmet":{"inspected":837,"kept":500},"cowboy_hat":{"inspected":1300,"kept":230},"sombrero":{"inspected":1300,"kept":298},"loafer":{"inspected":999,"kept":500},"cowboy_boot":{"inspected":960,"kept":500},"oboe":{"inspected":1300,"kept":478},"drum":{"inspected":918,"kept":500},"remote_control":{"inspected":646,"kept":500},"acoustic_guitar":{"inspected":690,"kept":500},"electric_guitar":{"inspected":791,"kept":500},"screen":{"inspected":579,"kept":500},"window_shade":{"inspected":566,"kept":500},"theater_curtain":{"inspected":797,"kept":500}},"note":"image_ids[synset][k] identifies <synset>/<synset>_<id>.JPEG","image_ids":{"n04039381":[10013,10090,10184,10347,10349,104,10470,10472,10498,10682,10705,10856,10924,10972,11033,11074,1123,11236,11364,11421,11426,11519,11553,11566,11643,1167,11709,11880,11969,12094,12117,12159,1222,12224,1223,12356,12411,12449,12538,12546,12576,12590,12632,12660,12663,12664,12679,12719,1283,12832,12925,13048,13068,13248,13369,13371,13404,13480,13489,13566,13677,13712,13714,13964,14134,14139,14144,14243,14362,14366,14468,14589,14918,14943,14993,15115,15133,15222,15254,15301,15338,15388,15489,15692,1575,15809,15941,15995,16015,16114,16119,16197,16257,16277,16279,16362,16364,16435,16507,16574,16580,16616,16646,1676,1683,16849,16860,16940,17014,17050,17104,17252,1737,17387,17418,17515,17536,17595,17717,17766,17854,18108,18125,18152,1817,18173,18227,18265,18282,18352,1843,18432,18514,18642,1874,18759,18773,18842,19076,19145,19172,19246,19248,19262,19270,19330,19361,19399,1948,19671,19782,19787,19853,19928,19936,19940,19943,19954,19956,19974,20065,20256,20287,20318,20355,20371,20608,20639,20689,20702,20840,20851,20917,20955,21241,21566,21573,21574,21608,21657,21988,22008,22143,22278,22459,22861,22957,23045,23055,23107,23170,23244,23255,23360,2421,2503,2591,2626,2741,2756,2765,2784,2901,2952,2965,30093,3015,30350,3236,32782,3297,3313,3322,3373,3410,35176,3530,3554,3635,37712,3778,3815,3854,38660,3888,3892,39462,3978,3992,4019,4064,4067,4068,4096,4108,4142,4160,41634,41798,4191,4248,4269,4343,4365,4367,4401,4442,44525,4477,4567,4579,4681,471,4716,4732,4771,481,48255,4863,4864,4881,4920,4937,5008,50596,5178,5189,5262,5274,5331,53338,5474,5587,571,5717,5767,5807,5967,597,5988,6044,6166,6205,6301,6317,6406,6441,6452,6473,6476,6525,6769,6788,6989,7077,71,7106,7161,7164,7166,7215,7252,7267,7292,7299,7388,7478,7505,7516,7525,7590,7619,7665,7708,7710,7770,7786,784,7884,7961,8011,8015,8023,8027,8072,8125,8129,813,8222,8310,8327,8393,8395,8409,8412,8423,8669,8772,8803,8813,8840,8969,8985,9058,9250,9282,9285,9306,9328,9338,9361,9377,9447,9593,963,9637,9905],"n04591713":[100,10035,10065,101,10109,1015,1035,10383,10440,1046,10469,10484,105,1051,10510,10525,10550,10569,10614,10629,10686,107,1070,10760,10795,108,1084,11,110,11182,1121,1126,11324,1138,11499,11504,11520,1155,11558,1160,11606,11621,1164,1172,11759,1191,121,1225,1237,124,1244,1251,12567,12569,1257,1260,127,12767,1277,128,1280,12876,1302,1310,1316,132,13234,1326,13283,13349,134,1344,1352,1353,13550,13589,13590,1361,1367,13696,1370,1374,1375,1390,1398,14,1401,1403,14045,1407,1411,14142,14192,14205,1428,1437,1440,14419,145,14540,14563,14579,14626,14630,14641,1468,1472,1473,14741,1476,14895,1496,1503,15073,15127,15172,15205,1524,15278,1531,15321,1548,1554,1566,1573,1587,1594,1601,1604,1606,16097,1610,1611,1615,1616,16175,1627,1630,1634,16352,16364,16396,1640,1643,16442,1649,1652,1658,1659,1660,16610,16654,1671,16710,16751,1679,16793,16805,1691,1692,1702,17048,17055,1713,1717,17170,17197,172,1728,1742,1744,17471,1752,17535,1755,1761,17618,1762,1764,1767,17676,1768,1773,1777,17776,1779,17826,1784,1786,179,1808,18116,1813,1814,18197,1822,1824,18281,183,1834,1836,1837,1848,18520,1857,1860,1876,1879,18806,1885,1893,18962,1900,1905,1908,19122,19169,19185,19198,1927,1930,1932,1935,1938,19409,19432,1952,1962,1969,197,1976,1978,1988,1989,1992,1993,2003,2010,2022,2024,2025,2026,2037,2038,2041,2042,2043,2047,2049,2052,2053,2058,2059,2063,2084,2088,2095,2116,2122,2123,2129,2131,2140,2144,215,2150,2154,2167,217,2170,2176,2178,2180,2194,2197,2199,2200,2212,2222,223,2233,2246,2252,2256,2259,2263,2271,2272,2288,2305,2310,2322,2327,2344,2345,2359,2362,2366,2369,2373,2419,2427,2432,2440,2448,2451,2456,2473,2479,2480,2485,25,2501,2506,2515,2525,2534,2537,2538,2549,2555,2557,2561,2566,2567,2569,2576,2589,2594,2605,261,2648,2666,2668,2676,2679,2680,2691,2694,2701,2713,2714,2718,2732,2740,2747,2753,2757,2760,2764,277,2775,2777,278,2787,2790,2793,2800,2802,2805,2808,2813,2817,2818,2826,2841,2842,2845,2848,2850,2852,2857,2879,2883,2899,2903,2918,2925,2938,2940,2952,2956,2957,2971,2972,2977,2978,2999,3002,3004,3010,3013,3016,3020,3022,3030,304,3052,3054,3069,3083,3085,3090,3093,3094,31,3104,3107,3112,3135,3139,3153,3158,3161,3174,3182,319,3191,3195,321,3214,3218,3242,3252,3255,3258,3260,3281,3284,3289,3291,3295,3299,3300,3309,3312,3315,3316,3327,3328,3332,3333,334,3343,3348,335,3358,3360,3370,3371,3376,3379,3393,3396,3399,3402,3404,3409,3410,3412,342,3420,3423,3429,3430,3438,3441,3442,3444,3448,3452,3454,3460,347,3470,3477,3488,3489,3491,3495,3496,3501,3502,3510,3513,3517,3522,353,3533,3534,3535,3544,3550,3554,356,3561,3562,3565,3568,3570],"n02883205":[102441,103964,10414,10423,10499,10716,10836,10868,10933,11249,11266,11268,11275,12209,1225,12313,12635,12683,12985,13214,13573,13679,13839,13978,14069,14134,14158,14395,14486,14489,14567,14710,14718,14865,15254,15261,15317,15665,1571,1594,15973,16052,16238,16384,169,17340,1737,17377,1747,17480,17589,17676,17712,1789,1795,1806,1815,18189,18414,18432,1877,18832,1949,20083,20091,202,20336,20342,20559,20564,20708,2076,2093,21117,2124,21243,21264,21385,21470,21733,2217,22630,22799,22977,23017,23066,2308,2316,23175,23241,23349,23381,23412,23469,23529,23570,23708,23785,23959,24058,24086,24104,24233,24303,24414,2452,25935,25983,26085,26218,26827,26901,27000,27266,27475,2762,2768,28828,29483,29518,29800,3013,30477,3075,30971,3112,31675,31689,3199,3203,3218,32945,33,33463,33605,3394,3440,34416,34466,3452,34807,34949,35920,36058,36300,36629,37159,3726,3773,38455,38463,38529,38590,39363,40402,40522,40637,40649,4089,41075,4111,41385,4174,41829,4247,429,431,43306,4407,44395,4445,44945,4495,4533,45414,45452,4560,46609,4704,47094,47843,48616,48715,4892,49319,4963,49642,50144,5015,5048,5155,51623,5585,5731,5739,5794,5802,5825,5841,5969,59905,6,6034,6053,6074,6098,6130,62028,6231,6252,63109,6343,6376,6458,6784,6860,6909,6912,6965,7047,7129,716,72227,7346,7497,7543,7721,7826,7877,7937,8052,8105,8229,8268,8368,8379,84107,8652,9003,9160,9291,9909],"n04254680":[10019,10043,10045,10049,10076,10112,10147,1015,10154,1016,10164,10170,10173,10190,10208,10241,1046,10460,10585,1060,1070,10747,10755,10766,10824,1090,10944,10992,1101,11026,11040,11069,1110,1113,11130,11201,11208,1131,11316,1137,11372,11404,11422,11443,1147,1150,11535,1160,11641,11751,11775,1184,1186,119,1190,1202,12086,12098,1220,1222,12287,1237,1240,1244,12455,1247,12484,1252,1253,1257,12573,12580,1264,1265,1266,1268,12724,1277,1279,1286,1295,1300,1305,1323,13233,13250,13251,13280,13307,13323,13379,13427,13436,1344,13449,13477,1352,1357,13623,1366,1376,13780,13803,13821,13898,1395,13987,1399,1401,14028,14038,1406,1411,14136,1424,14252,1430,1432,1434,14361,14369,1439,14417,14444,14687,14723,1473,1476,14812,14971,14994,1501,15039,1511,15224,15226,15240,15342,15422,1546,15590,157,1580,1584,1585,1591,15923,15943,1597,16005,16057,1607,16113,1613,1622,1627,1628,16425,1643,16523,1657,16593,16669,16734,1688,16966,16990,17123,17248,1740,1757,1759,18,1809,1824,1836,1848,1864,1892,190,1903,1904,1914,1926,1950,2005,2090,210,2107,2111,2116,2124,2155,2159,2202,2238,2270,2279,2282,2300,2302,2410,2413,2417,2422,2490,2551,2565,2585,2618,2637,2647,2667,2680,2772,2793,28,2812,2815,2868,294,2960,2968,2976,298,2984,3026,3061,3068,308,316,3164,32,324,3257,33,330,3300,3334,34,3413,3463,3495,3527,3541,3564,3617,3622,3715,376,3905,4023,404,4054,4065,4122,415,4164,4168,4181,422,4261,4279,4337,4344,437,4379,4422,4424,4452,4487,4510,4533,4586,4590,462,4627,4630,466,4667,467,4670,4697,4798,483,4877,4926,493,4941,4951,4956,4974,500,5002,5033,5079,5090,51,5100,5104,511,5120,5204,5260,5267,5276,5284,5301,5328,5334,5346,5349,5358,5368,5384,5387,539,5408,5415,5452,5458,5482,5517,5526,5530,5536,5553,5564,558,5584,559,5597,5598,5611,5613,5617,562,5621,5685,5719,5734,5744,577,579,581,5828,5860,5865,5901,5919,5934,5935,595,5985,5991,6019,6034,6039,6056,6061,6063,607,6086,6089,6096,6105,6152,6156,6161,6171,6182,6190,6209,6238,6252,6351,6368,6438,6470,6541,6544,656,6645,6711,6727,677,6813,6826,6915,6940,698,7078,7109,7146,7150,7184,7193,7226,7256,7260,7267,7280,73,7301,7311,7332,7338,7351,7355,7374,7410,7414,7437,7458,746,7474,7501,7514,7530,7560,7591,760,7607,763,7631,7668,7688,7701,7720,7722,7724,7726,7732,7733,7734,7755,7763,7779,7794,7810,7819,7822,7824,7830,7831,7844,7845,7846,7848,7851,7854,7892,7907,7908,7938,7939,794,7967,7986,7994,8013,8023,8027,8061,8063,8080,8095,8100,8107,8114,8126,8174,818,8197,8210,8235,824,8249,8257,8264,8266,8269,8274,8284,8293,8295,8319,8337,8338,8385,8411,8415,8419,8467,8475,8478,848,8506,854,857],"n04118538":[10198,10210,10219,10271,10466,1065,10755,10765,10921,11054,11096,11164,1119,11212,11270,1130,114,1146,11606,118,11850,11861,119,12229,12317,12341,12368,12599,12697,1288,1298,1346,13574,1369,13779,13853,13866,14011,14465,14536,147,15005,1510,1535,15451,15670,1571,15867,15991,16191,16198,1698,1736,17553,18495,1869,1935,19631,2022,20362,2107,21796,2276,2296,2302,234,24621,24875,2497,250,2755,2782,2858,2871,2926,3063,3066,3159,3272,3380,3482,358,3586,3623,3631,3637,3878,3943,3959,4054,4104,4121,4141,4150,4171,4184,4243,4284,4292,4361,4419,4525,4581,4628,4857,4881,4927,5200,5257,5291,5389,5419,5421,6114,6249,6328,6415,6467,6541,6566,6614,6648,6676,6803,6913,697,6978,7,7035,705,7198,7298,7375,7436,7507,756,7615,8031,809,85,8519,8592,8818,8937,9005,9049,9160,933,9823],"n04228054":[10244,10261,10306,10502,1057,10603,10755,10839,1084,10910,1096,10971,10973,10990,11041,1105,1127,11352,11353,11367,1144,11471,11535,11549,11638,11703,11767,11988,11992,120,12024,12050,12061,1225,1232,1303,13266,1328,13330,1345,1383,1395,13993,1434,145,1461,1479,15002,15024,1551,15676,15917,1596,16120,16211,16552,16629,16630,16933,16944,16946,1719,17548,17555,17607,1766,1813,18286,18398,19653,19675,20283,20378,2056,20634,20893,20970,21128,21413,21614,2185,2213,2259,2308,2324,2377,2395,2415,25016,2504,2521,2650,26843,2687,2693,2783,2860,2911,2994,30397,3058,30631,3080,3171,3172,3214,3217,3253,3319,3327,33610,34211,3454,3489,3519,3533,3538,3616,3718,3729,3817,3829,4142,4190,424,4417,4496,4503,4572,4578,462,4623,4744,4754,4794,48,4824,4833,4837,4838,4880,4900,4985,5022,5043,5073,5295,53,5396,5462,5501,556,5632,5686,5702,5877,5943,5977,6032,6033,613,6168,6206,6271,632,6332,6375,6414,66,6689,6695,6717,6782,693,701,7022,7116,7134,7157,7174,7209,7212,7302,7434,7455,7480,7526,7536,757,7626,7636,7667,7785,7886,7950,7989,8087,8116,8118,8177,8178,820,8218,8222,8325,84,8409,8413,8529,8873,904,929,931,9434,9509,9519,952,9590,9592,9611,9758,983,9835,9869,9998],"n02769748":[10023,10044,10045,100708,10089,101083,101091,101134,10135,10198,10204,10245,102866,103175,103198,1032,103229,10331,103341,103635,103643,103690,103716,103979,104665,10714,10791,10817,10922,10946,10986,11091,111,11144,11168,11236,11247,11248,11249,11277,11288,11293,11352,11373,1144,11443,11479,11744,1188,11946,12087,12149,1218,1220,12248,12336,12588,12727,12836,12871,12913,1295,1298,13046,13080,13105,1313,1319,13234,13273,13493,13551,1357,14060,14145,14180,14268,14315,14409,14510,14527,14540,1499,15053,15063,15153,15175,15269,15279,1528,15281,15310,15334,15342,15449,15456,15511,15571,15626,15635,15658,15669,15707,15813,15824,15844,15880,15914,15925,15964,16033,16048,16086,16206,16231,16326,16331,16366,1637,16376,1639,1641,16420,16431,1645,1651,16520,16613,16636,16701,16712,16802,16856,16875,1688,16882,16890,17001,17014,17033,17061,17099,17118,17135,1718,17192,17297,17338,17339,17433,17495,17548,17607,17655,17737,17748,17763,17779,178,17853,17858,17865,17927,17960,17977,17991,18011,18126,18129,18222,18245,1827,18275,18313,18321,18428,18446,18520,18543,18562,18564,18582,18656,18690,18841,18844,18852,18871,18874,18894,18956,18963,18987,19018,19085,19102,19188,19247,19268,19293,19300,19421,19502,19509,19510,19550,19586,19641,19662,19669,19678,19806,19938,1995,19957,2000,2001,20015,2016,20164,2053,20582,20635,20641,2065,20688,2072,20780,2082,2087,20903,2110,21174,21256,21293,21333,21335,2134,21392,21615,21685,21725,21834,2190,21984,2206,22069,22123,22130,2218,22227,22228,22260,22304,22388,2240,22445,2247,22486,22542,22689,22690,22705,22723,22726,2281,22813,22820,22921,22985,2300,23075,23085,23146,23197,23265,23270,23336,23377,23380,23468,23541,23542,23585,23754,2379,23828,23854,23878,2389,23898,24000,24012,24034,24048,24074,24142,242,24252,24293,24321,24449,24509,24514,2463,24665,24668,2472,24741,24743,2478,24785,2485,24873,250,25029,25169,25173,25223,25231,25236,25298,25344,25355,25467,25468,25561,25590,25606,25620,25684,2571,25747,25757,25841,2587,25894,25971,26073,26099,26109,26117,26152,26162,26173,26211,26302,26317,26346,26472,26542,26592,26626,26634,26644,26735,26776,26853,2688,26895,26941,26962,270,27044,27327,27402,27478,27516,27519,27616,2762,27717,27730,2774,27783,27842,27881,27919,28025,28038,28074,28315,28325,28427,28457,28485,28611,28612,28795,28841,28870,28877,28908,2897,29117,29160,29311,29488,29528,29547,29648,2966,29733,2979,29813,29822,29967,30069,30102,30125,30159,30166,30218,30491,30616,30688,30689,30699,30711,30807,30824,3084,3086,30867,30870,30910,30939,30978,31038,3105,31054,31103,31119,3114,3122,31225,31242,31288,31314,31317,31354,31390,31443,3146,31468,31473,31474,3149,31590,31595,31598,31614,31646,31664,31699,317,31730,31745,31770,31818,31886,31922,31934,31944,31960,31981,31997,3205,32058,32117,32142,32152,32234,32277,32329,3233,32399,32419,3242,32427,32469,32509,32546,32555,32584,32831,32839,32863,32889,32916,33015,33057,33148,33158,33187,33392,33397,33462,33485,33487],"n03127747":[1002,10078,10084,1019,1027,10284,10304,1031,10315,1036,1040,10451,10501,10510,10543,10567,1057,1060,10609,1061,10639,10648,1073,10757,10791,10864,10909,10926,10927,10938,10977,10981,10988,11072,11149,11151,11253,11270,1128,11362,11437,11497,11524,11554,11619,11646,11688,11752,11753,11771,1180,11800,11801,1187,11964,11990,12001,12105,12155,12167,12168,1221,1225,123,1233,12490,12576,12626,12628,12640,1269,1270,12705,12817,1284,12846,12904,12913,13004,13141,13191,13225,1327,1329,13292,13330,13343,13351,13370,13378,1339,13396,1340,13413,13436,13462,1349,13503,13511,13526,13639,1366,137,13702,13704,13767,13813,13871,13900,13915,13917,14040,14052,14078,1416,14164,14183,14197,1422,14331,14340,14342,14359,14404,14418,14427,1445,14456,14470,14472,14539,14611,14622,14634,14636,1467,147,14708,1479,14799,14818,14888,14957,1502,1507,15075,15197,15279,15332,15407,15413,1546,15483,15540,15543,1555,156,15630,15656,1577,15837,15883,15889,15894,15921,1604,16069,1612,16162,16195,1620,16223,16244,16257,16304,16376,16401,1641,16445,16454,1647,16506,16545,16570,16590,16629,16635,16657,16691,16701,16704,16772,16780,16787,16795,1681,1689,16995,17070,17130,17208,1726,17275,17314,17365,17520,1757,17665,17702,17788,17804,17869,1790,1800,18229,18281,18342,1836,1841,18414,1842,18441,18448,18456,18483,1849,1852,18614,18633,18661,18707,18717,18796,18933,18965,18984,19018,19022,19049,1906,1910,19109,19142,192,19230,1931,19320,19359,1936,19413,19530,1956,1963,19645,19684,1976,19877,19969,20039,2018,20254,20275,2033,2038,20449,20489,20496,2055,2056,20719,2104,2121,2122,2126,213,2140,21535,21646,22012,22124,22141,2265,2281,2327,2344,2351,2375,239,241,2414,2417,2436,2443,2450,2458,2479,2482,2533,2535,2537,2539,2547,2553,2564,2568,2576,2586,2593,2596,2631,2640,2650,2700,2768,277,2795,2824,2840,2855,2873,2888,2893,2916,2917,2921,2925,2950,2951,2955,2967,2986,2989,2994,3024,3033,3040,3053,3083,3110,3115,3131,3149,3157,3160,3161,3192,3193,3210,3250,3273,3279,3283,3301,3314,333,3336,3338,3348,3376,3381,3408,3414,3415,342,3421,3434,345,3453,3463,3479,3490,3495,3504,3518,3530,3545,3604,3659,3681,37,3704,3751,3770,3782,3797,3798,380,3801,3814,3826,3869,3883,3901,3912,3917,3927,3957,3968,3976,406,4062,410,4104,4134,4211,4229,4230,4243,4300,4324,433,4358,4361,4365,4382,443,4490,4501,4512,4527,4552,4554,4564,4575,4584,4591,4602,4604,4605,461,4624,4642,4646,4649,4654,4685,4694,4697,4702,4721,4739,4743,4751,4756,4764,4788,480,4834,4837,4856,4857,4859,4894,4899,4900,4912,4931,4936,4940,4951,4953,4955,5003,5005,5020,5022,5032,5057,5080,5091,5098,5139,5143,5177,5178,5196,5205,5227,5242,5257,5258,5266,5292,5299,5303,5305,5323,533,5344,5347,5352,5360,5365,5378,5398,5432,5500,5507,5527,5532],"n03124170":[10150,1025,10303,10401,10512,10593,10673,10734,10755,1079,1082,10828,10901,10917,1096,10982,1106,11136,11177,11182,114,11468,11557,11741,11811,11966,11993,12003,12087,12105,12181,12231,1225,12282,12301,12311,12324,12373,12423,12556,12557,1258,12627,12952,1317,13213,13237,1331,13332,13400,1341,13564,13616,13618,13623,13636,13734,13744,13746,13751,13755,13854,13870,13903,13910,13922,13927,13998,14045,14209,14254,14263,14337,14396,1453,14693,14995,150,15251,1552,1578,1598,1608,16155,16290,1687,1701,1702,1707,17362,18766,1883,1940,1942,1952,1990,19921,19952,2036,2123,2146,2175,2223,2268,2273,2325,2390,2410,2500,2504,2512,2566,2632,271,2812,2972,2982,2987,3017,3058,3093,3164,3165,3269,327,3332,3490,3495,3671,3673,3678,3738,3834,39,3902,3924,3948,4101,4223,4352,4416,4483,4517,4519,4597,4645,4994,5068,5090,512,5202,5219,5245,5262,5295,5340,5373,5383,5400,5421,5427,5452,5487,5494,5521,5576,5630,5654,5675,5701,5895,60,6047,6606,6694,6837,7040,7239,7488,7524,7620,7673,7702,7728,7730,7762,7811,7813,7816,7819,7822,7836,7881,7882,7885,7957,8051,8054,8077,8096,8165,8233,8346,8350,8375,8381,8440,8623,8834,892,8995,9053,9147,9176,927,9337,9388,9394,9429,9430,9524,9652,9680,9689,9703,973,9769,9817,9856,991],"n04259630":[10025,10032,10094,10161,10163,10177,10245,10247,10289,10362,1040,10450,10454,10533,10667,10744,10853,11001,1110,11158,11425,1170,1171,11860,11873,12039,12179,12246,12444,12536,12538,12584,12622,1271,12796,12909,13123,13242,13773,14079,1416,14340,14390,14394,144,14547,14617,14697,14912,1496,15009,15138,15236,15247,15438,15562,157,15750,15794,15938,1604,16045,16100,16123,16135,1615,16168,16194,16264,16341,16361,16446,16469,16626,16667,16795,16877,16917,16954,16972,17015,17146,17205,17295,17401,17441,17446,17456,17555,17608,17645,17685,17714,17793,178,17803,17854,18011,18058,18062,18199,18255,18283,18424,18469,18585,18602,19119,19218,19256,19717,19768,19804,1994,20113,2021,20278,2073,20995,2100,21095,21144,21163,2132,21421,21641,21717,2174,21750,21760,21807,21814,21834,21843,21874,21924,22005,22015,2204,22067,22075,22168,22190,22267,2227,22281,22303,22375,22593,22597,22712,22742,22918,22955,23047,23058,23588,23627,23768,23993,2459,24598,25038,25330,25390,25550,25574,256,25833,2585,2586,26142,26160,2622,26257,2629,26291,26311,26368,26588,26637,26735,27067,27098,2718,27200,27243,27246,27358,27398,27579,27636,2789,28203,2894,29525,3031,3070,31227,32351,338,3544,3553,3588,36590,3665,3698,3713,37320,3814,38448,38691,3953,3956,3985,4030,4100,4275,4364,4369,44,441,4499,4559,4664,4723,4785,4830,4870,4948,515,5167,5323,5617,579,585,5886,5904,6149,6320,6447,6474,6521,6572,6590,6673,6821,6840,6859,6945,7083,7238,7274,7309,7373,7475,7485,7533,7564,7652,7696,7708,7734,782,8037,8149,8241,8329,8526,869,8706,874,8798,883,8869,8964,8989,9001,906,916,9165,9316,9320,9325,9393,9403,9440,9447,9471,9556,9576,9622,9625,9669,9694,9721,9798,9906],"n03680355":[10143,10162,1017,10221,1030,10315,1036,10405,10462,10502,10525,10543,10556,10651,1067,10688,1071,10739,10759,10807,10823,10845,10860,10882,10923,110,1100,11006,11026,11038,1104,1111,1115,1124,11304,1131,11321,11330,11380,11397,11413,11421,11464,11466,11515,11526,11560,1157,1159,11602,1162,1170,1173,11770,11774,11777,11783,11814,1183,11884,11924,1201,12067,12099,12118,1212,1215,12150,12159,1220,1222,12316,12356,12358,12382,1241,1245,12504,1252,1253,12586,12600,12648,12717,1276,12796,12848,12943,12949,1295,130,1302,1308,13108,13162,1322,13252,13289,1335,13388,1341,13414,13487,1349,135,1357,13581,1362,13722,13745,13849,13858,1391,13927,13982,1402,1417,14235,14239,14289,1430,14349,14377,14478,1454,14686,14708,14776,14780,1479,14799,1484,14868,1504,15047,15054,1506,15070,15086,15210,1523,15257,15281,15298,15312,15326,15349,1543,1546,1569,1576,15817,15882,15927,1598,1621,1624,1635,16366,1642,1661,16842,16951,1696,17,17056,17172,17201,17203,17310,17318,1739,17457,17464,17484,17672,17781,1784,17897,18040,18169,1821,18234,18298,18356,18376,18410,1844,18505,1851,18891,18977,1901,19190,19218,19239,19478,1953,19863,19924,20094,20099,20181,2023,2025,20285,20481,20743,2085,2086,20888,20921,20969,21060,21190,2123,2126,21306,21312,2151,21682,21763,21988,2205,22110,22137,22148,22159,22282,2230,22334,2250,22644,2279,22836,2291,23054,23087,23111,2312,2318,23281,23495,23497,23533,23696,23910,23911,2393,2397,24007,2413,24135,24137,24159,2445,2453,24569,24613,2478,24787,2483,24831,25034,2506,25161,25242,25321,2548,2551,25548,2558,25601,25653,2567,2577,25780,25836,25863,25889,2590,2595,26077,2614,26175,26212,2622,2625,2640,2641,2657,2662,2669,2678,2689,2693,2702,2720,2737,2762,2778,2784,2812,2822,2826,284,2845,2846,2849,2868,2878,2910,2921,2927,2939,2963,3018,3020,3028,3046,3049,3103,3118,3133,3158,3191,3193,322,3287,3304,3313,3369,3386,34,3406,3458,3460,3462,3465,3498,3525,3595,3606,3611,3618,3641,3646,365,3669,3698,3744,377,3788,3809,3812,382,3861,3869,3870,3875,3879,3880,3915,3935,3940,3951,3961,3968,3974,3981,3991,4027,4034,4042,4058,4061,4088,4093,4111,412,4122,4126,4127,4137,4141,417,4170,4211,4215,4220,425,427,4280,4290,4319,4328,4375,4384,440,4421,4475,45,4513,452,4526,4556,4585,4593,4612,4622,4637,4649,4667,469,4699,4714,4727,473,4734,4747,4767,4773,4775,4776,4778,4823,4830,4832,484,4840,4843,4849,4851,4859,4871,4882,4906,4932,4964,4992,5003,5006,5017,5026,5050,5069,5084,5086,5114,514,5169,5182,5243,5247,53,531,5321,5322,5351,5361,5363,5369,5374,5382,5406,5407,5440,5467,5471,5472,548,5503,5506,5507,5509,5518,5579,5593,5637,5719,5734,586,5861,5897,601,6050,6064,610,6124,6135,6157,6159,620,639,6395,6399,6432,6479,654,670],"n03124043":[10079,1013,103,1035,10553,1058,1066,107,1075,1078,10967,111,1117,1127,11353,11440,1149,1159,11626,1168,117,1177,1188,1196,1200,1203,1207,121,1215,1229,12292,1232,1247,1248,1252,1259,1260,1299,13,130,1306,131,1311,1315,1319,13194,1320,1328,13494,1366,1377,1379,138,13832,13889,1395,1398,14,140,14046,1408,141,1417,1428,1432,1452,14565,1470,1476,1485,150,1532,1559,1570,1592,1597,1616,1626,1627,166,1690,1691,1693,1695,1703,1709,1713,1722,1727,1754,1770,1773,1799,180,1807,1818,1831,1834,1838,1845,1853,1865,188,18871,1922,1928,193,19300,1966,20311,20320,2043,2048,206,20684,2094,2105,2114,2116,21356,2152,2166,21739,21844,21860,2191,2207,221,2212,2233,225,2254,22856,2286,2291,22998,23079,2315,2332,23349,2340,23466,2352,23629,23752,2377,23936,23944,2400,24044,2407,24071,2438,24427,2447,245,246,24604,2470,2472,2475,2496,25277,25298,255,2550,256,25774,2589,2597,2598,2601,2624,26306,26376,2647,26493,2654,2664,2666,2667,2670,26730,2677,2698,2707,2709,2726,2729,2730,27427,2747,2753,2776,27849,2794,28130,2820,2833,28348,28402,2845,28480,2857,2861,2871,2886,2894,2898,29,2939,2941,2946,2968,297,299,300,30044,3020,3027,30292,3035,304,3041,3042,3045,305,3062,3064,30783,3081,3098,31170,315,3164,31687,317,318,3217,3251,3263,3264,3321,334,3344,3348,3362,3390,3409,3412,3414,342,3444,3447,3459,3464,3479,352,3542,3584,3593,3595,3608,3681,3703,371,3713,3726,3759,3805,3818,3841,3859,3940,3955,3993,4001,4011,4014,4021,4035,4040,4053,4060,4066,4069,4078,4084,4110,4131,4134,4149,4158,416,4163,4168,417,4178,4188,4191,4193,4194,42,4211,4219,4235,4242,4248,4254,4257,4259,4293,431,4353,4385,4388,440,4415,4432,4434,4441,4446,4448,4452,4458,4468,4477,4502,4505,4579,4673,4682,4686,4692,4702,4708,4759,4761,4767,477,4783,4793,4816,4851,4859,4864,4895,4903,4911,4923,4925,493,4934,4936,4940,4946,4948,4958,496,4967,4984,4991,5015,5032,5058,509,5090,5104,5112,5122,5136,5145,515,5153,5166,5178,5198,5201,5224,5229,5234,5235,5267,5314,5318,5329,5336,5339,5343,5371,5375,5377,538,5402,5409,5413,5424,5435,5438,544,5455,5477,5479,549,5498,5499,5501,5502,5503,5518,5569,5585,5589,5626,5637,564,5641,5643,569,5696,5711,5744,5753,5762,5806,5808,5814,5818,5846,5856,5865,5882,5883,589,5891,5901,5913,5934,5942,5945,5962,5963,5969,597,5996,6004,6017,602,6031,6042,6051,6063,6066,6082,6124,6131,6148,6188,6190,6194,6205,6207,6210,6214,6226,6227,6231,6236,625,6255,6259,6264,6269,6296,6301,6303,631,6311,6318,633,6338,6343,6349,6356,6358,6373,6375,6379,6382,6392,6399,6400,641,643,6430,644,6445,6446,645,6453],"n03838899":[10,1003,10111,10112,10144,10182,10223,10281,10328,10427,1059,10621,10668,10913,10914,10930,1117,11188,11431,11442,11485,11795,11829,1186,11878,12022,1216,1220,1227,12292,12312,12513,126,12822,1284,12926,13279,13399,1351,13656,13685,1383,13890,14099,14256,14373,14392,14424,1459,1500,15046,15091,1511,15337,15363,15371,15476,15511,15661,15690,15711,15764,15848,15855,1594,16089,16276,16314,16399,1642,16477,16540,16608,16858,16903,1694,16955,17015,17020,17078,1712,17202,17442,1745,17493,17537,17583,17983,18538,18870,19090,19426,19522,1955,19768,1978,19799,19897,19918,19949,20063,20146,2020,20254,20383,20609,20635,20658,21139,21289,21553,21683,217,2176,21823,21913,2204,22366,22539,2257,22632,2282,22942,22954,23021,23149,23213,23241,23434,23475,23627,2364,23823,23878,23890,23908,24223,24245,24366,24865,251,25220,25379,25677,26087,26096,26203,26502,26549,26589,26838,26866,26887,26927,26964,27021,27044,27095,27181,27234,27241,27256,27271,2742,27447,27503,27517,27522,27532,27643,27678,27747,27815,2783,27832,27889,27902,27947,27955,28028,28030,28033,28061,28136,28206,28244,28258,28485,28539,28563,28636,28655,28767,28777,28925,29020,29086,29213,29233,29329,2970,29719,29749,29885,29988,3,30058,30150,30196,30198,30212,30249,30251,30253,30288,3032,30370,30376,30394,30490,30550,30654,30678,30724,30739,30986,31206,31235,31236,31242,31329,3134,31372,31376,314,31473,31515,31520,31544,31579,31643,31659,31674,31698,31715,31829,31842,31875,31940,31941,31948,31983,31987,32004,32012,32031,32067,32105,32169,32177,32232,32237,32243,32255,32575,32582,32647,32648,32651,32800,32841,32864,32876,32965,32972,32976,32981,32991,33004,33035,33048,33102,33133,33213,33218,33243,33289,33290,33299,33315,33321,33330,33399,33408,33430,33457,33470,33562,33590,33603,33639,33651,33728,33745,33802,33817,3384,33848,33886,33914,340,34000,34024,34026,34425,34426,34432,34598,3469,34791,35032,35217,3527,35292,35513,35537,3565,35860,35867,35875,35902,36032,36271,36500,3656,366,37194,37569,37664,37804,37863,37941,38234,3840,39385,39667,39715,40007,40154,40221,40515,40885,40934,40980,41117,41410,41668,41699,41718,41744,42148,42170,42476,42566,43099,43272,43305,4350,43560,43672,43689,43833,43904,43907,44052,44159,4460,44701,4475,44912,44964,45030,45265,4527,45498,4556,45888,45935,45937,45972,46477,46501,46717,46843,47111,47175,48269,48543,48689,48734,48826,49082,49100,4913,49344,49709,50042,5006,50332,50390,51216,51309,5139,51492,51737,51739,51748,5205,52321,52381,52741,52763,52939,53316,53833,54303,54446,54531,54682,54815,54894,549,55037,55041,55583,55608,56017,56138,5630,5693,5735,57693,58099,5819,6218,6240,6263,6311,6407,6501,6669,6918,6927,694,7243,7251,7316,7438,7452,7505,7683,7723,7877,8045,805,8120,8550,8589,8598,8797,8823,8895,891,8982,9054,9128,9270,9300],"n03249569":[10072,10145,10176,10224,1030,10319,10711,10881,11019,11024,11068,11069,11071,11149,11255,1130,11493,11583,11727,11745,11776,1190,11932,12008,12101,12129,12241,12252,12262,12274,12284,12417,12449,12465,12665,12788,12811,12878,12907,12914,12976,13027,13220,13294,13393,13446,13454,13487,13584,1361,13664,13708,13799,1384,1404,14054,14115,14143,14167,1445,14461,14525,14534,14565,14569,14604,14753,1514,15270,15473,15593,15758,15813,15845,15994,160,16023,16093,16136,16170,16203,16214,16260,16304,16387,16460,16483,16521,16550,16712,16753,16760,1677,16807,16846,16942,16973,17054,17095,17174,17216,17313,17341,1735,17352,17392,17395,17404,17437,17439,17447,17452,17470,17506,17598,17606,17639,17679,17758,17835,17863,17932,17973,17994,18013,18156,18297,18457,18546,18656,18658,18669,18677,18796,18884,19098,19113,19118,19154,19187,19266,19303,19455,19465,19482,19490,19518,19602,19800,1992,19987,20057,20079,20123,20180,20181,20182,20304,20314,20374,20436,20509,20559,20591,20820,20875,20897,20973,20982,20995,2101,21060,21066,21215,21225,21320,21349,21368,21411,21517,21594,2172,21803,21946,21961,22044,22082,22135,22163,22274,22311,22327,22477,22485,22501,22669,22749,22840,22848,22861,22953,22956,23024,23059,23060,23070,23110,23220,2330,23367,23863,24093,2412,24134,24170,24268,24324,24613,24935,25014,25089,25280,25330,25479,25482,25517,2552,25541,25575,25626,25967,25976,26155,26328,26366,26373,26504,26513,26539,26609,26695,26818,26958,26990,27088,27139,27390,27608,27645,27746,27763,27772,27782,27793,27906,27971,2800,28078,2809,28097,28194,2821,28215,28245,28248,2832,28482,28525,28585,28593,2877,28797,2882,29201,29524,29605,2971,29775,29863,30018,30053,30120,30121,30233,30244,30280,30293,30316,30451,30494,30618,3066,30684,30739,3081,30914,31014,31033,31106,31109,31137,31172,31185,312,31271,31272,31275,31311,3132,31348,31375,31507,31603,31625,31643,31745,31763,31794,31822,31836,3190,3194,3221,32276,32454,33103,33200,33436,33617,33814,33823,33885,33999,3400,34017,34162,3448,34607,34752,34830,34833,34868,34879,35025,35030,35043,35050,35052,35162,3519,35228,35249,35310,35333,35362,35415,35430,35567,35589,35612,35637,35657,35714,35774,35812,35820,35840,35888,35932,35935,3596,35961,35971,36030,36059,36133,36162,36200,36234,36361,36434,36445,36477,36519,36603,36622,36668,36771,36807,36819,36853,36854,37051,37056,37062,37099,37143,37201,37374,37383,37773,3783,37850,37870,37899,3790,37903,3791,37946,37965,38281,38451,38641,38688,38744,38789,38838,38922,390,39002,39070,39072,3910,39187,39217,39264,39369,39451,39681,39763,3996,40000,40138,40273,4037,4045,4049,40579,40580,40732,40812,40955,41969,42071,42109,42120,42134,4218,42221,42276,42285,42312,42456,42488,42499,42507,42571,42631,42732,42765,42889,42913,42920,4294,42959,43080,43201,43251,43279,43350,43504,43515,43573,43583,43987,4430,44331,44585,44586,44675,44800,45216,45310,45408,45434,45468,45516,45554,45682,45696,45731,45743,45806,45811,45846,45860,45944,45986,46000,46081],"n04074963":[10005,10029,10107,10117,10129,10135,1015,10191,10247,10273,10282,10321,10395,10406,10424,1046,10468,10474,10509,1052,10557,10653,10655,10675,10704,10742,1075,10841,10947,10951,10968,10995,11012,11040,11081,11119,11143,11160,11163,11213,11226,11244,11289,11290,11339,11358,11419,11424,11434,11442,11445,11454,11500,11506,11519,11522,11535,11554,11559,1156,11575,11582,11590,1166,11668,11676,11704,11709,1177,1179,11798,11802,11807,11834,11845,11850,11862,11864,11875,11883,11895,11910,11947,11975,11976,1200,12015,12041,12050,12059,12073,12077,12090,12101,12130,12166,1225,12291,12303,12362,12451,12458,1247,1252,12534,12537,12568,12612,12643,12698,12720,12752,12763,1277,12787,12818,12819,1282,12849,12871,12893,12896,1290,12924,12958,12981,13005,1307,13088,13135,13216,13225,13252,13274,1345,13461,13484,13565,13635,13685,13692,13708,13718,1381,13855,13890,13938,13977,13991,14035,14041,1408,14085,14089,14104,14117,14125,14153,14158,1423,14250,14274,14307,14321,14331,14361,1438,14409,14450,14454,14490,1453,1454,1456,14573,14577,14593,1466,14676,14705,14724,14860,14864,14905,1491,14966,14979,14982,150,15043,15045,15058,15078,15089,15105,1512,15147,15152,15167,15170,15171,15189,15208,15212,15349,15412,15421,15444,1558,1567,15765,15774,15839,15876,15881,159,15909,15965,15970,16,16025,16049,16073,16078,16092,1611,16130,16151,16234,1624,16240,16285,16303,16314,16372,16394,16406,16431,1652,16551,16602,16616,16623,16674,1668,16692,1675,16779,16790,16836,16842,16845,16855,16858,16868,16876,16915,16924,16956,1696,16968,17141,17162,17185,1720,17241,17286,17333,17397,17418,17422,17424,17460,17466,17475,17537,17562,17592,17619,17625,17647,17717,1772,17720,17744,17801,1783,17883,17983,17989,1807,18107,18117,18173,18194,18202,18203,18236,18275,18300,18322,18345,18352,18383,18430,18461,1847,18507,18541,18566,18590,18697,18730,18741,18744,18786,18793,18833,18861,18883,18907,18942,18951,19043,19081,19099,19114,19162,19216,1923,19234,1925,19295,1933,1939,19396,19398,19428,19430,19436,19438,19473,19483,19493,19545,1955,19576,19578,19622,19637,1964,19650,1967,19673,19677,19710,1973,19742,19748,19798,19851,19858,19859,19870,19884,19895,19965,20017,20088,20093,20098,20133,20183,20213,20226,2025,20276,20286,20290,20314,20315,20316,20332,20341,20342,20407,20449,20476,20480,20513,2052,20520,20550,20561,20582,20627,20628,20631,20634,20684,20698,20716,20724,20727,20735,20745,208,20802,20808,2081,20829,20881,20888,20907,20909,20936,20981,20984,2102,21025,21040,21046,21060,21077,21086,2109,21112,21142,21180,21181,21195,21198,21213,21214,21234,21278,21280,21291,21338,21359,21371,21372,21403,21427,21431,21463,21464,21477,21484,21513,21517,21529,21533,21542,21548,21557,2158,21590,2161,2163,21644,21674,21685,21707,21730,21732,21735,21742,2175,21757,21836,22101,22166,224,22506,22560,22584,2264,22676,22688,22723,22748,22840,22901,22906,22916,22930,23,23076,23078,2312,23136,2319,23226,2325,23251,2329,23314,2338,2343],"n02676566":[10012,10017,1002,10062,10075,10100,10102,10114,10171,10299,1044,10467,1049,1056,10750,108,10830,10832,1087,10900,10902,10977,11034,11052,11067,11110,11113,11123,11129,11140,11184,11208,11215,1122,11239,11293,11301,11334,1136,11441,11513,11573,1158,11580,11643,118,11818,11897,11957,12007,12075,12103,12121,12164,12199,12229,12244,12344,1236,12360,12398,1240,12438,12503,1256,12565,12570,12573,12575,12643,12662,12691,12754,12763,12820,12827,12864,12910,12963,130,13036,1304,13067,13083,13126,13212,13267,13455,13473,13619,1365,13663,1393,1418,1434,1441,14507,15152,15190,15218,15296,1555,1587,1606,164,1645,1646,165,1651,167,1690,1691,17,1707,1728,1736,1757,178,1825,183,1835,1843,1855,1866,1882,1956,1964,1973,202,2046,2066,218,2187,219,22,2230,2237,2252,2256,2258,2263,2325,2330,2373,2380,242,2454,2460,2471,2480,2554,259,2631,2684,2696,2769,2778,2779,2803,281,2825,2876,2899,2913,2952,2954,2967,2970,2980,3004,306,3069,307,3085,3101,3109,3115,3120,3125,3127,3159,3161,3206,328,3314,3324,3325,3339,3340,3382,3385,3386,3394,3401,3402,341,3424,343,3440,3461,3471,3482,3492,3500,3523,3527,3528,3540,3541,3629,3650,3660,367,3750,3753,3767,380,3854,3876,3889,3892,3916,3920,3957,3977,3978,399,402,4057,4058,4059,406,4064,4074,4075,4095,4130,4134,4137,4160,4166,4171,4178,4208,4212,4236,4240,4241,4251,4252,4254,4305,4317,4343,4366,4391,4394,4402,4407,4415,4419,4425,4426,4441,4454,4462,4469,449,4493,4507,4530,4532,4537,4543,4573,4584,4595,4602,4604,4605,461,4621,4623,4632,4648,4668,467,4679,4697,4699,4706,4759,4789,4793,4795,4812,4823,4825,4839,4853,4877,4883,4893,4916,4928,4936,4946,5000,5001,5012,5109,511,5168,523,5255,5256,529,5293,5355,5356,5363,5364,5367,5372,5373,5380,5400,5408,5411,5412,5416,5421,5427,5430,5437,5438,5448,5450,5453,5454,5457,5460,5461,5464,5468,5476,5480,5489,5507,5508,5515,5518,5522,5524,5534,5535,5545,5559,556,5591,5601,5610,5637,5641,5645,5649,5684,5689,5713,5735,5742,5773,5776,5830,5860,5861,5871,5943,5966,602,6024,6030,6150,616,6178,6196,6200,6202,6234,6245,6253,6260,6265,6268,6269,6289,6292,6293,6302,6303,6304,6306,6319,6320,6326,6329,6335,6341,6343,6351,6354,6355,6363,6370,6372,6377,6378,6384,6390,6392,6402,6405,6414,6430,6435,6437,6466,6467,6469,6479,6489,6493,650,6518,6532,654,6544,6549,6554,6557,6559,6560,6563,6571,6575,6582,6583,6588,6589,6590,6604,6615,6625,6633,6636,6637,6644,6646,665,6658,6659,6660,6661,6672,6673,6674,6677,6682,6687,6703,6704,6705,6713,6737,6738,6744,6746,6750,6753,6762,6763,6764,6766,6770,6772,6778,6796,6799,6801,6839,684,6842,6843,6855,6857,6858,6865,6871,6875,6881],"n03272010":[10127,10170,10237,10363,10399,10424,10441,10443,10457,10510,106,10612,1067,10690,107,10795,10806,10815,10841,10848,10946,10973,11016,1109,11110,1114,11264,11276,11297,11343,11356,11378,11419,11443,11451,11498,115,11502,11505,11513,11538,11598,116,1165,11675,11740,11743,11764,11777,11814,11857,11879,11890,11925,11953,120,1203,12051,12069,12110,12151,12196,12204,1221,1242,12468,1259,1264,12662,1268,12924,1296,12967,1301,1304,13242,1328,1334,1336,1342,1345,1346,1377,13804,13813,13834,13914,13963,13968,1399,140,14010,1405,14073,1411,14119,14144,1415,142,1422,14226,1425,1432,14364,1442,1445,14490,14495,1462,1464,14690,14701,14736,1487,1496,1503,1507,15078,15107,1511,1523,1526,1529,1531,1536,1550,1551,1552,1553,1574,1576,15764,1579,15795,1582,15857,159,15907,15922,1594,1595,1608,1609,1616,1618,1630,1640,1643,1654,1656,1666,1676,16905,1699,17033,1708,1710,1711,1714,1726,1727,1739,1745,1747,175,1750,176,1760,1762,1763,17764,17768,1781,17811,1783,17873,1807,1852,1872,1881,189,1894,1924,1938,1939,1943,1953,1962,1973,1976,1988,1992,2001,2002,2018,2024,2033,2036,2042,2046,2058,2060,2070,2089,2114,2125,2126,2134,2137,2142,2150,2152,2159,2162,2168,2195,2197,2199,2210,2218,2223,2230,2232,2234,2238,2246,2256,2268,2278,2289,2294,2301,2312,2314,2316,232,2322,2323,2332,234,2372,2385,2387,2391,2411,2414,2420,2438,2442,2444,2459,2463,2467,2475,2481,2490,2529,2536,2559,2583,2618,263,2695,2772,278,2790,287,2880,2919,2922,2925,2929,2966,2999,3002,3022,3092,3136,3139,317,3181,3190,3191,3221,3227,3235,3239,3247,3251,3276,3281,3293,3294,330,3312,3313,3324,3338,3339,3343,3346,3353,3364,3371,3390,3393,34,3400,3414,3432,3452,3459,347,3471,3474,3475,3480,3482,3514,3521,3532,3538,3547,3552,3597,36,362,3621,364,3652,3669,3699,3715,3721,3726,3727,3728,373,3732,3743,3752,3763,3769,3770,3785,3790,3791,3793,3801,3805,3811,382,3832,386,3861,3870,3874,389,3896,3910,392,3929,3975,398,3981,3989,3993,3995,4005,4010,4016,4024,4053,4054,4061,4062,4075,4088,4092,4093,4099,412,4132,4135,4148,4199,4217,4218,4221,4229,4248,4252,4264,4287,431,433,4333,4340,4348,4361,4370,4372,4395,4441,4443,446,447,4472,4478,4509,4547,4553,4554,4572,4579,4587,459,4598,460,4607,4611,4616,4618,4621,4643,4648,4660,4669,4673,4693,4702,4703,4713,4726,4728,474,4751,4766,4768,4769,477,4774,4776,4778,4800,4806,4818,4821,4829,4830,4832,4836,4837,4845,4858,4861,4864,4865,4872,4876,4886,49,4900,4901,4902,491,4939,4950,4953,4966,5019,504,5103,5150,5152,5177,519,52,525,5253,5257,526,527,534,5362,5373,5381,5412,5421,5424,5425,5427,543,5437,544,549,5510,5514,552,5525],"n04152593":[10032,10033,1011,10111,10136,10240,10293,10382,1039,10409,10413,1052,10559,10572,10684,10707,10729,10778,10860,10874,10988,11016,11054,11079,11094,11120,11193,1122,11226,11247,11444,11495,1150,11516,11537,11572,11659,11730,11747,11804,11848,11876,11898,11901,11903,11945,12111,12136,1214,12184,12204,12249,12276,12299,12324,1244,12450,12470,12539,12547,1258,12581,12607,12653,12665,127,12727,12759,12771,1290,12912,12948,12952,12961,12975,12992,12996,13020,13026,13031,13082,13116,13122,13127,13168,13170,13181,13203,13206,1324,13244,13319,13328,13347,13402,13430,135,13511,13576,13603,13640,13665,13698,1375,13774,13802,13815,13819,13826,13834,13922,13962,13975,13979,13988,13993,14043,14058,14115,14228,14328,14343,14420,14440,14444,14474,145,14525,14537,14547,14553,14567,14576,14590,14638,14650,14665,14733,1474,14741,14776,14811,14818,14828,1483,14844,1485,14850,14890,1493,15007,15045,1507,15090,15129,15140,15212,15220,15235,15291,1533,15359,1543,15479,15517,15522,15533,1554,15547,15551,15569,1558,15696,15712,15748,15752,15767,15810,15879,15891,15954,16019,16096,16142,16189,16200,16264,1629,16323,16328,16329,16344,16363,16367,16370,16381,16391,16393,16416,16457,1646,16466,16478,16488,16515,16592,16627,16646,16690,16714,16718,1679,16819,16822,16846,16856,16866,16931,16966,16989,16990,16993,1706,17111,1712,1716,17181,17206,17233,17258,17329,17460,17469,17494,17512,17535,17629,17647,17767,17789,178,1782,17967,18034,18116,182,18217,18219,18233,18331,18361,18442,18451,185,18503,18540,18552,18557,18567,18570,18577,18585,18593,18611,18627,1863,18633,18643,18656,18674,18689,18698,18706,18708,1875,18781,18911,18921,18923,190,19066,19096,19194,19493,19553,19555,19604,1962,19716,19771,19779,19889,19923,1995,1997,20054,20092,2018,20281,2037,20371,20393,20412,20439,2051,20542,20554,2063,20696,20787,20874,20960,20962,21046,21134,21199,21202,21232,21480,2152,2153,21607,21732,2174,21772,2193,21966,22077,22166,22231,2226,22299,22306,22414,22421,22451,22460,22559,22609,22613,22642,22652,22675,22742,2283,23051,23055,2320,23232,23324,23354,23492,23503,23504,23528,23531,23540,23560,23627,23765,23836,23842,23888,23892,23952,24004,24028,24045,24069,24127,24223,24235,24260,24319,2441,24465,24508,24510,24566,24567,2457,24576,24651,2466,24697,2479,24839,24856,24901,25052,25066,25071,25131,25202,25203,25334,25368,2560,25630,25673,2568,25707,25837,26118,26146,26280,26390,2641,26479,26847,26887,26950,26980,26991,2712,2718,27273,27511,27530,27579,27590,2761,27710,2777,27847,27876,27895,27926,2793,27975,27986,28060,28105,28288,28312,2833,2841,28468,2858,28607,28626,28675,28760,288,28862,2889,28913,29083,29091,29097,29342,29410,29477,29489,29558,29593,29607,29609,2969,29774,29818,29859,2986,29990,3003,30034,30138,30172,30233,30380,30465,30487,30577,30630,3070,30743,30766,3085,30864,30909,3097,31026,31103,3116,31225,31304,3134,31376,3140,31429,31451,31503,31636,3164,3165,31822,31846,31938,31988,32010],"n04590129":[1001,10036,1006,1014,10201,10378,10412,1049,10499,10522,10550,10565,10597,10680,1069,10691,10697,10726,10734,10735,10736,10746,10756,10783,10862,10864,10881,10920,10940,11028,11034,11098,11107,1112,1113,11155,11157,1116,11167,1118,11265,11362,11388,1143,11484,11510,11535,1155,1159,1162,1167,11673,11706,1173,11820,11844,11845,1186,1194,11991,1215,1221,1223,12234,12238,1227,12321,12349,1239,12475,12548,12596,12649,1272,12733,12762,12774,12799,12862,12877,129,1290,12966,13042,13080,13289,1330,13365,13375,13399,13429,13434,13452,13501,13521,13577,13767,13799,13840,13918,13993,140,1407,14074,14136,14154,142,14261,1429,14372,14415,14465,14489,14611,1480,14803,14815,1494,14945,14978,14995,14997,1502,15112,15194,15209,1534,15342,1536,15442,15483,15533,1559,15622,15675,15800,15806,15822,15827,15830,15852,15867,15904,1592,1595,16084,16104,1613,16131,16167,16175,16218,1623,16231,16242,16331,16350,16357,16386,1640,16410,16427,16547,16600,1663,16683,1671,16759,16760,16763,16766,16788,16793,1680,16801,16815,16819,16839,16873,16886,1695,16974,1698,16998,17044,1706,17067,17086,17134,17145,17147,17174,1720,17237,1728,17300,17309,17311,17335,17340,17347,17387,17388,17392,17425,17431,17445,17464,17487,1749,17521,17526,17533,17606,1764,17648,17654,17661,17665,1767,17680,17681,17685,17692,17725,17729,17749,1778,1781,17833,1785,17897,1790,17925,1796,17996,18016,18024,18027,18046,18070,1812,18120,1816,18176,18209,18220,18333,18346,18351,18381,18415,18437,18448,18495,18506,18575,18637,1866,1869,18732,18751,188,1885,189,18927,18950,19100,19114,19117,19213,19295,19428,19499,1955,1968,19722,19727,19790,19795,19866,1993,1994,19977,1999,20,20009,20081,2009,20119,2012,20164,20228,20243,20259,20267,20274,2028,2030,20346,20384,2039,20396,20438,20487,20597,2060,20641,20667,20691,20719,20758,20763,20808,20811,2082,2086,2089,20897,20900,20919,20925,2094,20960,20983,2102,21054,21094,21115,2112,21124,21137,21140,21151,21174,21176,21190,21299,21318,21362,21377,21379,21396,21408,21418,21436,21466,21467,21479,21481,21492,21494,21511,21523,21542,21559,21585,21601,21608,21613,21618,21621,21631,21636,21642,21662,21689,21697,21736,21763,21804,21811,21827,21838,21839,21841,21858,21890,21891,21892,21908,21916,21938,2195,21963,21968,21976,21980,21998,22042,22048,22049,2206,22064,22068,22078,22110,22128,22135,22149,22164,22175,22194,22205,22207,22210,2223,22238,22241,22252,22263,22277,22281,22292,22294,22295,22307,22389,22407,22408,2243,22436,22476,22520,22524,22565,22597,22604,22609,22641,22645,22685,22728,22785,2280,2281,22812,2283,22843,22854,22879,22883,22891,22892,22943,2298,2302,23022,23023,23033,23058,23085,23131,23152,23180,23181,23247,23323,23324,23326,23336,23375,23379,23389,23441,23469,235,23505,23525,23533,23548,2355,23593,23600,23620,2365,23665,23719,23721,2373,23750,2376,23779,23894,23931,23966,23972,24008,24026,24046,24048,24073,24116,24117,24171,24183,24195,24231,24260,24300],"n04418357":[10012,10109,10121,10136,10249,1026,10293,1030,10333,10404,10416,10475,10487,1052,10530,10559,1056,10714,10779,10813,1082,10924,10949,10955,10989,1101,11025,11042,11115,11146,11151,11304,11361,11371,11391,11409,11425,11432,11485,1151,11526,11529,1156,11591,11635,11672,11674,11779,11850,11863,11962,1198,11980,11981,11998,12073,12088,1209,121,12219,12231,12233,12270,12288,12292,12317,12353,12397,12430,12439,12458,12508,12513,12572,12581,12635,12672,12703,12708,12728,12854,1289,12932,1300,13018,13035,13041,13043,13140,13203,13208,13364,13378,13381,13513,13527,13597,13614,1368,1372,13785,13793,1380,13920,140,1402,14107,14160,14214,14229,1426,14562,14607,14610,14622,14707,14791,14792,148,14906,14942,14988,15132,1529,1530,15350,1539,15509,15519,1552,15521,15532,15553,15577,15601,15635,15663,1576,15830,15884,1589,15897,1592,1597,15980,16041,16091,16096,161,16112,16163,1617,16203,16387,16470,16500,16508,16558,16589,16592,16632,16656,16666,16760,16761,16780,16809,1683,16839,16881,1693,16944,171,17118,17176,17216,1723,17243,17261,17312,17320,17341,17401,1741,1744,17476,17506,17518,1752,17556,1757,17594,17807,1782,17851,17862,17940,17967,18001,18018,1802,1810,18152,18160,18174,18215,18235,18284,18301,184,18402,18419,18438,18449,185,18538,18551,1861,18740,1876,18828,18848,1892,1897,18982,18995,19010,19022,1904,19106,19144,19178,19237,19239,1927,19390,19447,1947,19540,19642,19651,19660,19698,19704,19709,19772,19824,19852,19865,19866,19947,2007,20124,20149,20153,20241,20248,20313,2032,20326,20345,20379,2046,20521,20522,2053,20674,2073,2085,20863,20920,20978,20984,20997,2105,21069,21070,2143,21456,2146,21478,2153,21539,21633,21639,21661,2170,21787,21822,21826,21890,2190,21967,21978,21982,21997,22007,22021,22056,22097,221,22281,22357,22462,22465,2248,22486,22593,22654,22677,22691,22767,22927,2293,2295,22963,22967,23052,23053,2317,232,23266,23268,2340,23464,23471,2350,23516,23531,23567,23581,2366,23675,2372,23738,23757,2387,2393,24,24284,24370,24434,24446,2445,24513,24638,2471,24752,2476,24841,2486,2517,25255,2531,25363,25364,2545,2550,2551,25554,25661,25667,25699,25708,25739,25743,25877,2590,25910,25962,25982,26000,26036,26078,26340,2642,26423,26639,26695,2673,26765,26841,26867,26950,2714,27198,2728,2754,2758,2759,2763,27705,27761,27827,27830,27869,27934,27939,27940,28021,28058,28105,28157,28164,28166,28205,28432,2844,28465,2849,28531,28532,2856,28571,28670,28702,28750,28793,2893,28931,28971,28983,2900,29018,29038,2904,29191,2925,29371,2940,29431,29463,2955,29560,29576,29729,29804,29874,29914,2997,30043,3005,30144,30258,30285,3034,3044,30546,3056,30581,30634,30646,3070,30732,30860,30938,31130,31292,3136,3145,31484,3150,31543,3156,3161,3165,31708,31858,3188,31936,3209,32097,32176,32187,3225,32472,32492,32639,3273,32731,3278,3316,3318,332,3342,3371,3385,33970,34,34096,34097,34211,3437,34444,3459,3467,34764,3488,3518,35201]}}
|
discovery/prop_specificity.json
ADDED
|
@@ -0,0 +1,710 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"provenance": {
|
| 3 |
+
"generator": null,
|
| 4 |
+
"note": "discovery sweep not committed; no producer in the repo"
|
| 5 |
+
},
|
| 6 |
+
"n_prop_images": 8479,
|
| 7 |
+
"ranked_candidates": [
|
| 8 |
+
{
|
| 9 |
+
"dim": 11,
|
| 10 |
+
"prop_mean": 1.7091748714447021,
|
| 11 |
+
"person_pos_mean": 1.089888095855713,
|
| 12 |
+
"person_neg_mean": 1.1654655933380127,
|
| 13 |
+
"prop_vs_neg": 0.5437092781066895,
|
| 14 |
+
"person_vs_neg": -0.0755774974822998,
|
| 15 |
+
"score": 0.6192867755889893
|
| 16 |
+
},
|
| 17 |
+
{
|
| 18 |
+
"dim": 697,
|
| 19 |
+
"prop_mean": 1.63211190700531,
|
| 20 |
+
"person_pos_mean": 1.0918049812316895,
|
| 21 |
+
"person_neg_mean": 1.0371267795562744,
|
| 22 |
+
"prop_vs_neg": 0.5949851274490356,
|
| 23 |
+
"person_vs_neg": 0.05467820167541504,
|
| 24 |
+
"score": 0.5403069257736206
|
| 25 |
+
},
|
| 26 |
+
{
|
| 27 |
+
"dim": 572,
|
| 28 |
+
"prop_mean": 1.4398308992385864,
|
| 29 |
+
"person_pos_mean": 0.9548083543777466,
|
| 30 |
+
"person_neg_mean": 0.8750605583190918,
|
| 31 |
+
"prop_vs_neg": 0.5647703409194946,
|
| 32 |
+
"person_vs_neg": 0.07974779605865479,
|
| 33 |
+
"score": 0.48502254486083984
|
| 34 |
+
},
|
| 35 |
+
{
|
| 36 |
+
"dim": 671,
|
| 37 |
+
"prop_mean": 1.5082179307937622,
|
| 38 |
+
"person_pos_mean": 1.0776139497756958,
|
| 39 |
+
"person_neg_mean": 1.0892691612243652,
|
| 40 |
+
"prop_vs_neg": 0.418948769569397,
|
| 41 |
+
"person_vs_neg": -0.011655211448669434,
|
| 42 |
+
"score": 0.4306039810180664
|
| 43 |
+
},
|
| 44 |
+
{
|
| 45 |
+
"dim": 51,
|
| 46 |
+
"prop_mean": 1.2916672229766846,
|
| 47 |
+
"person_pos_mean": 0.8612672090530396,
|
| 48 |
+
"person_neg_mean": 0.6743829846382141,
|
| 49 |
+
"prop_vs_neg": 0.6172842383384705,
|
| 50 |
+
"person_vs_neg": 0.18688422441482544,
|
| 51 |
+
"score": 0.430400013923645
|
| 52 |
+
},
|
| 53 |
+
{
|
| 54 |
+
"dim": 186,
|
| 55 |
+
"prop_mean": 1.783549189567566,
|
| 56 |
+
"person_pos_mean": 1.3718806505203247,
|
| 57 |
+
"person_neg_mean": 1.2572942972183228,
|
| 58 |
+
"prop_vs_neg": 0.5262548923492432,
|
| 59 |
+
"person_vs_neg": 0.11458635330200195,
|
| 60 |
+
"score": 0.4116685390472412
|
| 61 |
+
},
|
| 62 |
+
{
|
| 63 |
+
"dim": 752,
|
| 64 |
+
"prop_mean": 1.4307368993759155,
|
| 65 |
+
"person_pos_mean": 1.0203551054000854,
|
| 66 |
+
"person_neg_mean": 0.9466467499732971,
|
| 67 |
+
"prop_vs_neg": 0.4840901494026184,
|
| 68 |
+
"person_vs_neg": 0.07370835542678833,
|
| 69 |
+
"score": 0.4103817939758301
|
| 70 |
+
},
|
| 71 |
+
{
|
| 72 |
+
"dim": 90,
|
| 73 |
+
"prop_mean": 1.4134135246276855,
|
| 74 |
+
"person_pos_mean": 1.027899980545044,
|
| 75 |
+
"person_neg_mean": 1.2588216066360474,
|
| 76 |
+
"prop_vs_neg": 0.15459191799163818,
|
| 77 |
+
"person_vs_neg": -0.23092162609100342,
|
| 78 |
+
"score": 0.3855135440826416
|
| 79 |
+
},
|
| 80 |
+
{
|
| 81 |
+
"dim": 161,
|
| 82 |
+
"prop_mean": 1.110310673713684,
|
| 83 |
+
"person_pos_mean": 0.7282975316047668,
|
| 84 |
+
"person_neg_mean": 0.8111143708229065,
|
| 85 |
+
"prop_vs_neg": 0.2991963028907776,
|
| 86 |
+
"person_vs_neg": -0.08281683921813965,
|
| 87 |
+
"score": 0.38201314210891724
|
| 88 |
+
},
|
| 89 |
+
{
|
| 90 |
+
"dim": 310,
|
| 91 |
+
"prop_mean": 1.6827064752578735,
|
| 92 |
+
"person_pos_mean": 1.306183934211731,
|
| 93 |
+
"person_neg_mean": 1.5448638200759888,
|
| 94 |
+
"prop_vs_neg": 0.13784265518188477,
|
| 95 |
+
"person_vs_neg": -0.2386798858642578,
|
| 96 |
+
"score": 0.3765225410461426
|
| 97 |
+
},
|
| 98 |
+
{
|
| 99 |
+
"dim": 88,
|
| 100 |
+
"prop_mean": 1.7690833806991577,
|
| 101 |
+
"person_pos_mean": 1.3999791145324707,
|
| 102 |
+
"person_neg_mean": 1.0576374530792236,
|
| 103 |
+
"prop_vs_neg": 0.7114459276199341,
|
| 104 |
+
"person_vs_neg": 0.34234166145324707,
|
| 105 |
+
"score": 0.369104266166687
|
| 106 |
+
},
|
| 107 |
+
{
|
| 108 |
+
"dim": 189,
|
| 109 |
+
"prop_mean": 1.2615772485733032,
|
| 110 |
+
"person_pos_mean": 0.893500030040741,
|
| 111 |
+
"person_neg_mean": 1.0122331380844116,
|
| 112 |
+
"prop_vs_neg": 0.2493441104888916,
|
| 113 |
+
"person_vs_neg": -0.11873310804367065,
|
| 114 |
+
"score": 0.36807721853256226
|
| 115 |
+
},
|
| 116 |
+
{
|
| 117 |
+
"dim": 613,
|
| 118 |
+
"prop_mean": 1.854291558265686,
|
| 119 |
+
"person_pos_mean": 1.4975982904434204,
|
| 120 |
+
"person_neg_mean": 1.73020339012146,
|
| 121 |
+
"prop_vs_neg": 0.12408816814422607,
|
| 122 |
+
"person_vs_neg": -0.23260509967803955,
|
| 123 |
+
"score": 0.3566932678222656
|
| 124 |
+
},
|
| 125 |
+
{
|
| 126 |
+
"dim": 201,
|
| 127 |
+
"prop_mean": 1.4382827281951904,
|
| 128 |
+
"person_pos_mean": 1.0972189903259277,
|
| 129 |
+
"person_neg_mean": 1.0087069272994995,
|
| 130 |
+
"prop_vs_neg": 0.4295758008956909,
|
| 131 |
+
"person_vs_neg": 0.08851206302642822,
|
| 132 |
+
"score": 0.3410637378692627
|
| 133 |
+
},
|
| 134 |
+
{
|
| 135 |
+
"dim": 360,
|
| 136 |
+
"prop_mean": 1.5004557371139526,
|
| 137 |
+
"person_pos_mean": 1.1636990308761597,
|
| 138 |
+
"person_neg_mean": 1.24490487575531,
|
| 139 |
+
"prop_vs_neg": 0.2555508613586426,
|
| 140 |
+
"person_vs_neg": -0.08120584487915039,
|
| 141 |
+
"score": 0.33675670623779297
|
| 142 |
+
},
|
| 143 |
+
{
|
| 144 |
+
"dim": 623,
|
| 145 |
+
"prop_mean": 1.1354831457138062,
|
| 146 |
+
"person_pos_mean": 0.8059989809989929,
|
| 147 |
+
"person_neg_mean": 0.7583788633346558,
|
| 148 |
+
"prop_vs_neg": 0.3771042823791504,
|
| 149 |
+
"person_vs_neg": 0.04762011766433716,
|
| 150 |
+
"score": 0.32948416471481323
|
| 151 |
+
},
|
| 152 |
+
{
|
| 153 |
+
"dim": 688,
|
| 154 |
+
"prop_mean": 1.4130481481552124,
|
| 155 |
+
"person_pos_mean": 1.0897259712219238,
|
| 156 |
+
"person_neg_mean": 1.1911897659301758,
|
| 157 |
+
"prop_vs_neg": 0.22185838222503662,
|
| 158 |
+
"person_vs_neg": -0.10146379470825195,
|
| 159 |
+
"score": 0.3233221769332886
|
| 160 |
+
},
|
| 161 |
+
{
|
| 162 |
+
"dim": 578,
|
| 163 |
+
"prop_mean": 1.6479562520980835,
|
| 164 |
+
"person_pos_mean": 1.3283374309539795,
|
| 165 |
+
"person_neg_mean": 1.4025310277938843,
|
| 166 |
+
"prop_vs_neg": 0.24542522430419922,
|
| 167 |
+
"person_vs_neg": -0.07419359683990479,
|
| 168 |
+
"score": 0.319618821144104
|
| 169 |
+
},
|
| 170 |
+
{
|
| 171 |
+
"dim": 81,
|
| 172 |
+
"prop_mean": 1.904716968536377,
|
| 173 |
+
"person_pos_mean": 1.597719430923462,
|
| 174 |
+
"person_neg_mean": 1.7867015600204468,
|
| 175 |
+
"prop_vs_neg": 0.11801540851593018,
|
| 176 |
+
"person_vs_neg": -0.18898212909698486,
|
| 177 |
+
"score": 0.30699753761291504
|
| 178 |
+
},
|
| 179 |
+
{
|
| 180 |
+
"dim": 692,
|
| 181 |
+
"prop_mean": 1.381159782409668,
|
| 182 |
+
"person_pos_mean": 1.0755085945129395,
|
| 183 |
+
"person_neg_mean": 1.1753791570663452,
|
| 184 |
+
"prop_vs_neg": 0.20578062534332275,
|
| 185 |
+
"person_vs_neg": -0.09987056255340576,
|
| 186 |
+
"score": 0.3056511878967285
|
| 187 |
+
},
|
| 188 |
+
{
|
| 189 |
+
"dim": 638,
|
| 190 |
+
"prop_mean": 1.2797389030456543,
|
| 191 |
+
"person_pos_mean": 0.9781198501586914,
|
| 192 |
+
"person_neg_mean": 1.0837996006011963,
|
| 193 |
+
"prop_vs_neg": 0.195939302444458,
|
| 194 |
+
"person_vs_neg": -0.10567975044250488,
|
| 195 |
+
"score": 0.3016190528869629
|
| 196 |
+
},
|
| 197 |
+
{
|
| 198 |
+
"dim": 522,
|
| 199 |
+
"prop_mean": 1.194052815437317,
|
| 200 |
+
"person_pos_mean": 0.8986038565635681,
|
| 201 |
+
"person_neg_mean": 0.8541845679283142,
|
| 202 |
+
"prop_vs_neg": 0.3398682475090027,
|
| 203 |
+
"person_vs_neg": 0.044419288635253906,
|
| 204 |
+
"score": 0.2954489588737488
|
| 205 |
+
},
|
| 206 |
+
{
|
| 207 |
+
"dim": 257,
|
| 208 |
+
"prop_mean": 1.8521565198898315,
|
| 209 |
+
"person_pos_mean": 1.5771883726119995,
|
| 210 |
+
"person_neg_mean": 1.6870157718658447,
|
| 211 |
+
"prop_vs_neg": 0.16514074802398682,
|
| 212 |
+
"person_vs_neg": -0.10982739925384521,
|
| 213 |
+
"score": 0.27496814727783203
|
| 214 |
+
},
|
| 215 |
+
{
|
| 216 |
+
"dim": 340,
|
| 217 |
+
"prop_mean": 0.9343926906585693,
|
| 218 |
+
"person_pos_mean": 0.6695823669433594,
|
| 219 |
+
"person_neg_mean": 0.6695160269737244,
|
| 220 |
+
"prop_vs_neg": 0.26487666368484497,
|
| 221 |
+
"person_vs_neg": 6.633996963500977e-05,
|
| 222 |
+
"score": 0.26481032371520996
|
| 223 |
+
},
|
| 224 |
+
{
|
| 225 |
+
"dim": 308,
|
| 226 |
+
"prop_mean": 1.525191068649292,
|
| 227 |
+
"person_pos_mean": 1.2669845819473267,
|
| 228 |
+
"person_neg_mean": 1.1947391033172607,
|
| 229 |
+
"prop_vs_neg": 0.33045196533203125,
|
| 230 |
+
"person_vs_neg": 0.07224547863006592,
|
| 231 |
+
"score": 0.25820648670196533
|
| 232 |
+
},
|
| 233 |
+
{
|
| 234 |
+
"dim": 479,
|
| 235 |
+
"prop_mean": 1.2297685146331787,
|
| 236 |
+
"person_pos_mean": 0.9748978018760681,
|
| 237 |
+
"person_neg_mean": 0.9749308824539185,
|
| 238 |
+
"prop_vs_neg": 0.25483763217926025,
|
| 239 |
+
"person_vs_neg": -3.30805778503418e-05,
|
| 240 |
+
"score": 0.2548707127571106
|
| 241 |
+
},
|
| 242 |
+
{
|
| 243 |
+
"dim": 299,
|
| 244 |
+
"prop_mean": 1.3217650651931763,
|
| 245 |
+
"person_pos_mean": 1.0688191652297974,
|
| 246 |
+
"person_neg_mean": 1.1240233182907104,
|
| 247 |
+
"prop_vs_neg": 0.19774174690246582,
|
| 248 |
+
"person_vs_neg": -0.055204153060913086,
|
| 249 |
+
"score": 0.2529458999633789
|
| 250 |
+
},
|
| 251 |
+
{
|
| 252 |
+
"dim": 440,
|
| 253 |
+
"prop_mean": 1.1131365299224854,
|
| 254 |
+
"person_pos_mean": 0.8602599501609802,
|
| 255 |
+
"person_neg_mean": 0.8018559217453003,
|
| 256 |
+
"prop_vs_neg": 0.31128060817718506,
|
| 257 |
+
"person_vs_neg": 0.05840402841567993,
|
| 258 |
+
"score": 0.2528765797615051
|
| 259 |
+
},
|
| 260 |
+
{
|
| 261 |
+
"dim": 458,
|
| 262 |
+
"prop_mean": 1.2792733907699585,
|
| 263 |
+
"person_pos_mean": 1.029525637626648,
|
| 264 |
+
"person_neg_mean": 0.9404508471488953,
|
| 265 |
+
"prop_vs_neg": 0.33882254362106323,
|
| 266 |
+
"person_vs_neg": 0.08907479047775269,
|
| 267 |
+
"score": 0.24974775314331055
|
| 268 |
+
},
|
| 269 |
+
{
|
| 270 |
+
"dim": 767,
|
| 271 |
+
"prop_mean": 1.4785064458847046,
|
| 272 |
+
"person_pos_mean": 1.2433205842971802,
|
| 273 |
+
"person_neg_mean": 1.2814769744873047,
|
| 274 |
+
"prop_vs_neg": 0.1970294713973999,
|
| 275 |
+
"person_vs_neg": -0.03815639019012451,
|
| 276 |
+
"score": 0.23518586158752441
|
| 277 |
+
},
|
| 278 |
+
{
|
| 279 |
+
"dim": 713,
|
| 280 |
+
"prop_mean": 2.0065953731536865,
|
| 281 |
+
"person_pos_mean": 1.7764008045196533,
|
| 282 |
+
"person_neg_mean": 1.8709570169448853,
|
| 283 |
+
"prop_vs_neg": 0.13563835620880127,
|
| 284 |
+
"person_vs_neg": -0.09455621242523193,
|
| 285 |
+
"score": 0.2301945686340332
|
| 286 |
+
},
|
| 287 |
+
{
|
| 288 |
+
"dim": 554,
|
| 289 |
+
"prop_mean": 1.3773629665374756,
|
| 290 |
+
"person_pos_mean": 1.1489109992980957,
|
| 291 |
+
"person_neg_mean": 1.0569530725479126,
|
| 292 |
+
"prop_vs_neg": 0.320409893989563,
|
| 293 |
+
"person_vs_neg": 0.0919579267501831,
|
| 294 |
+
"score": 0.22845196723937988
|
| 295 |
+
},
|
| 296 |
+
{
|
| 297 |
+
"dim": 0,
|
| 298 |
+
"prop_mean": 1.518669605255127,
|
| 299 |
+
"person_pos_mean": 1.292944312095642,
|
| 300 |
+
"person_neg_mean": 1.2706265449523926,
|
| 301 |
+
"prop_vs_neg": 0.24804306030273438,
|
| 302 |
+
"person_vs_neg": 0.02231776714324951,
|
| 303 |
+
"score": 0.22572529315948486
|
| 304 |
+
},
|
| 305 |
+
{
|
| 306 |
+
"dim": 351,
|
| 307 |
+
"prop_mean": 1.5037388801574707,
|
| 308 |
+
"person_pos_mean": 1.2783546447753906,
|
| 309 |
+
"person_neg_mean": 1.0354632139205933,
|
| 310 |
+
"prop_vs_neg": 0.46827566623687744,
|
| 311 |
+
"person_vs_neg": 0.24289143085479736,
|
| 312 |
+
"score": 0.22538423538208008
|
| 313 |
+
},
|
| 314 |
+
{
|
| 315 |
+
"dim": 266,
|
| 316 |
+
"prop_mean": 3.2978885173797607,
|
| 317 |
+
"person_pos_mean": 3.0799922943115234,
|
| 318 |
+
"person_neg_mean": 3.1888484954833984,
|
| 319 |
+
"prop_vs_neg": 0.1090400218963623,
|
| 320 |
+
"person_vs_neg": -0.108856201171875,
|
| 321 |
+
"score": 0.2178962230682373
|
| 322 |
+
},
|
| 323 |
+
{
|
| 324 |
+
"dim": 469,
|
| 325 |
+
"prop_mean": 1.2845133543014526,
|
| 326 |
+
"person_pos_mean": 1.0693851709365845,
|
| 327 |
+
"person_neg_mean": 1.0766862630844116,
|
| 328 |
+
"prop_vs_neg": 0.20782709121704102,
|
| 329 |
+
"person_vs_neg": -0.0073010921478271484,
|
| 330 |
+
"score": 0.21512818336486816
|
| 331 |
+
},
|
| 332 |
+
{
|
| 333 |
+
"dim": 250,
|
| 334 |
+
"prop_mean": 1.1550997495651245,
|
| 335 |
+
"person_pos_mean": 0.9470953941345215,
|
| 336 |
+
"person_neg_mean": 1.0209672451019287,
|
| 337 |
+
"prop_vs_neg": 0.1341325044631958,
|
| 338 |
+
"person_vs_neg": -0.07387185096740723,
|
| 339 |
+
"score": 0.20800435543060303
|
| 340 |
+
},
|
| 341 |
+
{
|
| 342 |
+
"dim": 684,
|
| 343 |
+
"prop_mean": 1.217105507850647,
|
| 344 |
+
"person_pos_mean": 1.0223654508590698,
|
| 345 |
+
"person_neg_mean": 0.9934371113777161,
|
| 346 |
+
"prop_vs_neg": 0.2236683964729309,
|
| 347 |
+
"person_vs_neg": 0.02892833948135376,
|
| 348 |
+
"score": 0.19474005699157715
|
| 349 |
+
},
|
| 350 |
+
{
|
| 351 |
+
"dim": 604,
|
| 352 |
+
"prop_mean": 1.4056569337844849,
|
| 353 |
+
"person_pos_mean": 1.2120150327682495,
|
| 354 |
+
"person_neg_mean": 1.3198471069335938,
|
| 355 |
+
"prop_vs_neg": 0.08580982685089111,
|
| 356 |
+
"person_vs_neg": -0.10783207416534424,
|
| 357 |
+
"score": 0.19364190101623535
|
| 358 |
+
},
|
| 359 |
+
{
|
| 360 |
+
"dim": 251,
|
| 361 |
+
"prop_mean": 1.238474726676941,
|
| 362 |
+
"person_pos_mean": 1.0456016063690186,
|
| 363 |
+
"person_neg_mean": 1.1859287023544312,
|
| 364 |
+
"prop_vs_neg": 0.052546024322509766,
|
| 365 |
+
"person_vs_neg": -0.1403270959854126,
|
| 366 |
+
"score": 0.19287312030792236
|
| 367 |
+
},
|
| 368 |
+
{
|
| 369 |
+
"dim": 275,
|
| 370 |
+
"prop_mean": 1.1440684795379639,
|
| 371 |
+
"person_pos_mean": 0.9552448391914368,
|
| 372 |
+
"person_neg_mean": 1.0024899244308472,
|
| 373 |
+
"prop_vs_neg": 0.1415785551071167,
|
| 374 |
+
"person_vs_neg": -0.0472450852394104,
|
| 375 |
+
"score": 0.1888236403465271
|
| 376 |
+
},
|
| 377 |
+
{
|
| 378 |
+
"dim": 236,
|
| 379 |
+
"prop_mean": 1.3713657855987549,
|
| 380 |
+
"person_pos_mean": 1.1866233348846436,
|
| 381 |
+
"person_neg_mean": 1.346700668334961,
|
| 382 |
+
"prop_vs_neg": 0.024665117263793945,
|
| 383 |
+
"person_vs_neg": -0.16007733345031738,
|
| 384 |
+
"score": 0.18474245071411133
|
| 385 |
+
},
|
| 386 |
+
{
|
| 387 |
+
"dim": 110,
|
| 388 |
+
"prop_mean": 1.3540358543395996,
|
| 389 |
+
"person_pos_mean": 1.1696140766143799,
|
| 390 |
+
"person_neg_mean": 1.1514066457748413,
|
| 391 |
+
"prop_vs_neg": 0.2026292085647583,
|
| 392 |
+
"person_vs_neg": 0.018207430839538574,
|
| 393 |
+
"score": 0.18442177772521973
|
| 394 |
+
},
|
| 395 |
+
{
|
| 396 |
+
"dim": 660,
|
| 397 |
+
"prop_mean": 1.294521689414978,
|
| 398 |
+
"person_pos_mean": 1.110160231590271,
|
| 399 |
+
"person_neg_mean": 1.258522391319275,
|
| 400 |
+
"prop_vs_neg": 0.035999298095703125,
|
| 401 |
+
"person_vs_neg": -0.1483621597290039,
|
| 402 |
+
"score": 0.18436145782470703
|
| 403 |
+
},
|
| 404 |
+
{
|
| 405 |
+
"dim": 141,
|
| 406 |
+
"prop_mean": 1.2327960729599,
|
| 407 |
+
"person_pos_mean": 1.0510427951812744,
|
| 408 |
+
"person_neg_mean": 1.1455810070037842,
|
| 409 |
+
"prop_vs_neg": 0.08721506595611572,
|
| 410 |
+
"person_vs_neg": -0.09453821182250977,
|
| 411 |
+
"score": 0.1817532777786255
|
| 412 |
+
},
|
| 413 |
+
{
|
| 414 |
+
"dim": 436,
|
| 415 |
+
"prop_mean": 0.7790431380271912,
|
| 416 |
+
"person_pos_mean": 0.6001676321029663,
|
| 417 |
+
"person_neg_mean": 0.7653905153274536,
|
| 418 |
+
"prop_vs_neg": 0.013652622699737549,
|
| 419 |
+
"person_vs_neg": -0.1652228832244873,
|
| 420 |
+
"score": 0.17887550592422485
|
| 421 |
+
},
|
| 422 |
+
{
|
| 423 |
+
"dim": 732,
|
| 424 |
+
"prop_mean": 2.213838815689087,
|
| 425 |
+
"person_pos_mean": 2.035112142562866,
|
| 426 |
+
"person_neg_mean": 2.0301244258880615,
|
| 427 |
+
"prop_vs_neg": 0.1837143898010254,
|
| 428 |
+
"person_vs_neg": 0.0049877166748046875,
|
| 429 |
+
"score": 0.1787266731262207
|
| 430 |
+
},
|
| 431 |
+
{
|
| 432 |
+
"dim": 160,
|
| 433 |
+
"prop_mean": 1.1959549188613892,
|
| 434 |
+
"person_pos_mean": 1.02139151096344,
|
| 435 |
+
"person_neg_mean": 0.985637366771698,
|
| 436 |
+
"prop_vs_neg": 0.21031755208969116,
|
| 437 |
+
"person_vs_neg": 0.03575414419174194,
|
| 438 |
+
"score": 0.17456340789794922
|
| 439 |
+
},
|
| 440 |
+
{
|
| 441 |
+
"dim": 543,
|
| 442 |
+
"prop_mean": 1.6499507427215576,
|
| 443 |
+
"person_pos_mean": 1.4781776666641235,
|
| 444 |
+
"person_neg_mean": 1.5063472986221313,
|
| 445 |
+
"prop_vs_neg": 0.14360344409942627,
|
| 446 |
+
"person_vs_neg": -0.028169631958007812,
|
| 447 |
+
"score": 0.17177307605743408
|
| 448 |
+
},
|
| 449 |
+
{
|
| 450 |
+
"dim": 27,
|
| 451 |
+
"prop_mean": 1.3894929885864258,
|
| 452 |
+
"person_pos_mean": 1.2205332517623901,
|
| 453 |
+
"person_neg_mean": 1.2239311933517456,
|
| 454 |
+
"prop_vs_neg": 0.16556179523468018,
|
| 455 |
+
"person_vs_neg": -0.0033979415893554688,
|
| 456 |
+
"score": 0.16895973682403564
|
| 457 |
+
}
|
| 458 |
+
],
|
| 459 |
+
"sweeps": [
|
| 460 |
+
{
|
| 461 |
+
"extra_neg_k": 0,
|
| 462 |
+
"F1": 0.884742021560669,
|
| 463 |
+
"threshold": 24.868803024291992,
|
| 464 |
+
"precision": 0.8963522911071777,
|
| 465 |
+
"recall": 0.8734287023544312,
|
| 466 |
+
"prop_false_positive_rate": 0.0593230314552784,
|
| 467 |
+
"added_dims": []
|
| 468 |
+
},
|
| 469 |
+
{
|
| 470 |
+
"extra_neg_k": 5,
|
| 471 |
+
"F1": 0.8799648880958557,
|
| 472 |
+
"threshold": 19.580781936645508,
|
| 473 |
+
"precision": 0.8911111354827881,
|
| 474 |
+
"recall": 0.8690940737724304,
|
| 475 |
+
"prop_false_positive_rate": 0.04576011374592781,
|
| 476 |
+
"added_dims": [
|
| 477 |
+
11,
|
| 478 |
+
697,
|
| 479 |
+
572,
|
| 480 |
+
671,
|
| 481 |
+
51
|
| 482 |
+
]
|
| 483 |
+
},
|
| 484 |
+
{
|
| 485 |
+
"extra_neg_k": 10,
|
| 486 |
+
"F1": 0.8703535795211792,
|
| 487 |
+
"threshold": 15.480006217956543,
|
| 488 |
+
"precision": 0.9121140241622925,
|
| 489 |
+
"recall": 0.8322497010231018,
|
| 490 |
+
"prop_false_positive_rate": 0.033730391412973404,
|
| 491 |
+
"added_dims": [
|
| 492 |
+
11,
|
| 493 |
+
697,
|
| 494 |
+
572,
|
| 495 |
+
671,
|
| 496 |
+
51,
|
| 497 |
+
186,
|
| 498 |
+
752,
|
| 499 |
+
90,
|
| 500 |
+
161,
|
| 501 |
+
310
|
| 502 |
+
]
|
| 503 |
+
},
|
| 504 |
+
{
|
| 505 |
+
"extra_neg_k": 15,
|
| 506 |
+
"F1": 0.8526602983474731,
|
| 507 |
+
"threshold": 10.094175338745117,
|
| 508 |
+
"precision": 0.8967001438140869,
|
| 509 |
+
"recall": 0.8127438426017761,
|
| 510 |
+
"prop_false_positive_rate": 0.027243778109550476,
|
| 511 |
+
"added_dims": [
|
| 512 |
+
11,
|
| 513 |
+
697,
|
| 514 |
+
572,
|
| 515 |
+
671,
|
| 516 |
+
51,
|
| 517 |
+
186,
|
| 518 |
+
752,
|
| 519 |
+
90,
|
| 520 |
+
161,
|
| 521 |
+
310,
|
| 522 |
+
88,
|
| 523 |
+
189,
|
| 524 |
+
613,
|
| 525 |
+
201,
|
| 526 |
+
360
|
| 527 |
+
]
|
| 528 |
+
},
|
| 529 |
+
{
|
| 530 |
+
"extra_neg_k": 20,
|
| 531 |
+
"F1": 0.8446601629257202,
|
| 532 |
+
"threshold": 2.4011502265930176,
|
| 533 |
+
"precision": 0.860224723815918,
|
| 534 |
+
"recall": 0.8296489119529724,
|
| 535 |
+
"prop_false_positive_rate": 0.031135747209191322,
|
| 536 |
+
"added_dims": [
|
| 537 |
+
11,
|
| 538 |
+
697,
|
| 539 |
+
572,
|
| 540 |
+
671,
|
| 541 |
+
51,
|
| 542 |
+
186,
|
| 543 |
+
752,
|
| 544 |
+
90,
|
| 545 |
+
161,
|
| 546 |
+
310,
|
| 547 |
+
88,
|
| 548 |
+
189,
|
| 549 |
+
613,
|
| 550 |
+
201,
|
| 551 |
+
360,
|
| 552 |
+
623,
|
| 553 |
+
688,
|
| 554 |
+
578,
|
| 555 |
+
81,
|
| 556 |
+
692
|
| 557 |
+
]
|
| 558 |
+
},
|
| 559 |
+
{
|
| 560 |
+
"extra_neg_k": 30,
|
| 561 |
+
"F1": 0.8187528252601624,
|
| 562 |
+
"threshold": -6.868839740753174,
|
| 563 |
+
"precision": 0.8484426140785217,
|
| 564 |
+
"recall": 0.7910706400871277,
|
| 565 |
+
"prop_false_positive_rate": 0.023115932941436768,
|
| 566 |
+
"added_dims": [
|
| 567 |
+
11,
|
| 568 |
+
697,
|
| 569 |
+
572,
|
| 570 |
+
671,
|
| 571 |
+
51,
|
| 572 |
+
186,
|
| 573 |
+
752,
|
| 574 |
+
90,
|
| 575 |
+
161,
|
| 576 |
+
310,
|
| 577 |
+
88,
|
| 578 |
+
189,
|
| 579 |
+
613,
|
| 580 |
+
201,
|
| 581 |
+
360,
|
| 582 |
+
623,
|
| 583 |
+
688,
|
| 584 |
+
578,
|
| 585 |
+
81,
|
| 586 |
+
692,
|
| 587 |
+
638,
|
| 588 |
+
522,
|
| 589 |
+
257,
|
| 590 |
+
340,
|
| 591 |
+
308,
|
| 592 |
+
479,
|
| 593 |
+
299,
|
| 594 |
+
440,
|
| 595 |
+
458,
|
| 596 |
+
767
|
| 597 |
+
]
|
| 598 |
+
},
|
| 599 |
+
{
|
| 600 |
+
"extra_neg_k": 40,
|
| 601 |
+
"F1": 0.7954637408256531,
|
| 602 |
+
"threshold": -25.408130645751953,
|
| 603 |
+
"precision": 0.7464842200279236,
|
| 604 |
+
"recall": 0.8513220548629761,
|
| 605 |
+
"prop_false_positive_rate": 0.043047528713941574,
|
| 606 |
+
"added_dims": [
|
| 607 |
+
11,
|
| 608 |
+
697,
|
| 609 |
+
572,
|
| 610 |
+
671,
|
| 611 |
+
51,
|
| 612 |
+
186,
|
| 613 |
+
752,
|
| 614 |
+
90,
|
| 615 |
+
161,
|
| 616 |
+
310,
|
| 617 |
+
88,
|
| 618 |
+
189,
|
| 619 |
+
613,
|
| 620 |
+
201,
|
| 621 |
+
360,
|
| 622 |
+
623,
|
| 623 |
+
688,
|
| 624 |
+
578,
|
| 625 |
+
81,
|
| 626 |
+
692,
|
| 627 |
+
638,
|
| 628 |
+
522,
|
| 629 |
+
257,
|
| 630 |
+
340,
|
| 631 |
+
308,
|
| 632 |
+
479,
|
| 633 |
+
299,
|
| 634 |
+
440,
|
| 635 |
+
458,
|
| 636 |
+
767,
|
| 637 |
+
713,
|
| 638 |
+
554,
|
| 639 |
+
0,
|
| 640 |
+
351,
|
| 641 |
+
266,
|
| 642 |
+
469,
|
| 643 |
+
250,
|
| 644 |
+
684,
|
| 645 |
+
604,
|
| 646 |
+
251
|
| 647 |
+
]
|
| 648 |
+
},
|
| 649 |
+
{
|
| 650 |
+
"extra_neg_k": 50,
|
| 651 |
+
"F1": 0.7818812131881714,
|
| 652 |
+
"threshold": -36.89189910888672,
|
| 653 |
+
"precision": 0.7386276125907898,
|
| 654 |
+
"recall": 0.8305158019065857,
|
| 655 |
+
"prop_false_positive_rate": 0.041278451681137085,
|
| 656 |
+
"added_dims": [
|
| 657 |
+
11,
|
| 658 |
+
697,
|
| 659 |
+
572,
|
| 660 |
+
671,
|
| 661 |
+
51,
|
| 662 |
+
186,
|
| 663 |
+
752,
|
| 664 |
+
90,
|
| 665 |
+
161,
|
| 666 |
+
310,
|
| 667 |
+
88,
|
| 668 |
+
189,
|
| 669 |
+
613,
|
| 670 |
+
201,
|
| 671 |
+
360,
|
| 672 |
+
623,
|
| 673 |
+
688,
|
| 674 |
+
578,
|
| 675 |
+
81,
|
| 676 |
+
692,
|
| 677 |
+
638,
|
| 678 |
+
522,
|
| 679 |
+
257,
|
| 680 |
+
340,
|
| 681 |
+
308,
|
| 682 |
+
479,
|
| 683 |
+
299,
|
| 684 |
+
440,
|
| 685 |
+
458,
|
| 686 |
+
767,
|
| 687 |
+
713,
|
| 688 |
+
554,
|
| 689 |
+
0,
|
| 690 |
+
351,
|
| 691 |
+
266,
|
| 692 |
+
469,
|
| 693 |
+
250,
|
| 694 |
+
684,
|
| 695 |
+
604,
|
| 696 |
+
251,
|
| 697 |
+
275,
|
| 698 |
+
236,
|
| 699 |
+
110,
|
| 700 |
+
660,
|
| 701 |
+
141,
|
| 702 |
+
436,
|
| 703 |
+
732,
|
| 704 |
+
160,
|
| 705 |
+
543,
|
| 706 |
+
27
|
| 707 |
+
]
|
| 708 |
+
}
|
| 709 |
+
]
|
| 710 |
+
}
|
discovery/variant_leaderboard.json
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"provenance": {
|
| 3 |
+
"generator": null,
|
| 4 |
+
"note": "discovery sweep not committed; no producer in the repo"
|
| 5 |
+
},
|
| 6 |
+
"results": [
|
| 7 |
+
{
|
| 8 |
+
"name": "ref: full 768 ridge",
|
| 9 |
+
"params": 769,
|
| 10 |
+
"F1": 0.9598035216331482,
|
| 11 |
+
"precision": 0.9898664355278015,
|
| 12 |
+
"recall": 0.9315127730369568,
|
| 13 |
+
"threshold": null
|
| 14 |
+
},
|
| 15 |
+
{
|
| 16 |
+
"name": "ref: K=92 ridge (cojoint top-92 + bias)",
|
| 17 |
+
"params": 93,
|
| 18 |
+
"F1": 0.9463722109794617,
|
| 19 |
+
"precision": 0.9854528307914734,
|
| 20 |
+
"recall": 0.9102730751037598,
|
| 21 |
+
"threshold": null
|
| 22 |
+
},
|
| 23 |
+
{
|
| 24 |
+
"name": "E: ternary weights top-50 pos vs top-50 neg, threshold",
|
| 25 |
+
"params": 1,
|
| 26 |
+
"F1": 0.8933987617492676,
|
| 27 |
+
"precision": 0.9200735092163086,
|
| 28 |
+
"recall": 0.8682271242141724,
|
| 29 |
+
"threshold": 31.819643020629883
|
| 30 |
+
},
|
| 31 |
+
{
|
| 32 |
+
"name": "C: threshold(sum top-20 pos \u2212 sum top-20 neg)",
|
| 33 |
+
"params": 1,
|
| 34 |
+
"F1": 0.8808632493019104,
|
| 35 |
+
"precision": 0.8952551484107971,
|
| 36 |
+
"recall": 0.8669267296791077,
|
| 37 |
+
"threshold": 24.8664608001709
|
| 38 |
+
},
|
| 39 |
+
{
|
| 40 |
+
"name": "E: ternary weights top-20 pos vs top-20 neg, threshold",
|
| 41 |
+
"params": 1,
|
| 42 |
+
"F1": 0.8808632493019104,
|
| 43 |
+
"precision": 0.8952551484107971,
|
| 44 |
+
"recall": 0.8669267296791077,
|
| 45 |
+
"threshold": 24.86646270751953
|
| 46 |
+
},
|
| 47 |
+
{
|
| 48 |
+
"name": "C: threshold(sum top-10 pos \u2212 sum top-10 neg)",
|
| 49 |
+
"params": 1,
|
| 50 |
+
"F1": 0.8801606893539429,
|
| 51 |
+
"precision": 0.9070836901664734,
|
| 52 |
+
"recall": 0.8547897934913635,
|
| 53 |
+
"threshold": 22.383634567260742
|
| 54 |
+
},
|
| 55 |
+
{
|
| 56 |
+
"name": "E: ternary weights top-10 pos vs top-10 neg, threshold",
|
| 57 |
+
"params": 1,
|
| 58 |
+
"F1": 0.8801606893539429,
|
| 59 |
+
"precision": 0.9070836901664734,
|
| 60 |
+
"recall": 0.8547897934913635,
|
| 61 |
+
"threshold": 22.383630752563477
|
| 62 |
+
},
|
| 63 |
+
{
|
| 64 |
+
"name": "B: threshold(sum top-2 pos dims)",
|
| 65 |
+
"params": 1,
|
| 66 |
+
"F1": 0.8780821561813354,
|
| 67 |
+
"precision": 0.9276410937309265,
|
| 68 |
+
"recall": 0.8335500359535217,
|
| 69 |
+
"threshold": 14.303534507751465
|
| 70 |
+
},
|
| 71 |
+
{
|
| 72 |
+
"name": "B: threshold(sum top-20 pos dims)",
|
| 73 |
+
"params": 1,
|
| 74 |
+
"F1": 0.8683924674987793,
|
| 75 |
+
"precision": 0.8716157078742981,
|
| 76 |
+
"recall": 0.8651928901672363,
|
| 77 |
+
"threshold": 62.11921310424805
|
| 78 |
+
},
|
| 79 |
+
{
|
| 80 |
+
"name": "C: threshold(sum top-5 pos \u2212 sum top-5 neg)",
|
| 81 |
+
"params": 1,
|
| 82 |
+
"F1": 0.8637353181838989,
|
| 83 |
+
"precision": 0.867512047290802,
|
| 84 |
+
"recall": 0.8599913120269775,
|
| 85 |
+
"threshold": 27.896242141723633
|
| 86 |
+
},
|
| 87 |
+
{
|
| 88 |
+
"name": "B: threshold(sum top-10 pos dims)",
|
| 89 |
+
"params": 1,
|
| 90 |
+
"F1": 0.8574432134628296,
|
| 91 |
+
"precision": 0.8325847387313843,
|
| 92 |
+
"recall": 0.883831799030304,
|
| 93 |
+
"threshold": 45.166908264160156
|
| 94 |
+
},
|
| 95 |
+
{
|
| 96 |
+
"name": "A: threshold(dim48)",
|
| 97 |
+
"params": 1,
|
| 98 |
+
"F1": 0.8451337814331055,
|
| 99 |
+
"precision": 0.8776844143867493,
|
| 100 |
+
"recall": 0.8149111270904541,
|
| 101 |
+
"threshold": 6.3439040184021
|
| 102 |
+
},
|
| 103 |
+
{
|
| 104 |
+
"name": "ref: K=1 ridge (dim48 + bias)",
|
| 105 |
+
"params": 2,
|
| 106 |
+
"F1": 0.8285356163978577,
|
| 107 |
+
"precision": 0.7985524535179138,
|
| 108 |
+
"recall": 0.8608582615852356,
|
| 109 |
+
"threshold": null
|
| 110 |
+
},
|
| 111 |
+
{
|
| 112 |
+
"name": "B: threshold(sum top-5 pos dims)",
|
| 113 |
+
"params": 1,
|
| 114 |
+
"F1": 0.8214052319526672,
|
| 115 |
+
"precision": 0.824454128742218,
|
| 116 |
+
"recall": 0.8183788657188416,
|
| 117 |
+
"threshold": 37.6262092590332
|
| 118 |
+
},
|
| 119 |
+
{
|
| 120 |
+
"name": "C: threshold(sum top-3 pos \u2212 sum top-3 neg)",
|
| 121 |
+
"params": 1,
|
| 122 |
+
"F1": 0.8199912905693054,
|
| 123 |
+
"precision": 0.8185744881629944,
|
| 124 |
+
"recall": 0.8214130997657776,
|
| 125 |
+
"threshold": 18.052114486694336
|
| 126 |
+
},
|
| 127 |
+
{
|
| 128 |
+
"name": "B: threshold(sum top-3 pos dims)",
|
| 129 |
+
"params": 1,
|
| 130 |
+
"F1": 0.7914334535598755,
|
| 131 |
+
"precision": 0.7131432294845581,
|
| 132 |
+
"recall": 0.8890333771705627,
|
| 133 |
+
"threshold": 23.4901123046875
|
| 134 |
+
},
|
| 135 |
+
{
|
| 136 |
+
"name": "D: threshold(max top-3 pos \u2212 max top-3 neg)",
|
| 137 |
+
"params": 1,
|
| 138 |
+
"F1": 0.7337717413902283,
|
| 139 |
+
"precision": 0.6004415154457092,
|
| 140 |
+
"recall": 0.9432163238525391,
|
| 141 |
+
"threshold": 4.771557331085205
|
| 142 |
+
},
|
| 143 |
+
{
|
| 144 |
+
"name": "D: threshold(max top-5 pos \u2212 max top-5 neg)",
|
| 145 |
+
"params": 1,
|
| 146 |
+
"F1": 0.7142618894577026,
|
| 147 |
+
"precision": 0.5805314779281616,
|
| 148 |
+
"recall": 0.9280450940132141,
|
| 149 |
+
"threshold": 6.046311378479004
|
| 150 |
+
},
|
| 151 |
+
{
|
| 152 |
+
"name": "D: threshold(max top-10 pos \u2212 max top-10 neg)",
|
| 153 |
+
"params": 1,
|
| 154 |
+
"F1": 0.7102322578430176,
|
| 155 |
+
"precision": 0.5886545181274414,
|
| 156 |
+
"recall": 0.8951018452644348,
|
| 157 |
+
"threshold": 4.326292991638184
|
| 158 |
+
},
|
| 159 |
+
{
|
| 160 |
+
"name": "D: threshold(max top-20 pos \u2212 max top-20 neg)",
|
| 161 |
+
"params": 1,
|
| 162 |
+
"F1": 0.7102322578430176,
|
| 163 |
+
"precision": 0.5886545181274414,
|
| 164 |
+
"recall": 0.8951018452644348,
|
| 165 |
+
"threshold": 4.326292991638184
|
| 166 |
+
}
|
| 167 |
+
],
|
| 168 |
+
"top_pos_dims_30": [
|
| 169 |
+
48,
|
| 170 |
+
525,
|
| 171 |
+
475,
|
| 172 |
+
645,
|
| 173 |
+
273,
|
| 174 |
+
292,
|
| 175 |
+
158,
|
| 176 |
+
510,
|
| 177 |
+
506,
|
| 178 |
+
337,
|
| 179 |
+
8,
|
| 180 |
+
309,
|
| 181 |
+
267,
|
| 182 |
+
217,
|
| 183 |
+
79,
|
| 184 |
+
13,
|
| 185 |
+
657,
|
| 186 |
+
207,
|
| 187 |
+
722,
|
| 188 |
+
311,
|
| 189 |
+
566,
|
| 190 |
+
278,
|
| 191 |
+
25,
|
| 192 |
+
627,
|
| 193 |
+
511,
|
| 194 |
+
332,
|
| 195 |
+
654,
|
| 196 |
+
719,
|
| 197 |
+
593,
|
| 198 |
+
305
|
| 199 |
+
],
|
| 200 |
+
"top_neg_dims_30": [
|
| 201 |
+
642,
|
| 202 |
+
224,
|
| 203 |
+
113,
|
| 204 |
+
565,
|
| 205 |
+
49,
|
| 206 |
+
637,
|
| 207 |
+
45,
|
| 208 |
+
520,
|
| 209 |
+
219,
|
| 210 |
+
290,
|
| 211 |
+
529,
|
| 212 |
+
617,
|
| 213 |
+
269,
|
| 214 |
+
745,
|
| 215 |
+
576,
|
| 216 |
+
701,
|
| 217 |
+
105,
|
| 218 |
+
694,
|
| 219 |
+
82,
|
| 220 |
+
283,
|
| 221 |
+
574,
|
| 222 |
+
310,
|
| 223 |
+
613,
|
| 224 |
+
90,
|
| 225 |
+
92,
|
| 226 |
+
650,
|
| 227 |
+
36,
|
| 228 |
+
53,
|
| 229 |
+
396,
|
| 230 |
+
17
|
| 231 |
+
]
|
| 232 |
+
}
|
eval.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"provenance": {
|
| 3 |
+
"generator": "verify.py",
|
| 4 |
+
"classifier": "classifier.json",
|
| 5 |
+
"classifier_sha256": "19b70ff5e4e2977b80bac7e8915acd70dfe42691ae7fa55470c7f1a2580d5d0c",
|
| 6 |
+
"pool": "VAL5000",
|
| 7 |
+
"split": "val2017",
|
| 8 |
+
"n_images": 5000,
|
| 9 |
+
"positive_rate": 0.539,
|
| 10 |
+
"task": "image-level person presence (binary)",
|
| 11 |
+
"protocol": "live backbone forward at 768 px, no feature caching",
|
| 12 |
+
"selection": "the first 5000 val2017 image ids in sorted order, which is the whole split"
|
| 13 |
+
},
|
| 14 |
+
"metrics": {
|
| 15 |
+
"F1": 0.8886,
|
| 16 |
+
"precision": 0.9011,
|
| 17 |
+
"recall": 0.8763,
|
| 18 |
+
"threshold": 25.284494400024414
|
| 19 |
+
}
|
| 20 |
+
}
|
eval_tight_fpr.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"provenance": {
|
| 3 |
+
"generator": null,
|
| 4 |
+
"classifier": "classifier_tight_fpr.json",
|
| 5 |
+
"classifier_sha256": "21da0c971c21e3504de458f97c396df23c8cbc97ad3813435703c8e9b89f66ef",
|
| 6 |
+
"pool": null,
|
| 7 |
+
"task": "image-level person presence (binary)",
|
| 8 |
+
"measured_by": "stage_0/discovery/prop_specificity.json, extra_neg_k=15"
|
| 9 |
+
},
|
| 10 |
+
"metrics": {
|
| 11 |
+
"F1": 0.8527,
|
| 12 |
+
"precision": 0.8967,
|
| 13 |
+
"recall": 0.8127,
|
| 14 |
+
"threshold": 10.094175338745117
|
| 15 |
+
},
|
| 16 |
+
"prop_false_positive_rate": 0.0272,
|
| 17 |
+
"baseline": {
|
| 18 |
+
"F1": 0.8847,
|
| 19 |
+
"prop_false_positive_rate": 0.0593
|
| 20 |
+
}
|
| 21 |
+
}
|
head.py
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""The classifier as a fused Linear with fixed ternary weights and one free bias.
|
| 2 |
+
|
| 3 |
+
model = FusedClassifier.from_hub()
|
| 4 |
+
score, present = model(image_tensor)
|
| 5 |
+
|
| 6 |
+
Constructed without a backbone the module still exposes `head`, the same
|
| 7 |
+
decision applied to an already-pooled vector.
|
| 8 |
+
"""
|
| 9 |
+
import argparse
|
| 10 |
+
import json
|
| 11 |
+
import sys
|
| 12 |
+
from pathlib import Path
|
| 13 |
+
|
| 14 |
+
import torch
|
| 15 |
+
import torch.nn as nn
|
| 16 |
+
import torch.nn.functional as F
|
| 17 |
+
|
| 18 |
+
sys.path.insert(0, str(Path(__file__).resolve().parent)) # repo root, for `common`
|
| 19 |
+
from common import BACKBONE, pool # noqa: E402
|
| 20 |
+
|
| 21 |
+
HERE = Path(__file__).resolve().parent
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
class FusedClassifier(nn.Module):
|
| 25 |
+
"""Backbone -> 40-dim slice -> ternary linear head -> binary decision.
|
| 26 |
+
|
| 27 |
+
`retained_dims` indexes the 768-D pooled vector; `retained_weight` is +1 on
|
| 28 |
+
the person-positive positions and -1 on the person-negative ones. The
|
| 29 |
+
threshold is the only free parameter.
|
| 30 |
+
"""
|
| 31 |
+
|
| 32 |
+
def __init__(self, backbone, pos_dims, neg_dims, threshold):
|
| 33 |
+
super().__init__()
|
| 34 |
+
self.backbone = backbone
|
| 35 |
+
retained = list(pos_dims) + list(neg_dims)
|
| 36 |
+
self.register_buffer('retained_dims', torch.tensor(retained, dtype=torch.long))
|
| 37 |
+
w = torch.zeros(1, len(retained))
|
| 38 |
+
w[0, :len(pos_dims)] = 1.0
|
| 39 |
+
w[0, len(pos_dims):] = -1.0
|
| 40 |
+
self.register_buffer('retained_weight', w)
|
| 41 |
+
self.threshold = nn.Parameter(torch.tensor(float(threshold)))
|
| 42 |
+
|
| 43 |
+
def head(self, pooled):
|
| 44 |
+
"""(..., 768) pooled vector -> (score, present), no backbone involved."""
|
| 45 |
+
retained = pooled.index_select(-1, self.retained_dims)
|
| 46 |
+
score = F.linear(retained, self.retained_weight).squeeze(-1)
|
| 47 |
+
return score, score > self.threshold
|
| 48 |
+
|
| 49 |
+
@torch.inference_mode()
|
| 50 |
+
def forward(self, x):
|
| 51 |
+
"""x: (B, 3, 768, 768) normalized. Returns (score (B,), present (B,))."""
|
| 52 |
+
if self.backbone is None:
|
| 53 |
+
raise RuntimeError('constructed without a backbone; use .head(pooled)')
|
| 54 |
+
dev = 'cuda' if x.is_cuda else 'cpu'
|
| 55 |
+
with torch.autocast(dev, dtype=torch.bfloat16):
|
| 56 |
+
out = self.backbone.forward_features(x)
|
| 57 |
+
return self.head(pool(out['x_norm_patchtokens'].float()))
|
| 58 |
+
|
| 59 |
+
@classmethod
|
| 60 |
+
def from_config(cls, backbone=None, classifier_json=None):
|
| 61 |
+
c = json.loads(Path(classifier_json or HERE / 'classifier.json').read_text())
|
| 62 |
+
return cls(backbone, c['pos_dims'], c['neg_dims'], c['threshold'])
|
| 63 |
+
|
| 64 |
+
@classmethod
|
| 65 |
+
def from_hub(cls, repo_or_path=None, classifier_json=None):
|
| 66 |
+
from common.models import load_backbone
|
| 67 |
+
return cls.from_config(load_backbone(repo_or_path or BACKBONE), classifier_json)
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
if __name__ == '__main__':
|
| 71 |
+
ap = argparse.ArgumentParser(description=__doc__)
|
| 72 |
+
ap.add_argument('--classifier', type=Path, default=HERE / 'classifier.json')
|
| 73 |
+
args = ap.parse_args()
|
| 74 |
+
m = FusedClassifier.from_hub(classifier_json=args.classifier).eval()
|
| 75 |
+
n_all = sum(p.numel() for p in m.parameters())
|
| 76 |
+
n_backbone = sum(p.numel() for p in m.backbone.parameters())
|
| 77 |
+
print(f'total params: {n_all:,}')
|
| 78 |
+
print(f'backbone params: {n_backbone:,}')
|
| 79 |
+
print(f'head params: {n_all - n_backbone} '
|
| 80 |
+
f'(one learnable threshold; weights are fixed buffers)')
|
| 81 |
+
print(f'retained dims: {m.retained_dims.numel()}')
|
infer.py
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Load a classifier variant and score images for person presence.
|
| 2 |
+
|
| 3 |
+
from infer import PersonDetector
|
| 4 |
+
det = PersonDetector.load('baseline')
|
| 5 |
+
score, present = det.predict('image.jpg')
|
| 6 |
+
|
| 7 |
+
`score` is positive for person scenes; `present` is `score > threshold`.
|
| 8 |
+
|
| 9 |
+
Variants
|
| 10 |
+
baseline the classifier
|
| 11 |
+
tight_fpr the same, with 15 extra prop-suppressing negative dims
|
| 12 |
+
"""
|
| 13 |
+
import argparse
|
| 14 |
+
import json
|
| 15 |
+
import sys
|
| 16 |
+
from pathlib import Path
|
| 17 |
+
from typing import Tuple
|
| 18 |
+
|
| 19 |
+
import torch
|
| 20 |
+
|
| 21 |
+
sys.path.insert(0, str(Path(__file__).resolve().parent)) # repo root, for `common`
|
| 22 |
+
from common import BACKBONE, RES, backbone_pooled, device, load_image, score # noqa: E402
|
| 23 |
+
from common.models import load_backbone # noqa: E402
|
| 24 |
+
|
| 25 |
+
HERE = Path(__file__).resolve().parent
|
| 26 |
+
CONFIGS = {'baseline': 'classifier.json', 'tight_fpr': 'classifier_tight_fpr.json'}
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
class PersonDetector:
|
| 30 |
+
def __init__(self, forward_fn, pos_dims, neg_dims, threshold, dev):
|
| 31 |
+
self._forward = forward_fn
|
| 32 |
+
self._dev = dev
|
| 33 |
+
self._pos = torch.tensor(pos_dims, dtype=torch.long, device=dev)
|
| 34 |
+
self._neg = torch.tensor(neg_dims, dtype=torch.long, device=dev)
|
| 35 |
+
self._thr = float(threshold)
|
| 36 |
+
|
| 37 |
+
@property
|
| 38 |
+
def threshold(self) -> float:
|
| 39 |
+
return self._thr
|
| 40 |
+
|
| 41 |
+
@torch.inference_mode()
|
| 42 |
+
def predict(self, image) -> Tuple[float, bool]:
|
| 43 |
+
pooled = self._forward(load_image(image, RES, self._dev))
|
| 44 |
+
s = float(score(pooled, self._pos, self._neg))
|
| 45 |
+
return s, s > self._thr
|
| 46 |
+
|
| 47 |
+
@classmethod
|
| 48 |
+
def load(cls, variant: str = 'baseline', backbone_repo: str = BACKBONE,
|
| 49 |
+
root=None) -> 'PersonDetector':
|
| 50 |
+
root = Path(root) if root else HERE
|
| 51 |
+
if variant not in CONFIGS:
|
| 52 |
+
raise ValueError(f'unknown variant {variant!r}; expected one of '
|
| 53 |
+
f'{sorted(CONFIGS)}')
|
| 54 |
+
dev = device()
|
| 55 |
+
backbone = load_backbone(backbone_repo).to(dev)
|
| 56 |
+
c = cls._classifier(root / CONFIGS[variant])
|
| 57 |
+
return cls(lambda x: backbone_pooled(backbone, x)[0],
|
| 58 |
+
c['pos_dims'], c['neg_dims'], c['threshold'], dev)
|
| 59 |
+
|
| 60 |
+
@staticmethod
|
| 61 |
+
def _classifier(path) -> dict:
|
| 62 |
+
"""Read a classifier config, cross-checking the safetensors beside it."""
|
| 63 |
+
path = Path(path)
|
| 64 |
+
c = json.loads(path.read_text())
|
| 65 |
+
weights = path.with_suffix('.safetensors')
|
| 66 |
+
if weights.exists():
|
| 67 |
+
from safetensors.torch import load_file
|
| 68 |
+
t = load_file(str(weights))
|
| 69 |
+
for key in ('pos_dims', 'neg_dims'):
|
| 70 |
+
if t[key].tolist() != c[key]:
|
| 71 |
+
raise ValueError(f'{weights.name} disagrees with {path.name} on {key}')
|
| 72 |
+
if abs(float(t['threshold'][0]) - float(c['threshold'])) > 1e-4:
|
| 73 |
+
raise ValueError(f'{weights.name} disagrees with {path.name} on threshold')
|
| 74 |
+
return c
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
if __name__ == '__main__':
|
| 78 |
+
ap = argparse.ArgumentParser(description=__doc__)
|
| 79 |
+
ap.add_argument('variant', choices=sorted(CONFIGS))
|
| 80 |
+
ap.add_argument('images', nargs='+')
|
| 81 |
+
args = ap.parse_args()
|
| 82 |
+
det = PersonDetector.load(args.variant)
|
| 83 |
+
for path in args.images:
|
| 84 |
+
s, present = det.predict(path)
|
| 85 |
+
print(f'{path} score={s:+.3f} threshold={det.threshold:+.3f} person={present}')
|
per_dim_thresholds.json
ADDED
|
@@ -0,0 +1,348 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"provenance": {
|
| 3 |
+
"generator": "calibrate.py",
|
| 4 |
+
"classifier": "classifier.json",
|
| 5 |
+
"classifier_sha256": "19b70ff5e4e2977b80bac7e8915acd70dfe42691ae7fa55470c7f1a2580d5d0c",
|
| 6 |
+
"pool": "BALANCED_VAL",
|
| 7 |
+
"split": "val2017",
|
| 8 |
+
"n_images": 4614,
|
| 9 |
+
"positive_rate": 0.5,
|
| 10 |
+
"seed": 0,
|
| 11 |
+
"selection": "val2017 subsampled without replacement to equal person-positive and person-negative counts"
|
| 12 |
+
},
|
| 13 |
+
"quant_scale": 8,
|
| 14 |
+
"per_dim_thresholds": [
|
| 15 |
+
{
|
| 16 |
+
"dim_index_in_40": 0,
|
| 17 |
+
"dim_global": 48,
|
| 18 |
+
"is_pos": true,
|
| 19 |
+
"threshold": 6.572150230407715,
|
| 20 |
+
"threshold_int8": 53,
|
| 21 |
+
"per_dim_F1": 0.8464522361755371
|
| 22 |
+
},
|
| 23 |
+
{
|
| 24 |
+
"dim_index_in_40": 1,
|
| 25 |
+
"dim_global": 525,
|
| 26 |
+
"is_pos": true,
|
| 27 |
+
"threshold": 7.047104358673096,
|
| 28 |
+
"threshold_int8": 56,
|
| 29 |
+
"per_dim_F1": 0.7466137409210205
|
| 30 |
+
},
|
| 31 |
+
{
|
| 32 |
+
"dim_index_in_40": 2,
|
| 33 |
+
"dim_global": 475,
|
| 34 |
+
"is_pos": true,
|
| 35 |
+
"threshold": 3.269585132598877,
|
| 36 |
+
"threshold_int8": 26,
|
| 37 |
+
"per_dim_F1": 0.6843164563179016
|
| 38 |
+
},
|
| 39 |
+
{
|
| 40 |
+
"dim_index_in_40": 3,
|
| 41 |
+
"dim_global": 645,
|
| 42 |
+
"is_pos": true,
|
| 43 |
+
"threshold": 7.4769134521484375,
|
| 44 |
+
"threshold_int8": 60,
|
| 45 |
+
"per_dim_F1": 0.7112371325492859
|
| 46 |
+
},
|
| 47 |
+
{
|
| 48 |
+
"dim_index_in_40": 4,
|
| 49 |
+
"dim_global": 273,
|
| 50 |
+
"is_pos": true,
|
| 51 |
+
"threshold": 2.0735650062561035,
|
| 52 |
+
"threshold_int8": 17,
|
| 53 |
+
"per_dim_F1": 0.7335397005081177
|
| 54 |
+
},
|
| 55 |
+
{
|
| 56 |
+
"dim_index_in_40": 5,
|
| 57 |
+
"dim_global": 292,
|
| 58 |
+
"is_pos": true,
|
| 59 |
+
"threshold": 1.5521039962768555,
|
| 60 |
+
"threshold_int8": 12,
|
| 61 |
+
"per_dim_F1": 0.732986569404602
|
| 62 |
+
},
|
| 63 |
+
{
|
| 64 |
+
"dim_index_in_40": 6,
|
| 65 |
+
"dim_global": 158,
|
| 66 |
+
"is_pos": true,
|
| 67 |
+
"threshold": 2.054447889328003,
|
| 68 |
+
"threshold_int8": 16,
|
| 69 |
+
"per_dim_F1": 0.6832557320594788
|
| 70 |
+
},
|
| 71 |
+
{
|
| 72 |
+
"dim_index_in_40": 7,
|
| 73 |
+
"dim_global": 510,
|
| 74 |
+
"is_pos": true,
|
| 75 |
+
"threshold": 0.10592363774776459,
|
| 76 |
+
"threshold_int8": 1,
|
| 77 |
+
"per_dim_F1": 0.6806007027626038
|
| 78 |
+
},
|
| 79 |
+
{
|
| 80 |
+
"dim_index_in_40": 8,
|
| 81 |
+
"dim_global": 506,
|
| 82 |
+
"is_pos": true,
|
| 83 |
+
"threshold": 0.642810583114624,
|
| 84 |
+
"threshold_int8": 5,
|
| 85 |
+
"per_dim_F1": 0.7115705609321594
|
| 86 |
+
},
|
| 87 |
+
{
|
| 88 |
+
"dim_index_in_40": 9,
|
| 89 |
+
"dim_global": 337,
|
| 90 |
+
"is_pos": true,
|
| 91 |
+
"threshold": 1.3417854309082031,
|
| 92 |
+
"threshold_int8": 11,
|
| 93 |
+
"per_dim_F1": 0.705616295337677
|
| 94 |
+
},
|
| 95 |
+
{
|
| 96 |
+
"dim_index_in_40": 10,
|
| 97 |
+
"dim_global": 8,
|
| 98 |
+
"is_pos": true,
|
| 99 |
+
"threshold": 0.520650327205658,
|
| 100 |
+
"threshold_int8": 4,
|
| 101 |
+
"per_dim_F1": 0.6678624749183655
|
| 102 |
+
},
|
| 103 |
+
{
|
| 104 |
+
"dim_index_in_40": 11,
|
| 105 |
+
"dim_global": 309,
|
| 106 |
+
"is_pos": true,
|
| 107 |
+
"threshold": 0.44822290539741516,
|
| 108 |
+
"threshold_int8": 4,
|
| 109 |
+
"per_dim_F1": 0.6864839196205139
|
| 110 |
+
},
|
| 111 |
+
{
|
| 112 |
+
"dim_index_in_40": 12,
|
| 113 |
+
"dim_global": 267,
|
| 114 |
+
"is_pos": true,
|
| 115 |
+
"threshold": 0.7230344414710999,
|
| 116 |
+
"threshold_int8": 6,
|
| 117 |
+
"per_dim_F1": 0.7057974338531494
|
| 118 |
+
},
|
| 119 |
+
{
|
| 120 |
+
"dim_index_in_40": 13,
|
| 121 |
+
"dim_global": 217,
|
| 122 |
+
"is_pos": true,
|
| 123 |
+
"threshold": 1.1072767972946167,
|
| 124 |
+
"threshold_int8": 9,
|
| 125 |
+
"per_dim_F1": 0.6852783560752869
|
| 126 |
+
},
|
| 127 |
+
{
|
| 128 |
+
"dim_index_in_40": 14,
|
| 129 |
+
"dim_global": 79,
|
| 130 |
+
"is_pos": true,
|
| 131 |
+
"threshold": 0.9621400237083435,
|
| 132 |
+
"threshold_int8": 8,
|
| 133 |
+
"per_dim_F1": 0.6922308206558228
|
| 134 |
+
},
|
| 135 |
+
{
|
| 136 |
+
"dim_index_in_40": 15,
|
| 137 |
+
"dim_global": 13,
|
| 138 |
+
"is_pos": true,
|
| 139 |
+
"threshold": 2.015596389770508,
|
| 140 |
+
"threshold_int8": 16,
|
| 141 |
+
"per_dim_F1": 0.6755585670471191
|
| 142 |
+
},
|
| 143 |
+
{
|
| 144 |
+
"dim_index_in_40": 16,
|
| 145 |
+
"dim_global": 657,
|
| 146 |
+
"is_pos": true,
|
| 147 |
+
"threshold": 0.7083938121795654,
|
| 148 |
+
"threshold_int8": 6,
|
| 149 |
+
"per_dim_F1": 0.6905635595321655
|
| 150 |
+
},
|
| 151 |
+
{
|
| 152 |
+
"dim_index_in_40": 17,
|
| 153 |
+
"dim_global": 207,
|
| 154 |
+
"is_pos": true,
|
| 155 |
+
"threshold": 0.7881279587745667,
|
| 156 |
+
"threshold_int8": 6,
|
| 157 |
+
"per_dim_F1": 0.7052351236343384
|
| 158 |
+
},
|
| 159 |
+
{
|
| 160 |
+
"dim_index_in_40": 18,
|
| 161 |
+
"dim_global": 722,
|
| 162 |
+
"is_pos": true,
|
| 163 |
+
"threshold": 0.895519495010376,
|
| 164 |
+
"threshold_int8": 7,
|
| 165 |
+
"per_dim_F1": 0.6906405091285706
|
| 166 |
+
},
|
| 167 |
+
{
|
| 168 |
+
"dim_index_in_40": 19,
|
| 169 |
+
"dim_global": 311,
|
| 170 |
+
"is_pos": true,
|
| 171 |
+
"threshold": 1.051217794418335,
|
| 172 |
+
"threshold_int8": 8,
|
| 173 |
+
"per_dim_F1": 0.6888962388038635
|
| 174 |
+
},
|
| 175 |
+
{
|
| 176 |
+
"dim_index_in_40": 20,
|
| 177 |
+
"dim_global": 642,
|
| 178 |
+
"is_pos": false,
|
| 179 |
+
"threshold": 4.502034664154053,
|
| 180 |
+
"threshold_int8": 36,
|
| 181 |
+
"per_dim_F1": 0.6846261024475098
|
| 182 |
+
},
|
| 183 |
+
{
|
| 184 |
+
"dim_index_in_40": 21,
|
| 185 |
+
"dim_global": 224,
|
| 186 |
+
"is_pos": false,
|
| 187 |
+
"threshold": 5.5922465324401855,
|
| 188 |
+
"threshold_int8": 45,
|
| 189 |
+
"per_dim_F1": 0.6726456880569458
|
| 190 |
+
},
|
| 191 |
+
{
|
| 192 |
+
"dim_index_in_40": 22,
|
| 193 |
+
"dim_global": 113,
|
| 194 |
+
"is_pos": false,
|
| 195 |
+
"threshold": 2.338114023208618,
|
| 196 |
+
"threshold_int8": 19,
|
| 197 |
+
"per_dim_F1": 0.6799814701080322
|
| 198 |
+
},
|
| 199 |
+
{
|
| 200 |
+
"dim_index_in_40": 23,
|
| 201 |
+
"dim_global": 565,
|
| 202 |
+
"is_pos": false,
|
| 203 |
+
"threshold": 1.811521291732788,
|
| 204 |
+
"threshold_int8": 14,
|
| 205 |
+
"per_dim_F1": 0.6747174263000488
|
| 206 |
+
},
|
| 207 |
+
{
|
| 208 |
+
"dim_index_in_40": 24,
|
| 209 |
+
"dim_global": 49,
|
| 210 |
+
"is_pos": false,
|
| 211 |
+
"threshold": 1.7180224657058716,
|
| 212 |
+
"threshold_int8": 14,
|
| 213 |
+
"per_dim_F1": 0.680044949054718
|
| 214 |
+
},
|
| 215 |
+
{
|
| 216 |
+
"dim_index_in_40": 25,
|
| 217 |
+
"dim_global": 637,
|
| 218 |
+
"is_pos": false,
|
| 219 |
+
"threshold": 7.861576080322266,
|
| 220 |
+
"threshold_int8": 63,
|
| 221 |
+
"per_dim_F1": 0.6734788417816162
|
| 222 |
+
},
|
| 223 |
+
{
|
| 224 |
+
"dim_index_in_40": 26,
|
| 225 |
+
"dim_global": 45,
|
| 226 |
+
"is_pos": false,
|
| 227 |
+
"threshold": 2.251237630844116,
|
| 228 |
+
"threshold_int8": 18,
|
| 229 |
+
"per_dim_F1": 0.6706920266151428
|
| 230 |
+
},
|
| 231 |
+
{
|
| 232 |
+
"dim_index_in_40": 27,
|
| 233 |
+
"dim_global": 520,
|
| 234 |
+
"is_pos": false,
|
| 235 |
+
"threshold": 6.079483985900879,
|
| 236 |
+
"threshold_int8": 49,
|
| 237 |
+
"per_dim_F1": 0.675870954990387
|
| 238 |
+
},
|
| 239 |
+
{
|
| 240 |
+
"dim_index_in_40": 28,
|
| 241 |
+
"dim_global": 219,
|
| 242 |
+
"is_pos": false,
|
| 243 |
+
"threshold": 2.141653060913086,
|
| 244 |
+
"threshold_int8": 17,
|
| 245 |
+
"per_dim_F1": 0.668889582157135
|
| 246 |
+
},
|
| 247 |
+
{
|
| 248 |
+
"dim_index_in_40": 29,
|
| 249 |
+
"dim_global": 290,
|
| 250 |
+
"is_pos": false,
|
| 251 |
+
"threshold": 2.1265642642974854,
|
| 252 |
+
"threshold_int8": 17,
|
| 253 |
+
"per_dim_F1": 0.6621823906898499
|
| 254 |
+
},
|
| 255 |
+
{
|
| 256 |
+
"dim_index_in_40": 30,
|
| 257 |
+
"dim_global": 529,
|
| 258 |
+
"is_pos": false,
|
| 259 |
+
"threshold": 2.183765411376953,
|
| 260 |
+
"threshold_int8": 17,
|
| 261 |
+
"per_dim_F1": 0.669143795967102
|
| 262 |
+
},
|
| 263 |
+
{
|
| 264 |
+
"dim_index_in_40": 31,
|
| 265 |
+
"dim_global": 617,
|
| 266 |
+
"is_pos": false,
|
| 267 |
+
"threshold": 2.6399528980255127,
|
| 268 |
+
"threshold_int8": 21,
|
| 269 |
+
"per_dim_F1": 0.6687593460083008
|
| 270 |
+
},
|
| 271 |
+
{
|
| 272 |
+
"dim_index_in_40": 32,
|
| 273 |
+
"dim_global": 269,
|
| 274 |
+
"is_pos": false,
|
| 275 |
+
"threshold": 1.357992172241211,
|
| 276 |
+
"threshold_int8": 11,
|
| 277 |
+
"per_dim_F1": 0.6660473942756653
|
| 278 |
+
},
|
| 279 |
+
{
|
| 280 |
+
"dim_index_in_40": 33,
|
| 281 |
+
"dim_global": 745,
|
| 282 |
+
"is_pos": false,
|
| 283 |
+
"threshold": 2.195744514465332,
|
| 284 |
+
"threshold_int8": 18,
|
| 285 |
+
"per_dim_F1": 0.6753367185592651
|
| 286 |
+
},
|
| 287 |
+
{
|
| 288 |
+
"dim_index_in_40": 34,
|
| 289 |
+
"dim_global": 576,
|
| 290 |
+
"is_pos": false,
|
| 291 |
+
"threshold": 2.358708620071411,
|
| 292 |
+
"threshold_int8": 19,
|
| 293 |
+
"per_dim_F1": 0.6699551939964294
|
| 294 |
+
},
|
| 295 |
+
{
|
| 296 |
+
"dim_index_in_40": 35,
|
| 297 |
+
"dim_global": 701,
|
| 298 |
+
"is_pos": false,
|
| 299 |
+
"threshold": 1.7730076313018799,
|
| 300 |
+
"threshold_int8": 14,
|
| 301 |
+
"per_dim_F1": 0.670412540435791
|
| 302 |
+
},
|
| 303 |
+
{
|
| 304 |
+
"dim_index_in_40": 36,
|
| 305 |
+
"dim_global": 105,
|
| 306 |
+
"is_pos": false,
|
| 307 |
+
"threshold": 2.2044856548309326,
|
| 308 |
+
"threshold_int8": 18,
|
| 309 |
+
"per_dim_F1": 0.6687593460083008
|
| 310 |
+
},
|
| 311 |
+
{
|
| 312 |
+
"dim_index_in_40": 37,
|
| 313 |
+
"dim_global": 694,
|
| 314 |
+
"is_pos": false,
|
| 315 |
+
"threshold": 2.0147933959960938,
|
| 316 |
+
"threshold_int8": 16,
|
| 317 |
+
"per_dim_F1": 0.6694493293762207
|
| 318 |
+
},
|
| 319 |
+
{
|
| 320 |
+
"dim_index_in_40": 38,
|
| 321 |
+
"dim_global": 82,
|
| 322 |
+
"is_pos": false,
|
| 323 |
+
"threshold": 2.640681743621826,
|
| 324 |
+
"threshold_int8": 21,
|
| 325 |
+
"per_dim_F1": 0.6809103488922119
|
| 326 |
+
},
|
| 327 |
+
{
|
| 328 |
+
"dim_index_in_40": 39,
|
| 329 |
+
"dim_global": 283,
|
| 330 |
+
"is_pos": false,
|
| 331 |
+
"threshold": 1.7581170797348022,
|
| 332 |
+
"threshold_int8": 14,
|
| 333 |
+
"per_dim_F1": 0.6612855195999146
|
| 334 |
+
}
|
| 335 |
+
],
|
| 336 |
+
"popcount": {
|
| 337 |
+
"final_threshold": 13,
|
| 338 |
+
"F1": 0.8764044642448425,
|
| 339 |
+
"precision": 0.8911290168762207,
|
| 340 |
+
"recall": 0.8621586561203003
|
| 341 |
+
},
|
| 342 |
+
"additive": {
|
| 343 |
+
"F1": 0.8842884302139282,
|
| 344 |
+
"precision": 0.8891323208808899,
|
| 345 |
+
"recall": 0.8794971704483032
|
| 346 |
+
},
|
| 347 |
+
"F1_delta_popcount_vs_additive": -0.007883965969085693
|
| 348 |
+
}
|
pyproject.toml
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[build-system]
|
| 2 |
+
requires = ["setuptools>=68"]
|
| 3 |
+
build-backend = "setuptools.build_meta"
|
| 4 |
+
|
| 5 |
+
[project]
|
| 6 |
+
name = "one-parameter-classifier"
|
| 7 |
+
version = "0.0.0"
|
| 8 |
+
description = "Image-level person classification on EUPE-ViT-B features with a single free parameter"
|
| 9 |
+
requires-python = ">=3.9"
|
| 10 |
+
dependencies = [
|
| 11 |
+
"torch>=2.0",
|
| 12 |
+
"numpy",
|
| 13 |
+
"pillow",
|
| 14 |
+
"safetensors",
|
| 15 |
+
"transformers>=4.40",
|
| 16 |
+
"huggingface-hub",
|
| 17 |
+
"pycocotools",
|
| 18 |
+
]
|
| 19 |
+
|
| 20 |
+
[project.optional-dependencies]
|
| 21 |
+
dev = ["pytest>=7"]
|
| 22 |
+
synth = ["nosis"]
|
| 23 |
+
|
| 24 |
+
[tool.setuptools]
|
| 25 |
+
packages = ["common"]
|
| 26 |
+
py-modules = ["infer", "head", "verify", "calibrate", "rtl_gen", "synth"]
|
| 27 |
+
|
| 28 |
+
[tool.pytest.ini_options]
|
| 29 |
+
testpaths = ["tests"]
|
rtl/popcount.v
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Popcount-reformulated 1-parameter person classifier, runtime thresholds.
|
| 2 |
+
// Generated by rtl_gen.py; do not edit by hand.
|
| 3 |
+
//
|
| 4 |
+
// Inputs are the 40 Stage 0 classifier dims as signed INT8, post-LayerNorm and
|
| 5 |
+
// post-max-pool. Output is one bit. Combinational, no multipliers, no memory.
|
| 6 |
+
|
| 7 |
+
module person_classifier_popcount (
|
| 8 |
+
input signed [7:0] f00, f01, f02, f03, f04, f05, f06, f07, f08, f09,
|
| 9 |
+
input signed [7:0] f10, f11, f12, f13, f14, f15, f16, f17, f18, f19,
|
| 10 |
+
input signed [7:0] f20, f21, f22, f23, f24, f25, f26, f27, f28, f29,
|
| 11 |
+
input signed [7:0] f30, f31, f32, f33, f34, f35, f36, f37, f38, f39,
|
| 12 |
+
input signed [7:0] t00, t01, t02, t03, t04, t05, t06, t07, t08, t09,
|
| 13 |
+
input signed [7:0] t10, t11, t12, t13, t14, t15, t16, t17, t18, t19,
|
| 14 |
+
input signed [7:0] t20, t21, t22, t23, t24, t25, t26, t27, t28, t29,
|
| 15 |
+
input signed [7:0] t30, t31, t32, t33, t34, t35, t36, t37, t38, t39,
|
| 16 |
+
input signed [5:0] final_threshold,
|
| 17 |
+
output person_present
|
| 18 |
+
);
|
| 19 |
+
wire [5:0] count_pos =
|
| 20 |
+
(f00 > t00) + (f01 > t01) + (f02 > t02) +
|
| 21 |
+
(f03 > t03) + (f04 > t04) + (f05 > t05) +
|
| 22 |
+
(f06 > t06) + (f07 > t07) + (f08 > t08) +
|
| 23 |
+
(f09 > t09) + (f10 > t10) + (f11 > t11) +
|
| 24 |
+
(f12 > t12) + (f13 > t13) + (f14 > t14) +
|
| 25 |
+
(f15 > t15) + (f16 > t16) + (f17 > t17) +
|
| 26 |
+
(f18 > t18) + (f19 > t19);
|
| 27 |
+
|
| 28 |
+
wire [5:0] count_neg =
|
| 29 |
+
(f20 > t20) + (f21 > t21) + (f22 > t22) +
|
| 30 |
+
(f23 > t23) + (f24 > t24) + (f25 > t25) +
|
| 31 |
+
(f26 > t26) + (f27 > t27) + (f28 > t28) +
|
| 32 |
+
(f29 > t29) + (f30 > t30) + (f31 > t31) +
|
| 33 |
+
(f32 > t32) + (f33 > t33) + (f34 > t34) +
|
| 34 |
+
(f35 > t35) + (f36 > t36) + (f37 > t37) +
|
| 35 |
+
(f38 > t38) + (f39 > t39);
|
| 36 |
+
|
| 37 |
+
wire signed [6:0] diff = {1'b0, count_pos} - {1'b0, count_neg};
|
| 38 |
+
assign person_present = diff > final_threshold;
|
| 39 |
+
endmodule
|
rtl/popcount_folded.v
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Popcount-reformulated 1-parameter person classifier, thresholds baked in.
|
| 2 |
+
// Generated by rtl_gen.py; do not edit by hand.
|
| 3 |
+
//
|
| 4 |
+
// Inputs are the 40 Stage 0 classifier dims as signed INT8, post-LayerNorm and
|
| 5 |
+
// post-max-pool. Output is one bit. Combinational, no multipliers, no memory.
|
| 6 |
+
//
|
| 7 |
+
// Per-dim thresholds are the calibrated float values scaled by 8 and rounded.
|
| 8 |
+
|
| 9 |
+
module person_classifier_popcount_folded (
|
| 10 |
+
input signed [7:0] f00, f01, f02, f03, f04, f05, f06, f07, f08, f09,
|
| 11 |
+
input signed [7:0] f10, f11, f12, f13, f14, f15, f16, f17, f18, f19,
|
| 12 |
+
input signed [7:0] f20, f21, f22, f23, f24, f25, f26, f27, f28, f29,
|
| 13 |
+
input signed [7:0] f30, f31, f32, f33, f34, f35, f36, f37, f38, f39,
|
| 14 |
+
output person_present
|
| 15 |
+
);
|
| 16 |
+
localparam signed [7:0] T00 = 53, T01 = 56, T02 = 26, T03 = 60, T04 = 17,
|
| 17 |
+
T05 = 12, T06 = 16, T07 = 1, T08 = 5, T09 = 11,
|
| 18 |
+
T10 = 4, T11 = 4, T12 = 6, T13 = 9, T14 = 8,
|
| 19 |
+
T15 = 16, T16 = 6, T17 = 6, T18 = 7, T19 = 8,
|
| 20 |
+
T20 = 36, T21 = 45, T22 = 19, T23 = 14, T24 = 14,
|
| 21 |
+
T25 = 63, T26 = 18, T27 = 49, T28 = 17, T29 = 17,
|
| 22 |
+
T30 = 17, T31 = 21, T32 = 11, T33 = 18, T34 = 19,
|
| 23 |
+
T35 = 14, T36 = 18, T37 = 16, T38 = 21, T39 = 14;
|
| 24 |
+
localparam signed [5:0] FINAL_T = 13;
|
| 25 |
+
|
| 26 |
+
wire [5:0] count_pos =
|
| 27 |
+
(f00 > T00) + (f01 > T01) + (f02 > T02) +
|
| 28 |
+
(f03 > T03) + (f04 > T04) + (f05 > T05) +
|
| 29 |
+
(f06 > T06) + (f07 > T07) + (f08 > T08) +
|
| 30 |
+
(f09 > T09) + (f10 > T10) + (f11 > T11) +
|
| 31 |
+
(f12 > T12) + (f13 > T13) + (f14 > T14) +
|
| 32 |
+
(f15 > T15) + (f16 > T16) + (f17 > T17) +
|
| 33 |
+
(f18 > T18) + (f19 > T19);
|
| 34 |
+
|
| 35 |
+
wire [5:0] count_neg =
|
| 36 |
+
(f20 > T20) + (f21 > T21) + (f22 > T22) +
|
| 37 |
+
(f23 > T23) + (f24 > T24) + (f25 > T25) +
|
| 38 |
+
(f26 > T26) + (f27 > T27) + (f28 > T28) +
|
| 39 |
+
(f29 > T29) + (f30 > T30) + (f31 > T31) +
|
| 40 |
+
(f32 > T32) + (f33 > T33) + (f34 > T34) +
|
| 41 |
+
(f35 > T35) + (f36 > T36) + (f37 > T37) +
|
| 42 |
+
(f38 > T38) + (f39 > T39);
|
| 43 |
+
|
| 44 |
+
wire signed [6:0] diff = {1'b0, count_pos} - {1'b0, count_neg};
|
| 45 |
+
assign person_present = diff > FINAL_T;
|
| 46 |
+
endmodule
|
rtl/sum.v
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Additive 1-parameter person classifier, runtime threshold.
|
| 2 |
+
// Generated by rtl_gen.py; do not edit by hand.
|
| 3 |
+
//
|
| 4 |
+
// Inputs are the 40 Stage 0 classifier dims as signed INT8, post-LayerNorm and
|
| 5 |
+
// post-max-pool. Output is one bit. Combinational, no multipliers, no memory.
|
| 6 |
+
|
| 7 |
+
module person_classifier_1p (
|
| 8 |
+
input signed [7:0] f00, f01, f02, f03, f04, f05, f06, f07, f08, f09,
|
| 9 |
+
input signed [7:0] f10, f11, f12, f13, f14, f15, f16, f17, f18, f19,
|
| 10 |
+
input signed [7:0] f20, f21, f22, f23, f24, f25, f26, f27, f28, f29,
|
| 11 |
+
input signed [7:0] f30, f31, f32, f33, f34, f35, f36, f37, f38, f39,
|
| 12 |
+
input signed [15:0] threshold,
|
| 13 |
+
output person_present
|
| 14 |
+
);
|
| 15 |
+
// Score = sum(f00..f19) - sum(f20..f39); worst case 20 * 127 = 2540 fits in 16 bits.
|
| 16 |
+
wire signed [15:0] pos_sum =
|
| 17 |
+
{{8{f00[7]}}, f00} + {{8{f01[7]}}, f01} + {{8{f02[7]}}, f02} + {{8{f03[7]}}, f03} +
|
| 18 |
+
{{8{f04[7]}}, f04} + {{8{f05[7]}}, f05} + {{8{f06[7]}}, f06} + {{8{f07[7]}}, f07} +
|
| 19 |
+
{{8{f08[7]}}, f08} + {{8{f09[7]}}, f09} + {{8{f10[7]}}, f10} + {{8{f11[7]}}, f11} +
|
| 20 |
+
{{8{f12[7]}}, f12} + {{8{f13[7]}}, f13} + {{8{f14[7]}}, f14} + {{8{f15[7]}}, f15} +
|
| 21 |
+
{{8{f16[7]}}, f16} + {{8{f17[7]}}, f17} + {{8{f18[7]}}, f18} + {{8{f19[7]}}, f19};
|
| 22 |
+
|
| 23 |
+
wire signed [15:0] neg_sum =
|
| 24 |
+
{{8{f20[7]}}, f20} + {{8{f21[7]}}, f21} + {{8{f22[7]}}, f22} + {{8{f23[7]}}, f23} +
|
| 25 |
+
{{8{f24[7]}}, f24} + {{8{f25[7]}}, f25} + {{8{f26[7]}}, f26} + {{8{f27[7]}}, f27} +
|
| 26 |
+
{{8{f28[7]}}, f28} + {{8{f29[7]}}, f29} + {{8{f30[7]}}, f30} + {{8{f31[7]}}, f31} +
|
| 27 |
+
{{8{f32[7]}}, f32} + {{8{f33[7]}}, f33} + {{8{f34[7]}}, f34} + {{8{f35[7]}}, f35} +
|
| 28 |
+
{{8{f36[7]}}, f36} + {{8{f37[7]}}, f37} + {{8{f38[7]}}, f38} + {{8{f39[7]}}, f39};
|
| 29 |
+
|
| 30 |
+
wire signed [15:0] score = pos_sum - neg_sum;
|
| 31 |
+
assign person_present = score > threshold;
|
| 32 |
+
endmodule
|
rtl/sum_folded.v
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Additive 1-parameter person classifier, threshold baked in.
|
| 2 |
+
// Generated by rtl_gen.py; do not edit by hand.
|
| 3 |
+
//
|
| 4 |
+
// Inputs are the 40 Stage 0 classifier dims as signed INT8, post-LayerNorm and
|
| 5 |
+
// post-max-pool. Output is one bit. Combinational, no multipliers, no memory.
|
| 6 |
+
|
| 7 |
+
module person_classifier_sum_folded (
|
| 8 |
+
input signed [7:0] f00, f01, f02, f03, f04, f05, f06, f07, f08, f09,
|
| 9 |
+
input signed [7:0] f10, f11, f12, f13, f14, f15, f16, f17, f18, f19,
|
| 10 |
+
input signed [7:0] f20, f21, f22, f23, f24, f25, f26, f27, f28, f29,
|
| 11 |
+
input signed [7:0] f30, f31, f32, f33, f34, f35, f36, f37, f38, f39,
|
| 12 |
+
output person_present
|
| 13 |
+
);
|
| 14 |
+
// Stage 0 threshold 25.2845 at the x8 scale used for the per-dim ones.
|
| 15 |
+
localparam signed [15:0] FINAL_T = 16'sd202;
|
| 16 |
+
|
| 17 |
+
wire signed [15:0] pos_sum =
|
| 18 |
+
{{8{f00[7]}}, f00} + {{8{f01[7]}}, f01} + {{8{f02[7]}}, f02} + {{8{f03[7]}}, f03} +
|
| 19 |
+
{{8{f04[7]}}, f04} + {{8{f05[7]}}, f05} + {{8{f06[7]}}, f06} + {{8{f07[7]}}, f07} +
|
| 20 |
+
{{8{f08[7]}}, f08} + {{8{f09[7]}}, f09} + {{8{f10[7]}}, f10} + {{8{f11[7]}}, f11} +
|
| 21 |
+
{{8{f12[7]}}, f12} + {{8{f13[7]}}, f13} + {{8{f14[7]}}, f14} + {{8{f15[7]}}, f15} +
|
| 22 |
+
{{8{f16[7]}}, f16} + {{8{f17[7]}}, f17} + {{8{f18[7]}}, f18} + {{8{f19[7]}}, f19};
|
| 23 |
+
|
| 24 |
+
wire signed [15:0] neg_sum =
|
| 25 |
+
{{8{f20[7]}}, f20} + {{8{f21[7]}}, f21} + {{8{f22[7]}}, f22} + {{8{f23[7]}}, f23} +
|
| 26 |
+
{{8{f24[7]}}, f24} + {{8{f25[7]}}, f25} + {{8{f26[7]}}, f26} + {{8{f27[7]}}, f27} +
|
| 27 |
+
{{8{f28[7]}}, f28} + {{8{f29[7]}}, f29} + {{8{f30[7]}}, f30} + {{8{f31[7]}}, f31} +
|
| 28 |
+
{{8{f32[7]}}, f32} + {{8{f33[7]}}, f33} + {{8{f34[7]}}, f34} + {{8{f35[7]}}, f35} +
|
| 29 |
+
{{8{f36[7]}}, f36} + {{8{f37[7]}}, f37} + {{8{f38[7]}}, f38} + {{8{f39[7]}}, f39};
|
| 30 |
+
|
| 31 |
+
wire signed [15:0] score = pos_sum - neg_sum;
|
| 32 |
+
assign person_present = score > FINAL_T;
|
| 33 |
+
endmodule
|
rtl_gen.py
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Generate all four RTL variants from per_dim_thresholds.json.
|
| 2 |
+
|
| 3 |
+
python rtl_gen.py
|
| 4 |
+
|
| 5 |
+
Kept separate from calibrate.py so the RTL can be regenerated from the committed
|
| 6 |
+
thresholds without the feature cache the calibration needs.
|
| 7 |
+
"""
|
| 8 |
+
import argparse
|
| 9 |
+
import json
|
| 10 |
+
import sys
|
| 11 |
+
from pathlib import Path
|
| 12 |
+
|
| 13 |
+
sys.path.insert(0, str(Path(__file__).resolve().parent)) # repo root, for `common`
|
| 14 |
+
from common import read_artifact # noqa: E402
|
| 15 |
+
|
| 16 |
+
HERE = Path(__file__).resolve().parent
|
| 17 |
+
N_DIMS = 40
|
| 18 |
+
N_POS = 20
|
| 19 |
+
|
| 20 |
+
HEADER = '''// {title}
|
| 21 |
+
// Generated by rtl_gen.py; do not edit by hand.
|
| 22 |
+
//
|
| 23 |
+
// Inputs are the 40 Stage 0 classifier dims as signed INT8, post-LayerNorm and
|
| 24 |
+
// post-max-pool. Output is one bit. Combinational, no multipliers, no memory.
|
| 25 |
+
'''
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def _ports(name: str, width: int, per_line: int = 10) -> str:
|
| 29 |
+
"""Declaration lines for f00..f39 or t00..t39."""
|
| 30 |
+
rows = []
|
| 31 |
+
for start in range(0, N_DIMS, per_line):
|
| 32 |
+
names = ', '.join(f'{name}{i:02d}' for i in range(start, start + per_line))
|
| 33 |
+
rows.append(f' input signed [{width - 1}:0] {names},')
|
| 34 |
+
return '\n'.join(rows)
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def _sign_extended_sum(lo: int, hi: int, per_line: int = 4) -> str:
|
| 38 |
+
"""Sign-extended 16-bit addition of f{lo}..f{hi-1}."""
|
| 39 |
+
terms = [f'{{{{8{{f{i:02d}[7]}}}}, f{i:02d}}}' for i in range(lo, hi)]
|
| 40 |
+
rows = [' + '.join(terms[i:i + per_line]) for i in range(0, len(terms), per_line)]
|
| 41 |
+
return ' +\n '.join(rows)
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
def _popcount(lo: int, hi: int, threshold, per_line: int = 3) -> str:
|
| 45 |
+
"""Sum of the per-dim comparisons, written inline.
|
| 46 |
+
|
| 47 |
+
The comparisons are summed directly rather than collected into a vector and
|
| 48 |
+
indexed. Indexing a vector is the more readable form, but it relies on
|
| 49 |
+
bit-select lowering that the synthesis backend gets wrong at index 0, and a
|
| 50 |
+
decision circuit is not the place to depend on that.
|
| 51 |
+
"""
|
| 52 |
+
terms = [f'(f{i:02d} > {threshold(i)})' for i in range(lo, hi)]
|
| 53 |
+
rows = [' + '.join(terms[i:i + per_line]) for i in range(0, len(terms), per_line)]
|
| 54 |
+
return ' +\n '.join(rows)
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
def _threshold_bank(values, per_line: int = 5) -> str:
|
| 58 |
+
"""localparam bank holding the 40 baked INT8 thresholds."""
|
| 59 |
+
rows = []
|
| 60 |
+
for start in range(0, N_DIMS, per_line):
|
| 61 |
+
rows.append(', '.join(f'T{i:02d} = {values[i]:>4}'
|
| 62 |
+
for i in range(start, min(start + per_line, N_DIMS))))
|
| 63 |
+
return (',\n' + ' ' * 29).join(rows)
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
def emit_sum() -> str:
|
| 67 |
+
return HEADER.format(title='Additive 1-parameter person classifier, runtime threshold.') + f'''
|
| 68 |
+
module person_classifier_1p (
|
| 69 |
+
{_ports('f', 8)}
|
| 70 |
+
input signed [15:0] threshold,
|
| 71 |
+
output person_present
|
| 72 |
+
);
|
| 73 |
+
// Score = sum(f00..f19) - sum(f20..f39); worst case 20 * 127 = 2540 fits in 16 bits.
|
| 74 |
+
wire signed [15:0] pos_sum =
|
| 75 |
+
{_sign_extended_sum(0, 20)};
|
| 76 |
+
|
| 77 |
+
wire signed [15:0] neg_sum =
|
| 78 |
+
{_sign_extended_sum(20, 40)};
|
| 79 |
+
|
| 80 |
+
wire signed [15:0] score = pos_sum - neg_sum;
|
| 81 |
+
assign person_present = score > threshold;
|
| 82 |
+
endmodule
|
| 83 |
+
'''
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
def emit_sum_folded(final_int8: int, final_float: float, quant_scale: int) -> str:
|
| 87 |
+
return HEADER.format(title='Additive 1-parameter person classifier, threshold baked in.') + f'''
|
| 88 |
+
module person_classifier_sum_folded (
|
| 89 |
+
{_ports('f', 8)}
|
| 90 |
+
output person_present
|
| 91 |
+
);
|
| 92 |
+
// Stage 0 threshold {final_float:.4f} at the x{quant_scale} scale used for the per-dim ones.
|
| 93 |
+
localparam signed [15:0] FINAL_T = 16'sd{final_int8};
|
| 94 |
+
|
| 95 |
+
wire signed [15:0] pos_sum =
|
| 96 |
+
{_sign_extended_sum(0, 20)};
|
| 97 |
+
|
| 98 |
+
wire signed [15:0] neg_sum =
|
| 99 |
+
{_sign_extended_sum(20, 40)};
|
| 100 |
+
|
| 101 |
+
wire signed [15:0] score = pos_sum - neg_sum;
|
| 102 |
+
assign person_present = score > FINAL_T;
|
| 103 |
+
endmodule
|
| 104 |
+
'''
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
def emit_popcount() -> str:
|
| 108 |
+
title = 'Popcount-reformulated 1-parameter person classifier, runtime thresholds.'
|
| 109 |
+
return HEADER.format(title=title) + f'''
|
| 110 |
+
module person_classifier_popcount (
|
| 111 |
+
{_ports('f', 8)}
|
| 112 |
+
{_ports('t', 8)}
|
| 113 |
+
input signed [5:0] final_threshold,
|
| 114 |
+
output person_present
|
| 115 |
+
);
|
| 116 |
+
wire [5:0] count_pos =
|
| 117 |
+
{_popcount(0, 20, lambda i: f't{i:02d}')};
|
| 118 |
+
|
| 119 |
+
wire [5:0] count_neg =
|
| 120 |
+
{_popcount(20, 40, lambda i: f't{i:02d}')};
|
| 121 |
+
|
| 122 |
+
wire signed [6:0] diff = {{1'b0, count_pos}} - {{1'b0, count_neg}};
|
| 123 |
+
assign person_present = diff > final_threshold;
|
| 124 |
+
endmodule
|
| 125 |
+
'''
|
| 126 |
+
|
| 127 |
+
|
| 128 |
+
def emit_popcount_folded(thresholds, final_threshold: int, quant_scale: int) -> str:
|
| 129 |
+
title = 'Popcount-reformulated 1-parameter person classifier, thresholds baked in.'
|
| 130 |
+
return HEADER.format(title=title) + f'''//
|
| 131 |
+
// Per-dim thresholds are the calibrated float values scaled by {quant_scale} and rounded.
|
| 132 |
+
|
| 133 |
+
module person_classifier_popcount_folded (
|
| 134 |
+
{_ports('f', 8)}
|
| 135 |
+
output person_present
|
| 136 |
+
);
|
| 137 |
+
localparam signed [7:0] {_threshold_bank(thresholds)};
|
| 138 |
+
localparam signed [5:0] FINAL_T = {final_threshold};
|
| 139 |
+
|
| 140 |
+
wire [5:0] count_pos =
|
| 141 |
+
{_popcount(0, 20, lambda i: f'T{i:02d}')};
|
| 142 |
+
|
| 143 |
+
wire [5:0] count_neg =
|
| 144 |
+
{_popcount(20, 40, lambda i: f'T{i:02d}')};
|
| 145 |
+
|
| 146 |
+
wire signed [6:0] diff = {{1'b0, count_pos}} - {{1'b0, count_neg}};
|
| 147 |
+
assign person_present = diff > FINAL_T;
|
| 148 |
+
endmodule
|
| 149 |
+
'''
|
| 150 |
+
|
| 151 |
+
|
| 152 |
+
def generate(out_dir: Path = None, thresholds_json: Path = None,
|
| 153 |
+
classifier_json: Path = None):
|
| 154 |
+
"""Write all four modules; returns the paths written."""
|
| 155 |
+
out_dir = out_dir or HERE / 'rtl'
|
| 156 |
+
cal = read_artifact(thresholds_json or HERE / 'per_dim_thresholds.json')
|
| 157 |
+
classifier = json.loads(
|
| 158 |
+
(classifier_json or HERE / 'classifier.json').read_text())
|
| 159 |
+
|
| 160 |
+
scale = cal['quant_scale']
|
| 161 |
+
per_dim = [p['threshold_int8'] for p in cal['per_dim_thresholds']]
|
| 162 |
+
final_pop = cal['popcount']['final_threshold']
|
| 163 |
+
stage_0_thr = float(classifier['threshold'])
|
| 164 |
+
stage_0_int8 = int(round(stage_0_thr * scale))
|
| 165 |
+
|
| 166 |
+
out_dir.mkdir(parents=True, exist_ok=True)
|
| 167 |
+
written = {
|
| 168 |
+
'sum.v': emit_sum(),
|
| 169 |
+
'sum_folded.v': emit_sum_folded(stage_0_int8, stage_0_thr, scale),
|
| 170 |
+
'popcount.v': emit_popcount(),
|
| 171 |
+
'popcount_folded.v': emit_popcount_folded(per_dim, final_pop, scale),
|
| 172 |
+
}
|
| 173 |
+
for name, text in written.items():
|
| 174 |
+
(out_dir / name).write_text(text, encoding='utf-8')
|
| 175 |
+
return [out_dir / n for n in written]
|
| 176 |
+
|
| 177 |
+
|
| 178 |
+
if __name__ == '__main__':
|
| 179 |
+
ap = argparse.ArgumentParser(description=__doc__)
|
| 180 |
+
ap.add_argument('--out', type=Path, default=None)
|
| 181 |
+
args = ap.parse_args()
|
| 182 |
+
for path in generate(args.out):
|
| 183 |
+
print(f'wrote {path}')
|
synth.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Synthesize the four decision variants with nosis and write circuit.json.
|
| 2 |
+
|
| 3 |
+
python synth.py
|
| 4 |
+
|
| 5 |
+
nosis is a pure-Python SystemVerilog to Lattice ECP5 synthesizer. Counts are
|
| 6 |
+
LUT4s, carry cells and slices on that device. Adder trees land on the carry
|
| 7 |
+
chain, so CCU2C rather than LUT4 is the resource that moves with the form of the
|
| 8 |
+
decision, and `bound` records which resource limits each variant.
|
| 9 |
+
"""
|
| 10 |
+
import argparse
|
| 11 |
+
import re
|
| 12 |
+
import subprocess
|
| 13 |
+
import sys
|
| 14 |
+
from pathlib import Path
|
| 15 |
+
|
| 16 |
+
sys.path.insert(0, str(Path(__file__).resolve().parent)) # repo root, for `common`
|
| 17 |
+
from common import read_artifact, write_artifact # noqa: E402
|
| 18 |
+
|
| 19 |
+
HERE = Path(__file__).resolve().parent
|
| 20 |
+
NOSIS_ROOT = Path(r'D:\nosis')
|
| 21 |
+
VARIANTS = {
|
| 22 |
+
'sum': ('person_classifier_1p', 'runtime input'),
|
| 23 |
+
'sum_folded': ('person_classifier_sum_folded', 'baked'),
|
| 24 |
+
'popcount': ('person_classifier_popcount', 'runtime inputs'),
|
| 25 |
+
'popcount_folded': ('person_classifier_popcount_folded', 'baked'),
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def synth_one(src: Path, top: str, build: Path, nosis_root: Path):
|
| 30 |
+
build.mkdir(parents=True, exist_ok=True)
|
| 31 |
+
r = subprocess.run(
|
| 32 |
+
[sys.executable, '-m', 'nosis', str(src), '--top', top, '--stats',
|
| 33 |
+
'-o', str(build / f'{top}.json')],
|
| 34 |
+
cwd=str(nosis_root), capture_output=True, text=True)
|
| 35 |
+
if r.returncode != 0:
|
| 36 |
+
raise SystemExit(f'nosis failed on {src.name}:\n'
|
| 37 |
+
f'{r.stdout[-2000:]}{r.stderr[-2000:]}')
|
| 38 |
+
(build / f'{top}.log').write_text(r.stdout, encoding='utf-8')
|
| 39 |
+
|
| 40 |
+
def grab(pattern, cast=int):
|
| 41 |
+
m = re.search(pattern, r.stdout)
|
| 42 |
+
return cast(m.group(1)) if m else None
|
| 43 |
+
|
| 44 |
+
def text(pattern):
|
| 45 |
+
m = re.search(pattern, r.stdout)
|
| 46 |
+
return m.group(1) if m else None
|
| 47 |
+
|
| 48 |
+
return {'slices': grab(r'Slices:\s+(\d+)'), 'lut4': grab(r'LUTs:\s+(\d+)'),
|
| 49 |
+
'ccu2c': grab(r'CCU2C:\s+(\d+)'), 'ffs': grab(r'FFs:\s+(\d+)'),
|
| 50 |
+
'bound': text(r'Bound:\s+(\S+)'),
|
| 51 |
+
'critical_path_ns': grab(r'Critical path delay:\s+([\d.]+)', float),
|
| 52 |
+
'device': text(r'Device:\s+(\S+)')}
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
def main():
|
| 56 |
+
ap = argparse.ArgumentParser(description=__doc__)
|
| 57 |
+
ap.add_argument('--rtl', type=Path, default=HERE / 'rtl')
|
| 58 |
+
ap.add_argument('--build', type=Path, default=HERE / 'build')
|
| 59 |
+
ap.add_argument('--nosis', type=Path, default=NOSIS_ROOT)
|
| 60 |
+
ap.add_argument('--out', type=Path, default=HERE / 'circuit.json')
|
| 61 |
+
args = ap.parse_args()
|
| 62 |
+
|
| 63 |
+
accuracy = read_artifact(args.out)['accuracy']
|
| 64 |
+
variants = {}
|
| 65 |
+
print(f"{'variant':>18}{'slices':>8}{'LUT4':>7}{'CCU2C':>7}{'bound':>7}{'ns':>8}")
|
| 66 |
+
for name, (top, thresholds) in VARIANTS.items():
|
| 67 |
+
src = args.rtl / f'{name}.v'
|
| 68 |
+
if not src.exists():
|
| 69 |
+
raise SystemExit(f'{src} missing; run rtl_gen.py first')
|
| 70 |
+
s = synth_one(src, top, args.build, args.nosis)
|
| 71 |
+
s.update({'rtl': f'rtl/{name}.v', 'thresholds': thresholds})
|
| 72 |
+
variants[name] = s
|
| 73 |
+
print(f'{name:>18}{s["slices"]:>8}{s["lut4"]:>7}{s["ccu2c"]:>7}'
|
| 74 |
+
f'{s["bound"]:>7}{s["critical_path_ns"]:>8.2f}', flush=True)
|
| 75 |
+
|
| 76 |
+
device = next((v['device'] for v in variants.values() if v['device']), None)
|
| 77 |
+
write_artifact(args.out, {'variants': variants, 'accuracy': accuracy},
|
| 78 |
+
generator='synth.py',
|
| 79 |
+
tool='nosis', target={'family': 'ecp5', 'device': device},
|
| 80 |
+
inputs='40 signed INT8 feature channels at the classifier dims',
|
| 81 |
+
note='LUT4, carry and slice counts on an ECP5, not abstract gates')
|
| 82 |
+
print(f'\n[done] wrote {args.out}')
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
if __name__ == '__main__':
|
| 86 |
+
main()
|
tests/conftest.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Shared fixtures and helpers for the consistency suite."""
|
| 2 |
+
import json
|
| 3 |
+
import sys
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
|
| 6 |
+
import pytest
|
| 7 |
+
|
| 8 |
+
REPO = Path(__file__).resolve().parents[1]
|
| 9 |
+
sys.path.insert(0, str(REPO))
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def load(rel: str) -> dict:
|
| 13 |
+
"""Parse a repo-relative JSON file."""
|
| 14 |
+
return json.loads((REPO / rel).read_text(encoding='utf-8'))
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
@pytest.fixture(scope='session')
|
| 18 |
+
def repo() -> Path:
|
| 19 |
+
return REPO
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
@pytest.fixture(scope='session')
|
| 23 |
+
def classifier() -> dict:
|
| 24 |
+
return load('classifier.json')
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
@pytest.fixture(scope='session')
|
| 28 |
+
def tight() -> dict:
|
| 29 |
+
return load('classifier_tight_fpr.json')
|
tests/test_artifacts.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Every committed artifact matches the schema its generator declares."""
|
| 2 |
+
import pytest
|
| 3 |
+
|
| 4 |
+
from common.artifacts import REGISTRY
|
| 5 |
+
from conftest import REPO, load
|
| 6 |
+
|
| 7 |
+
# Artifacts whose producing sweep was never committed, so provenance.generator
|
| 8 |
+
# is null. A new entry here is a new gap and has to be added deliberately.
|
| 9 |
+
KNOWN_GAPS = {
|
| 10 |
+
'eval_tight_fpr.json',
|
| 11 |
+
'discovery/dim_selection.json',
|
| 12 |
+
'discovery/dim48_characterization.json',
|
| 13 |
+
'discovery/prop_specificity.json',
|
| 14 |
+
'discovery/prop_image_manifest.json',
|
| 15 |
+
'discovery/variant_leaderboard.json',
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
@pytest.mark.parametrize('rel', sorted(REGISTRY))
|
| 20 |
+
def test_artifact_exists(rel):
|
| 21 |
+
assert (REPO / rel).exists(), f'{rel} is registered but missing'
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
@pytest.mark.parametrize('rel', sorted(REGISTRY))
|
| 25 |
+
def test_artifact_has_provenance(rel):
|
| 26 |
+
doc = load(rel)
|
| 27 |
+
assert 'provenance' in doc, f'{rel} has no provenance block'
|
| 28 |
+
assert next(iter(doc)) == 'provenance', f'{rel} does not open with its provenance block'
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
@pytest.mark.parametrize('rel', sorted(r for r in REGISTRY if REGISTRY[r].payload_keys))
|
| 32 |
+
def test_artifact_payload_keys(rel):
|
| 33 |
+
spec = REGISTRY[rel]
|
| 34 |
+
got = tuple(k for k in load(rel) if k != 'provenance')
|
| 35 |
+
assert got == spec.payload_keys, f'{rel} payload keys {got} != declared {spec.payload_keys}'
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
@pytest.mark.parametrize('rel', sorted(REGISTRY))
|
| 39 |
+
def test_artifact_generator(rel):
|
| 40 |
+
spec = REGISTRY[rel]
|
| 41 |
+
generator = load(rel)['provenance']['generator']
|
| 42 |
+
assert generator in (spec.generator, None), \
|
| 43 |
+
f'{rel} claims generator {generator!r}, registry says {spec.generator!r}'
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
@pytest.mark.parametrize('rel', sorted(REGISTRY))
|
| 47 |
+
def test_artifact_pool(rel):
|
| 48 |
+
spec = REGISTRY[rel]
|
| 49 |
+
pool = load(rel)['provenance'].get('pool')
|
| 50 |
+
if spec.pool is not None and pool is not None:
|
| 51 |
+
assert pool == spec.pool, f'{rel} names pool {pool!r}, registry says {spec.pool!r}'
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
def test_known_gaps_are_exactly_the_ungenerated_artifacts():
|
| 55 |
+
ungenerated = {rel for rel in REGISTRY
|
| 56 |
+
if load(rel)['provenance']['generator'] is None}
|
| 57 |
+
assert ungenerated == KNOWN_GAPS
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
def test_classifier_hashes_are_current():
|
| 61 |
+
"""Every artifact naming a classifier config records that file's current hash."""
|
| 62 |
+
from common.artifacts import sha256_of
|
| 63 |
+
for rel in sorted(REGISTRY):
|
| 64 |
+
p = load(rel)['provenance']
|
| 65 |
+
if 'classifier' not in p:
|
| 66 |
+
continue
|
| 67 |
+
assert p['classifier_sha256'] == sha256_of(REPO / p['classifier']), \
|
| 68 |
+
f'{rel} pins a stale hash for {p["classifier"]}'
|
tests/test_dims.py
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""The 40 classifier dims agree everywhere they are written down."""
|
| 2 |
+
from safetensors.torch import load_file
|
| 3 |
+
|
| 4 |
+
from conftest import REPO, load
|
| 5 |
+
|
| 6 |
+
N_POS = 20
|
| 7 |
+
N_NEG = 20
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def test_baseline_counts(classifier):
|
| 11 |
+
assert len(classifier['pos_dims']) == N_POS
|
| 12 |
+
assert len(classifier['neg_dims']) == N_NEG
|
| 13 |
+
assert not set(classifier['pos_dims']) & set(classifier['neg_dims'])
|
| 14 |
+
assert classifier['fixed_parameters']['dim_indices'] == N_POS + N_NEG
|
| 15 |
+
assert classifier['free_parameters'] == 1
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def test_tight_fpr_extends_the_baseline(classifier, tight):
|
| 19 |
+
assert tight['pos_dims'] == classifier['pos_dims']
|
| 20 |
+
assert tight['neg_dims_original'] == classifier['neg_dims']
|
| 21 |
+
assert tight['neg_dims'] == tight['neg_dims_original'] + tight['neg_dims_extra']
|
| 22 |
+
assert len(set(tight['neg_dims'])) == len(tight['neg_dims'])
|
| 23 |
+
assert tight['fixed_parameters']['dim_indices'] == len(tight['pos_dims']) + len(tight['neg_dims'])
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def test_leaderboard_prefixes_match_the_shipped_lists(classifier):
|
| 27 |
+
board = load('discovery/variant_leaderboard.json')
|
| 28 |
+
assert board['top_pos_dims_30'][:N_POS] == classifier['pos_dims']
|
| 29 |
+
assert board['top_neg_dims_30'][:N_NEG] == classifier['neg_dims']
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def test_tight_fpr_extra_dims_come_from_the_prop_sweep(tight):
|
| 33 |
+
sweep = load('discovery/prop_specificity.json')
|
| 34 |
+
k = len(tight['neg_dims_extra'])
|
| 35 |
+
row = next(s for s in sweep['sweeps'] if s['extra_neg_k'] == k)
|
| 36 |
+
assert row['added_dims'] == tight['neg_dims_extra']
|
| 37 |
+
assert abs(row['threshold'] - tight['threshold']) < 1e-6
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
def test_per_dim_thresholds_index_the_same_dims(classifier):
|
| 41 |
+
cal = load('per_dim_thresholds.json')
|
| 42 |
+
entries = cal['per_dim_thresholds']
|
| 43 |
+
assert [e['dim_global'] for e in entries] == classifier['pos_dims'] + classifier['neg_dims']
|
| 44 |
+
assert [e['dim_index_in_40'] for e in entries] == list(range(N_POS + N_NEG))
|
| 45 |
+
assert [e['is_pos'] for e in entries] == [True] * N_POS + [False] * N_NEG
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
def test_quantized_thresholds_match_their_floats():
|
| 49 |
+
cal = load('per_dim_thresholds.json')
|
| 50 |
+
scale = cal['quant_scale']
|
| 51 |
+
for e in cal['per_dim_thresholds']:
|
| 52 |
+
assert e['threshold_int8'] == round(e['threshold'] * scale)
|
| 53 |
+
assert -128 <= e['threshold_int8'] <= 127
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
def test_safetensors_agree_with_the_json_configs(classifier, tight):
|
| 57 |
+
for name, c in (('classifier', classifier), ('classifier_tight_fpr', tight)):
|
| 58 |
+
t = load_file(str(REPO / f'{name}.safetensors'))
|
| 59 |
+
assert t['pos_dims'].tolist() == c['pos_dims']
|
| 60 |
+
assert t['neg_dims'].tolist() == c['neg_dims']
|
| 61 |
+
assert t['retained_dims'].tolist() == c['pos_dims'] + c['neg_dims']
|
| 62 |
+
assert abs(float(t['threshold'][0]) - c['threshold']) < 1e-4
|
| 63 |
+
w = t['retained_weight'][0].tolist()
|
| 64 |
+
assert w == [1.0] * len(c['pos_dims']) + [-1.0] * len(c['neg_dims'])
|
tests/test_head.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""The fused linear head is identical to the ternary sum it replaces."""
|
| 2 |
+
import sys
|
| 3 |
+
|
| 4 |
+
import torch
|
| 5 |
+
|
| 6 |
+
from common import D, score
|
| 7 |
+
from conftest import REPO
|
| 8 |
+
|
| 9 |
+
sys.path.insert(0, str(REPO))
|
| 10 |
+
from head import FusedClassifier # noqa: E402
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def test_fused_head_equals_ternary_score(classifier):
|
| 14 |
+
torch.manual_seed(0)
|
| 15 |
+
model = FusedClassifier.from_config(None, REPO / 'classifier.json').eval()
|
| 16 |
+
pooled = torch.randn(64, D) * 4.0
|
| 17 |
+
fused, present = model.head(pooled)
|
| 18 |
+
direct = score(pooled, classifier['pos_dims'], classifier['neg_dims'])
|
| 19 |
+
assert torch.allclose(fused, direct, atol=1e-4)
|
| 20 |
+
assert torch.equal(present, direct > classifier['threshold'])
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def test_only_the_threshold_is_learnable(classifier):
|
| 24 |
+
model = FusedClassifier.from_config(None, REPO / 'classifier.json')
|
| 25 |
+
learnable = [n for n, p in model.named_parameters() if p.requires_grad]
|
| 26 |
+
assert learnable == ['threshold']
|
| 27 |
+
assert sum(p.numel() for p in model.parameters()) == 1
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def test_tight_fpr_head_reads_its_own_dim_count(tight):
|
| 31 |
+
model = FusedClassifier.from_config(
|
| 32 |
+
None, REPO / 'classifier_tight_fpr.json')
|
| 33 |
+
assert model.retained_dims.numel() == len(tight['pos_dims']) + len(tight['neg_dims'])
|
| 34 |
+
torch.manual_seed(1)
|
| 35 |
+
pooled = torch.randn(32, D) * 4.0
|
| 36 |
+
fused, _ = model.head(pooled)
|
| 37 |
+
direct = score(pooled, tight['pos_dims'], tight['neg_dims'])
|
| 38 |
+
assert torch.allclose(fused, direct, atol=1e-4)
|
tests/test_rtl.py
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""The generated RTL carries the calibrated constants and computes the decision.
|
| 2 |
+
|
| 3 |
+
The constant and structural checks run everywhere. The simulation checks run
|
| 4 |
+
when Icarus Verilog is available, either on PATH or via the IVERILOG and VVP
|
| 5 |
+
environment variables.
|
| 6 |
+
"""
|
| 7 |
+
import os
|
| 8 |
+
import re
|
| 9 |
+
import shutil
|
| 10 |
+
import subprocess
|
| 11 |
+
|
| 12 |
+
import pytest
|
| 13 |
+
|
| 14 |
+
from conftest import REPO, load
|
| 15 |
+
|
| 16 |
+
RTL = REPO / 'rtl'
|
| 17 |
+
N_DIMS = 40
|
| 18 |
+
N_POS = 20
|
| 19 |
+
N_VECTORS = 512
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def tool(name, env_var):
|
| 23 |
+
return os.environ.get(env_var) or shutil.which(name)
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
IVERILOG = tool('iverilog', 'IVERILOG')
|
| 27 |
+
VVP = tool('vvp', 'VVP')
|
| 28 |
+
needs_sim = pytest.mark.skipif(not (IVERILOG and VVP),
|
| 29 |
+
reason='Icarus Verilog not found on PATH or in IVERILOG/VVP')
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
@pytest.fixture(scope='module')
|
| 33 |
+
def calibration():
|
| 34 |
+
return load('per_dim_thresholds.json')
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def source(name: str) -> str:
|
| 38 |
+
return (RTL / f'{name}.v').read_text(encoding='utf-8')
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
# ---------------- constants and structure ----------------
|
| 42 |
+
|
| 43 |
+
def test_baked_per_dim_thresholds_match_the_calibration(calibration):
|
| 44 |
+
text = source('popcount_folded')
|
| 45 |
+
baked = {int(i): int(v) for i, v in re.findall(r'T(\d\d) =\s*(-?\d+)', text)}
|
| 46 |
+
assert len(baked) == N_DIMS
|
| 47 |
+
for e in calibration['per_dim_thresholds']:
|
| 48 |
+
assert baked[e['dim_index_in_40']] == e['threshold_int8']
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
def test_baked_final_threshold_matches_the_calibration(calibration):
|
| 52 |
+
text = source('popcount_folded')
|
| 53 |
+
assert int(re.search(r'FINAL_T = (-?\d+);', text).group(1)) == \
|
| 54 |
+
calibration['popcount']['final_threshold']
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
def test_sum_folded_threshold_is_the_quantized_threshold(classifier, calibration):
|
| 58 |
+
text = source('sum_folded')
|
| 59 |
+
baked = int(re.search(r"FINAL_T = 16'sd(-?\d+);", text).group(1))
|
| 60 |
+
assert baked == round(classifier['threshold'] * calibration['quant_scale'])
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
@pytest.mark.parametrize('name,threshold', [('popcount', 't{:02d}'),
|
| 64 |
+
('popcount_folded', 'T{:02d}')])
|
| 65 |
+
def test_each_channel_is_compared_against_its_own_threshold(name, threshold):
|
| 66 |
+
text = source(name)
|
| 67 |
+
pairs = re.findall(r'\(f(\d\d) > (\w+)\)', text)
|
| 68 |
+
assert len(pairs) == N_DIMS
|
| 69 |
+
for feature, thr in pairs:
|
| 70 |
+
assert thr == threshold.format(int(feature))
|
| 71 |
+
assert [int(f) for f, _ in pairs] == list(range(N_DIMS))
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
@pytest.mark.parametrize('name', ['popcount', 'popcount_folded'])
|
| 75 |
+
def test_no_bit_select_on_a_vector(name):
|
| 76 |
+
"""Bit-select lowering is unreliable at index 0 in the synthesis backend.
|
| 77 |
+
|
| 78 |
+
The comparisons are summed inline instead, so nothing here depends on it.
|
| 79 |
+
"""
|
| 80 |
+
text = '\n'.join(l for l in source(name).splitlines()
|
| 81 |
+
if not l.strip().startswith('//'))
|
| 82 |
+
assert not re.search(r'\b(pos|neg)_bits\b', text)
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
@pytest.mark.parametrize('name', ['sum', 'sum_folded', 'popcount', 'popcount_folded'])
|
| 86 |
+
def test_every_feature_port_is_declared_once(name):
|
| 87 |
+
declared = re.findall(r'\bf(\d\d)\b(?=[,)\s])', source(name).split(');')[0])
|
| 88 |
+
assert sorted(set(declared)) == [f'{i:02d}' for i in range(N_DIMS)]
|
| 89 |
+
|
| 90 |
+
|
| 91 |
+
# ---------------- simulation ----------------
|
| 92 |
+
|
| 93 |
+
def vectors(n: int, seed: int = 0):
|
| 94 |
+
"""Deterministic signed-INT8 feature vectors, uniform over the input range."""
|
| 95 |
+
import random
|
| 96 |
+
rng = random.Random(seed)
|
| 97 |
+
return [[rng.randint(-128, 127) for _ in range(N_DIMS)] for _ in range(n)]
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
def popcount_boundary_vectors(thresholds, k: int, n: int, seed: int = 0):
|
| 101 |
+
"""Vectors placing the count difference within two of K, on the per-dim thresholds.
|
| 102 |
+
|
| 103 |
+
An `off` channel sits at exactly its threshold, so `>` must reject it.
|
| 104 |
+
"""
|
| 105 |
+
import random
|
| 106 |
+
rng = random.Random(seed)
|
| 107 |
+
out = []
|
| 108 |
+
while len(out) < n:
|
| 109 |
+
diff = k + rng.randint(-2, 2)
|
| 110 |
+
n_neg = rng.randint(0, max(0, N_POS - abs(diff)))
|
| 111 |
+
n_pos = diff + n_neg
|
| 112 |
+
if not (0 <= n_pos <= N_POS and 0 <= n_neg <= N_POS):
|
| 113 |
+
continue
|
| 114 |
+
pos_on = [True] * n_pos + [False] * (N_POS - n_pos)
|
| 115 |
+
neg_on = [True] * n_neg + [False] * (N_POS - n_neg)
|
| 116 |
+
rng.shuffle(pos_on)
|
| 117 |
+
rng.shuffle(neg_on)
|
| 118 |
+
on = pos_on + neg_on
|
| 119 |
+
vec = [max(-128, min(127, t + 1)) if on[i] else max(-128, min(127, t))
|
| 120 |
+
for i, t in enumerate(thresholds)]
|
| 121 |
+
out.append(vec)
|
| 122 |
+
return out
|
| 123 |
+
|
| 124 |
+
|
| 125 |
+
def additive_boundary_vectors(threshold: int, n: int, seed: int = 0):
|
| 126 |
+
"""Vectors whose signed sum lands within a few counts of the comparator threshold."""
|
| 127 |
+
import random
|
| 128 |
+
rng = random.Random(seed)
|
| 129 |
+
out = []
|
| 130 |
+
while len(out) < n:
|
| 131 |
+
vec = [rng.randint(-20, 20) for _ in range(N_DIMS)]
|
| 132 |
+
target = threshold + rng.randint(-4, 4)
|
| 133 |
+
# Solve f00 so that sum(pos) - sum(neg) hits the target exactly.
|
| 134 |
+
vec[0] = target - (sum(vec[1:N_POS]) - sum(vec[N_POS:]))
|
| 135 |
+
if -128 <= vec[0] <= 127:
|
| 136 |
+
out.append(vec)
|
| 137 |
+
return out
|
| 138 |
+
|
| 139 |
+
|
| 140 |
+
def additive_reference(vec, threshold):
|
| 141 |
+
return (sum(vec[:N_POS]) - sum(vec[N_POS:])) > threshold
|
| 142 |
+
|
| 143 |
+
|
| 144 |
+
def popcount_reference(vec, thresholds, k):
|
| 145 |
+
pos = sum(1 for i in range(N_POS) if vec[i] > thresholds[i])
|
| 146 |
+
neg = sum(1 for i in range(N_POS, N_DIMS) if vec[i] > thresholds[i])
|
| 147 |
+
return (pos - neg) > k
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
def literal(value: int, width: int) -> str:
|
| 151 |
+
return f"-{width}'sd{-value}" if value < 0 else f"{width}'sd{value}"
|
| 152 |
+
|
| 153 |
+
|
| 154 |
+
def make_testbench(module: str, extra_ports: str, n: int) -> str:
|
| 155 |
+
features = ', '.join(f'f{i:02d}' for i in range(N_DIMS))
|
| 156 |
+
connections = ',\n '.join(f'.f{i:02d}(f{i:02d})' for i in range(N_DIMS))
|
| 157 |
+
slices = '\n '.join(
|
| 158 |
+
f'f{i:02d} = vecs[i][{319 - 8 * i}:{312 - 8 * i}];' for i in range(N_DIMS))
|
| 159 |
+
return f'''`timescale 1ns/1ps
|
| 160 |
+
module tb;
|
| 161 |
+
reg [319:0] vecs [0:{n - 1}];
|
| 162 |
+
reg signed [7:0] {features};
|
| 163 |
+
wire out;
|
| 164 |
+
integer i;
|
| 165 |
+
{module} dut (
|
| 166 |
+
{connections},{extra_ports}
|
| 167 |
+
.person_present(out));
|
| 168 |
+
initial begin
|
| 169 |
+
$readmemh("vectors.hex", vecs);
|
| 170 |
+
for (i = 0; i < {n}; i = i + 1) begin
|
| 171 |
+
{slices}
|
| 172 |
+
#1;
|
| 173 |
+
$display("%b", out);
|
| 174 |
+
end
|
| 175 |
+
$finish;
|
| 176 |
+
end
|
| 177 |
+
endmodule
|
| 178 |
+
'''
|
| 179 |
+
|
| 180 |
+
|
| 181 |
+
def run_sim(tmp_path, rtl_name, module, extra_ports, vecs):
|
| 182 |
+
tmp_path.mkdir(parents=True, exist_ok=True)
|
| 183 |
+
hexfile = tmp_path / 'vectors.hex'
|
| 184 |
+
hexfile.write_text('\n'.join(
|
| 185 |
+
''.join(f'{v & 0xFF:02x}' for v in vec) for vec in vecs) + '\n')
|
| 186 |
+
(tmp_path / 'tb.v').write_text(make_testbench(module, extra_ports, len(vecs)))
|
| 187 |
+
subprocess.run([IVERILOG, '-g2005', '-o', 'tb.vvp',
|
| 188 |
+
str(RTL / f'{rtl_name}.v'), 'tb.v'],
|
| 189 |
+
cwd=tmp_path, check=True, capture_output=True)
|
| 190 |
+
out = subprocess.run([VVP, 'tb.vvp'], cwd=tmp_path, check=True,
|
| 191 |
+
capture_output=True, text=True).stdout
|
| 192 |
+
bits = [line.strip() for line in out.splitlines() if line.strip() in ('0', '1')]
|
| 193 |
+
assert len(bits) == len(vecs), f'{module}: {len(bits)} results for {len(vecs)} vectors'
|
| 194 |
+
return [b == '1' for b in bits]
|
| 195 |
+
|
| 196 |
+
|
| 197 |
+
@needs_sim
|
| 198 |
+
def test_sum_matches_the_additive_reference(tmp_path, classifier, calibration):
|
| 199 |
+
thr = round(classifier['threshold'] * calibration['quant_scale'])
|
| 200 |
+
vecs = vectors(N_VECTORS) + additive_boundary_vectors(thr, N_VECTORS)
|
| 201 |
+
got = run_sim(tmp_path, 'sum', 'person_classifier_1p',
|
| 202 |
+
f'\n .threshold({literal(thr, 16)}),', vecs)
|
| 203 |
+
assert got == [additive_reference(v, thr) for v in vecs]
|
| 204 |
+
|
| 205 |
+
|
| 206 |
+
@needs_sim
|
| 207 |
+
def test_sum_folded_matches_the_additive_reference(tmp_path, classifier, calibration):
|
| 208 |
+
thr = round(classifier['threshold'] * calibration['quant_scale'])
|
| 209 |
+
vecs = vectors(N_VECTORS) + additive_boundary_vectors(thr, N_VECTORS)
|
| 210 |
+
got = run_sim(tmp_path, 'sum_folded', 'person_classifier_sum_folded', '', vecs)
|
| 211 |
+
assert got == [additive_reference(v, thr) for v in vecs]
|
| 212 |
+
|
| 213 |
+
|
| 214 |
+
@needs_sim
|
| 215 |
+
def test_popcount_matches_the_popcount_reference(tmp_path, calibration):
|
| 216 |
+
thresholds = [e['threshold_int8'] for e in calibration['per_dim_thresholds']]
|
| 217 |
+
k = calibration['popcount']['final_threshold']
|
| 218 |
+
ports = ''.join(f'\n .t{i:02d}({literal(t, 8)}),'
|
| 219 |
+
for i, t in enumerate(thresholds))
|
| 220 |
+
ports += f'\n .final_threshold({literal(k, 6)}),'
|
| 221 |
+
vecs = vectors(N_VECTORS) + popcount_boundary_vectors(thresholds, k, N_VECTORS)
|
| 222 |
+
got = run_sim(tmp_path, 'popcount', 'person_classifier_popcount', ports, vecs)
|
| 223 |
+
assert got == [popcount_reference(v, thresholds, k) for v in vecs]
|
| 224 |
+
|
| 225 |
+
|
| 226 |
+
@needs_sim
|
| 227 |
+
def test_popcount_folded_matches_the_popcount_reference(tmp_path, calibration):
|
| 228 |
+
thresholds = [e['threshold_int8'] for e in calibration['per_dim_thresholds']]
|
| 229 |
+
k = calibration['popcount']['final_threshold']
|
| 230 |
+
vecs = vectors(N_VECTORS) + popcount_boundary_vectors(thresholds, k, N_VECTORS)
|
| 231 |
+
got = run_sim(tmp_path, 'popcount_folded', 'person_classifier_popcount_folded',
|
| 232 |
+
'', vecs)
|
| 233 |
+
assert got == [popcount_reference(v, thresholds, k) for v in vecs]
|
| 234 |
+
|
| 235 |
+
|
| 236 |
+
@needs_sim
|
| 237 |
+
def test_folding_a_threshold_does_not_change_the_decision(tmp_path, classifier,
|
| 238 |
+
calibration):
|
| 239 |
+
"""Each runtime-threshold module agrees with its baked counterpart."""
|
| 240 |
+
thr = round(classifier['threshold'] * calibration['quant_scale'])
|
| 241 |
+
vecs = vectors(N_VECTORS, seed=1) + additive_boundary_vectors(thr, N_VECTORS, seed=1)
|
| 242 |
+
runtime = run_sim(tmp_path / 'a', 'sum', 'person_classifier_1p',
|
| 243 |
+
f'\n .threshold({literal(thr, 16)}),', vecs)
|
| 244 |
+
baked = run_sim(tmp_path / 'b', 'sum_folded', 'person_classifier_sum_folded', '', vecs)
|
| 245 |
+
assert runtime == baked
|
verify.py
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Score a classifier config over a named pool and write its eval artifact.
|
| 2 |
+
|
| 3 |
+
python verify.py # baseline on VAL5000
|
| 4 |
+
python verify.py --classifier classifier_tight_fpr.json
|
| 5 |
+
python verify.py --pool CALIB1000
|
| 6 |
+
|
| 7 |
+
Writes eval.json for the baseline config and eval_tight_fpr.json for the
|
| 8 |
+
tight-FPR one, unless --out says otherwise.
|
| 9 |
+
"""
|
| 10 |
+
import argparse
|
| 11 |
+
import json
|
| 12 |
+
import sys
|
| 13 |
+
from pathlib import Path
|
| 14 |
+
|
| 15 |
+
import torch
|
| 16 |
+
|
| 17 |
+
sys.path.insert(0, str(Path(__file__).resolve().parent)) # repo root, for `common`
|
| 18 |
+
from common import BACKBONE, device, f1_at, load_pool, score_pool, write_artifact # noqa: E402
|
| 19 |
+
from common.models import load_backbone # noqa: E402
|
| 20 |
+
from common.pools import VAL5000, by_name # noqa: E402
|
| 21 |
+
|
| 22 |
+
HERE = Path(__file__).resolve().parent
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
def out_path_for(classifier: Path) -> Path:
|
| 26 |
+
"""classifier.json -> eval.json; classifier_tight_fpr.json -> eval_tight_fpr.json."""
|
| 27 |
+
suffix = classifier.stem[len('classifier'):]
|
| 28 |
+
return classifier.parent / f'eval{suffix}.json'
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
def main():
|
| 32 |
+
ap = argparse.ArgumentParser(description=__doc__)
|
| 33 |
+
ap.add_argument('--classifier', type=Path, default=HERE / 'classifier.json')
|
| 34 |
+
ap.add_argument('--backbone', default=BACKBONE)
|
| 35 |
+
ap.add_argument('--pool', default=VAL5000.name)
|
| 36 |
+
ap.add_argument('--out', type=Path, default=None)
|
| 37 |
+
args = ap.parse_args()
|
| 38 |
+
|
| 39 |
+
dev = device()
|
| 40 |
+
pool = by_name(args.pool)
|
| 41 |
+
c = json.loads(args.classifier.read_text())
|
| 42 |
+
print(f'[init] loading {args.backbone}', flush=True)
|
| 43 |
+
backbone = load_backbone(args.backbone).to(dev)
|
| 44 |
+
|
| 45 |
+
print(f'[pool] {pool.name}', flush=True)
|
| 46 |
+
loaded = load_pool(pool, dev)
|
| 47 |
+
pos = torch.tensor(c['pos_dims'], dtype=torch.long, device=dev)
|
| 48 |
+
neg = torch.tensor(c['neg_dims'], dtype=torch.long, device=dev)
|
| 49 |
+
|
| 50 |
+
scores, _ = score_pool(backbone, loaded, pos, neg)
|
| 51 |
+
m = f1_at(scores, loaded.labels, c['threshold'])
|
| 52 |
+
print(f'[verify] F1={m.f1:.4f} P={m.precision:.4f} R={m.recall:.4f}', flush=True)
|
| 53 |
+
|
| 54 |
+
path = args.out or out_path_for(args.classifier)
|
| 55 |
+
write_artifact(
|
| 56 |
+
path, {'metrics': {k: round(v, 4) if k != 'threshold' else v
|
| 57 |
+
for k, v in m.asdict().items()}},
|
| 58 |
+
generator='verify.py', classifier=args.classifier,
|
| 59 |
+
pool_info=loaded.provenance(),
|
| 60 |
+
task='image-level person presence (binary)',
|
| 61 |
+
protocol='live backbone forward at 768 px, no feature caching')
|
| 62 |
+
print(f'[done] wrote {path}', flush=True)
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
if __name__ == '__main__':
|
| 66 |
+
main()
|