Text-to-Speech
Transformers
Safetensors
hifi_gan
feature-extraction
audio
vocoder
hifi-gan
bigvgan
neural-vocoder
speaker-conditioning
audio-watermarking
custom_code
Instructions to use mlr2000/vocoder-small with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use mlr2000/vocoder-small with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-to-speech", model="mlr2000/vocoder-small", trust_remote_code=True)# Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("mlr2000/vocoder-small", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
File size: 4,995 Bytes
1fdc661 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | {
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# VocBulwark watermark round-trip\n",
"\n",
"The full pipeline, in three self-contained models loaded from the Hub:\n",
"\n",
"1. **Speaker encoder** — a reference clip → a fixed-size speaker embedding (*whose* voice).\n",
"2. **Vocoder** — a mel spectrogram (*what* is said) + that embedding → a 24 kHz waveform, with the fixed provenance watermark embedded automatically.\n",
"3. **Detector** — the waveform → how many watermark bits match.\n",
"\n",
"In a real TTS system you usually already have the mel (from an acoustic model) and the speaker embedding (precomputed once per speaker), so step 1 is only needed to *make* an embedding from audio. Here we reconstruct one clip (use it as both content and speaker reference) to exercise the watermark.\n",
"\n",
"Needs only `torch`, `transformers`, `soundfile`, `torchaudio`. Put one or more `.wav` files in an `example_audio/` folder next to this notebook. If the repos are private, run `huggingface-cli login` first."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from pathlib import Path\n",
"\n",
"SPK_REPO = \"mlr2000/vocoder-small-speaker-encoder\" # <- speaker encoder\n",
"GEN_REPO = \"mlr2000/vocoder-small\" # <- vocoder (paired with SPK_REPO)\n",
"DET_REPO = \"mlr2000/vocoder-small-watermark-detector\" # <- matching detector\n",
"TGT_SR = 24000 # vocoder output SR\n",
"MAX_SAMPLES = 16 * TGT_SR\n",
"\n",
"AUDIO_DIR = next(p for p in [Path(\"example_audio\"), Path(\"../example_audio\")] if p.exists())"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import torch\n",
"from transformers import AutoModel\n",
"\n",
"enc = AutoModel.from_pretrained(SPK_REPO, trust_remote_code=True).eval()\n",
"gen = AutoModel.from_pretrained(GEN_REPO, trust_remote_code=True).eval()\n",
"det = AutoModel.from_pretrained(DET_REPO, trust_remote_code=True).eval()\n",
"RAW_SR = enc.config.raw_sample_rate # SR the speaker encoder expects\n",
"print(f\"embedding dim: {enc.config.embedding_size} | watermark: {len(gen.config.fixed_watermark)} bits\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import soundfile as sf\n",
"import torchaudio.functional as AF\n",
"from transformers import WhisperFeatureExtractor\n",
"\n",
"# Mel front-end — must match the trained vocoder (n_fft=1024, hop=256, mel channels from config).\n",
"N_MELS = gen.config.hifigan_in_channels\n",
"mel_fe = WhisperFeatureExtractor(sampling_rate=TGT_SR, n_fft=1024, feature_size=N_MELS, hop_length=256)\n",
"mel_fe.n_samples = MAX_SAMPLES\n",
"mel_fe.chunk_length = MAX_SAMPLES / TGT_SR\n",
"\n",
"def load_inputs(path):\n",
" \"\"\"A clip -> (mel = content, raw = speaker reference @ RAW_SR).\"\"\"\n",
" w, sr = sf.read(str(path))\n",
" w = torch.tensor(w, dtype=torch.float32)\n",
" if w.dim() == 2:\n",
" w = w.mean(1) # mono\n",
" raw = AF.resample(w, sr, RAW_SR) if sr != RAW_SR else w # speaker ref @ RAW_SR\n",
" tgt = AF.resample(raw, RAW_SR, TGT_SR) # content @ 24 kHz\n",
" mel = mel_fe(tgt.numpy(), sampling_rate=TGT_SR, padding=\"longest\",\n",
" return_tensors=\"pt\")[\"input_features\"]\n",
" return mel, raw.unsqueeze(0)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from IPython.display import Audio, display\n",
"\n",
"for path in sorted(AUDIO_DIR.glob(\"*.wav\")):\n",
" mel, raw = load_inputs(path)\n",
" with torch.no_grad():\n",
" emb = enc.embed(raw) # [1, embedding_size]\n",
" # The vocoder embeds its fixed watermark automatically.\n",
" audio = gen(mel_spectrogram=mel, speaker_embedding=emb).audio.squeeze(1)\n",
" r = det.detect(audio)\n",
" print(f\"{path.name}: {r['matches']}/{r['n_bits']} bits matched p={r['p_value']:.1e}\")\n",
" display(Audio(audio[0].numpy(), rate=TGT_SR))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Sanity check: an **unrelated** clip (here, random noise) is not from our model, so it matches only about half the bits with a large `p_value`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print(\"random noise:\", det.detect(torch.randn(1, TGT_SR)))"
]
}
],
"metadata": {
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
|