Automatic Speech Recognition
Transformers
Safetensors
prosody_to_text
feature-extraction
prosody
speech-recognition
custom_code
Instructions to use Daporte/prosody2text-weights with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use Daporte/prosody2text-weights with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("automatic-speech-recognition", model="Daporte/prosody2text-weights", trust_remote_code=True)# pip install -U transformers accelerate # Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("Daporte/prosody2text-weights", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
|
Download README.md from Daporte/prosody2text-weights: direct link, hf CLI and curl.
- Browser
- Download file 7.93 kB
-
https://huggingface.co/Daporte/prosody2text-weights/resolve/main/README.md
- Command line
-
hf download hf://Daporte/prosody2text-weights/README.md
-
curl -L -o README.md https://huggingface.co/Daporte/prosody2text-weights/resolve/main/README.md
7.93 kB
| license: mit | |
| library_name: transformers | |
| tags: | |
| - prosody | |
| - speech-recognition | |
| - custom_code | |
| pipeline_tag: automatic-speech-recognition | |
| # Prosody2text | |
| Two signals — **interpolated f0 and intensity at 200 Hz** — into a mel | |
| spectrogram, and the mel into words. No phonetic content at any point: the | |
| model sees only how the pitch moved and how loud it was. | |
| That is the claim this repo exists to let you check. | |
| Companion to the paper. The interactive version, where you *draw* a contour | |
| instead of speaking one, is at | |
| [Daporte/Prosody2text](https://huggingface.co/spaces/Daporte/Prosody2text). | |
| ## Use it | |
| ```python | |
| from transformers import AutoModel | |
| model = AutoModel.from_pretrained( | |
| "Daporte/prosody2text-weights", trust_remote_code=True | |
| ) | |
| result = model.transcribe("utterance.wav") | |
| print(result.text) # the chosen hypothesis | |
| print(result.candidates) # the whole beam -- ten of them | |
| print(result.mel.shape) # the predicted mel | |
| print(result.features.f0_hz) # what the conformer was actually given | |
| print(result.fallback) # True if this is the no-speech boilerplate | |
| ``` | |
| `trust_remote_code=True` is needed because the architecture is not one of | |
| Transformers' own: a conformer and a fine-tuned Whisper held alongside each | |
| other, each loaded from its own checkpoint. The code it runs is the modeling | |
| files in this repo. | |
| Already have the contours? Hand them over directly — physical units, Hz and | |
| dB on the 200 Hz grid: | |
| ```python | |
| result = model(f0_hz=f0, intensity_db=intensity_db) | |
| ``` | |
| The normalisation to the model's own scale happens inside, so it cannot be | |
| applied twice — which produces a mel that looks plausible and is wrong. | |
| `AutoModel.from_pretrained(..., whisper=False)` loads the conformer alone: a | |
| 45 MB download rather than 3.1 GB, and enough to look at the predicted mel. | |
| ## Evaluate on a dataset | |
| `evaluate_dataset.py` runs the pipeline over any HuggingFace speech dataset | |
| and scores it against the reference transcripts. A microphone tells you the | |
| pipeline runs; a dataset tells you whether it is *right*. | |
| ```sh | |
| pip install transformers torch numpy scipy safetensors \ | |
| amfm-decompy==1.0.12.2 praat-parselmouth \ | |
| datasets jiwer soundfile | |
| hf download Daporte/prosody2text-weights evaluate_dataset.py --local-dir . | |
| python evaluate_dataset.py \ | |
| --dataset espnet/yodas-granary \ | |
| --data_files data/en001/asr_only/00000000.parquet \ | |
| --split train --count 3000 --fp16 \ | |
| --save ours_en001.jsonl | |
| ``` | |
| With `uv` instead of `pip`, in an empty directory: | |
| ```sh | |
| uv init --bare # uv add needs a pyproject.toml to add to | |
| uv add transformers torch numpy scipy safetensors \ | |
| amfm-decompy==1.0.12.2 praat-parselmouth \ | |
| datasets jiwer soundfile | |
| uv run hf download Daporte/prosody2text-weights evaluate_dataset.py \ | |
| --local-dir . | |
| uv run python evaluate_dataset.py --dataset espnet/yodas-granary \ | |
| --data_files data/en001/asr_only/00000000.parquet \ | |
| --split train --count 3000 --fp16 --save ours_en001.jsonl | |
| ``` | |
| `uv run python`, not `python`: the bare command is the system interpreter, | |
| which does not have any of the above installed. | |
| Streaming by default, so this does not download the whole split. Each line | |
| of the output is one utterance: | |
| ```json | |
| {"prediction": "...", "candidates": ["...", "..."], "reference": "...", "id": "0"} | |
| ``` | |
| Those field names match the published inference runs', so comparing against | |
| them is a join on `id` rather than a translation. | |
| Anything with an audio column and a transcript works. The transcript column | |
| is found from `text`, `sentence`, `transcription`, `transcript` or | |
| `normalized_text`; pass `--text_column` otherwise. `--help` lists the rest. | |
| ### On a GPU | |
| Whisper at beam 10 is about **1 s per utterance on an RTX 3090** against | |
| **~20 s on CPU**, so a few thousand utterances is the difference between an | |
| hour and a day. `--fp16` halves the VRAM and is a further 1.8× faster; it | |
| transcribed every template identically to fp32. | |
| If it reports `whisper: cpu` on a machine that has a GPU, the usual cause is | |
| that `libcuda.so.1` sits somewhere the dynamic loader does not search — | |
| `nvidia-smi` works, but torch reports no driver at all. The model detects | |
| this and prints the fix. On most distributions none of this arises. | |
| ### What the numbers mean | |
| WER is reported **over the corpus**, not averaged per utterance: it is total | |
| errors over total reference words, so averaging would weight a three-word | |
| reference the same as a thirty-word one and give a different, wrong number. | |
| The normalisation — punctuation removed, case folded — matches the published | |
| runs, because case and punctuation alone would otherwise count as errors and | |
| the figure would measure typography rather than the model. | |
| Each line also prints the substitution/deletion/insertion split, which is | |
| worth reading: on this pipeline a hypothesis is usually the right *length* | |
| with the wrong words, and that is a different failure from dropping or | |
| inventing half the utterance. | |
| ## What is here | |
| | | | | | |
| |---|---|---| | |
| | `conformer/` | 45 MB | f0 + intensity → mel | | |
| | `whisper/` | 3.1 GB | Whisper-medium fine-tuned on prosody-predicted mels | | |
| | `tokenizer/` | 5 MB | the stock whisper-medium tokenizer, vendored | | |
| | `config.json` | | the mel contract, and the `auto_map` | | |
| | `modeling_prosody.py`, `configuration_prosody.py` | | the architecture | | |
| | `features.py`, `speech.py`, `conformer.py`, `conformer_model.py`, `whisper_decoder.py` | | the pipeline | | |
| | `evaluate_dataset.py` | | dataset evaluation | | |
| Only inference files. A training checkpoint also carries optimizer state — | |
| 6 GB of Adam moments for this model — which nothing here reads. | |
| ## Notes | |
| **The feature extraction is not interchangeable with sensible-looking | |
| alternatives.** The yaapt settings, the half-frame zero-padding, the | |
| six-frame trim and the two clamps all move the contour, and the conformer | |
| only ever saw one combination of them. `speech.py` carries that combination | |
| and is checked bit-identical against the reference implementation. | |
| **The mel contract lives in `config.json`.** `mel_bins` and `length_ratio` | |
| must match what the conformer was trained with; a wrong `length_ratio` | |
| mis-times the mel against the audio without failing, which is the worst way | |
| for it to be wrong. | |
| **Recordings are trimmed; dataset clips usually need not be.** A live | |
| microphone hands over the room before and after the words, and yaapt finds a | |
| pitch in noise, so an untrimmed recording puts several hundred milliseconds | |
| of nothing into the mel. The trim cuts anything more than 18 dB under the | |
| loudest frame. `--no_trim`, or `trim=False`, turns it off — which is the | |
| closer match to the published runs. | |
| **The conformer is the trained module, not an export.** `generate()` is | |
| non-autoregressive and sizes its output from the real input length, so a | |
| phrase is predicted at its own duration. An earlier version of this repo | |
| shipped an ONNX export instead, whose input width is baked in at 2000 | |
| frames — every phrase padded to ten seconds, with the decoder attending over | |
| the padding. Measured against the training pipeline's own predictions that | |
| is 0.9357 correlation against 0.9985 here, which is two orders of magnitude | |
| more than the f0 extraction differs by. The architecture in | |
| `conformer_model.py` is extracted verbatim from the training code and checked | |
| bit-identical to it on CPU. | |
| **This is not trainable as it stands.** It subclasses `PreTrainedModel` so | |
| that `from_pretrained`, the `AutoModel` API and download metrics work, but | |
| `forward` runs the two models in sequence under `no_grad` rather than | |
| building one differentiable graph, and the weights load from two checkpoints | |
| rather than one state dict. It exists to run the published pipeline. | |
| ## Licence | |
| MIT for the code. The weights derive from | |
| [openai/whisper-medium](https://huggingface.co/openai/whisper-medium) and | |
| carry its terms. | |