diff --git a/AGENTS.md b/AGENTS.md index 908d051..2e47cf1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -32,7 +32,7 @@ Win POIDH Arbitrum bounty 323 by shipping a privacy-first local MV3 Chrome exten - **Manifest V3.** `onnxruntime-web` in an offscreen document. WebGPU with WASM fallback (probe the adapter; do not latch a WebGPU error). - **Auto-scan ordinary webpages.** Confidence on every badge: AI / OK / uncertain. - **Hybrid is allowed:** neural + C2PA + EXIF/XMP + PNG/JPEG comments + weak URL hints. A URL hint alone must not cross 0.65. -- **Current fusion: CF-primary, three tiers.** CommunityForensics TTA takes the maximum raw sigmoid from inspected views. CF is authoritative at >= 0.65. Sub-floor tier: below CF 0.03, rescue only when CF >= 0.005 (not flatlined) AND DINO >= 0.999; a CF hard zero is never overridden. Strong tier: CF in [0.03, 0.30) needs DINO >= 0.96. Normal tier: CF in [0.30, 0.65) needs DINO >= 0.70. The flat-graphic gate blocks every rescue tier on catalog art and UI-like images. Bands were fit under a hard stress-set constraint (240 stock/catalog/product reals, zero new FPs allowed). **Do not restore raw max(CF, DINO), remove the graphic gate, or loosen these bands without rerunning the bench plus the stress set and live-site checks.** +- **Current fusion: CF-primary, three tiers.** CommunityForensics TTA takes the maximum raw sigmoid from inspected views. CF is authoritative at >= 0.65. Sub-floor tier: below CF 0.02, rescue only when CF >= 0.0005 (not flatlined) AND DINO >= 0.995; a CF hard zero is never overridden. Strong tier: CF in [0.02, 0.10) needs DINO >= 0.90. Normal tier: CF in [0.10, 0.65) needs DINO >= 0.70. The flat-graphic gate blocks every rescue tier on catalog art and UI-like images. Bands were re-derived for the hard-negative probe under a hard stress-set constraint (240 full-resolution stock/catalog/product reals; no DINO-attributable stress FP allowed), choosing a conservative near-optimum over the grid maximum. **Do not restore raw max(CF, DINO), remove the graphic gate, or loosen these bands without rerunning the bench plus the stress set and live-site checks.** - **Overlay:** badge store must be an iterable `Map`, not a `WeakMap`. Reposition on scroll / resize / `visualViewport` / mutations. Never wrap images. - **Load-unpacked users do not auto-update.** GitHub Releases zip + popup banner is the update path. Do not assume CWS. - **Cross-device:** macOS (owner), Windows, Linux. WASM must work when WebGPU has no adapter. @@ -65,7 +65,7 @@ Win POIDH Arbitrum bounty 323 by shipping a privacy-first local MV3 Chrome exten | File | Role | |---|---| -| `src/fuse.js` | `DEFAULT_THRESHOLD` 0.65, `DINO_CF_FLOOR` 0.03, `DINO_STRONG_RESCUE_FLOOR` 0.30, `DINO_STRONG_RESCUE_MIN` 0.96, `DINO_RESCUE_MIN` 0.70, `DINO_SUBFLOOR_CF_MIN` 0.005, `DINO_SUBFLOOR_MIN` 0.999, CF-primary `fuseNeuralScores` | +| `src/fuse.js` | `DEFAULT_THRESHOLD` 0.65, `DINO_CF_FLOOR` 0.02, `DINO_STRONG_RESCUE_FLOOR` 0.10, `DINO_STRONG_RESCUE_MIN` 0.90, `DINO_RESCUE_MIN` 0.70, `DINO_SUBFLOOR_CF_MIN` 0.0005, `DINO_SUBFLOOR_MIN` 0.995, CF-primary `fuseNeuralScores` | | `src/graphic-gate.js` | Shared flat-graphic policy for browser and Node evaluation | | `src/pixel-resize.js` | Pillow-exact bicubic resize shared by the extension and the Node harness for the CF path (byte-exact vs Pillow 12.3.0 goldens) | | `src/offscreen.js` | ORT WebGPU/WASM, DINO 224 then CF TTA | @@ -76,7 +76,7 @@ Win POIDH Arbitrum bounty 323 by shipping a privacy-first local MV3 Chrome exten | `src/c2pa-reader.js` | C2PA reader | - Issue 23 (fixed in PR 24 / v1.0.7): overlay WeakMap drift + DINO max false positives. -- The public 893-image fixture on the Pillow-exact preprocess and three-tier policy: 87.7% BA, 75.8% TPR, 99.6% TNR (harness-verified, not simulated). Stress set (240 stock/catalog/product reals): 2 FPs, identical images to the prior policy. Browser vs Node parity: 16/16 decisions, max per-view CF delta 0.0005. The DINO path still uses canvas/RawImage resize (probe trained against it); retraining the probe on Pillow-preprocessed features is the documented follow-up. Live-smoke checks still remain required before any claim. +- The public 893-image fixture with the hard-negative probe and re-derived bands: 90.5% BA, 81.2% TPR, 99.8% TNR (harness-verified, not simulated). Stress set (240 full-resolution stock/catalog/product reals): 4 FPs, all CF-driven at >= 0.65 where CF is authoritative by design; zero DINO-attributable stress FPs (shipped v1.1.0 measured 7 on identical bytes). The DINO probe is trained on features from the shared Pillow-exact path plus 1,915 hard-negative reals (stock, catalog, product, interiors; rows disjoint from the stress set). Full-resolution professional stock photos can spike CF itself; check exactly that during live smoke. Live-smoke checks still remain required before any claim. --- diff --git a/README.md b/README.md index c9e2688..bceb7f8 100644 --- a/README.md +++ b/README.md @@ -56,8 +56,8 @@ Maintainers cut a release with `git tag v1.0.0 && git push origin v1.0.0`. That Two independent neural heads cover complementary failure modes, plus deterministic metadata: 1. **CommunityForensics head:** ViT-Small official FP32 ONNX (CLIP 384). `p(AI) = sigmoid(logit)`. Near-zero false positives on real photos, but under-scores several modern generators (Flux, GPT-4o-image, photoreal DALL-E 3). -2. **DINOv2 probe head:** frozen DINOv2-small backbone (224 center view) with a transparent logistic head over CLS+mean-pooled features (`models/probe/dino-probe.json`: plain standardize/weights/bias, no lookup tables). Trained on ~9.6k images from public datasets across Flux, SD3.5, SDXL-era, Midjourney, DALL-E 3, GPT-4o-image and diverse real photos, with web-realistic JPEG/resize augmentation. This head carries the modern generators. -3. **Neural fusion:** CF-primary with three rescue tiers. When CommunityForensics is confident AI (`>= 0.65`), its score wins. Between `0.03` and `0.30`, DINO can only rescue if it is near-saturated (`p(AI) >= 0.96`); between `0.30` and `0.65`, DINO can lift at `p(AI) >= 0.70`. Below the `0.03` floor a rescue additionally requires CF to be at least faintly awake (`>= 0.005`) and DINO to be saturated (`>= 0.999`): CF emits hard zeros on real photos it is certain about, while AI images in its blind spots still elicit a faint response, so a flatlined CF is itself evidence of a real photo and is never overridden. On flat graphics and catalog art (low palette / high flat-run pixels), a graphic gate suppresses every DINO rescue tier when CF stays below `0.65`, so icons and UI shots do not mass-label AI 100%. CF-confident AI illustrations (`>= 0.65`) are unchanged. Displayed confidence is this raw fused probability; the AI verdict stays at raw `>= 0.65` with no remapping and no logit bias. The rescue bands were fit on the public bench below under a hard constraint measured on a separate 240-image stock, catalog, and product photo stress set: zero new false positives allowed relative to the previous policy. +2. **DINOv2 probe head:** frozen DINOv2-small backbone (224 center view) with a transparent logistic head over CLS+mean-pooled features (`models/probe/dino-probe.json`: plain standardize/weights/bias, no lookup tables). Trained on ~11.4k images from public datasets across Flux, SD3.5, SDXL-era, Midjourney, DALL-E 3, GPT-4o-image and diverse real photos, including ~1.9k hard-negative reals (stock photography, product catalogs, interiors, high-saturation nature) that teach the head not to fire on professional real photos, with web-realistic JPEG/resize augmentation. Features are extracted through the same Pillow-exact resize the extension ships, so training matches serving exactly. This head carries the modern generators. +3. **Neural fusion:** CF-primary with three rescue tiers. When CommunityForensics is confident AI (`>= 0.65`), its score wins. Between `0.02` and `0.10`, DINO can only rescue if it is highly confident (`p(AI) >= 0.90`); between `0.10` and `0.65`, DINO can lift at `p(AI) >= 0.70`. Below the `0.02` floor a rescue additionally requires CF to be at least faintly awake (`>= 0.0005`) and DINO to be saturated (`>= 0.995`): CF emits hard zeros on real photos it is certain about, while AI images in its blind spots still elicit a faint response, so a flatlined CF is itself evidence of a real photo and is never overridden. On flat graphics and catalog art (low palette / high flat-run pixels), a graphic gate suppresses every DINO rescue tier when CF stays below `0.65`, so icons and UI shots do not mass-label AI 100%. CF-confident AI illustrations (`>= 0.65`) are unchanged. Displayed confidence is this raw fused probability; the AI verdict stays at raw `>= 0.65` with no remapping and no logit bias. The rescue bands were re-derived for the current probe under a hard constraint measured on a separate 240-image full-resolution stock, catalog, and product photo stress set (no DINO-attributable false positives allowed), and a deliberately conservative near-optimum was chosen over the grid maximum. 4. **Adaptive TTA:** the DINO pass and the official 440 center crop always run. Extra CommunityForensics views (440 corners + 512 center) run only when a head is at least mildly suspicious (CF center or DINO in `[0.15, 0.65)`), so confident reals cost two passes total. `Math.max` of sigmoids, early exit at `>= 0.9`. Under heavy queue load (more than 12 pending) CF drops to center-only; the DINO pass still runs. 5. **Metadata:** C2PA, EXIF/XMP/IPTC, generator text in PNG/JPEG, weak URL hints. Strong metadata forces 0.95-0.99; a URL hint alone cannot cross 65%. @@ -77,13 +77,12 @@ Eval harness: `npm run eval -- ./path/to/labeled-folder` after `npm run fetch-mo |---|---:|---:|---:| | CommunityForensics center crop only | 66.4% | 32.8% | 100% | | CommunityForensics adaptive max diagnostic | 73.4% | 47.2% | 99.6% | -| DINOv2 probe only | 93.0% | 89.7% | 96.3% | | Legacy raw max ensemble (not shipped) | 96.1% | 96.1% | 96.1% | | Prior policy, prior Node resize (historical) | 85.0% | 70.4% | 99.6% | -| Prior policy on the Pillow-exact preprocess | 82.9% | 66.3% | 99.6% | -| Production three-tier policy, Pillow-exact preprocess | 87.7% | 75.8% | 99.6% | +| v1.1.0 policy and probe, Pillow-exact preprocess | 87.7% | 75.8% | 99.6% | +| Production: hard-negative probe, re-derived bands | 90.5% | 81.2% | 99.8% | -The legacy raw max result is included to make the tradeoff visible, not as a product claim. It caused unacceptable false positives on live stock and catalog images, so production keeps the CF guard. The historical 85.0% row was measured through a Node resize the extension never ran; the Pillow-exact rows are computed by the same resize the extension ships, byte for byte, and browser versus Node decisions agree 16/16 on a stratified parity sample. The production policy also holds 2 false positives in 240 on a stock, catalog, and product photo stress set, identical images to the prior policy. Public fixtures are directional only and are not a claim about Kenny's private held-out set. +The legacy raw max result is included to make the tradeoff visible, not as a product claim. It caused unacceptable false positives on live stock and catalog images, so production keeps the CF guard. The historical 85.0% row was measured through a Node resize the extension never ran; later rows are computed by the same Pillow-exact resize the extension ships, byte for byte. On a 240-image full-resolution stock, catalog, and product photo stress set the production policy shows 4 false positives, all driven by CommunityForensics alone scoring `>= 0.65` (where it is authoritative by design), and zero attributable to a DINO rescue; the v1.1.0 configuration measured 7 on identical bytes. Public fixtures are directional only and are not a claim about Kenny's private held-out set. ## Limitations @@ -105,9 +104,9 @@ See [PRIVACY.md](PRIVACY.md) and [docs/privacy.html](docs/privacy.html). Images ## Reproducing the probe head ```bash -node eval/fetch-train.mjs /tmp/train # ~9.6k images from public HF datasets +node eval/fetch-train.mjs /tmp/train # ~11.4k images from public HF datasets (incl. hard-negative reals) node eval/extract-features.mjs /tmp/train models/Xenova/dinov2-small/onnx/model.onnx /tmp/feat-train --augment node eval/train-probe.mjs /tmp/feat-train models/probe/dino-probe.json ``` -The head is a linear probe (768 weights + bias + feature mean/std) over frozen DINOv2 features; the JSON is human-auditable. No benchmark images, hashes, or lookup tables are involved. +The head is a linear probe (768 weights + bias + feature mean/std) over frozen DINOv2 features; the JSON is human-auditable. No benchmark images, hashes, or lookup tables are involved. Fetching pulls live public datasets, so counts can drift by a few images between runs; an authenticated Hugging Face token (`HF_TOKEN` or the CLI cache) raises the datasets-server rate limit and is picked up automatically. diff --git a/eval/extract-features.mjs b/eval/extract-features.mjs index c277679..a380643 100644 --- a/eval/extract-features.mjs +++ b/eval/extract-features.mjs @@ -107,34 +107,12 @@ async function degradeBytes(buffer, rand) { return { buffer: outBuf, aug: parts.join('+') }; } -function toCHWDino(data, channels, size) { - const plane = size * size; - const out = new Float32Array(3 * plane); - for (let i = 0; i < plane; i++) { - const base = i * channels; - out[i] = (data[base] / 255 - DINO_MEAN[0]) / DINO_STD[0]; - out[i + plane] = (data[base + 1] / 255 - DINO_MEAN[1]) / DINO_STD[1]; - out[i + 2 * plane] = (data[base + 2] / 255 - DINO_MEAN[2]) / DINO_STD[2]; - } - return out; -} - -export async function dinoPreprocess(rawImage) { - const { width, height } = rawImage; - let rw, rh; - if (width < height) { - rw = DINO_SHORTEST; - rh = Math.round((height * DINO_SHORTEST) / width); - } else { - rh = DINO_SHORTEST; - rw = Math.round((width * DINO_SHORTEST) / height); - } - const resized = await rawImage.resize(rw, rh); - const sx = Math.floor((rw - DINO_CROP) / 2); - const sy = Math.floor((rh - DINO_CROP) / 2); - const cropped = await resized.crop([sx, sy, sx + DINO_CROP - 1, sy + DINO_CROP - 1]); - return toCHWDino(cropped.data, cropped.channels, DINO_CROP); -} +// Preprocess comes from the shipped module so probe training, the Node +// harness, and the extension all compute identical DINO inputs (Pillow- +// exact resize, guarded grayscale handling). A local duplicate here once +// drifted from production; do not reintroduce one. +import { dinoPreprocessRawImage as dinoPreprocess } from '../src/dino.js'; +export { dinoPreprocess }; /** CLS + mean(patch tokens) from last_hidden_state [1, T, H]. */ export function poolFeatures(hidden, tokens, hiddenSize) { diff --git a/eval/fetch-train.mjs b/eval/fetch-train.mjs index 00d8602..f221230 100644 --- a/eval/fetch-train.mjs +++ b/eval/fetch-train.mjs @@ -10,7 +10,7 @@ * Usage: node eval/fetch-train.mjs */ -import { mkdir, writeFile, readdir } from 'node:fs/promises'; +import { access, mkdir, writeFile, readdir } from 'node:fs/promises'; import { join } from 'node:path'; const OUT = process.argv[2]; @@ -37,13 +37,49 @@ const SOURCES = [ { name: 'food', label: 'real', dataset: 'ethz/food101', columns: ['image'], count: 300, offsets: [200, 400, 600] }, { name: 'celeba', label: 'real', dataset: 'nielsr/CelebA-faces', columns: ['image'], count: 300, offsets: [200, 400, 600] }, { name: 'imgnet', label: 'real', dataset: 'frgfm/imagenette', columns: ['image'], count: 300, offsets: [5000, 6000, 7000] }, + // --- Hard-negative reals: professional stock, product catalogs, + // interiors, and high-saturation nature. These teach the probe not to + // fire on polished real photography (github issue 23 failure mode). + // Rows are strictly disjoint from the eval stress set, which uses + // unsplash-lite rows 0-79 and rows 0-391 (stride 10) of the others. + { name: 'unsplash2', label: 'real', dataset: '1aurent/unsplash-lite', urlColumn: 'photo.image_url', urlParam: 'w=1600', nameByRow: true, columns: [], count: 800, offsets: [200, 300, 400, 500, 600, 700, 800, 900] }, + { name: 'abo2', label: 'real', dataset: 'amaye15/amazon_berkeley_objects', columns: ['image'], minSide: 200, nameByRow: true, count: 300, offsets: [500, 600, 700] }, + { name: 'lsunbed2', label: 'real', dataset: 'pcuenq/lsun-bedrooms', columns: ['image'], nameByRow: true, count: 300, offsets: [500, 600, 700] }, + { name: 'deepfashion2', label: 'real', dataset: 'Marqo/deepfashion-inshop', split: 'data', columns: ['image'], nameByRow: true, count: 300, offsets: [500, 600, 700] }, + { name: 'flowers2', label: 'real', dataset: 'nkirschi/oxford-flowers', columns: ['image'], nameByRow: true, count: 300, offsets: [500, 600, 700] }, ]; const FETCH_TIMEOUT = 30000; const CONCURRENCY = 10; +// Optional Hugging Face auth: raises the datasets-server rate limit far +// above the anonymous tier. Reads HF_TOKEN or the huggingface-cli cache; +// the token is only ever attached to huggingface.co hosts. +let HF_TOKEN = process.env.HF_TOKEN || null; +if (!HF_TOKEN) { + try { + const { readFileSync } = await import('node:fs'); + const { homedir } = await import('node:os'); + HF_TOKEN = readFileSync(`${homedir()}/.cache/huggingface/token`, 'utf8').trim() || null; + } catch {} +} + +function hfHeaders(url) { + if (!HF_TOKEN) return undefined; + try { + const host = new URL(url).hostname; + if (host === 'huggingface.co' || host.endsWith('.huggingface.co')) { + return { Authorization: `Bearer ${HF_TOKEN}` }; + } + } catch {} + return undefined; +} + async function fetchJson(url) { - const res = await fetch(url, { signal: AbortSignal.timeout(FETCH_TIMEOUT) }); + const res = await fetch(url, { + signal: AbortSignal.timeout(FETCH_TIMEOUT), + headers: hfHeaders(url), + }); if (!res.ok) throw new Error(`${res.status} ${url}`); return res.json(); } @@ -64,13 +100,30 @@ function extToUse(url, contentType) { return 'jpg'; } -async function downloadImage(url, destBase) { - const res = await fetch(url, { signal: AbortSignal.timeout(FETCH_TIMEOUT) }); +async function downloadImage(url, destBase, minSide) { + for (const ext of ['jpg', 'png', 'webp']) { + try { + await access(`${destBase}.${ext}`); + return true; // already fetched on a prior attempt + } catch {} + } + const res = await fetch(url, { + signal: AbortSignal.timeout(FETCH_TIMEOUT), + headers: hfHeaders(url), + }); if (!res.ok) throw new Error(`download ${res.status}`); const type = res.headers.get('content-type') || ''; const buf = Buffer.from(await res.arrayBuffer()); if (buf.length < 4096) throw new Error('too small'); + if (minSide) { + // Skip (not substitute) images under the gate, mirroring how the + // shipped probe's hard negatives were assembled. + const sharp = (await import('sharp')).default; + const meta = await sharp(buf).metadata(); + if (Math.min(meta.width || 0, meta.height || 0) < minSide) return false; + } await writeFile(`${destBase}.${extToUse(url, type)}`, buf); + return true; } async function pool(items, worker, concurrency) { @@ -97,6 +150,17 @@ async function pullSource(spec) { const dir = join(OUT, spec.label); await mkdir(dir, { recursive: true }); + // Resumable: a rerun after a rate-limit abort skips sources that already + // hit their target count, so retries spend the request budget only on + // what is still missing. + try { + const existing = (await readdir(dir)).filter((f) => f.startsWith(`${spec.name}-`)).length; + if (existing >= spec.count) { + console.log(`[${spec.name}] already complete (${existing}/${spec.count}), skipping`); + return; + } + } catch {} + let resolved; try { resolved = await resolveConfigSplit(spec); @@ -124,18 +188,49 @@ async function pullSource(spec) { let fromThisOffset = 0; for (const row of rowsData.rows || []) { if (jobs.length >= spec.count || fromThisOffset >= perOffset) break; + const rowName = spec.nameByRow + ? `${spec.name}-${row.row_idx ?? offset + fromThisOffset}` + : null; + if (spec.urlColumn) { + // Dotted paths reach into nested row objects, e.g. 'photo.image_url'. + const url = spec.urlColumn + .split('.') + .reduce((v, k) => (v == null ? v : v[k]), row.row); + if (typeof url !== 'string' || !url) continue; + const src = spec.urlParam + ? `${url}${url.includes('?') ? '&' : '?'}${spec.urlParam}` + : url; + jobs.push({ + src, + destBase: join(dir, rowName ?? `${spec.name}-${String(seq++).padStart(5, '0')}`), + }); + fromThisOffset++; + continue; + } for (const col of spec.columns) { if (jobs.length >= spec.count || fromThisOffset >= perOffset) break; const src = row.row?.[col]?.src; if (!src) continue; - jobs.push({ src, destBase: join(dir, `${spec.name}-${String(seq++).padStart(5, '0')}`) }); + jobs.push({ + src, + destBase: join(dir, rowName ?? `${spec.name}-${String(seq++).padStart(5, '0')}`), + }); fromThisOffset++; } } } - const { done, failed } = await pool(jobs, (j) => downloadImage(j.src, j.destBase), CONCURRENCY); - console.log(`[${spec.name}] ${done} downloaded, ${failed} failed (${spec.label})`); + let skipped = 0; + const { done, failed } = await pool( + jobs, + (j) => + downloadImage(j.src, j.destBase, spec.minSide).then((saved) => { + if (!saved) skipped++; + }), + CONCURRENCY + ); + const skipNote = skipped ? `, ${skipped} skipped under ${spec.minSide}px` : ''; + console.log(`[${spec.name}] ${done - skipped} downloaded, ${failed} failed${skipNote} (${spec.label})`); } async function main() { diff --git a/models/probe/dino-probe.json b/models/probe/dino-probe.json index de56dd4..0475f4c 100644 --- a/models/probe/dino-probe.json +++ b/models/probe/dino-probe.json @@ -1 +1 @@ -{"backbone":"dinov2-small","pooling":"cls+mean","dims":768,"featureMean":[-0.738905,-0.411827,0.270413,-0.473094,0.378236,-0.048525,-0.209464,-0.292543,0.434923,0.372315,-0.144415,0.39701,-0.531787,0.203034,0.730197,0.022278,0.010487,-0.836739,0.159953,-1.00452,0.692091,-0.324785,-0.266485,-0.367564,-0.193056,0.304512,0.111995,-0.538593,1.007014,0.037047,-0.320727,-0.784867,-0.037184,-0.012917,0.552202,0.416338,-0.594595,0.853682,0.279672,0.452163,-0.210598,0.88698,-0.37809,0.102201,-0.345266,-0.720505,-0.712039,0.118456,0.910794,0.298082,0.166965,-0.042104,0.08766,-0.492237,-0.746249,0.274061,0.637606,0.370995,-0.386304,-0.834688,0.745792,0.492766,-0.051457,-0.530743,-0.357024,0.449974,-0.262674,0.131173,0.866854,-0.181417,-0.755383,0.081133,-0.753867,0.101576,0.656691,-0.387593,-0.164871,-0.089536,-0.232643,-0.149508,0.17343,-0.537804,0.087839,-0.045834,-1.160009,-0.177396,-0.456569,-0.22252,-0.399173,0.293812,0.444919,-0.341038,-0.357314,-0.550648,0.79425,-0.323576,0.962954,0.209499,0.174179,-0.525074,-0.269319,0.945198,-0.505049,-0.415334,0.091252,0.257392,-0.206611,-0.352976,0.172338,-0.414392,-0.119295,0.360585,0.415652,0.35705,0.125183,-0.294974,-0.34141,0.448872,-0.521913,-0.088394,0.19289,1.222234,-0.195394,0.434542,0.8288,-0.84679,0.446597,-0.478627,-0.193321,0.442183,0.334537,-0.563713,-0.258073,0.262174,0.133456,1.104287,-0.444177,0.356184,-0.468508,0.236093,-0.926265,0.135389,0.050828,-0.410634,0.192959,-0.514925,0.060553,0.757182,0.238571,0.146093,0.224619,-0.831592,-0.350924,0.111689,-0.446393,-0.944793,0.974925,-0.42169,0.283608,-0.370744,-0.134494,-0.384592,-0.582376,-0.079458,0.482424,-0.320277,-0.103025,-0.242148,-0.499863,0.246419,0.156991,0.220729,0.167757,0.207283,0.468934,-0.284902,-0.085076,-0.32254,0.319602,0.661193,0.704365,0.475449,0.068,-0.32372,0.211143,-0.30412,0.60611,0.046199,0.276315,-0.378912,-0.109733,-0.132597,-0.206951,-0.20309,-0.102523,-0.374058,0.425309,0.530976,-0.626863,-0.274295,0.223593,-1.012587,0.321735,0.067798,0.17944,-0.010223,0.455517,-0.584065,0.343352,0.235446,0.720296,-0.493012,0.524633,-0.115555,-0.185904,-0.271907,-0.361468,-0.1893,-0.080557,-0.121821,0.236954,-0.510587,-0.892244,-0.424535,-0.579737,0.049173,-0.020765,0.440694,-0.564067,0.247372,0.021531,-0.567042,-0.574333,0.45648,-0.073081,0.186555,0.206289,-0.543446,-0.266324,-0.285132,0.331696,0.141599,0.000587,-0.318791,0.310538,-0.076477,0.221562,-0.422953,-0.457196,-0.05275,0.029664,0.433214,0.236718,0.217956,-0.3242,0.266526,0.635686,0.40417,0.402826,-0.103079,0.049018,0.55069,-0.387832,-0.1383,0.300441,-0.573453,-0.397328,-0.510652,-0.128541,-0.208905,0.330616,-0.20161,-0.356535,0.268665,0.688,0.257482,0.106356,1.016814,-0.07298,-0.094128,-0.446231,-0.222177,0.063995,-0.356276,0.388781,0.028232,-0.686454,-0.045578,-0.111982,-0.308916,-0.255083,-0.715231,0.689362,0.548718,0.397671,-0.026819,0.645902,-0.016866,1.006106,0.319438,-0.130572,-0.05081,-0.398499,0.238459,1.033708,0.088092,-0.180763,0.14802,0.075234,0.21159,-0.215715,0.164858,0.476317,-0.593836,-0.328805,0.05208,0.596582,0.062612,-0.834625,-0.177273,0.250836,0.86573,0.158526,-0.134793,-0.248438,0.918305,0.447862,-1.152845,0.45582,-0.937037,-0.019793,-0.316876,0.820406,-0.332802,0.184148,-0.642324,0.374019,0.134388,0.494373,0.3437,0.513305,-0.065481,0.060217,-0.259254,0.237906,0.636076,-0.126686,-0.780147,0.185336,0.606843,0.181579,0.222797,0.313898,-0.330921,-0.715874,-0.034456,-0.13869,0.347949,0.453711,-0.180435,-0.488637,-0.188293,0.506892,-0.426352,-0.189523,0.74656,-0.084786,0.284351,0.294824,0.271253,-0.812947,0.561732,-0.44868,0.513416,0.607847,-0.344844,0.439201,0.288095,-0.386594,0.173299,-0.608728,0.033246,0.571664,0.179872,-0.512247,0.187311,-0.080736,-0.373233,0.456035,0.023294,-0.046632,-0.259016,-0.128097,0.718076,0.5064,0.204417,-0.538667,0.280896,0.332969,0.245952,-0.711661,-0.408006,0.030083,-0.444479,-0.050211,-0.637736,0.002279,0.171655,-0.028649,0.75788,0.024465,-0.260148,0.450876,-0.213581,-0.340206,-0.121918,-0.257921,-0.128166,0.945546,-0.191157,0.119829,0.742177,0.440607,0.184767,0.081867,0.74612,-0.205815,0.305152,0.271437,-0.530826,-1.128038,-0.264115,0.513235,-0.19991,0.187005,0.3347,0.24792,-0.579784,-0.422861,0.20485,-0.006871,0.455653,0.212239,-0.764691,1.067527,-0.045585,-0.334894,-0.099442,-0.573423,1.121409,0.019503,-0.335628,2.476465,0.18318,-0.682112,-0.234493,-0.64318,-0.131091,0.715786,0.366413,-0.450207,-0.073779,-0.027003,-2.102322,0.337529,0.10306,-0.25444,0.029055,-0.220034,-0.233424,-0.420049,-0.319124,-0.6828,0.272066,0.601028,-0.219932,-0.053193,-0.586281,0.592707,-0.120658,0.847286,-0.096447,0.099884,-0.795122,-0.16085,0.877303,0.188071,0.124363,0.182961,0.28153,-0.165854,-0.144628,0.851896,-0.446856,0.402568,-0.223721,0.611491,0.086515,0.412216,-0.559146,-0.469917,0.090681,-0.602717,-0.102733,0.521749,-0.409906,-0.028841,0.617274,0.283401,-0.094222,0.775755,-0.140193,0.068939,0.239387,0.030617,0.177768,-0.101115,-0.161315,-0.037136,-0.617596,-0.753446,0.603207,0.526237,-0.024123,-0.791428,-0.517999,-0.006656,-0.038133,-0.096861,-0.229272,0.024274,0.942612,-0.241483,0.119378,0.409476,-0.043194,-0.053987,0.546398,0.012814,-0.901107,0.687195,-0.159144,-0.309751,-0.387958,0.16105,-0.106996,-1.047495,-0.14133,1.269548,-0.474053,0.231368,-0.343631,-0.252701,0.161773,0.252844,0.565309,0.468628,0.550998,0.206217,-0.145746,0.041665,0.282371,-0.139673,1.25317,0.378081,1.079058,0.134609,-0.099285,0.088182,0.183124,0.658726,-0.307522,-0.093829,0.173985,-0.133553,0.152764,0.231958,-0.534345,0.140029,-0.084175,0.066195,0.278927,-0.5254,-0.14453,-0.145252,-0.52947,0.462889,0.419383,0.234349,0.530881,0.635542,-0.331754,0.230665,0.635731,0.596811,0.175434,-0.279948,0.34365,0.102184,0.163345,-0.215577,-0.446936,0.456536,0.689098,-0.319217,-0.557828,-0.537816,-0.100622,-0.031819,0.212884,0.32929,-0.111519,-0.702567,0.420019,0.234329,-0.290069,-0.249991,-0.393156,-0.810658,0.034252,-0.436196,-0.272887,0.053218,-0.209028,0.324075,-0.326414,-0.262679,-0.640557,0.267367,0.098673,0.1878,-0.374394,-0.474168,-0.179662,-0.204828,0.135618,0.529107,-0.028808,0.067216,-0.012782,0.898184,0.355907,0.217087,0.331596,0.473815,-0.184721,0.509546,0.136808,0.339455,-0.260644,0.156106,-0.460213,-0.215351,-0.637137,0.033508,0.109133,-0.205634,0.2137,0.72825,0.535666,-0.405641,0.907605,-3.014998,-0.01717,-0.532494,-0.219459,0.524582,-0.322984,0.73764,0.401374,-0.691647,-0.428664,-0.191564,-0.1108,-0.176812,-0.120482,0.225883,0.651862,0.162393,-0.167563,0.275379,0.230781,0.052582,0.380169,0.163844,-0.036527,-0.224266,-0.350573,0.756383,0.30107,0.000872,0.099483,-0.54769,0.401381,0.44622,0.312016,0.859539,-0.386545,-0.205186,-0.105593,0.08659,-0.204321,-0.376678,0.008636,0.293873,0.459214,0.34823,1.177419,-0.078389,0.52601,-0.184535,-0.568681,0.720712,-0.459839,0.189647,-0.056513,0.524401,-0.323688,0.050032,-0.387041,0.323948,0.274342,0.373378,0.23581,0.547863,0.158888,0.046011,-0.365633,0.342714,1.135415,-0.200119,-0.102666,0.154399,0.310199,0.145673,0.238682,0.280299,-0.404117,-0.194744,-0.301674,-0.203897,0.080834,0.571034,-0.215784,-0.026154,0.481719,1.003557,-0.246995,0.270321,-0.410499,-0.239814,0.357534,-0.099828,-0.349123,-0.339732,0.419126,0.728745,0.311787,0.559448,0.166206,0.292377,-0.212875,-0.475633,-0.572168,-0.765356,0.522451,0.577148,0.187934],"featureStd":[2.592105,1.450131,2.367914,2.450757,2.430174,1.415987,2.260621,1.964699,2.526612,2.563107,2.378392,2.536566,2.457142,2.404446,2.614927,2.463045,2.48245,2.558441,1.847536,2.27434,2.324177,2.338314,2.486187,1.682119,2.374114,2.34219,2.518924,2.334648,1.566228,2.651068,2.286439,2.333294,2.158509,2.615745,2.319807,2.404845,2.588969,2.457549,2.619891,2.810322,2.498071,2.549607,2.676015,2.342172,2.270668,2.353932,2.394862,2.481787,2.569354,2.292265,2.361441,2.495869,2.514755,2.225827,2.310304,2.646915,2.44828,2.346637,2.632154,2.370387,2.406272,2.480935,2.41512,2.582627,1.859087,2.500706,2.391301,2.490959,2.219511,2.259052,2.640445,2.197661,2.672226,2.38818,2.812832,2.472602,2.388819,2.392087,2.398444,1.509429,2.227933,2.520444,2.355402,2.455357,2.069446,2.404543,2.363876,2.41625,2.343224,2.297192,2.568593,2.408214,2.408497,2.583051,2.629599,2.119339,2.234972,2.479562,2.388885,2.549582,2.554205,2.517504,2.556057,2.697954,2.153762,2.522882,2.590341,2.440297,2.588962,2.548545,2.361184,2.613168,2.448001,2.199002,2.518133,2.419614,2.381398,2.526786,2.545711,2.554765,2.379777,2.019821,2.356777,2.578693,2.593174,1.895847,2.607847,2.535066,2.499139,2.67805,2.002393,2.388674,2.618895,2.37171,2.616682,2.737326,2.472028,2.436377,2.061757,2.608947,2.107927,2.13449,2.147191,2.326284,2.367433,2.61006,2.217595,2.334839,2.195086,2.250801,2.327183,2.248932,2.441035,2.460219,2.542271,2.535592,2.467735,2.474175,2.524151,2.058678,2.529085,2.502261,2.230562,2.308285,2.531284,2.463697,2.347183,2.281444,2.591166,2.334066,2.471698,2.516362,2.376999,2.615407,2.551169,2.396339,2.273837,2.359191,2.399093,2.418793,2.491084,1.780833,2.527854,2.147623,2.313904,2.407043,2.453997,2.561188,1.813885,2.064441,2.349032,2.600961,2.354576,2.287544,2.555957,2.100219,2.426201,2.382326,2.397034,1.946416,2.508329,1.960776,2.567792,2.864302,2.387389,2.451452,2.452592,2.378125,2.853225,2.144132,2.433649,1.995547,2.058279,2.592444,2.546804,2.477043,2.074489,2.611366,2.351314,2.831157,2.223476,2.515063,2.523968,2.365415,2.407015,2.280827,2.395887,1.935223,2.57331,2.361972,2.42029,2.689461,1.958302,2.498208,2.429435,2.504051,2.419564,2.570186,2.43088,2.385283,1.811424,2.429199,2.41497,2.289721,1.983195,1.82214,2.209182,2.35182,2.646702,2.402891,2.419567,2.534392,2.452044,2.035257,2.369367,2.467146,2.194748,2.594769,2.15051,2.463294,2.474815,1.934299,1.782773,1.991174,1.970286,2.510842,2.212059,2.374875,2.64833,2.53063,1.837885,2.422039,2.416127,2.380997,2.546797,1.99397,2.427571,2.265999,0.906246,2.382452,2.247754,2.457458,2.611842,2.574616,2.497911,2.554619,2.142613,2.461802,1.959413,2.40556,2.749036,1.948647,2.57571,2.694052,2.685946,2.436281,2.167147,2.382383,2.755703,2.573183,2.640816,2.25346,2.672518,2.221897,2.770725,2.225844,2.290207,2.401638,2.198833,2.468083,2.463821,2.494356,2.408333,2.585509,2.146079,2.287326,2.679889,2.129627,1.828304,2.362511,2.380858,2.482073,2.282518,1.891543,2.256055,1.921242,2.891545,2.463126,2.447222,2.268682,2.569908,2.353304,2.475626,2.374837,2.555353,2.457539,2.416903,2.492713,1.768111,2.2157,2.44538,2.356548,2.63906,2.532508,2.467168,2.361687,2.541924,2.628662,2.491128,2.379233,2.193263,2.500615,2.616477,2.370996,2.423245,2.4116,2.3629,2.441935,2.657792,2.145695,1.909002,2.428026,2.61926,2.497972,1.991128,2.278184,2.531698,2.730053,2.028492,2.585346,2.123605,2.590183,1.926391,2.655259,2.639991,2.124234,2.344554,2.402377,2.47834,1.470625,2.462079,2.471494,2.63454,1.865209,1.432958,0.87004,1.423253,1.341375,1.315788,0.518888,1.149156,1.044988,1.349565,1.195402,1.244196,1.532066,1.353682,1.330463,1.350596,1.44316,1.400701,1.546068,1.425009,1.21134,1.139672,1.320478,1.365195,1.464466,1.280025,1.54836,1.426176,1.355594,0.738074,1.43471,1.106823,1.301547,1.357951,1.436836,1.133865,1.262096,1.510582,1.220715,1.433768,1.676432,1.459852,1.453833,1.604823,1.526033,1.057826,1.384762,1.408031,1.293899,1.366343,1.213962,1.282062,1.285297,1.377999,1.175986,1.15905,1.581186,1.466845,1.382634,1.590697,1.484257,1.400762,1.302137,1.451335,1.537815,0.850871,1.321617,1.359629,1.366262,2.612379,1.201641,1.592813,1.236958,1.230686,1.501647,1.500223,1.393206,1.341393,1.318176,1.352884,0.874778,1.280354,1.457778,1.364796,1.437778,0.720919,1.251151,1.478911,1.434686,1.255654,1.21717,1.530256,1.326271,1.164824,1.539109,1.53376,1.2281,1.272483,1.474631,1.341456,1.568607,1.414016,1.421989,1.619979,1.608721,1.268637,1.405648,1.522359,1.413457,1.499705,1.554283,1.266873,1.559727,1.342894,1.209958,1.330373,1.352229,1.398928,1.377613,1.467862,1.332637,1.335988,0.984597,1.369341,1.399329,1.382633,0.736881,1.602645,1.370167,1.351844,1.617858,1.156745,1.306735,1.525175,1.26762,1.589335,2.656537,1.366627,1.350945,1.599226,1.328243,0.92834,0.930863,1.015676,1.240919,1.304466,1.480118,1.138472,1.280383,1.193404,1.323706,1.135371,1.053944,1.258404,1.288702,1.569497,1.510685,1.394,1.395484,1.457685,0.967908,1.405114,1.497488,1.340096,1.23576,1.489164,1.593272,1.266461,1.252627,1.527686,1.313625,1.361744,1.180384,1.271203,1.598181,1.524657,1.296159,1.056604,1.277028,1.222613,2.188154,1.483977,1.042907,1.444505,1.103505,1.24257,1.307526,1.420892,1.476883,0.689582,0.911192,1.227962,1.609135,1.306576,1.083228,1.426206,1.033514,1.468805,1.379213,1.183435,0.963287,1.350479,0.869382,1.652832,1.616303,1.26191,1.327123,1.253266,1.328165,3.655344,1.121132,1.36359,1.08169,1.119017,1.491281,1.294281,1.467695,0.903709,1.464507,1.154926,3.438648,1.053239,1.527947,1.443134,1.130671,1.339193,1.290292,1.354561,0.855242,1.395574,1.357615,1.262054,1.641495,1.011631,1.450581,1.364346,1.396929,1.396627,1.458863,1.582202,1.328091,0.695288,1.321764,1.483162,1.106002,1.007282,0.902628,1.067056,1.306788,1.427998,1.471961,1.427045,1.454994,1.231639,1.076712,1.431191,1.641636,1.037508,1.530902,1.139011,1.383898,1.706888,0.978283,1.578705,1.106429,1.363935,1.384356,1.178186,1.338683,1.464426,1.478826,0.818953,1.394732,1.26975,1.378769,1.451409,1.115967,1.265859,1.177112,0.573232,1.307246,1.135887,1.357425,1.487615,1.476995,1.439976,1.387036,2.110904,1.353888,0.901793,1.251009,1.563743,1.070319,1.362902,1.533454,1.537997,1.406997,1.05781,1.398817,1.435778,1.503587,1.68967,1.477864,1.52731,1.218468,1.567672,1.203599,1.289849,1.325557,0.877015,1.31521,1.455638,1.487289,1.421154,1.419386,1.069195,1.117963,1.409829,1.205403,1.457496,1.219225,1.359316,1.447365,1.198625,1.455533,1.275286,1.029454,2.894469,1.246498,1.459497,1.10029,1.48214,1.25877,1.269233,1.317614,1.525711,1.422289,1.361963,1.304743,0.950994,1.031898,1.286693,1.521709,1.571422,1.234867,1.353328,1.202493,1.371557,1.451483,1.293402,1.337881,1.055766,1.394349,1.453861,1.334674,1.357162,1.261398,1.374668,1.348087,1.563086,1.499072,0.754012,1.223227,1.369952,1.607655,0.770564,1.153861,1.336116,1.621008,0.980082,1.548269,1.035453,1.432863,0.849194,1.490781,1.61509,1.154034,1.235767,1.446839,1.452929,0.720548,1.431379,1.4069,1.514581,0.96446],"weights":[-0.031169,0.028923,-0.12732,-0.147882,0.153282,-0.105549,0.019848,-0.041793,0.002593,0.039145,-0.116583,0.00697,-0.013127,-0.048374,0.109489,0.04461,0.003826,-0.205346,-0.032982,-0.177174,-0.09221,-0.015905,-0.139541,0.1671,-0.000265,-0.005133,0.018485,-0.11452,0.184529,0.321251,0.053416,0.173585,0.022657,0.20388,-0.179644,0.171905,-0.063519,-0.112618,-0.096202,0.247652,0.000599,0.131411,-0.200817,0.016473,-0.012124,0.042554,0.097533,0.00007,-0.056195,0.046563,0.031083,-0.090693,-0.186597,0.094833,0.028836,0.021607,0.007034,0.000707,0.075237,-0.18048,0.003751,0.089633,0.067302,-0.185885,-0.156929,0.081551,0.153029,0.151529,-0.104045,-0.058287,-0.050251,0.142574,0.062374,-0.092846,0.00292,-0.035148,-0.001599,-0.067995,0.018414,0.129388,-0.077448,-0.216084,-0.351228,-0.019531,-0.16353,-0.033752,0.103515,0.098102,0.056842,0.003044,0.133269,0.168118,-0.163509,-0.056949,0.117466,-0.056541,0.071908,0.067046,0.012757,-0.032394,-0.05204,0.336283,-0.197845,-0.044495,-0.064096,-0.072945,0.213621,0.053751,0.258014,-0.147419,0.039332,-0.12528,0.100659,0.158669,0.131227,-0.004736,-0.028825,-0.043347,0.05859,0.015704,0.071936,0.680427,0.021728,0.148536,-0.223654,-0.163909,0.1383,-0.172762,-0.065164,-0.18543,0.086447,0.22619,0.090163,0.022008,0.054179,0.293748,0.144756,0.024253,0.24984,0.168043,0.225754,0.113309,0.163089,0.161824,0.103465,-0.107403,-0.090613,0.040531,-0.092383,-0.123906,0.143723,-0.159137,-0.143304,0.08618,0.102968,-0.102197,-0.050514,-0.045778,0.110567,-0.356537,-0.213089,0.03199,-0.164972,-0.23215,-0.144163,0.205359,-0.092384,0.046328,-0.218285,-0.066379,0.129082,-0.181984,0.068037,-0.163472,0.247921,-0.015588,-0.098782,0.005768,0.136556,-0.014107,-0.121016,0.229004,-0.248922,0.094644,0.057981,-0.115975,0.09042,0.102148,-0.1654,0.170159,-0.039749,0.146474,-0.185218,-0.155393,-0.062845,0.025414,0.058153,0.082567,0.003514,-0.384557,-0.226605,-0.144656,-0.047465,-0.012415,-0.040441,0.098639,-0.19415,-0.059595,-0.249627,0.245625,-0.027203,-0.296121,0.185775,-0.07761,-0.254302,-0.055295,-0.159968,-0.226679,-0.05335,0.156808,-0.01859,0.02111,0.032597,-0.077524,-0.036581,-0.214677,-0.154007,0.044052,-0.243314,0.017852,0.044472,0.001995,0.061629,0.129263,-0.036245,-0.040765,0.06899,0.086224,-0.058623,0.070835,-0.126109,0.033618,-0.11173,-0.066447,0.225991,-0.002644,-0.069908,-0.056665,-0.084773,0.114712,0.072701,0.022293,-0.08231,0.083184,-0.043116,0.069803,0.059529,0.13488,-0.213875,-0.034484,-0.152904,-0.062611,0.216934,-0.148786,-0.058936,-0.05905,-0.04205,0.018337,0.253876,-0.290214,0.15853,-0.139767,0.081622,0.084345,-0.103853,-0.178216,-0.136258,0.103739,0.198817,0.074438,0.154494,0.099488,0.074926,-0.111253,-0.001365,0.064122,-0.035425,-0.053398,0.021767,0.135434,0.072939,-0.40558,-0.038857,0.054278,0.16073,0.162335,-0.028157,-0.13874,-0.071278,-0.199362,-0.062759,-0.05684,-0.030747,-0.19959,0.057711,0.054473,-0.234327,-0.076788,0.074785,0.200056,-0.111603,0.248847,0.035926,-0.134548,0.221023,0.176627,0.177953,-0.136463,-0.176524,-0.029639,0.025688,-0.245599,0.006387,-0.194128,0.036617,-0.008445,0.176396,0.04153,0.032238,0.013154,-0.211211,0.072322,-0.063463,-0.073,0.371262,0.171548,-0.153907,0.103319,0.070827,0.057645,-0.083283,-0.028046,0.30587,0.054643,0.296624,0.207807,-0.049798,-0.108169,0.146681,0.045856,-0.06135,0.048679,-0.25386,-0.016968,0.124855,0.025923,0.065017,0.040284,0.028577,0.027477,-0.224043,-0.041671,0.105121,-0.015357,-0.176247,-0.053757,0.110512,-0.052223,0.106365,0.129947,0.147149,0.172639,-0.617405,-0.023446,-0.025333,-0.15533,-0.007965,0.10639,-0.174483,-0.152158,-0.029607,-0.117823,-0.075749,0.174388,-0.020375,0.023596,0.036147,0.146719,0.060369,0.275892,0.077585,0.031607,0.000202,0.034421,-0.149406,0.017887,0.029432,-0.08427,0.21804,-0.218306,0.032381,-0.064921,-0.052588,0.028517,0.111108,-0.252816,0.142264,0.053449,0.118085,-0.059967,-0.063586,-0.109617,0.35522,-0.042793,-0.052014,-0.241133,0.091545,-0.171116,0.029549,-0.156421,-0.09176,-0.04227,0.057402,0.265394,-0.044677,0.058059,0.164481,0.079841,-0.149096,0.166468,0.024842,0.001066,0.282272,0.029807,0.098034,-0.132844,-0.094277,0.143313,0.245423,-0.06489,0.144596,-0.025013,0.009355,-0.269602,-0.041221,0.126659,-0.07871,0.038978,0.000816,-0.098381,-0.102568,0.133395,-0.112235,0.009979,-0.080574,-0.245667,0.191927,0.272874,-0.036635,0.084258,-0.399512,-0.138902,0.004177,0.134414,0.080721,-0.049495,-0.020823,0.401175,0.124122,0.078807,-0.056579,-0.127073,-0.061958,-0.140134,0.111215,0.030778,0.158986,0.160003,0.12688,0.045094,-0.060507,0.079626,-0.086093,0.055022,-0.011483,-0.182321,-0.016998,-0.098123,0.130651,-0.173376,0.162394,0.009876,0.263751,0.002172,-0.043392,-0.206341,-0.249838,0.037421,-0.379298,-0.114348,-0.34909,-0.127169,-0.04753,-0.091116,0.099075,-0.373544,-0.074176,0.113166,-0.053405,-0.086373,0.233635,0.158471,-0.010557,0.013354,-0.119898,0.057881,-0.080481,-0.10127,0.01143,0.160331,-0.33439,-0.00574,-0.307416,-0.123408,0.042558,-0.008891,-0.013014,-0.013542,0.247762,-0.174626,-0.010107,-0.241476,0.127665,-0.116692,0.060458,-0.034226,0.088375,0.055411,-0.189195,-0.085225,0.023051,-0.041179,0.041454,-0.040121,0.1234,0.027679,0.017335,0.097757,0.144275,0.199606,-0.091018,0.06754,0.269927,0.053352,0.23272,0.127603,0.158824,-0.256166,0.470489,0.138155,-0.214024,-0.162492,0.124526,-0.025906,-0.227803,0.051044,-0.086635,0.23146,-0.066198,0.198958,0.122703,-0.175396,0.117882,0.162066,0.098682,-0.108902,0.033524,-0.069447,0.133912,-0.025579,0.242391,-0.132508,-0.097404,0.036962,0.178066,0.009179,-0.026864,0.255824,0.239081,0.214655,0.150201,-0.042573,-0.006011,-0.273968,-0.171325,-0.147066,-0.069304,-0.121984,0.005654,-0.081626,0.189375,0.02069,-0.210313,-0.143978,0.006735,-0.110437,-0.236894,-0.260521,-0.030875,0.047549,0.244704,-0.11755,-0.031892,-0.030964,-0.095127,-0.096465,0.252754,0.084867,-0.086847,-0.118678,-0.167298,0.008286,-0.131997,0.1484,0.086101,0.031075,0.219662,0.119593,0.159369,-0.02102,0.322038,-0.01704,-0.431339,0.054104,-0.009434,0.368174,0.029897,0.259821,0.009234,0.060747,-0.059127,0.015852,-0.044204,0.00829,-0.01533,0.068122,0.198563,-0.039658,0.328221,-0.159189,-0.293106,-0.066082,-0.206421,0.406885,-0.081354,-0.296444,-0.046966,0.075022,0.010498,-0.113417,0.02839,-0.039407,-0.115017,0.17581,0.060946,0.039038,0.02264,-0.321763,0.338251,-0.013901,0.241805,-0.051368,-0.115503,-0.064995,0.096418,-0.114405,0.114172,-0.039413,0.234884,-0.164858,-0.111223,0.04133,-0.065971,-0.125851,-0.003284,-0.134959,-0.019411,-0.058146,0.184165,0.169486,0.041003,-0.156943,-0.063526,0.196255,-0.041262,-0.000419,-0.027192,-0.123971,-0.115063,0.044039,0.087301,-0.042837,0.10221,0.053521,0.090258,-0.092311,-0.09146,0.107299,-0.041393,-0.08018,0.122682,-0.015979,0.073088,-0.18673,0.060571,-0.027591,0.1496,-0.273545,0.082858,-0.096297,-0.105651,0.008838,0.014598,-0.025075,-0.161312,0.012446,0.134646,0.033646,0.02597,0.378273,0.066293,-0.027298,-0.053306,-0.178338,-0.052757,-0.234043,0.186504,0.047541,-0.066418,0.014214,0.195612,0.057648,0.01828,-0.087783,0.104403,-0.067441,-0.071156,-0.144521,0.139925,-0.014928,-0.120075,-0.187185,-0.023173,-0.074025,-0.093403,0.141353,0.34863,0.018457,-0.023347,-0.102042,0.123165,-0.213144,-0.188534,0.17354,-0.120959,0.147642,-0.0176,-0.283622],"bias":0.832581,"trainedOn":"9587 images (see eval/fetch-train.mjs sources)"} \ No newline at end of file +{"backbone":"dinov2-small","pooling":"cls+mean","dims":768,"featureMean":[-0.587975,-0.094064,0.388187,-0.183691,0.389014,-0.03528,-0.034767,-0.26375,0.313221,0.418463,-0.150547,0.241793,-0.441617,0.148957,0.852502,0.057653,-0.201931,-0.814269,0.303307,-0.769804,0.555188,-0.318358,-0.237053,-0.204962,-0.215752,0.205432,0.049399,-0.511024,0.793436,-0.121574,-0.30079,-0.626142,0.028857,0.134217,0.492368,0.534628,-0.53921,0.678229,0.23157,0.371823,-0.192139,0.889275,-0.262973,0.158686,-0.360628,-0.631063,-0.802162,-0.092029,0.962817,0.371611,0.225355,-0.120516,0.342901,-0.285793,-0.694951,0.176231,0.498634,0.417661,-0.397721,-0.789725,0.763898,0.55714,0.111621,-0.539031,-0.324011,0.390558,-0.269609,0.107317,0.870136,-0.075503,-0.5581,0.282389,-0.603112,0.02453,0.482026,-0.532884,-0.317824,0.080954,-0.445118,-0.020532,0.11349,-0.412927,0.080437,-0.192541,-0.991158,-0.222681,-0.430975,-0.1809,-0.423271,0.311884,0.337933,-0.279033,-0.321905,-0.39488,0.776455,-0.458481,0.933325,0.074337,0.048853,-0.465585,-0.465498,0.900798,-0.367444,-0.576422,0.036017,0.325469,-0.341783,-0.374923,0.429428,-0.250852,-0.002197,0.087273,0.471771,0.181571,0.013947,-0.366408,-0.123343,0.30949,-0.417957,-0.28191,0.241463,1.256193,-0.115599,0.425791,0.821136,-0.721735,0.341678,-0.454495,-0.246905,0.50968,0.194299,-0.225802,-0.095598,0.203785,0.072845,1.058425,-0.296343,0.18367,-0.547833,0.075871,-0.663155,0.142279,-0.097237,-0.566986,0.060041,-0.312514,0.122253,0.747029,0.140247,0.266245,0.197988,-0.777732,-0.176156,0.176283,-0.490247,-0.887124,0.891164,-0.520175,0.206008,-0.442203,-0.195839,-0.460117,-0.515188,-0.167662,0.252814,-0.268552,-0.092051,-0.229226,-0.432826,0.457736,0.152554,0.1797,0.184788,0.292237,0.442868,-0.428969,-0.144477,-0.249511,0.31072,0.69643,0.445749,0.34417,0.055399,-0.010668,-0.018404,-0.080901,0.514875,0.276385,0.368935,-0.335876,-0.082503,-0.170969,-0.235624,-0.203766,0.028701,-0.050326,0.70553,0.400489,-0.43496,-0.354247,0.225182,-1.024071,0.352065,-0.253172,0.11066,0.066061,0.511124,-0.363477,0.278419,0.095486,0.665825,-0.502027,0.36272,-0.230787,-0.122765,-0.195727,-0.334865,-0.131487,-0.041678,-0.261052,0.262479,-0.370835,-0.839509,-0.432078,-0.328707,-0.029437,-0.054144,0.3592,-0.629387,0.083973,0.062789,-0.643402,-0.465046,0.379701,0.144936,0.081448,0.029463,-0.469032,-0.33728,-0.141475,0.359924,-0.028534,-0.109033,-0.336319,0.478765,-0.212261,-0.036019,-0.433826,-0.33183,-0.069357,-0.160389,0.314752,0.252278,0.228326,-0.532176,0.003395,0.561955,0.318074,0.204979,-0.393821,0.06273,0.245302,-0.140247,-0.303843,0.0621,-0.447401,-0.33335,-0.38036,-0.014597,-0.13101,0.266009,-0.427313,-0.377637,0.431003,0.589889,0.192261,0.082655,0.932067,-0.078612,-0.241809,-0.38188,-0.315707,0.134304,-0.363783,0.419194,0.134956,-0.599328,-0.18083,0.00489,-0.35889,-0.420401,-0.646764,0.631955,0.546848,-0.008727,0.139225,0.464238,0.095301,0.910026,0.274171,-0.035885,-0.081271,-0.609026,0.290416,1.145015,0.076189,-0.050211,0.173622,-0.10273,0.081563,-0.26311,0.273861,0.640575,-0.529366,-0.064814,-0.126189,0.651274,0.050973,-0.588272,-0.08474,0.296692,0.746444,0.064172,-0.075513,-0.264548,0.343813,0.633145,-0.895489,0.48237,-0.961604,0.079797,-0.177856,0.783591,-0.232921,0.195083,-0.572718,0.128741,0.243497,0.384929,0.417505,0.389078,-0.078273,0.076579,-0.147265,0.055735,0.72316,0.149476,-0.785862,0.059903,0.491495,0.008462,0.26414,0.233666,-0.301515,-0.631521,-0.216402,0.000337,0.201215,0.686283,-0.44991,-0.468667,-0.148807,0.454872,-0.251726,-0.381843,0.740801,0.047709,0.261875,0.328339,0.449155,-0.746784,0.614152,-0.439847,0.393123,0.487923,-0.420936,0.316907,0.406955,-0.23812,0.127694,-0.508902,0.184567,0.367506,0.301398,-0.459783,0.269441,0.003876,-0.246342,0.40167,-0.005977,-0.022747,-0.311014,-0.145334,0.765235,0.359748,0.102194,-0.435697,0.243568,0.38334,0.282357,-0.857057,-0.367895,0.195357,-0.297623,-0.128924,-0.588836,0.091792,0.219812,-0.014878,0.582207,-0.041479,-0.328032,0.262317,-0.283182,-0.415969,-0.137839,-0.255672,-0.024226,0.92589,-0.200145,0.121445,0.609069,0.409984,0.266544,0.067213,0.760914,-0.132166,0.379301,0.274816,-0.498351,-1.182898,-0.437314,0.543169,-0.163434,0.157789,0.379634,0.366162,-0.528209,-0.404568,0.131411,-0.084018,0.458094,0.136039,-0.560245,1.104399,0.015471,-0.274156,-0.139152,-0.532252,1.000395,0.05223,-0.336412,2.858806,0.292073,-0.505123,-0.125639,-0.528936,-0.113324,0.559894,0.253012,-0.406573,-0.036457,-0.186097,-2.012433,0.350996,0.115555,-0.393161,-0.114788,-0.228742,-0.271938,-0.409634,-0.284322,-0.684934,0.248736,0.499936,-0.225719,-0.012959,-0.405655,0.587531,-0.12975,0.73205,-0.133194,0.027896,-0.752818,-0.204851,0.824072,0.260058,-0.041193,0.082104,0.360634,-0.183001,-0.149601,1.02941,-0.34026,0.485442,-0.347906,0.65163,0.081318,0.395741,-0.667851,-0.301977,0.023849,-0.546042,-0.189208,0.499515,-0.56946,-0.005725,0.58731,0.227737,-0.11464,0.836479,-0.11108,0.039808,0.212948,0.003946,0.311947,-0.104226,-0.152645,-0.07588,-0.443603,-0.690995,0.5637,0.362842,-0.008355,-0.619502,-0.519172,0.079569,-0.012055,-0.226433,-0.197385,0.076349,0.887509,-0.199224,0.189152,0.370053,-0.016252,0.04095,0.540584,0.022476,-0.89539,0.703288,-0.234887,-0.266262,-0.379109,0.166099,-0.125871,-0.966179,-0.204287,1.156931,-0.400043,0.190622,-0.316264,-0.287796,0.214263,0.289405,0.62934,0.448696,0.640105,0.229525,-0.227672,0.045887,0.345327,-0.060931,1.210493,0.222469,1.009345,0.076387,0.010478,-0.040406,0.296481,0.604571,-0.181672,-0.036949,0.129302,-0.116943,0.118876,0.215726,-0.496861,0.242137,-0.111106,0.225012,0.267288,-0.517544,-0.066322,-0.152625,-0.574932,0.486472,0.248472,0.160378,0.524943,0.695064,-0.309064,0.115739,0.602706,0.499806,0.116116,-0.229776,0.235418,0.169756,0.140619,-0.158813,-0.327554,0.471144,0.619871,-0.344533,-0.511594,-0.452695,-0.02769,0.069816,0.174441,0.314005,-0.023002,-0.722868,0.346391,0.284689,-0.245952,-0.298563,-0.393169,-0.642809,-0.042394,-0.45433,-0.13287,0.013168,-0.126427,0.267186,-0.331327,-0.280022,-0.576007,0.223661,0.045645,0.059177,-0.389933,-0.365972,-0.277524,-0.264547,-0.027986,0.546796,-0.086678,0.027024,-0.201344,0.85308,0.300601,0.206311,0.209232,0.407434,-0.279145,0.713712,0.100246,0.25919,-0.135071,0.102692,-0.432944,-0.178766,-0.563679,0.072287,-0.06057,-0.200482,0.316457,0.764198,0.453713,-0.376656,0.759194,-2.95688,-0.085011,-0.587951,-0.277082,0.570713,-0.323983,0.734727,0.445457,-0.438078,-0.509942,-0.149286,-0.135624,-0.317897,-0.116691,0.208374,0.593096,-0.130487,-0.035505,0.235881,0.177243,-0.02024,0.316018,0.13533,-0.038237,-0.334865,-0.261194,0.793838,0.31482,0.01806,0.076425,-0.584499,0.332502,0.391397,0.345847,0.951976,-0.378782,-0.07094,-0.092787,0.148784,-0.22873,-0.325966,0.00571,0.33515,0.464256,0.252271,1.121228,0.001736,0.218373,-0.078143,-0.500651,0.722513,-0.437303,0.264046,-0.013276,0.481954,-0.291381,0.182062,-0.336424,0.144196,0.294189,0.390059,0.203474,0.526969,0.196394,-0.006748,-0.371501,0.227491,1.15031,-0.127903,-0.120548,0.109119,0.279924,0.026226,0.280413,0.212739,-0.368002,-0.12312,-0.398959,-0.113201,-0.017459,0.687796,-0.332111,-0.084421,0.448106,0.868388,-0.07666,0.324594,-0.407628,-0.114554,0.329985,-0.074088,-0.279454,-0.342857,0.453994,0.776692,0.206599,0.499095,0.228425,0.299621,-0.115071,-0.349495,-0.568216,-0.696514,0.499988,0.479448,0.241467],"featureStd":[2.563339,1.423751,2.391731,2.456788,2.49136,1.400176,2.292005,2.056408,2.517597,2.521402,2.372317,2.559408,2.45855,2.427769,2.646003,2.431169,2.445219,2.565531,1.868967,2.321755,2.425466,2.340049,2.457585,1.771333,2.345232,2.428889,2.528439,2.373985,1.537687,2.612333,2.253525,2.297394,2.204188,2.561985,2.336477,2.420455,2.580578,2.46789,2.619453,2.796326,2.510579,2.602715,2.72787,2.353813,2.338165,2.356565,2.419166,2.427417,2.570777,2.364378,2.408781,2.458287,2.503559,2.226682,2.301121,2.605879,2.499298,2.316271,2.639385,2.400107,2.391448,2.495875,2.45487,2.638347,1.880394,2.506346,2.431533,2.508441,2.234693,2.330746,2.708151,2.218388,2.655668,2.427462,2.777788,2.465547,2.431291,2.468739,2.37641,1.478274,2.249462,2.473785,2.354831,2.457668,2.094002,2.46003,2.395645,2.392076,2.360279,2.303572,2.532654,2.423549,2.423603,2.638671,2.624535,2.138809,2.282007,2.484847,2.385271,2.566783,2.570779,2.502948,2.505383,2.631558,2.157913,2.546465,2.570621,2.436125,2.627695,2.559257,2.346806,2.628764,2.499247,2.21057,2.495273,2.389233,2.37116,2.536734,2.599883,2.537106,2.417322,2.255326,2.403314,2.570478,2.581508,1.873178,2.554678,2.586836,2.45965,2.797326,2.026586,2.436644,2.622622,2.402128,2.652706,2.795144,2.452358,2.44751,2.116027,2.573459,2.12307,2.109779,2.204842,2.367895,2.393208,2.535227,2.232362,2.345313,2.201099,2.283726,2.384232,2.233622,2.401564,2.523832,2.522131,2.548948,2.527035,2.461946,2.529115,2.117318,2.524763,2.483101,2.219972,2.302431,2.501387,2.487032,2.413064,2.277877,2.568198,2.394802,2.454288,2.473629,2.355906,2.596616,2.559672,2.453075,2.332952,2.402885,2.379027,2.406555,2.546166,1.821679,2.506817,2.187776,2.404567,2.475402,2.459834,2.533744,1.788142,2.165477,2.344194,2.567156,2.336603,2.284975,2.512372,2.063715,2.576186,2.409388,2.369309,1.99447,2.49246,1.984343,2.593194,2.806756,2.360273,2.491558,2.429415,2.390794,2.825627,2.139903,2.39918,1.94134,2.045114,2.538592,2.516611,2.487707,2.101606,2.6445,2.34486,2.906039,2.203376,2.479163,2.650604,2.487676,2.432678,2.266505,2.405849,1.927561,2.557759,2.378572,2.4282,2.785256,1.99228,2.510639,2.498752,2.511649,2.40036,2.519058,2.416581,2.38335,1.793607,2.460965,2.470414,2.278076,2.034328,1.855927,2.207901,2.387337,2.709988,2.456251,2.461658,2.589948,2.387838,2.056813,2.431863,2.47,2.278761,2.669976,2.184396,2.50537,2.497214,1.974584,1.817137,2.023247,2.003098,2.532809,2.258775,2.412525,2.615696,2.5519,1.873439,2.435615,2.401814,2.385866,2.525769,2.012105,2.435133,2.32145,0.887453,2.386744,2.237844,2.431284,2.587771,2.585727,2.48945,2.499703,2.090283,2.455885,1.996087,2.488211,2.747732,1.923782,2.593993,2.661347,2.645931,2.462117,2.211663,2.382341,2.744653,2.546234,2.705935,2.284904,2.726695,2.266985,2.79901,2.268376,2.282386,2.467811,2.228202,2.436372,2.486526,2.482785,2.427398,2.649818,2.184376,2.368342,2.676703,2.142772,1.839423,2.376691,2.400639,2.466783,2.326979,2.035177,2.282886,1.992425,2.795572,2.448023,2.499468,2.253212,2.567494,2.378672,2.410847,2.348834,2.572547,2.482672,2.468286,2.604575,1.825566,2.290337,2.460326,2.38687,2.611959,2.53012,2.397307,2.408846,2.497394,2.608252,2.529612,2.395428,2.277117,2.598885,2.582701,2.319226,2.42093,2.493205,2.36651,2.548446,2.709813,2.203807,1.960416,2.393026,2.563166,2.502107,1.979449,2.27817,2.535586,2.682707,2.023539,2.557767,2.106403,2.569568,1.918993,2.598817,2.63012,2.16562,2.372143,2.464213,2.507679,1.509507,2.459894,2.532621,2.611947,1.873226,1.451609,0.873068,1.507175,1.370198,1.337026,0.542871,1.168773,1.052381,1.361305,1.205763,1.316309,1.545503,1.373617,1.346212,1.378905,1.450366,1.372689,1.577827,1.472313,1.282475,1.226887,1.321852,1.38988,1.530707,1.278118,1.698951,1.457573,1.350219,0.734797,1.426415,1.116985,1.328873,1.425924,1.432487,1.15739,1.291616,1.533029,1.257384,1.439381,1.694039,1.472631,1.534007,1.703732,1.546579,1.081434,1.405172,1.447181,1.307805,1.37513,1.226256,1.32392,1.269335,1.378694,1.176068,1.189424,1.589318,1.472203,1.392489,1.54868,1.65596,1.398851,1.377896,1.456501,1.548904,0.863664,1.358282,1.377703,1.388008,3.07776,1.226226,1.648239,1.310923,1.235637,1.572233,1.535958,1.417871,1.339792,1.36561,1.372263,0.878759,1.27591,1.433725,1.43432,1.442349,0.728772,1.355112,1.495507,1.420357,1.271516,1.254941,1.499588,1.352564,1.184815,1.615235,1.523036,1.221451,1.340205,1.523329,1.326951,1.578474,1.429487,1.443677,1.585238,1.627051,1.288435,1.437949,1.587061,1.420339,1.542493,1.593181,1.287701,1.581101,1.384512,1.216999,1.350132,1.351405,1.410688,1.433633,1.492631,1.329771,1.356843,1.016007,1.424585,1.398494,1.395426,0.773151,1.570321,1.404215,1.362366,1.658203,1.163558,1.374075,1.557446,1.310952,1.602988,2.663496,1.358993,1.377992,1.6492,1.345186,0.918971,0.915915,1.045367,1.271844,1.3002,1.479599,1.175982,1.298311,1.200051,1.348142,1.146518,1.047058,1.23253,1.336482,1.552355,1.538983,1.456771,1.428194,1.493379,0.986838,1.444949,1.490811,1.378081,1.247501,1.462104,1.606163,1.309522,1.31344,1.546898,1.324669,1.347637,1.198871,1.283499,1.617502,1.514197,1.304956,1.103404,1.351248,1.244666,2.179316,1.539226,1.023734,1.483796,1.157546,1.278345,1.370669,1.415046,1.488564,0.707914,0.921098,1.218571,1.615242,1.301283,1.098433,1.422374,1.021985,1.54172,1.461086,1.194443,0.979504,1.346751,0.881797,1.710535,1.602752,1.296485,1.438342,1.240706,1.374595,3.686193,1.141107,1.361027,1.119765,1.137682,1.452947,1.294702,1.469604,0.963966,1.5049,1.188284,3.35446,1.063295,1.502364,1.475061,1.144183,1.36933,1.303373,1.399739,0.855995,1.400695,1.384467,1.284687,1.731605,1.044219,1.47373,1.386845,1.428565,1.420343,1.450092,1.594293,1.330814,0.733376,1.392799,1.513457,1.136232,1.060654,0.923388,1.140062,1.31058,1.471831,1.558134,1.498227,1.524653,1.247509,1.094212,1.474443,1.652402,1.043264,1.614091,1.154902,1.402944,1.701094,0.999415,1.541207,1.135141,1.48277,1.413376,1.173311,1.345356,1.500386,1.520166,0.828264,1.422589,1.302662,1.375878,1.472845,1.193459,1.307843,1.277927,0.568834,1.340484,1.163376,1.348385,1.494592,1.507615,1.492269,1.37488,2.265013,1.352972,0.908678,1.318431,1.572155,1.097068,1.396133,1.566597,1.588988,1.465789,1.039578,1.440679,1.518713,1.525624,1.71682,1.518885,1.563492,1.328193,1.627306,1.238113,1.335884,1.378961,0.926811,1.295457,1.496077,1.482566,1.416775,1.414534,1.110109,1.174102,1.434897,1.236167,1.50211,1.238025,1.343233,1.446214,1.283604,1.506051,1.294865,1.079944,2.804473,1.276789,1.491145,1.108357,1.50822,1.268057,1.277292,1.305346,1.551649,1.42735,1.434159,1.390352,0.944331,1.098727,1.325469,1.523672,1.560828,1.237817,1.348674,1.230404,1.359842,1.442747,1.311544,1.342781,1.081361,1.50474,1.457578,1.311738,1.380079,1.362,1.42215,1.404854,1.629569,1.616786,0.809509,1.231428,1.412988,1.59879,0.791528,1.143669,1.346903,1.593552,0.984954,1.561255,1.066744,1.434838,0.842069,1.504124,1.593388,1.207101,1.266067,1.488557,1.492854,0.744757,1.484142,1.426548,1.524166,0.975931],"weights":[-0.081457,0.243648,-0.225218,-0.169947,0.225016,0.170034,0.03206,0.054691,-0.018925,0.143766,-0.026322,0.055291,-0.047651,0.032654,0.205422,-0.070852,0.098549,-0.108047,-0.073795,-0.340322,-0.093948,-0.138501,0.007231,0.204754,0.026447,-0.016591,-0.056891,-0.196476,-0.014824,0.429538,0.247424,-0.06594,0.116814,0.157796,0.013285,0.157843,-0.024776,0.044651,-0.00997,0.202294,0.044879,0.137424,-0.123622,-0.067153,-0.138646,0.064572,0.078377,-0.053077,-0.038814,0.07101,-0.049879,-0.16953,-0.104095,0.022557,-0.001668,0.011751,0.028149,-0.102688,0.036642,-0.168124,-0.020827,0.01907,0.097448,-0.187312,-0.126548,0.082511,0.054171,0.089187,-0.095548,-0.133465,-0.039426,0.156973,0.021203,-0.125457,0.114095,0.081166,0.117216,-0.145833,-0.09563,-0.103718,-0.058805,0.014085,-0.148769,-0.097828,-0.027833,-0.067145,-0.009173,0.116523,0.055617,-0.06809,0.004511,0.169872,-0.109988,-0.161624,0.12829,-0.075347,0.136846,0.00019,0.073358,-0.064854,-0.099912,0.435489,-0.107479,-0.075336,0.003926,-0.002231,0.183309,0.314958,0.071703,-0.138815,0.122821,-0.120271,0.070813,0.132543,0.143431,-0.032286,0.055921,0.064292,-0.019539,0.000705,0.027086,0.674251,-0.044296,0.100988,-0.143357,-0.194966,0.08067,-0.180376,0.029048,-0.09401,0.062155,0.061872,0.159053,0.035346,0.038791,0.298283,0.158273,0.037271,0.067471,0.04207,0.082619,-0.0774,0.056161,0.008148,0.094685,-0.071021,-0.050006,0.008676,-0.098756,-0.07124,-0.004173,-0.092651,-0.095455,0.056193,0.046074,0.047616,-0.119663,-0.049501,0.023162,-0.394534,-0.135531,0.102286,-0.251315,-0.10251,0.037699,0.188043,-0.000192,0.065561,-0.233373,-0.027913,0.063757,-0.201134,0.146926,-0.124252,0.314485,0.088858,-0.1119,-0.126078,0.066581,-0.058273,-0.197029,0.124338,-0.214286,-0.051568,0.093482,-0.162371,0.099643,0.095765,-0.108806,0.07045,0.060139,0.080126,-0.102542,-0.147891,0.094386,0.16546,-0.055066,0.025554,0.099738,-0.365377,-0.156143,-0.283326,-0.071636,0.005434,-0.117091,0.06598,-0.099219,0.016595,-0.414636,0.026287,0.114357,-0.152953,0.273808,0.011443,-0.245307,-0.094156,-0.151094,-0.263426,0.074924,0.012132,-0.115646,0.019402,-0.035212,-0.146809,-0.074407,-0.129001,-0.092195,0.071077,-0.387747,-0.021007,0.089693,-0.086846,0.210338,0.077302,-0.132677,0.004301,-0.001034,-0.099452,-0.130119,-0.034428,-0.112476,-0.022546,-0.085149,0.137015,0.312603,-0.015583,-0.102079,0.177807,0.031654,0.037381,-0.030275,0.164051,-0.036915,0.124149,0.095516,0.024521,-0.089554,-0.058733,-0.143653,-0.095884,-0.137739,0.12333,0.235751,-0.17705,-0.039127,-0.054714,0.137955,-0.095921,0.133185,-0.38074,0.106537,-0.087855,-0.026327,0.075363,-0.089438,-0.062773,-0.064974,0.11573,0.097177,-0.001606,0.035532,0.08109,0.049199,-0.227145,-0.065545,-0.060277,0.022414,-0.006485,-0.031386,0.119625,0.102448,-0.188357,-0.063515,0.042441,0.016031,0.29159,0.069047,0.007328,0.031445,-0.176366,-0.08358,-0.037083,0.06106,-0.120694,0.187841,0.002445,-0.275092,0.141698,-0.015408,0.193978,-0.155578,0.155919,-0.035422,-0.114471,0.236957,0.167128,0.127266,-0.240741,0.083647,0.090334,0.052485,-0.252682,-0.128539,-0.398054,0.151615,-0.036786,0.352297,0.005128,0.191412,-0.025162,-0.008338,0.147737,-0.10208,-0.104898,0.313876,0.134905,-0.15745,0.182032,0.091668,0.119143,0.007621,0.004981,0.200833,-0.008415,0.383005,0.146449,-0.036689,-0.184246,0.209787,-0.040478,0.167321,0.09463,-0.24097,-0.18644,0.108458,-0.07613,0.076612,0.119228,-0.038336,-0.01566,-0.080516,-0.087887,0.17265,0.026148,-0.283115,-0.014933,0.219139,0.070329,0.012642,0.040184,0.144651,0.169792,-0.583839,-0.140227,-0.016112,-0.224718,-0.089589,0.114248,-0.110299,-0.28979,0.038565,-0.061427,-0.01873,0.04439,-0.056265,-0.035865,0.048661,0.117036,-0.012862,0.130876,0.117224,-0.171824,0.038375,-0.031332,-0.086314,-0.010104,0.050006,-0.139123,0.258927,-0.149445,-0.013002,-0.054082,-0.001516,-0.163914,0.066577,-0.329434,-0.056079,0.199027,0.218349,-0.143964,0.028616,-0.01767,0.255606,0.019351,-0.237984,-0.238015,-0.014418,-0.079807,0.038086,-0.090441,-0.170147,-0.197393,0.044074,0.156245,0.025269,0.105257,0.126224,0.067614,-0.116274,0.050055,-0.036691,-0.076149,0.254499,-0.024493,0.063384,-0.04706,0.029765,0.168353,0.005363,-0.100667,0.219408,0.094198,0.178848,-0.305266,0.018123,0.174171,-0.055421,-0.115201,-0.203174,0.015376,-0.073919,0.003862,-0.268183,0.041964,-0.040446,-0.302749,0.22499,0.26372,0.110751,0.101927,-0.423837,0.121622,0.060784,0.128127,0.0856,-0.013953,0.079741,0.350311,0.086559,0.00716,-0.274383,0.008423,-0.175252,-0.033616,0.063535,0.058031,0.186615,0.101766,0.097673,0.042975,0.014053,0.042877,-0.063415,-0.008634,0.088639,-0.124177,-0.15965,-0.232323,-0.092798,-0.076249,0.008717,0.040389,0.110181,-0.149078,0.064759,-0.069419,-0.189416,-0.016244,-0.266373,-0.118572,-0.377839,-0.123671,0.09747,-0.085846,0.095556,-0.525107,-0.090147,0.256864,-0.074322,0.016612,0.096516,0.04498,-0.080052,0.024206,0.106356,0.038869,-0.021533,-0.150991,-0.058703,0.233279,-0.182667,0.039223,-0.337572,-0.083162,0.190308,0.11053,-0.094335,0.148717,0.280603,-0.071604,0.013325,-0.093145,0.176479,-0.135395,0.224458,-0.011949,0.000563,0.099575,-0.145454,-0.161416,0.163031,-0.01824,0.10996,-0.075753,0.106943,0.010894,-0.130705,0.053814,0.129077,0.164393,0.010224,-0.075681,0.289722,0.103859,0.118684,0.116485,0.088848,-0.287096,0.237279,0.121324,-0.216554,-0.037481,0.103655,0.176615,-0.05177,-0.004725,0.044608,0.236358,-0.04354,0.092989,0.093324,-0.174783,0.079028,0.127601,0.146458,-0.19123,0.014011,-0.101307,-0.038114,-0.172168,0.071626,0.086095,-0.147336,-0.000212,0.131615,0.120906,-0.048134,0.102588,0.238975,0.313415,0.178945,-0.014734,-0.198558,-0.024199,-0.353183,-0.105753,-0.146657,-0.11517,0.185532,0.037829,-0.080533,-0.192221,-0.110014,-0.02279,0.073505,-0.206699,-0.318547,-0.034564,-0.046703,0.061234,0.189022,-0.021279,0.005977,-0.009736,-0.093911,0.031461,0.081592,0.146584,0.00192,0.032365,0.077123,-0.012098,-0.051313,0.204698,0.070688,-0.11474,0.253649,-0.002112,0.219313,0.042202,0.365921,-0.154353,-0.485518,0.091765,-0.030512,0.469405,0.085303,0.107868,0.032859,-0.070756,-0.081762,0.085716,-0.088679,0.116826,-0.041618,0.019496,0.288136,-0.076379,0.290843,0.059277,-0.221325,-0.060858,-0.128098,0.329421,0.006754,-0.216244,-0.010112,0.014993,-0.121952,-0.124906,0.014636,0.036092,-0.050246,0.035799,0.113942,-0.080357,0.000055,-0.28208,0.343512,-0.100207,0.060561,0.030195,0.106094,0.044598,0.138056,-0.111851,0.316635,0.144566,0.315448,-0.223404,-0.146216,0.144168,0.031196,-0.035985,-0.021097,-0.150297,-0.066331,-0.104001,0.118236,0.101161,-0.112572,-0.196233,0.166055,-0.04059,0.100159,-0.041086,0.082764,0.09781,-0.167007,-0.014734,0.108889,-0.017342,0.107201,-0.133385,0.019889,-0.053159,-0.081804,0.077919,-0.089554,-0.032317,0.184395,-0.108852,0.154564,-0.264223,0.081922,-0.065863,0.095774,-0.283429,0.004652,-0.118008,-0.003448,-0.046645,0.016908,-0.178154,-0.241081,-0.003112,0.103053,-0.03818,-0.016019,0.256059,0.093395,0.085516,-0.25439,-0.097247,-0.224456,-0.23207,0.143807,0.096084,0.016272,0.221791,-0.018835,0.142323,0.170375,-0.138686,0.243539,0.052488,0.077392,-0.06885,0.23759,-0.147734,-0.174491,-0.240178,-0.063987,-0.035578,-0.130591,0.045047,0.507429,0.015757,0.02958,-0.160653,0.036911,-0.224094,-0.151191,0.226922,-0.113722,0.232051,-0.037799,-0.251835],"bias":0.032176,"trainedOn":"11405 images (see eval/fetch-train.mjs sources)"} \ No newline at end of file diff --git a/src/clip-preprocess.js b/src/clip-preprocess.js index 8e820f0..df2c85f 100644 --- a/src/clip-preprocess.js +++ b/src/clip-preprocess.js @@ -145,25 +145,26 @@ export function imageDataToCHW(imageData) { } /** - * Copy a CROP_SIZE window out of a packed row-major pixel buffer. + * Copy a square window out of a packed row-major pixel buffer. * @param {Uint8Array|Uint8ClampedArray} data width * height * channels * @param {number} width * @param {number} height * @param {number} channels * @param {number} sx * @param {number} sy - * @returns {Uint8ClampedArray} CROP_SIZE * CROP_SIZE * channels + * @param {number} [cropSize] window side, defaults to the CF crop + * @returns {Uint8ClampedArray} cropSize * cropSize * channels */ -export function cropPackedPixels(data, width, height, channels, sx, sy) { - if (sx < 0 || sy < 0 || sx + CROP_SIZE > width || sy + CROP_SIZE > height) { +export function cropPackedPixels(data, width, height, channels, sx, sy, cropSize = CROP_SIZE) { + if (sx < 0 || sy < 0 || sx + cropSize > width || sy + cropSize > height) { throw new Error( - `Crop ${CROP_SIZE} at ${sx},${sy} does not fit inside ${width}x${height}` + `Crop ${cropSize} at ${sx},${sy} does not fit inside ${width}x${height}` ); } - const rowLength = CROP_SIZE * channels; - const out = new Uint8ClampedArray(CROP_SIZE * rowLength); - for (let y = 0; y < CROP_SIZE; y++) { + const rowLength = cropSize * channels; + const out = new Uint8ClampedArray(cropSize * rowLength); + for (let y = 0; y < cropSize; y++) { const start = ((sy + y) * width + sx) * channels; out.set(data.subarray(start, start + rowLength), y * rowLength); } diff --git a/src/dino.js b/src/dino.js index aa67ea8..15dc550 100644 --- a/src/dino.js +++ b/src/dino.js @@ -10,6 +10,9 @@ * shortest edge 256, center crop 224, ImageNet mean/std. */ +import { pillowResize } from './pixel-resize.js'; +import { cropPackedPixels, needsCanvasFallback } from './clip-preprocess.js'; + export const DINO_MODEL_ID = 'Xenova/dinov2-small'; export const DINO_ONNX_PATH = 'onnx/model.onnx'; export const DINO_SHORTEST_EDGE = 256; @@ -61,9 +64,10 @@ export function dinoPackedRgbToCHW(data, channels) { } /** - * Node eval path using transformers.js RawImage helpers. Keeping this beside - * the browser preprocessor makes the extension and reproducible harness share - * the same resize, center-crop, channel, and normalization policy. + * Node eval path. Shares the Pillow-exact resize with the browser path so + * the extension, the harness, and probe training all compute identical + * DINO inputs. The probe head shipped with this revision is trained on + * features extracted through this exact path. * @param {import('@huggingface/transformers').RawImage} rawImage * @returns {Promise} */ @@ -72,45 +76,58 @@ export async function dinoPreprocessRawImage(rawImage) { rawImage.width, rawImage.height ); - const resized = await rawImage.resize(resizedW, resizedH); + const resized = pillowResize( + rawImage.data, + rawImage.width, + rawImage.height, + rawImage.channels, + resizedW, + resizedH + ); const sx = Math.floor((resizedW - DINO_CROP_SIZE) / 2); const sy = Math.floor((resizedH - DINO_CROP_SIZE) / 2); - const cropped = await resized.crop([ + const crop = cropPackedPixels( + resized, + resizedW, + resizedH, + rawImage.channels, sx, sy, - sx + DINO_CROP_SIZE - 1, - sy + DINO_CROP_SIZE - 1, - ]); - - if (cropped.width !== DINO_CROP_SIZE || cropped.height !== DINO_CROP_SIZE) { - throw new Error( - `DINO crop produced ${cropped.width}x${cropped.height}, expected ${DINO_CROP_SIZE}` - ); - } - - return dinoPackedRgbToCHW(cropped.data, cropped.channels); + DINO_CROP_SIZE + ); + return dinoPackedRgbToCHW(crop, rawImage.channels); } /** - * Browser path: center 224 crop from an ImageBitmap. + * Browser path: center 224 crop from an ImageBitmap through the same + * Pillow-exact resize as the Node path. Oversized bitmaps fall back to + * the legacy canvas resize (same guard as the CF path). * @param {ImageBitmap} bitmap * @returns {Float32Array} */ export function dinoPreprocessBitmap(bitmap) { const { width: rw, height: rh } = dinoResizeDimensions(bitmap.width, bitmap.height); - const resizeCanvas = new OffscreenCanvas(rw, rh); - const resizeCtx = resizeCanvas.getContext('2d', { willReadFrequently: true }); - resizeCtx.imageSmoothingEnabled = true; - resizeCtx.imageSmoothingQuality = 'high'; - resizeCtx.drawImage(bitmap, 0, 0, rw, rh); - const sx = Math.floor((rw - DINO_CROP_SIZE) / 2); const sy = Math.floor((rh - DINO_CROP_SIZE) / 2); - const crop = new OffscreenCanvas(DINO_CROP_SIZE, DINO_CROP_SIZE); - const cropCtx = crop.getContext('2d', { willReadFrequently: true }); - cropCtx.drawImage(resizeCanvas, sx, sy, DINO_CROP_SIZE, DINO_CROP_SIZE, 0, 0, DINO_CROP_SIZE, DINO_CROP_SIZE); - const imageData = cropCtx.getImageData(0, 0, DINO_CROP_SIZE, DINO_CROP_SIZE); - return dinoPackedRgbToCHW(imageData.data, 4); + + if (needsCanvasFallback(bitmap.width, bitmap.height)) { + const resizeCanvas = new OffscreenCanvas(rw, rh); + const resizeCtx = resizeCanvas.getContext('2d', { willReadFrequently: true }); + resizeCtx.imageSmoothingEnabled = true; + resizeCtx.imageSmoothingQuality = 'high'; + resizeCtx.drawImage(bitmap, 0, 0, rw, rh); + const imageData = resizeCtx.getImageData(0, 0, rw, rh); + const crop = cropPackedPixels(imageData.data, rw, rh, 4, sx, sy, DINO_CROP_SIZE); + return dinoPackedRgbToCHW(crop, 4); + } + + const nativeCanvas = new OffscreenCanvas(bitmap.width, bitmap.height); + const nativeCtx = nativeCanvas.getContext('2d', { willReadFrequently: true }); + nativeCtx.drawImage(bitmap, 0, 0); + const rgba = nativeCtx.getImageData(0, 0, bitmap.width, bitmap.height).data; + const resized = pillowResize(rgba, bitmap.width, bitmap.height, 4, rw, rh); + const crop = cropPackedPixels(resized, rw, rh, 4, sx, sy, DINO_CROP_SIZE); + return dinoPackedRgbToCHW(crop, 4); } /** diff --git a/src/fuse.js b/src/fuse.js index cc4e0a4..6531f5f 100644 --- a/src/fuse.js +++ b/src/fuse.js @@ -6,11 +6,11 @@ export const DEFAULT_THRESHOLD = 0.65; export const UNCERTAIN_LOW = 0.45; /** CF scores below this need the saturated sub-floor tier to be rescued. */ -export const DINO_CF_FLOOR = 0.03; +export const DINO_CF_FLOOR = 0.02; /** CF below this requires near-saturated DINO before it can be rescued. */ -export const DINO_STRONG_RESCUE_FLOOR = 0.30; +export const DINO_STRONG_RESCUE_FLOOR = 0.10; /** DINO must be this confident to lift a low CF score into the rescue band. */ -export const DINO_STRONG_RESCUE_MIN = 0.96; +export const DINO_STRONG_RESCUE_MIN = 0.90; /** DINO must be this confident to lift CF in the normal uncertain band. */ export const DINO_RESCUE_MIN = 0.70; /** @@ -18,12 +18,14 @@ export const DINO_RESCUE_MIN = 0.70; * faintly awake AND DINO is saturated. CF emits hard zeros on real photos * it is certain about, while AI images in its blind spots still elicit a * faint response, so "CF flatlined" is itself evidence of a real photo. - * Derived on the Pillow-path bench with a 240-image stock/catalog stress - * guard (zero stress regression allowed); see PR for the measurement. + * Bands re-derived for the hard-negative probe (trained with stock, + * catalog, product, and interior reals) on the Pillow-path bench under a + * 240-image stress guard; a deliberately conservative near-optimum was + * chosen over the grid maximum. See PR for the measurement. */ -export const DINO_SUBFLOOR_CF_MIN = 0.005; +export const DINO_SUBFLOOR_CF_MIN = 0.0005; /** DINO saturation required for the sub-floor rescue. */ -export const DINO_SUBFLOOR_MIN = 0.999; +export const DINO_SUBFLOOR_MIN = 0.995; export const URL_HINT_MAX_BOOST = 0.05; /** diff --git a/tests/dino.test.mjs b/tests/dino.test.mjs index 81f4358..03ab7c9 100644 --- a/tests/dino.test.mjs +++ b/tests/dino.test.mjs @@ -69,33 +69,34 @@ describe('dinoPackedRgbToCHW', () => { }); describe('dinoPreprocessRawImage', () => { - it('uses the shared 256-short-edge center crop', async () => { + it('resizes to the 256 short edge and center-crops 224 via pillowResize', async () => { const plane = DINO_CROP_SIZE * DINO_CROP_SIZE; - let resizeArgs = null; - let cropArgs = null; + // Constant-value pixels survive Pillow bicubic exactly, so a flat + // image proves the resize plus window-crop path end to end. const rawImage = { width: 1024, height: 768, - async resize(width, height) { - resizeArgs = [width, height]; - return { - async crop(box) { - cropArgs = box; - return { - width: DINO_CROP_SIZE, - height: DINO_CROP_SIZE, - channels: 3, - data: new Uint8Array(plane * 3), - }; - }, - }; - }, + channels: 3, + data: new Uint8Array(1024 * 768 * 3).fill(200), }; const chw = await dinoPreprocessRawImage(rawImage); - assert.deepEqual(resizeArgs, [341, 256]); - assert.deepEqual(cropArgs, [58, 16, 281, 239]); assert.equal(chw.length, 3 * plane); + // (200/255 - 0.485) / 0.229 in the R plane, everywhere. + const expectedR = (200 / 255 - 0.485) / 0.229; + assert.ok(Math.abs(chw[0] - expectedR) < 1e-6); + assert.ok(Math.abs(chw[plane - 1] - expectedR) < 1e-6); + }); + + it('handles grayscale sources without NaN poisoning', async () => { + const rawImage = { + width: 512, + height: 512, + channels: 1, + data: new Uint8Array(512 * 512).fill(128), + }; + const chw = await dinoPreprocessRawImage(rawImage); + for (let i = 0; i < 10; i++) assert.ok(Number.isFinite(chw[i])); }); }); @@ -108,9 +109,9 @@ describe('fuseNeuralScores', () => { it('does not let saturated DINO override a hard-zero CF', () => { // CF hard zeros mark confident reals; no rescue tier may touch them. assert.equal(fuseNeuralScores(0.0, 0.9999), 0.0); - assert.equal(fuseNeuralScores(0.004, 0.9999), 0.004); + assert.equal(fuseNeuralScores(0.0004, 0.9999), 0.0004); // Below the CF floor, high-but-unsaturated DINO still cannot rescue. - assert.equal(fuseNeuralScores(0.02, 0.99), 0.02); + assert.equal(fuseNeuralScores(0.015, 0.99), 0.015); }); it('ignores DINO rescue when it is not high-confidence', () => { @@ -124,12 +125,12 @@ describe('fuseNeuralScores', () => { }); it('only rescues low CF scores with near-saturated DINO', () => { - assert.equal(fuseNeuralScores(0.10, 0.99), 0.99); - assert.equal(fuseNeuralScores(0.10, 0.70), 0.10); - assert.equal(fuseNeuralScores(0.25, 0.97), 0.97); - assert.equal(fuseNeuralScores(0.25, 0.95), 0.25); + assert.equal(fuseNeuralScores(0.05, 0.99), 0.99); + assert.equal(fuseNeuralScores(0.05, 0.89), 0.05); + assert.equal(fuseNeuralScores(0.25, 0.75), 0.75); + assert.equal(fuseNeuralScores(0.25, 0.65), 0.25); // Sub-floor tier: faintly awake CF plus saturated DINO rescues. - assert.equal(fuseNeuralScores(0.01, 0.9995), 0.9995); + assert.equal(fuseNeuralScores(0.01, 0.996), 0.996); assert.equal(fuseNeuralScores(0.01, 0.99), 0.01); }); diff --git a/tests/fuse.test.mjs b/tests/fuse.test.mjs index 17669d2..8fc8e2f 100644 --- a/tests/fuse.test.mjs +++ b/tests/fuse.test.mjs @@ -46,23 +46,23 @@ describe('fuseNeuralScores policy', () => { }); it('CF flatlined below the sub-floor CF minimum is never rescued', () => { - assert.equal(DINO_SUBFLOOR_CF_MIN, 0.005); - const fused = fuseNeuralScores(0.004, 0.9999); - assert.equal(fused, 0.004); + assert.equal(DINO_SUBFLOOR_CF_MIN, 0.0005); + const fused = fuseNeuralScores(0.0004, 0.9999); + assert.equal(fused, 0.0004); assert.equal(isAiAtThreshold(fused), false); }); it('sub-floor rescue needs saturated DINO, not just high DINO', () => { - assert.equal(DINO_SUBFLOOR_MIN, 0.999); + assert.equal(DINO_SUBFLOOR_MIN, 0.995); const notSaturated = fuseNeuralScores(0.01, 0.99); assert.equal(notSaturated, 0.01); - const saturated = fuseNeuralScores(0.01, 0.9995); - assert.equal(saturated, 0.9995); + const saturated = fuseNeuralScores(0.01, 0.996); + assert.equal(saturated, 0.996); assert.equal(isAiAtThreshold(saturated), true); }); it('graphic gate blocks the sub-floor rescue too', () => { - const fused = fuseNeuralScores(0.01, 0.9995, { graphicGate: true }); + const fused = fuseNeuralScores(0.01, 0.996, { graphicGate: true }); assert.equal(fused, 0.01); assert.equal(isAiAtThreshold(fused), false); }); @@ -81,17 +81,17 @@ describe('fuseNeuralScores policy', () => { }); it('CF below DINO floor ignores non-saturated DINO even when high', () => { - assert.equal(DINO_CF_FLOOR, 0.03); - const fused = fuseNeuralScores(0.02, 0.99); - assert.equal(fused, 0.02); + assert.equal(DINO_CF_FLOOR, 0.02); + const fused = fuseNeuralScores(0.015, 0.99); + assert.equal(fused, 0.015); assert.equal(isAiAtThreshold(fused), false); }); it('low CF is only rescued by near-saturated DINO', () => { - assert.equal(DINO_STRONG_RESCUE_FLOOR, 0.30); - assert.equal(DINO_STRONG_RESCUE_MIN, 0.96); - assert.equal(fuseNeuralScores(0.25, 0.97), 0.97); - assert.equal(fuseNeuralScores(0.25, 0.95), 0.25); + assert.equal(DINO_STRONG_RESCUE_FLOOR, 0.10); + assert.equal(DINO_STRONG_RESCUE_MIN, 0.90); + assert.equal(fuseNeuralScores(0.05, 0.91), 0.91); + assert.equal(fuseNeuralScores(0.05, 0.89), 0.05); }); it('includes the DINO floor boundary in the lift band', () => {