open-standards/wai/wai-web/demo/int_hyper.html
Transaction Science 89e0da789e wai: compact binary model + in-browser conditional-codec demo
Makes the in-browser decode of the full conditional codec practical: the model
shrinks from ~52MB JSON to ~23.5MB binary (~15.5MB gzipped on the wire), and a
real HTML page decodes a SOTA-class learned codec in the browser, verifying its
hash against the native reference.

- typed IntModel: refactored run_net/decode/decode_conditional off serde_json
  Value onto an IntModel { afrac, gf, shift, layers: Vec<IntLayer> }, built by
  either IntModel::from_json (existing schema) or IntModel::from_bytes (compact
  binary: magic WHM1, int12 weights as i16, IGDN gamma as i32, the rest i64).
  Decode is byte-identical whichever the source.
- export tool writes *_model.bin alongside the JSON (model_to_bin).
- conformance: the binary model decodes byte-identically to JSON (new assert in
  tests/int_hyper_synth.rs); all 3 tests green in release (~11s, the 100s was
  debug — release wasm decode is ~10s).
- wasm: decodeIntHyperBin (binary path) beside decodeIntHyper (JSON); shared
  cond_decode helper. demo/verify_int_hyper_wasm.mjs checks both paths.
- demo/int_hyper.html + .js: fetch the binary models + 1.4KB bitstream, decode
  with pure-i64 wasm (no ML runtime), paint the canvas, FNV-1a the RGB against
  cond.json. Verified in headless Chrome: 256x256, 42.61 dB, decoded hash
  adeb12d347d0bf7e == native, ~10s decode, zero console errors.

The PTQ model files are large and NOT committed (gitignored demo/int_hyper/);
regenerate with tools/wai_sota_int_synth_export.py. pkg/ stays a build artifact.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-25 03:14:46 -04:00

55 lines
3.6 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WAI — integer-exact conditional codec, in-browser</title>
<style>
:root { --bg:#06080c; --bg2:#0d1117; --border:#1e2736; --text:#e6edf5; --text2:#8b99ad; --text3:#4a5568; --g:#00e5a0; --w:#f0b429; --mono:'JetBrains Mono','SF Mono',Menlo,monospace; }
* { box-sizing:border-box; margin:0; padding:0; }
body { background:var(--bg); color:var(--text); font-family:var(--mono); padding:24px; }
h1 { font-size:15px; letter-spacing:.04em; margin-bottom:4px; } h1 em { font-style:normal; color:var(--g); }
.sub { font-size:11px; color:var(--text2); margin-bottom:14px; max-width:880px; line-height:1.5; }
code { color:var(--w); }
canvas { background:#04060a; border:1px solid var(--border); border-radius:10px; display:block; image-rendering:pixelated; }
.hud { display:flex; gap:22px; margin-top:10px; font-size:11px; color:var(--text2); flex-wrap:wrap; }
.hud b { color:var(--text); } .hash { color:var(--g); }
#badge { font-size:12px; padding:4px 12px; border-radius:99px; display:inline-block; background:var(--bg2); color:var(--text2); border:1px solid var(--border); margin-top:10px; }
#badge.ok { background:rgba(0,229,160,.12); color:var(--g); border-color:rgba(0,229,160,.5); }
#badge.bad { background:rgba(255,107,107,.12); color:#ff6b6b; border-color:rgba(255,107,107,.5); }
.note { margin-top:14px; font-size:10.5px; color:var(--text3); max-width:880px; line-height:1.55; }
.note b { color:var(--text2); }
</style>
</head>
<body>
<h1>WAI <em>integer-exact conditional codec</em> — in-browser, no ML runtime</h1>
<p class="sub">
A <code>wai.neural.int_hyper</code> bitstream arrived: a factorized side-stream <code>z</code> and the
Gaussian-conditional main stream <code>y</code>, both rANS-coded. This tab decodes it to RGB with the
<b>same pure-i64 Rust</b> that decodes natively, compiled to wasm32 — <b>no onnxruntime-web, no WebGPU,
no float anywhere</b>. The <i>whole</i> path is integer: factorized <code>z</code> → integer
hyper-decoder → integer-σ entropy bucketing → integer synthesis. Because of that (the integer-entropy
contract) the reconstruction is byte-identical on every machine, so the page re-checks its FNV-1a against
the hash the native reference produced — a SOTA-class learned codec verified client-side, no server.
</p>
<canvas id="c" width="512" height="512"></canvas>
<div id="badge">loading model…</div>
<div class="hud">
<span>image <b id="dims">—</b></span>
<span>bitstream <b id="bits">—</b></span>
<span>quality <b id="psnr">—</b></span>
<span>decoded hash <b class="hash" id="got">—</b></span>
<span>native hash <b class="hash" id="want">—</b></span>
</div>
<p class="note">
<b>Why this is the moat:</b> the SOTA learned-image family is float, so its entropy decode desyncs on
~1e-5 of cross-platform drift in the scale σ — reproducible only on the same build, never receiptable.
<code>int_hyper</code> is a real pretrained codec (post-training-quantized to integer, ~0.6&nbsp;dB off
the float baseline) whose entire decode is integer, so the hash above is portable: this browser, a native
sink, and the conformance corpus all produce the same bytes. The wire carried a ~1.4&nbsp;KB bitstream;
the model is the installed codec. <b>Note:</b> the model files are large (PTQ weights) and not committed —
generate them with <code>tools/wai_sota_int_synth_export.py</code> into <code>demo/int_hyper/</code>.
</p>
<script type="module" src="int_hyper.js"></script>
</body>
</html>