ProSDD-ASV19 / implementation-notes.md
korallll's picture
Wrapper code (speech-spoof-bench)
22aafa1 verified
|
Raw History Blame Contribute Delete
5.23 kB

ProSDD-ASV19 β€” implementation notes

Plan: speech-spoof-bench/docs/plans/2026-11-07-eleven-model-batch-arena-submission.md (model #6).

Source

  • Code: github.com/ProSDD/codes @ bdb80440cd946368e77f4b51f6ddf26c7443dc33 β€” model_stage2realfake.py (ProSDDStage2), main_eval.py (inference_forward), data_utils_eval.py (pad). No LICENSE file (β†’ LICENSE.source). Evaluation_scores/ProSDD_*Trained/readme.txt are empty: no per-utterance author scores.
  • Weights: authors' Google Drive folder 1h250-Um5qWo-rpeOE6K_Gdeygy46k3xg, file ProSDD_Trained2019 (id 1RHY-VELyi4XH-L1egeRcgWjHdkdWV2bO), fetched with gdown into benchmarks/_ckpt_dl/ProSDD/; 1.27 GB, sha256 d2cb857cf7b14a9caa200cde14100062e72fe2a39865bc435f83f5be74da1c8a. No extension; it is a zip-format torch save of a plain OrderedDict state_dict (431 tensors, no module. prefix) β†’ loads with torch.load(weights_only=True); ProSDD_Trained2019 here is a symlink. No license β†’ NOT re-hosted (meta links Drive).
  • Backbone config vendored as xlsr300m_config.json (facebook/wav2vec2-xls-r-300m @ 1a640f3, copied from Forensics-XLSR-Wild); Wav2Vec2Model(config) instead of from_pretrained (no Hub download).

Wrapper (prosdd_asv19.py:ProSDDASV19, _net.py:ProSDDNet)

  • _net.ProSDDNet.forward = inference_forward verbatim: ssl.feature_extractor β†’ transpose β†’ ssl.feature_projection (tuple[0]) β†’ latent truncated / zero-padded to T_target=200 (64000 samples give 199 frames, so 1 zero frame is always appended) β†’ ssl.encoder(attention_mask=None) β†’ mean over all 200 frames β†’ cls_head Linear(1024,512)-ReLU-Dropout-Linear(512,2). classifier_pool = mean (checkpoint has no attn/attn_q tensors).
  • Preprocessing = data_utils_eval.pad: 64000 samples; longer β†’ centre crop s=(n-64000)//2; shorter β†’ zero pad left=(64000-n)//2, rest right. No amplitude normalisation, no resampling. Empty clip β†’ zeros (source would also give zeros). FP32, TF32 off (cuDNN + matmul).
  • Score = logits[:,1] (class 1 = bona fide in the source) β†’ higher = bona fide.
  • Strict load: checkpoint keys outside ssl.*/cls_head.* must equal the allow-list {mask_embed, pros_ln.weight/bias, final_proj.weight/bias} (Stage-I masked-prediction token, prosody-target LN, 1024β†’448 speaker+prosody head; all training-only), asserted; then load_state_dict(strict=True): 0 missing / 0 unexpected. ssl.masked_spec_embed is loaded (it is a Wav2Vec2Model parameter) but unused at inference. The source's own strict=False load into ProSDDStage2 reports 0 missing / 0 unexpected.
  • Params: 315,964,546 total; 315,963,522 forward path (minus masked_spec_embed, 1024) β†’ meta 315.963522.
  • Source parity (source_parity.py <src_dir>): authors' ProSDDStage2 (from_pretrained swapped for the vendored config) + main_eval.inference_forward + data_utils_eval.pad, per clip, vs the wrapper batched, on 16 J-SPAW clips + a 20000-sample and a 139944-sample clip: max |Ξ” logit| = 1.0e-5 (batching noise).
  • Unit tests test_prosdd_asv19.py: pad/crop, strict load, eval mode + param count, 199β†’200 frames, batch == single (atol 1e-3), determinism, bona fide > spoof on J-SPAW clips. 8 passed.

Batch sweep (sweep.py, 64000-sample input, 2026-11-07; run with the ASV19 checkpoint, same graph for both)

card best notes
RTX 4070 Ti SUPER (idx 2) 126.2 utt/s @24 plateau 16–64 β†’ batch_size = 24
RTX 5060 Ti (idx 0) 47.8 utt/s @4 ~32 at bs β‰₯ 8 (card shared with another job during the sweep) β†’ 4 on 5060

Sanity (PyTorch, RTX 5060 Ti idx 0)

  • Full J-SPAW_LA: EER 24.734% (2397 trials, 0 skipped). Not ~50 / not inverted.
  • ASVspoof2019_LA quick check (subset_eer.py 2000, 2000 clips sampled with seed 0 from eval shard 0): EER 0.449% (2000 clips: 223 bona fide / 1777 spoof) vs paper 0.42%.
  • Training data (paper): Stage I LibriSpeech train-clean-100 + dev (bona fide only); Stage II ASVspoof 2019 LA train/dev, RawBoost 3. Arena ASVspoof sets are eval partitions β†’ no trained_on entries.

TensorRT (trt_prosdd_asv19.py, sidecar trt_prosdd-asv19.json, TRT 10.16.1.11)

Adapted from Forensics-XLSR-Wild's script: _ExportNet returns the (B,2) logits; n_classes taken from the traced output; ONNX file named per card (prosdd-asv19_<GPU>.onnx) so the two cards can export concurrently (only the 4070 copy kept). Build parity on 64 InTheWild clips; FP16 kept iff Spearman β‰₯ 0.9999.

card precision best batch utt/s (sweep) build Spearman J-SPAW EER J-SPAW Spearman vs PT / max Ξ”
RTX 4070 Ti SUPER (idx 2) FP32 (FP16 build Spearman 0.99977 < 0.9999) 32 186.5 1.0 24.734 (=PT) 0.999999 / 0.0164
RTX 5060 Ti (idx 0) FP32 (FP16 build Spearman 0.99986 < 0.9999) 8 61.5 1.0 24.734 (=PT) 0.999999 / 0.0172

Both cards pass (|Ξ”EER| ≀ 0.25, Spearman β‰₯ 0.999). Unused FP16 engines deleted. J-SPAW_LA submitted from PyTorch scores (results_pt/ β†’ results/); TRT runs in results_trt2/, results_trt0/; compare with cmp_scores.py. Scripts: run_pt.sh, run_trt_export.sh <gpu>, run_trt_jspaw.sh <gpu>.