Views
No views yet

facebook/audioseal
audioseal_wm_16bits generator and stays compatible with the unmodified
audioseal_detector_16bits detector.msaidov/audioseal-robust-audioldm-16bits,
the same experiment run against a structurally different diffusion attack
(AudioLDM latent-diffusion resynthesis).src/audioseal_robust)generator.pth, repackaged for stock AudioSeal (see Checkpoint format). The raw training checkpoint is kept alongside as generator_train_ckpt.pthtraining_config.yaml, read back out of the checkpoint's own embedded xp.cfgrequires_grad_(False), never taken out of eval()), and used purely as
a differentiable objective. Nothing about the detector, the architecture, the
16-bit payload, or the 16 kHz sample rate changes — so existing AudioSeal
detection code keeps working unchanged.nbits: 16, dimension: 128, n_filters: 32,
ratios: [8, 5, 4, 2], 2 LSTM layers), initialised from the pretrained
audioseal_wm_16bits weights — this is a fine-tune, not a from-scratch train.src/sgmse/ and driven from the authors' VoiceBank-DEMAND pretrained
checkpoint (sgmse_vb_pretrained.ckpt).no_grad, so
gradients propagate all the way back through the whole reverse-diffusion chain
into the generator. The corruption depth t* is sampled per example, uniformly
over the full [0, 1] range, so the generator sees everything from a barely
perturbed signal to a full re-synthesis.sgmse_mixed recipe:| branch | weight | meaning |
|---|---|---|
identity | 0.5 | unattacked — anchors bit accuracy on the easy case |
sgmse | 0.5 | full differentiable SGMSE reverse-diffusion attack |
attack.weights.audioldm: 0.0)
so it can serve as a generalization probe — i.e. "does robustness learned
against one diffusion attack transfer to a structurally different one?"train-clean-100 by cumulative duration, taken in
sorted file order for determinism (~2.9 k utterances).dev-clean — a split never seen in training.x_wm = x + scale · G(x, m)scale is set per example so the watermark lands at a target SNR drawn
uniformly from [24, 36] dB relative to the host signal, rather than using
whatever raw amplitude the generator happens to emit. The attack is then applied,
and the frozen detector scores the result.L = λ_det · (BCE(presence) + λ_bit · BCE(message bits)) + λ_perc · L_melL_mel is a psychoacoustic mel loss: L1 between log-mel spectrograms of x and
x_wm, with each mel bin weighted by a Terhardt absolute-threshold-of-hearing
curve so perturbation energy in less audible bands is penalised less.| hyperparameter | value |
|---|---|
λ_det | 1.0 |
λ_perc | 0.0 — perceptual loss disabled for this run |
λ_bit | 2.0 — up-weights the hard sub-problem (bit decoding) over the easy one (mere presence) |
| optimizer | Adam, lr 5e-5, betas (0.5, 0.9), weight decay 0.0 |
| gradient clipping | max_norm = 3.0 (clip only, no gradient normalization) |
| activation-gradient clamp | max_x_wm_grad_norm = 1000.0 at the generator/attack boundary |
| precision | bf16 autocast on the forward pass; BCE and SGMSE's log/exp forced back to fp32 |
| batch size | 8 |
| mel loss | n_fft 1024, hop 256, win 1024, 80 mels, f_min 20 Hz |
| seed | 1234 |
Note onλ_perc = 0.0. Perceptual loss was switched off for this run to isolate the detection objective while diagnosing a bit-accuracy plateau. The watermark is still amplitude-constrained by the 24–36 dB SNR scaling above, so it is not unbounded — but this checkpoint was not optimized for perceptual transparency. Measure SI-SNR/PESQ yourself before assuming imperceptibility.
epochs: 100 and updates_per_epoch: 1000 are caps, not targets —
the inner loop also ends when the dataloader is exhausted, whichever comes first.
On this ~10 h subset at batch size 8 that is ≈365 optimizer steps per epoch, so
the cap never bound. This checkpoint is saved at the end of epoch index 3,
i.e. after 4 completed passes over the subset (≈1.5 k optimizer steps).
Trained on a single A100.generator.pth is a plain torch.save dict, in the same shape AudioSeal's own
generator_base.pth uses:{"model": <generator state_dict>, "xp.cfg": <architecture config, plain dicts>}xp.cfg describes the architecture, not the training run. It is the stock
audioseal_wm_16bits config (nbits, seanet, decoder) as plain dicts and
lists — exactly what AudioSeal.parse_config reads. It references no OmegaConf
or project-specific classes, so torch.load needs nothing but torch, and
nbits is picked up automatically.....conv.conv.weight). AudioSeal picks
its SEANet by interpreter version — AudioCraft's (flat) below Python 3.10,
Moshi's (an extra inner_conv level) at or above it — and its loader only
converts flat → inner_conv. Flat is therefore the only naming that loads on
both sides of that split, which is why upstream publishes it and why this
checkpoint does too."audioseal_robust" key the loader ignores — together with the source
checkpoint name and the exporting commit.
training_config.yaml is that same data as YAML.generator_train_ckpt.pth is the unmodified file the training run wrote
(generator_epoch3.pth), kept for provenance. Its tensors already use the
flat naming, because it was written by a Python < 3.10 process. It is still
not usable on its own: its xp.cfg pickles
audioseal_robust.config.TrainConfig and thirteen sibling dataclasses by
reference, so torch.load fails with
ModuleNotFoundError: No module named 'audioseal_robust' unless the training
repo is importable — and even then AudioSeal.load_generator rejects it, because
a TrainConfig has no seanet block. Reach for it only if you are reproducing
the run.audioseal_robust.export_checkpoint,
which reloads its own output through AudioSeal.load_generator and compares it
tensor-by-tensor against the source before writing the file.pip install audioseal huggingface_hub1import torch
2from audioseal import AudioSeal
3from huggingface_hub import hf_hub_download
4
5generator = AudioSeal.load_generator(
6 hf_hub_download("msaidov/audioseal-robust-sgmse-16bits", "generator.pth")
7)
8
9# Watermark exactly as with stock AudioSeal.
10wav, sr = ..., 16000 # (batch, channels, samples), 16 kHz
11msg = torch.randint(0, 2, (wav.shape[0], 16))
12watermarked = wav + generator.get_watermark(wav, sr, message=msg)
13
14# The stock detector is unchanged and still applies.
15detector = AudioSeal.load_detector("audioseal_detector_16bits")
16prob, decoded = detector.detect_watermark(watermarked, sr)nbits= to pass and no state-dict reconciliation to do: both come
out of the checkpoint itself (see Checkpoint format).huggingface_hub, AudioSeal will fetch the URL
itself through torch.hub:1generator = AudioSeal.load_generator(
2 "https://huggingface.co/msaidov/audioseal-robust-sgmse-16bits/resolve/main/generator.pth"
3)embed_watermark in
src/audioseal_robust/train.py.t* robustness curve:1PYTHONPATH=src python -m audioseal_robust.evaluate \
2 generator_checkpoint=generator.pth \
3 eval_dir=/path/to/LibriSpeech/test-clean \
4 recipe=after_sgmse_training \
5 attack.sgmse.checkpoint=/path/to/sgmse_vb_pretrained.ckptafter_sgmse_training eval recipe reports identity, bigvgan, dac and
sgmse, and holds audioldm and mbd out as unseen-attack generalization
probes.sgmse_mixed-trained generator
measured considerably worse against held-out AudioLDM than against SGMSE
itself. Do not treat "robust" in the model name as a security guarantee —
measure it on your own threat model.
facebook/audioseal
(Meta Platforms), from which these weights are derived. The SGMSE
(sp-uhh/sgmse, MIT) model is used only as a
training-time attack; its weights are not redistributed here.1@article{sanroman2024proactive,
2 title = {Proactive Detection of Voice Cloning with Localized Watermarking},
3 author = {San Roman, Robin and Fernandez, Pierre and Elsahar, Hady and
4 D{\'e}fossez, Alexandre and Furon, Teddy and Tran, Tuan},
5 journal = {ICML},
6 year = {2024}
7}
8
9@article{richter2023speech,
10 title = {Speech Enhancement and Dereverberation with Diffusion-based
11 Generative Models},
12 author = {Richter, Julius and Welker, Simon and Lemercier, Jean-Marie and
13 Lay, Bunlong and Gerkmann, Timo},
14 journal = {IEEE/ACM Transactions on Audio, Speech, and Language Processing},
15 volume = {31},
16 pages = {2351--2364},
17 year = {2023},
18 doi = {10.1109/TASLP.2023.3285241}
19}