open-standards/wai/tools/wai_snac_export.py
Transaction Science 46c5688b86 wai: the WAI open standard — full cargo-class surface + provenance
Commit the WAI standard source: a content + capability-dispatch standard
whose thesis is "carries whatever it can reconstruct, verifies whatever
it carries." Source only — large vendored/model assets and build output
are gitignored.

Reconstruct classes (each: spec + conformance corpus + in-tab browser
sink that re-derives the corpus hash, one wai.det.fixed64 fixed-point
floor, one *-equivalence apiece):
  - interactive worlds  (replay-equivalence)   + 3 sim registrants,
    multiplayer over a relay, session receipts, glTF + real SPZ assets
  - spatial audio        (mixdown-equivalence)
  - haptics              (sample-equivalence)
  - state-feeds          (replay-equivalence, non-physics sim)
  - avatars / digital humans (pose-equivalence) + telepresence over the relay
  - volumetric / 4D splats   (frame-state-equivalence) + WebGPU EWA render,
    real-SPZ-derived clip

Verify half (lever 4):
  - asset provenance: a signed, energy-accounted lineage for opaque
    captured content WAI does not reconstruct; tamper-evident, in-tab.

Cross-cutting: JWP receipt profiles per class; a native energy meter
(IOReport via macmon, no sudo) emitting receipts with REAL measured
joules; the learned-image/neural codec family and JPEG AI entropy port
from earlier work.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-13 22:28:51 -04:00

78 lines
3 KiB
Python
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.

"""Export the REAL pretrained SNAC model to the ONNX `wai.neural.snac` decoder
(`wai-rs/src/neural/snac.rs`), via the model surgery needed to make it both
exportable AND deterministic.
Two upstream blockers, both patched here (monkey-patch, no fork):
1. NoiseBlock injects `torch.randn` — that makes the decode STOCHASTIC (a codec
must be reproducible) AND bakes a bad shape on ONNX export. We zero the
noise: `x + 0*linear(x)` → deterministic, exportable. (Quality cost is the
noise texture only.)
2. Snake1d's `@torch.jit.script snake` does a reshape-roundtrip that ONNX
mis-traces. We replace it with the identical 3D formula, no reshape.
Verified: snac_24khz exports clean and the ONNX matches the (now deterministic)
torch decode to ~9e-7; `wai-rs` then decodes the resulting envelope to ~9e-7 of
that reference (`snac_real_model_matches_reference`).
Run (needs torch + snac + onnxruntime):
python tools/wai_snac_export.py --model hubertsiuzdak/snac_24khz \
--out-dir wai-web/demo/models/snac_24khz
"""
from __future__ import annotations
import argparse
from pathlib import Path
import torch
import torch.nn as nn
def patch_for_export():
import snac.layers
# 1. deterministic, export-clean noise.
def noise_fwd(self, x):
return x + 0.0 * self.linear(x)
snac.layers.NoiseBlock.forward = noise_fwd
# 2. reshape-free snake.
def snake1d_fwd(self, x):
return x + (self.alpha + 1e-9).reciprocal() * torch.sin(self.alpha * x) ** 2
snac.layers.Snake1d.forward = snake1d_fwd
class _Dec(nn.Module):
def __init__(s, m): super().__init__(); s.m = m
def forward(s, *codes):
return s.m.decoder(s.m.quantizer.from_codes(list(codes)))
def main() -> int:
ap = argparse.ArgumentParser()
ap.add_argument("--model", default="hubertsiuzdak/snac_24khz")
ap.add_argument("--out-dir", required=True)
ap.add_argument("--opset", type=int, default=17)
args = ap.parse_args()
patch_for_export()
from snac import SNAC
m = SNAC.from_pretrained(args.model).eval()
out = Path(args.out_dir); out.mkdir(parents=True, exist_ok=True)
# Probe the codebook hierarchy (N levels, their strides) from a dummy encode.
dummy_audio = torch.zeros(1, 1, m.sampling_rate)
with torch.no_grad():
codes = m.encode(dummy_audio)
n = len(codes)
names = [f"codes_{i}" for i in range(n)]
torch.onnx.export(
_Dec(m).eval(), tuple(codes), str(out / "decoder.onnx"),
input_names=names, output_names=["audio_values"],
dynamic_axes={**{f"codes_{i}": {1: f"t{i}"} for i in range(n)}, "audio_values": {2: "s"}},
opset_version=args.opset, dynamo=False)
print(f"exported {args.model}: {n} code levels @ {m.sampling_rate} Hz → {out}/decoder.onnx")
print("decode is deterministic (zero-noise). Encode tool: pack <III> sr,n_samples,n_levels "
"+ n×u32 lengths + per-level u16 codes (see snac.rs).")
return 0
if __name__ == "__main__":
raise SystemExit(main())