WST-Graph-Q82 / implementation-notes.md
korallll's picture
Wrapper code (speech-spoof-bench)
2167ccf verified
|
Raw History Blame Contribute Delete
4.77 kB

WST-Graph-Q82 — implementation notes

Plan: speech-spoof-bench/docs/plans/2026-11-09-thirteen-model-batch-arena-submission.md (model #12).

Source

  • HF kwokho1/wst-graph @ 080000c1685451c7759f43d2ae7d0f08477cfdf8, q82-seed9/wst_graph_q82_seed9_batch32_cuda.ts (sha256 79edfcd396d14984c54ecbe08eae48e80605764291f004d2aa0cec0cf533f0f1), card license: mit (no LICENSE file → LICENSE.source). Symlinked here from _ckpt_dl. Only traced TorchScript programs are released (GitHub saki-ciallo/WST-Graph promised); no Python source to vendor.
  • Paper: arXiv 2609.29372 (Ng, Song, Feng, Xia, 2026). Trained on ASVspoof 2019 LA (random 4 s crops), 12 epochs, focal loss, three seeds (9/114/514). Evaluation windows start at the onset (first 64000 samples).

Security review of the TorchScript program (before first run)

  • Unzipped into a scratch dir and read code/__torch__/**.py (the program's model.code); also loaded on CPU (torch.jit.load(map_location="cpu"), no forward) and walked every submodule's graph.
  • Node kinds: only aten::* and prim::* (prim::CallMethod/Constant/GetAttr/ListConstruct/NumToTensor/Tuple*); no torch.ops outside aten/prim, no file/OS/network ops, no custom classes beyond the model's own modules (__torch__.models.*, __torch__.kymatio.scattering1d.frontend.torch_frontend.ScatteringTorch1D, __torch__.export_deployment_formats.WSTGraphDeploymentWrapper, torch.nn modules).
  • Pickles (data.pkl, constants.pkl, traced_inputs.pkl, read with pickletools, no execution): globals are only the __torch__ module classes above, torch.*Storage, torch._utils._rebuild_tensor_v2, collections.OrderedDict, torch.jit._pickle.restore_type_tag. Verdict: clean. _net.check_graph re-asserts the aten/prim-only rule on load.
  • Traced (not scripted): torch.device("cuda:0") constants baked in → CUDA only; traced example input [32, 64000].

Wrapper (wst_graph_q82.py:WSTGraphQ82, _net.py)

  • Preprocessing = model-card quick start: first 64000 samples, right zero-pad, input_length = retained count (int64). No normalisation, no resampling. Empty clip (card raises) → zeros with input_length 1.
  • Score = logits[:,0] − logits[:,1] (class 0 = bona fide). FP32; TF32 off (no effect on this program).
  • Batch: the "batch32" file is batch-dynamic (tested B = 1, 4, 7, 16, 32, 48: OK; zero-padding rows with length 1 does not change the real rows, |Δ| ≤ 8e-6; companions never change a clip's score). B=1 runs a different cuFFT/GEMM path: |Δ| vs B≥2 up to 1.3e-2 on J-SPAW clips, while B≥2 agree to ≤ 4e-5. The wrapper therefore pads a lone clip with one zero clip (length 1) and drops its score. Repeat runs are not bitwise identical (cuFFT, ~1e-5).
  • "Strict load": all tensors live inside the program; tests assert 166 parameter tensors, 120,364 parameters (paper Table 6 says 120k), aten/prim-only graph, eval mode, file sha256. Buffers (fixed WST filters, grid maps, normaliser stats, BN running stats): 11,119,491 elements.
  • Seed: the paper reports Table 6 (OOD) as "single-seed results" without naming the seed, other tables as three-seed averages → no headline seed → seed 9 (card example), same for Q81 and Q82. Not chosen on Arena data.

Parity / tests

  • source_parity.py: the card's quick-start code (verbatim tensor prep, model(input_values, input_length)) vs the wrapper on 16 J-SPAW_LA clips + a 20000-sample and a 139944-sample clip: max |Δ| vs card per-clip (B=1) 2.07e-3; vs card same batch 0.0 (the per-clip gap is the B=1 path above). Log: logs_source_parity.txt.
  • test_wst_graph_q82.py: prep crop/pad, sha256, op allow-list + params + eval, batch == single (atol 2e-4), prefix-only, determinism (atol 1e-4), bona fide > spoof on ASVspoof2019_LA clips (J-SPAW is near-random for this model). 8 passed.

Sanity (PyTorch, RTX 5060 Ti idx 3)

  • Full J-SPAW_LA (run_pt.sh): EER 43.644% (2397 trials, 0 skipped) — near random, as expected (the paper reports ~44–49% on most OOD sets; 19LA 2.92, ITW 44.46). Not inverted: ASVspoof2019_LA 2000-clip eval subset (subset_eer.py 2000): EER 3.033% (paper 19LA: 19LA 2.92).
  • Training data: ASVspoof 2019 LA train (dev for selection) → no trained_on entries.

Batch sweep (sweep.py, 64000-sample input)

card result choice
RTX 5060 Ti (idx 3), 2026-11-09, card shared with the LaST-Net Arena lane (3.8 GiB, 100% util) 77.6 utt/s @32, 76.4 @24, 66.7 @16; B=48 OOM (shared card); 6.6 GiB @32. Q82 is ~4× heavier than Q81 (twice the second-order paths) batch_size = 32
RTX 4070 Ti SUPER (idx 2) not swept (not assigned) same 32

TensorRT

Not attempted (plan: no TRT for the TorchScript rows).