Add files using upload-large-folder tool
Browse files- .gitattributes +4 -0
- README.md +212 -0
- acoustic_encoder.onnx +3 -0
- fp16/acoustic_encoder.onnx +3 -0
- fp16/acoustic_encoder.onnx.data +3 -0
- fp16/higgs_decoder.onnx +3 -0
- fp16/higgs_decoder.onnx.data +3 -0
- fp16/model_config.json +12 -0
- fp16/quantizer_encoder.onnx +3 -0
- fp16/semantic_encoder.onnx +3 -0
- fp16/semantic_encoder.onnx.data +3 -0
- higgs_audio_tokenizer_architecture.png +3 -0
- higgs_decoder.onnx +3 -0
- higgs_inference.py +392 -0
- model_config.json +12 -0
- quantizer_encoder.onnx +3 -0
- semantic_encoder.onnx +3 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,7 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
higgs_audio_tokenizer_architecture.png filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
fp16/semantic_encoder.onnx.data filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
fp16/acoustic_encoder.onnx.data filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
fp16/higgs_decoder.onnx.data filter=lfs diff=lfs merge=lfs -text
|
README.md
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: other
|
| 3 |
+
library_name: onnx
|
| 4 |
+
base_model:
|
| 5 |
+
- bosonai/higgs-audio-v2-tokenizer
|
| 6 |
+
- eustlb/higgs-audio-v2-tokenizer
|
| 7 |
+
---
|
| 8 |
+
|
| 9 |
+
# Higgs Audio Tokenizer
|
| 10 |
+
|
| 11 |
+
<div align="center" style="display: flex; justify-content: center; margin-top: 10px; flex-wrap: wrap; gap: 8px;">
|
| 12 |
+
<a href="https://boson.ai/blog/higgs-audio-v2"><img src='https://img.shields.io/badge/π-Launch Blogpost-228B22' style="margin-right: 5px;"></a>
|
| 13 |
+
<a href="https://github.com/boson-ai/higgs-audio"><img src="https://img.shields.io/badge/π»-Github%20Repo-9C276A" style="margin-right: 5px;"></a>
|
| 14 |
+
</div>
|
| 15 |
+
|
| 16 |
+
Check our open-source repository https://github.com/boson-ai/higgs-audio for more details!
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
We introduce a new discretized audio tokenizer that runs at just **25 frames per second** while keepingβor even improvingβaudio quality compared to tokenizers with twice the bitrate. Our model is the first to train on **24 kHz data** covering speech, music, and sound events in one unified system. It also uses a simple non-diffusion encoder/decoder for fast, batch inference.
|
| 20 |
+
|
| 21 |
+
<p>
|
| 22 |
+
<img src="./higgs_audio_tokenizer_architecture.png" alt="Architecture diagram of the Higgs Audio Tokenizer" width=900>
|
| 23 |
+
</p>
|
| 24 |
+
|
| 25 |
+
## Usage
|
| 26 |
+
|
| 27 |
+
### Transformers π€
|
| 28 |
+
|
| 29 |
+
Higgs Audio V2 Tokenizer is supported natively in `transformers`: [see the doc](https://huggingface.co/docs/transformers/en/model_doc/higgs_audio_v2_tokenizer).
|
| 30 |
+
|
| 31 |
+
```bash
|
| 32 |
+
uv pip install "transformers>=5.3.0"
|
| 33 |
+
```
|
| 34 |
+
|
| 35 |
+
### Onnx
|
| 36 |
+
|
| 37 |
+
The model is divided into 4 submodels :
|
| 38 |
+
|
| 39 |
+
- `account_encoder.onnx`
|
| 40 |
+
- `higgs_decoder.onnx`
|
| 41 |
+
- `quantizer_encoder.onnx`
|
| 42 |
+
- `semantic_encoder.onnx`
|
| 43 |
+
|
| 44 |
+
```bash
|
| 45 |
+
python higgs_inference.py --input speech.wav --output reconstructed.wav
|
| 46 |
+
```
|
| 47 |
+
|
| 48 |
+
## Basics of Audio Quantization
|
| 49 |
+
|
| 50 |
+
An audio signal sampled at \\(f_s\\) Hz is first split into frames by an encoder with hop size \\(M\\), giving a frame rate \\(f_r = \frac{f_s}{M}\quad\text{(frames/s)}.\\)
|
| 51 |
+
Two common quantizers are:
|
| 52 |
+
|
| 53 |
+
- **Residual Vector Quantization (RVQ)**: \\(N_q\\) cascaded vectorβquantizer layers, each with codebook size \\(N_{cb}\\). When \\(N_{q}=1\\), it degenerates to ordinary vector quantization.
|
| 54 |
+
- **Finite Scalar Quantization (FSQ)**: A single-layer scalar quantizer in which
|
| 55 |
+
every scalar coefficient is independently mapped to one of \\(N_{cb}\\) discrete levels.
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
If every combination of codewords is a token, the vocabulary size is \\(N_{cb}^{N_q}\\), and each token needs \\(N_q\log_2 N_{cb}\\) bits. The overall bitrate (bits/s, BPS) is simply \\(f_r \times N_q \log_2 N_{cb}\\).
|
| 59 |
+
We aim to push this bitrate as low as possible without hurting audio fidelity.
|
| 60 |
+
|
| 61 |
+
## What Makes Ours Better
|
| 62 |
+
|
| 63 |
+
- **Low Frame Rate**: Runs at justβ―25β―fps, halving the frame rate of many baselines while preserving high audio quality.
|
| 64 |
+
- **Unified 24 kHz Training**: A single model jointly trained on speech, music, and soundβevent data, capturing both semantic and acoustic nuances and greatly simplifying downstream audioβlanguageβmodel training.
|
| 65 |
+
- **Fast Inference**: A nonβdiffusion encoder/decoder that processes batches quickly, making it practical for real-time or large-scale tasks.
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
## Evaluation Data and Metrics
|
| 69 |
+
|
| 70 |
+
We test on four subsets:
|
| 71 |
+
|
| 72 |
+
- **Speech, Music and Sound Event**: Include 1,000 clips per category, with each clip lasting 10 seconds. Clips are randomly sampled from [DAPS](https://ccrma.stanford.edu/~gautham/Site/daps.html) (Speech), [MUSDB](https://sigsep.github.io/datasets/musdb.html) (Music), and [AudioSet](https://research.google.com/audioset/index.html) (Sound Event).
|
| 73 |
+
|
| 74 |
+
- **Audiophile**: Contains 150 clips, each 30 seconds long, curated from eleven high-fidelity test discs that were designed for perceptual listening tests. The clips feature both high-quality music and sound events.
|
| 75 |
+
|
| 76 |
+
We measure:
|
| 77 |
+
|
| 78 |
+
- **Acoustic Quality**: Acoustic reconstruction error between the original and reconstructed audio.
|
| 79 |
+
- **Semantic Integrity**: Degree of semantic preservation, evaluated on the English and Chinese subsets of [SeedTTS](https://arxiv.org/abs/2406.02430)[15].
|
| 80 |
+
- **Aesthetics**: SOTA unified model-based quality metrics computed with [Meta Audiobox Aesthetics](https://github.com/facebookresearch/audiobox-aesthetics)[8].
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
We compare our tokenizer with a wide range of baselines, from tokenizers mainly built for better acoustic reconstruction and compression rate, to those focused on semantic integrity, and to tokenizers used in existing large audio language models. We also compare with tokenizers that are pretrained specifically on speech or on music.
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
The tables below summarize the tokenizers evaluated. As shown, our tokenizer achieves a well-rounded balance of efficiency, semantic fidelity, and acoustic quality.
|
| 87 |
+
|
| 88 |
+
### Acoustic Evaluation
|
| 89 |
+
|
| 90 |
+
This table reports the ShortβTime Fourier Transform (STFT) distance between the original and reconstructed audio. Baselines are listed chronologically and grouped by whether semantic distillation (SD) is applied. Despite DACβs top acoustic quality at 12Γ the bitrate, our tokenizer leads all other baselines.
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
| Tokenizer | π¬ | π΅ | π₯ | SD | \\(f_s\\) | \\(f_r\\) | BPS<sup>*</sup> (k) β | Speech β | Sound Event β | Music β | Audiophile β |
|
| 94 |
+
|-----------|----|----|----|----|-------|-------|--------------------------|----------|----------------|--------|--------------|
|
| 95 |
+
| [Encodec](https://huggingface.co/facebook/encodec_24khz)[3] | β | β | β | | 24 | 75 | 24 | 1.96 | 2.65 | 2.52 | 2.30 |
|
| 96 |
+
| [DAC](https://huggingface.co/hance-ai/descript-audio-codec-24khz)[2] | β | β | β | | 24 | 75 | 24 | **1.13** | **1.45** | **1.34** | **1.62** |
|
| 97 |
+
| [SNAC-24k](https://huggingface.co/hubertsiuzdak/snac_24khz)[6] | β | | | | 24 | (12, 23, 47) | 0.98 | 1.92 | 2.69 | 2.54 | 2.52 |
|
| 98 |
+
| [SNAC-44k](https://huggingface.co/hubertsiuzdak/snac_44khz)[6] | | β | β | | 44.1 | (14, 29, 57, 115) | 2.6 | 1.83 | 2.25 | 2.05 | 2.00 |
|
| 99 |
+
| [WavTokenizer](https://huggingface.co/novateur/WavTokenizer-medium-music-audio-75token/blob/main/wavtokenizer_medium_music_audio_320_24k_v2.ckpt)[7] | | β | β | | 24 | 75 | 0.9 | 1.93 | 2.44 | 2.17 | 2.15 |
|
| 100 |
+
| [WavTokenizer (Speech)](https://huggingface.co/novateur/WavTokenizer-large-speech-75token/tree/main)[7] | β | | | | 24 | 75 | 0.9 | 1.78 | 2.47 | 2.42 | 2.47 |
|
| 101 |
+
| [MuCodec](https://huggingface.co/haoheliu/audioldm_48k/tree/main)[11] | | β | | | 48 | 25 | 0.35 | 2.87 | 3.69 | 3.36 | 2.97 |
|
| 102 |
+
| [FlowDec-75m](https://github.com/facebookresearch/FlowDec?tab=readme-ov-file)[12] | β | β | β | | 48 | 75 | 7.5 | 1.73 | 2.14 | 2.01 | 2.03 |
|
| 103 |
+
| [FlowDec-25s](https://github.com/facebookresearch/FlowDec?tab=readme-ov-file)[12] | β | β | β | | 48 | 25 | 4 | 1.94 | 2.42 | 2.25 | 2.33 |
|
| 104 |
+
| [SpeechTokenizer](https://huggingface.co/fnlp/SpeechTokenizer/tree/main/speechtokenizer_hubert_avg)[14] | β | | | β | 16 | 50 | 4 | 3.21 | 3.58 | 3.65 | 3.69 |
|
| 105 |
+
| [SemantiCodec](https://huggingface.co/haoheliu/SemantiCodec/tree/main/semanticodec_tokenrate_100)[5] | β | β | β | β | 16 | 100 | 1.35 | 3.05 | 3.28 | 3.24 | 3.18 |
|
| 106 |
+
| [Mimi](https://huggingface.co/docs/transformers/en/model_doc/mimi)[13] | β | | | β | 24 | 12.5 | 4.4 | 1.77 | 2.40 | 2.30 | 2.15 |
|
| 107 |
+
| [XCodec](https://huggingface.co/ZhenYe234/xcodec/blob/main/config_hubert_general.yaml)[1] | β | β | β | β | 16 | 50 | 4 | 2.95 | 3.16 | 3.00 | 3.03 |
|
| 108 |
+
| [CosyVoice 2](https://huggingface.co/FunAudioLLM/CosyVoice2-0.5B)[13] | β | | | β | 16 | 25 | -<sup>**</sup>| 2.30 | 3.30 | 3.14 | 3.25 |
|
| 109 |
+
| [XCodec2](https://huggingface.co/HKUST-Audio/xcodec2/blob/main/ckpt/epoch%3D4-step%3D1400000.ckpt)[9] | β | | | β | 16 | 50 | 0.8 | 3.06 | 3.72 | 3.62 | 3.64 |
|
| 110 |
+
| [XY](https://huggingface.co/fnlp/XY_Tokenizer_TTSD_V0/tree/main)[10] | β | | | β | 24 | 12.5 | 1 | 1.89 | 2.51 | 2.40 | 2.26 |
|
| 111 |
+
| Ours | β | β | β | β | 24 | 25 | 2 | **1.62** | **2.03** | **1.85** | **1.80** |
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
|
| 115 |
+
<sup>* Bits-per-second is calculated according to the checkpoint the author provided.</sup>
|
| 116 |
+
|
| 117 |
+
<sup>** CosyVoice 2 uses the continuous feature as the conditioning; we include it for completeness.</sup>
|
| 118 |
+
|
| 119 |
+
|
| 120 |
+
### Semantic Evaluation
|
| 121 |
+
[SeedTTS](https://github.com/BytedanceSpeech/seed-tts-eval) is a dataset that includes prompt/target audio and texts. We reconstruct the target audio, and use the word error rate (WER) and speaker similarity (SIM) metrics to evaluate the semantic integrity. SIM is calculated by the similarity between the prompt audio and reconstructed target audio with [WavLM-large](https://drive.google.com/file/d/1-aE1NfzpRCLxA4GUxX9ITI3F9LlbtEGP/view) as the embedding model.
|
| 122 |
+
|
| 123 |
+
The following table compares our tokenizer with semantic-distillation-trained baselines and shows that it delivers performance comparable to tokenizers operating at 2.2Γ our modelβs bitrate.
|
| 124 |
+
|
| 125 |
+
| Model | BPS (k) | en WER β | en SIM β | zh WER β | zh SIM β |
|
| 126 |
+
|------------------|---------|------------|------------|------------|------------|
|
| 127 |
+
| [SpeechTokenizer](https://huggingface.co/fnlp/SpeechTokenizer/tree/main/speechtokenizer_hubert_avg) | 4 | 2.82 | 0.63 | 2.04 | 0.65 |
|
| 128 |
+
| [SemantiCodec](https://huggingface.co/haoheliu/SemantiCodec/tree/main/semanticodec_tokenrate_100) | 1.35 | 3.46 | 0.56 | 2.18 | 0.60 |
|
| 129 |
+
| [Mimi](https://huggingface.co/docs/transformers/en/model_doc/mimi) | 4.4 | **2.35** | **0.70** | **1.48** | **0.72** |
|
| 130 |
+
| [XCodec](https://huggingface.co/ZhenYe234/xcodec/blob/main/config_hubert_general.yaml) | 4.0 | 2.68 | 0.63 | 1.66 | 0.66 |
|
| 131 |
+
| [CosyVoice 2](https://huggingface.co/FunAudioLLM/CosyVoice2-0.5B) | - | 3.17 | 0.65 | 2.11 | 0.70 |
|
| 132 |
+
| [XCodec2](https://huggingface.co/HKUST-Audio/xcodec2/blob/main/ckpt/epoch%3D4-step%3D1400000.ckpt) | 0.8 | 2.74 | 0.62 | 1.91 | 0.67 |
|
| 133 |
+
| [XY-MOSS-TTSD](https://huggingface.co/fnlp/XY_Tokenizer_TTSD_V0/tree/main) | 1.0 | 2.72 | 0.61 | 1.58 | 0.67 |
|
| 134 |
+
| Ours | 2.0 | 2.52 | 0.67 | **1.48** | 0.71 |
|
| 135 |
+
|
| 136 |
+
|
| 137 |
+
|
| 138 |
+
### Audiobox Aesthetics Evaluation
|
| 139 |
+
|
| 140 |
+
This model-based evaluation[8] further demonstrates the superiority of our tokenizer. CU denotes the Content Usefulness and CE denotes the Content Enjoyment; both are rated on a 1-10 scale. Notably, our tokenizer performs best on the Audiophile set, demonstrating a clear advantage when the original audio quality is high.
|
| 141 |
+
|
| 142 |
+
|
| 143 |
+
| Model | BPS (k) | Music CE β | Music CU β | Sound Event CE β | Sound Event CU β | Speech CE β | Speech CU β | Audiophile CE β | Audiophile CU β |
|
| 144 |
+
|------------------|---------|--------------|--------------|--------------------|--------------------|---------------|---------------|--------------------|--------------------|
|
| 145 |
+
| Origin | - | 6.20 | 7.10 | 4.47 | 5.64 | 5.03 | 4.87 | 7.17 | 7.65 |
|
| 146 |
+
| [SpeechTokenizer](https://huggingface.co/fnlp/SpeechTokenizer/tree/main/speechtokenizer_hubert_avg) | 4.0 | 3.55 | 5.22 | 3.03 | 4.50 | 4.68 | 4.58 | 3.59 | 5.07 |
|
| 147 |
+
| [SemantiCodec](https://huggingface.co/haoheliu/SemantiCodec/tree/main/semanticodec_tokenrate_100) | 1.35 | 6.01 | 6.83 | 4.22 | 5.30 | 4.28 | 4.12 | 6.97 | 7.43 |
|
| 148 |
+
| [Mimi](https://huggingface.co/docs/transformers/en/model_doc/mimi) | 4.4 | 6.01 | 6.83 | 4.26 | 5.35 | 4.87 | 4.72 | 6.80 | 7.29 |
|
| 149 |
+
| [XCodec](https://huggingface.co/ZhenYe234/xcodec/blob/main/config_hubert_general.yaml) | 4.0 | **6.30** | **7.10** | **4.43** | 5.45 | **4.96** | **4.79** | 7.06 | 7.49 |
|
| 150 |
+
| [CosyVoice 2](https://huggingface.co/FunAudioLLM/CosyVoice2-0.5B) | - | 5.21 | 6.14 | 4.08 | 4.73 | **4.91** | **4.75** | 5.97 | 6.56 |
|
| 151 |
+
| [XCodec2](https://huggingface.co/HKUST-Audio/xcodec2/blob/main/ckpt/epoch%3D4-step%3D1400000.ckpt) | 0.8 | 4.38 | 5.66 | 3.43 | 4.63 | **4.93** | **4.78** | 4.56 | 5.46 |
|
| 152 |
+
| [XY-MOSS-TTSD](https://huggingface.co/fnlp/XY_Tokenizer_TTSD_V0/tree/main) | 1.0 | 5.77 | 6.80 | 4.23 | 5.34 | 4.88 | 4.72 | 6.95 | 7.48 |
|
| 153 |
+
| Ours | 2.0 | **6.35** | **7.15** | **4.47** | **5.51** | 4.90 | 4.70 | **7.21** | **7.66** |
|
| 154 |
+
|
| 155 |
+
|
| 156 |
+
|
| 157 |
+
Note that since some tokenizers are trained on 16 kHz data, we upsample their audio outputs to 24 kHz before computing metrics. Different upsampling methods may cause slight variations (e.g., 4.36 vs. 4.43 for XCodec Sound Event CE). We report the best results we could obtain and highlight any results within 0.05 of the best one.
|
| 158 |
+
|
| 159 |
+
|
| 160 |
+
|
| 161 |
+
|
| 162 |
+
|
| 163 |
+
|
| 164 |
+
|
| 165 |
+
<!-- xcodec [1]
|
| 166 |
+
dac [2]
|
| 167 |
+
encodec [3]
|
| 168 |
+
moshi [4]
|
| 169 |
+
semanticodec [5]
|
| 170 |
+
snac [6]
|
| 171 |
+
wavtokenizer [7]
|
| 172 |
+
xcodec [8]
|
| 173 |
+
xcodec2 [9]
|
| 174 |
+
xy-tokenizer [10]
|
| 175 |
+
mucodec [11]
|
| 176 |
+
flowdec [12]
|
| 177 |
+
cosyvoice2 [13]
|
| 178 |
+
speechtokenizer [14] -->
|
| 179 |
+
|
| 180 |
+
|
| 181 |
+
|
| 182 |
+
|
| 183 |
+
## Reference
|
| 184 |
+
[1] [Ye, Zhen, et al. "Codec does matter: Exploring the semantic shortcoming of codec for audio language model." Proceedings of the AAAI Conference on Artificial Intelligence. Vol. 39. No. 24. 2025.](https://arxiv.org/abs/2408.17175)
|
| 185 |
+
|
| 186 |
+
[2] [Kumar, Rithesh, et al. "High-fidelity audio compression with improved rvqgan." Advances in Neural Information Processing Systems 36 (2023): 27980-27993.](https://dl.acm.org/doi/10.5555/3666122.3667336)
|
| 187 |
+
|
| 188 |
+
[3] [DΓ©fossez, Alexandre, et al. "High fidelity neural audio compression." arXiv preprint arXiv:2210.13438 (2022).](https://arxiv.org/abs/2210.13438)
|
| 189 |
+
|
| 190 |
+
[4] [DΓ©fossez, Alexandre, et al. "Moshi: a speech-text foundation model for real-time dialogue." arXiv preprint arXiv:2410.00037 (2024).](https://arxiv.org/abs/2410.00037)
|
| 191 |
+
|
| 192 |
+
[5] [Liu, Haohe, et al. "Semanticodec: An ultra low bitrate semantic audio codec for general sound." IEEE Journal of Selected Topics in Signal Processing (2024).](https://ieeexplore.ieee.org/document/10768970)
|
| 193 |
+
|
| 194 |
+
[6] [Siuzdak, Hubert, Florian GrΓΆtschla, and Luca A. LanzendΓΆrfer. "Snac: Multi-scale neural audio codec." arXiv preprint arXiv:2410.14411 (2024).](https://arxiv.org/abs/2410.14411)
|
| 195 |
+
|
| 196 |
+
[7] [Ji, Shengpeng, et al. "Wavtokenizer: an efficient acoustic discrete codec tokenizer for audio language modeling." arXiv preprint arXiv:2408.16532 (2024).](https://arxiv.org/abs/2408.16532)
|
| 197 |
+
|
| 198 |
+
[8] [Tjandra, Andros, et al. "Meta audiobox aesthetics: Unified automatic quality assessment for speech, music, and sound." arXiv preprint arXiv:2502.05139 (2025).](https://arxiv.org/abs/2502.05139)
|
| 199 |
+
|
| 200 |
+
[9] [Ye, Zhen, et al. "Llasa: Scaling Train-Time and Inference-Time Compute for Llama-based Speech Synthesis." arXiv preprint arXiv:2502.04128 (2025).](https://arxiv.org/abs/2502.04128)
|
| 201 |
+
|
| 202 |
+
[10] [Gong, Yitian, et al. "XY-Tokenizer: Mitigating the Semantic-Acoustic Conflict in Low-Bitrate Speech Codecs." arXiv preprint arXiv:2506.23325 (2025).](https://arxiv.org/abs/2506.23325)
|
| 203 |
+
|
| 204 |
+
[11] [Xu, Yaoxun, et al. "MuCodec: Ultra Low-Bitrate Music Codec." arXiv preprint arXiv:2409.13216 (2024).](https://arxiv.org/abs/2409.13216)
|
| 205 |
+
|
| 206 |
+
[12] [Welker, Simon, et al. "FlowDec: A flow-based full-band general audio codec with high perceptual quality." arXiv preprint arXiv:2503.01485 (2025).](https://arxiv.org/abs/2503.01485)
|
| 207 |
+
|
| 208 |
+
[13] [Du, Zhihao, et al. "Cosyvoice 2: Scalable streaming speech synthesis with large language models." arXiv preprint arXiv:2412.10117 (2024).](https://arxiv.org/abs/2412.10117)
|
| 209 |
+
|
| 210 |
+
[14] [Zhang, Xin, et al. "Speechtokenizer: Unified speech tokenizer for speech large language models." arXiv preprint arXiv:2308.16692 (2023).](https://arxiv.org/abs/2308.16692)
|
| 211 |
+
|
| 212 |
+
[15] [Anastassiou, Philip, et al. "Seed-tts: A family of high-quality versatile speech generation models." arXiv preprint arXiv:2406.02430 (2024).](https://arxiv.org/abs/2406.02430)
|
acoustic_encoder.onnx
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:9fbc3a4c81c7753ace690104b320d9ef41eababc50196084a7b2c3bd2e291f16
|
| 3 |
+
size 205546480
|
fp16/acoustic_encoder.onnx
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:e24702e1a492d619fe7d1fe0c7cd3d530eba8144f5da826630e4dd97fec1b5fc
|
| 3 |
+
size 295846
|
fp16/acoustic_encoder.onnx.data
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b3725792aa9cc9ef9779955a648c87444f3d700a067c7fdd68cf006e26992073
|
| 3 |
+
size 102615039
|
fp16/higgs_decoder.onnx
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:f2e1ba8ede642099a4151d0d0762eebf9ba996a5821a2205005afc0a2e4c820a
|
| 3 |
+
size 308494
|
fp16/higgs_decoder.onnx.data
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:5be7ff51d117dd1cd001b87ec6e6e93f61cbe923355c50841a15fcaf19f64a19
|
| 3 |
+
size 43100160
|
fp16/model_config.json
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"type": "onnxmodel",
|
| 3 |
+
"config": {
|
| 4 |
+
"model_path": "D:\\Projects\\olive-recipes\\OmniVoice\\higgs\\models",
|
| 5 |
+
"onnx_file_name": "higgs_decoder.onnx",
|
| 6 |
+
"inference_settings": null,
|
| 7 |
+
"use_ort_extensions": false,
|
| 8 |
+
"external_initializers_file_name": null,
|
| 9 |
+
"constant_inputs_file_name": null,
|
| 10 |
+
"model_attributes": null
|
| 11 |
+
}
|
| 12 |
+
}
|
fp16/quantizer_encoder.onnx
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:3c1fd5d644b67ef532022f5f9558a6a30b495be92013918d33ce2f6be3d8f87c
|
| 3 |
+
size 6091791
|
fp16/semantic_encoder.onnx
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:c24e3d4de75911dcb25adf3a993c9fd5689dfb4c97df02dcc82e58ab82ee30d7
|
| 3 |
+
size 334295
|
fp16/semantic_encoder.onnx.data
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:90080ded4fe1e847a9b924feea365ad2e9c04fa93569d34e6d6fa7218ee9a238
|
| 3 |
+
size 218235902
|
higgs_audio_tokenizer_architecture.png
ADDED
|
Git LFS Details
|
higgs_decoder.onnx
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:601a69b103986d47a91c21bcffc9c8eef8aa462d0267256efff75033fa25cdff
|
| 3 |
+
size 86500102
|
higgs_inference.py
ADDED
|
@@ -0,0 +1,392 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Standalone Higgs Audio V2 Tokenizer β ONNX inference.
|
| 3 |
+
|
| 4 |
+
Encodes audio to discrete codec codes and decodes codes back to audio,
|
| 5 |
+
using the four exported ONNX sub-models:
|
| 6 |
+
|
| 7 |
+
acoustic_encoder.onnx β DAC encoder: (1,1,T_24k) β (1,256,T_frames)
|
| 8 |
+
semantic_encoder.onnx β HuBERT encoder: (1,T_16k) β (1,768,T_frames)
|
| 9 |
+
quantizer_encoder.onnx β RVQ encode: (1,256,T)+(1,768,T) β (8,1,T)
|
| 10 |
+
higgs_decoder.onnx β DAC decode: (8,1,T) β (1,1,T_24k)
|
| 11 |
+
|
| 12 |
+
No PyTorch, no transformers required at runtime β only onnxruntime.
|
| 13 |
+
|
| 14 |
+
Usage:
|
| 15 |
+
# Round-trip encode β decode (sanity check)
|
| 16 |
+
python higgs_inference.py --input speech.wav --output reconstructed.wav
|
| 17 |
+
|
| 18 |
+
# Encode only β save codes as .npy
|
| 19 |
+
python higgs_inference.py --input speech.wav --encode-only --codes-out codes.npy
|
| 20 |
+
|
| 21 |
+
# Decode only from saved codes
|
| 22 |
+
python higgs_inference.py --decode-only --codes-in codes.npy --output decoded.wav
|
| 23 |
+
|
| 24 |
+
# Use a different models directory
|
| 25 |
+
python higgs_inference.py --models-dir path/to/higgs/models --input speech.wav --output out.wav
|
| 26 |
+
"""
|
| 27 |
+
|
| 28 |
+
import argparse
|
| 29 |
+
import sys
|
| 30 |
+
from pathlib import Path
|
| 31 |
+
|
| 32 |
+
import numpy as np
|
| 33 |
+
|
| 34 |
+
# ---------------------------------------------------------------------------
|
| 35 |
+
# Constants (from audio_tokenizer/config.json)
|
| 36 |
+
# ---------------------------------------------------------------------------
|
| 37 |
+
SR_24K = 24_000 # acoustic DAC sample rate
|
| 38 |
+
SR_16K = 16_000 # HuBERT semantic sample rate
|
| 39 |
+
HOP_LENGTH = 960 # DAC downsampling factor: product of [8,5,4,2,3]
|
| 40 |
+
D_ACOUSTIC = 256 # acoustic encoder output channels
|
| 41 |
+
D_SEMANTIC = 768 # semantic encoder output channels
|
| 42 |
+
N_CODEBOOKS = 8 # RVQ codebooks
|
| 43 |
+
CODEBOOK_SIZE = 1024 # entries per codebook
|
| 44 |
+
DEFAULT_MODELS_DIR = Path(__file__).parent / "higgs" / "models"
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
# =============================================================================
|
| 48 |
+
# Audio I/O
|
| 49 |
+
# =============================================================================
|
| 50 |
+
|
| 51 |
+
def load_wav(path: str, target_sr: int) -> np.ndarray:
|
| 52 |
+
"""Load an audio file, resample to target_sr, mix to mono.
|
| 53 |
+
|
| 54 |
+
Returns float32 array in [-1, 1], shape (T,).
|
| 55 |
+
Tries torchaudio first (accurate), falls back to scipy.
|
| 56 |
+
"""
|
| 57 |
+
path = str(path)
|
| 58 |
+
|
| 59 |
+
# --- torchaudio (preferred) ---
|
| 60 |
+
try:
|
| 61 |
+
import torchaudio, torch
|
| 62 |
+
wav, sr = torchaudio.load(path)
|
| 63 |
+
if sr != target_sr:
|
| 64 |
+
wav = torchaudio.functional.resample(wav, sr, target_sr)
|
| 65 |
+
if wav.shape[0] > 1:
|
| 66 |
+
wav = wav.mean(0, keepdim=True)
|
| 67 |
+
return wav.squeeze(0).numpy().astype(np.float32)
|
| 68 |
+
except ImportError:
|
| 69 |
+
pass
|
| 70 |
+
|
| 71 |
+
# --- scipy fallback ---
|
| 72 |
+
from scipy.io import wavfile
|
| 73 |
+
from scipy.signal import resample_poly
|
| 74 |
+
from math import gcd
|
| 75 |
+
sr, data = wavfile.read(path)
|
| 76 |
+
if data.dtype == np.int16:
|
| 77 |
+
data = data.astype(np.float32) / 32768.0
|
| 78 |
+
elif data.dtype == np.int32:
|
| 79 |
+
data = data.astype(np.float32) / 2147483648.0
|
| 80 |
+
elif data.dtype != np.float32:
|
| 81 |
+
data = data.astype(np.float32)
|
| 82 |
+
if data.ndim > 1:
|
| 83 |
+
data = data.mean(axis=1)
|
| 84 |
+
if sr != target_sr:
|
| 85 |
+
g = gcd(target_sr, sr)
|
| 86 |
+
data = resample_poly(data, target_sr // g, sr // g).astype(np.float32)
|
| 87 |
+
return data
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
def save_wav(path: str, waveform: np.ndarray, sr: int = SR_24K):
|
| 91 |
+
"""Save float32 numpy waveform as 16-bit PCM WAV."""
|
| 92 |
+
path = str(path)
|
| 93 |
+
try:
|
| 94 |
+
import soundfile as sf
|
| 95 |
+
sf.write(path, waveform, sr, subtype="PCM_16")
|
| 96 |
+
return
|
| 97 |
+
except ImportError:
|
| 98 |
+
pass
|
| 99 |
+
from scipy.io import wavfile
|
| 100 |
+
pcm = np.clip(waveform, -1.0, 1.0)
|
| 101 |
+
wavfile.write(path, sr, (pcm * 32767).astype(np.int16))
|
| 102 |
+
|
| 103 |
+
|
| 104 |
+
# =============================================================================
|
| 105 |
+
# ONNX session loader
|
| 106 |
+
# =============================================================================
|
| 107 |
+
|
| 108 |
+
class HiggsOnnxSessions:
|
| 109 |
+
"""Holds the four Higgs ONNX InferenceSession objects."""
|
| 110 |
+
|
| 111 |
+
MODEL_FILES = {
|
| 112 |
+
"acoustic_encoder": "acoustic_encoder.onnx",
|
| 113 |
+
"semantic_encoder": "semantic_encoder.onnx",
|
| 114 |
+
"quantizer_encoder": "quantizer_encoder.onnx",
|
| 115 |
+
"higgs_decoder": "higgs_decoder.onnx",
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
def __init__(self, models_dir: str, provider: str = "CPUExecutionProvider"):
|
| 119 |
+
import onnxruntime as ort
|
| 120 |
+
models_dir = Path(models_dir)
|
| 121 |
+
opts = ort.SessionOptions()
|
| 122 |
+
opts.log_severity_level = 3 # suppress INFO / WARNING noise
|
| 123 |
+
|
| 124 |
+
self.sessions = {}
|
| 125 |
+
for key, filename in self.MODEL_FILES.items():
|
| 126 |
+
p = models_dir / filename
|
| 127 |
+
if not p.exists():
|
| 128 |
+
raise FileNotFoundError(
|
| 129 |
+
f"Missing: {p}\n"
|
| 130 |
+
f"Export Higgs models first:\n"
|
| 131 |
+
f" cd OmniVoice && python optimize.py --higgs-only"
|
| 132 |
+
)
|
| 133 |
+
self.sessions[key] = ort.InferenceSession(
|
| 134 |
+
str(p), sess_options=opts, providers=[provider]
|
| 135 |
+
)
|
| 136 |
+
print(f"Loaded {len(self.sessions)} Higgs ONNX sessions from {models_dir}")
|
| 137 |
+
|
| 138 |
+
def __getitem__(self, key):
|
| 139 |
+
return self.sessions[key]
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
# =============================================================================
|
| 143 |
+
# dtype helper β cast float32 inputs to whatever the ONNX session expects
|
| 144 |
+
# =============================================================================
|
| 145 |
+
|
| 146 |
+
_ORT_TO_NP = {
|
| 147 |
+
"tensor(float16)": np.float16,
|
| 148 |
+
"tensor(float)": np.float32,
|
| 149 |
+
"tensor(double)": np.float64,
|
| 150 |
+
"tensor(int64)": np.int64,
|
| 151 |
+
"tensor(int32)": np.int32,
|
| 152 |
+
}
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
def _cast_feed(feed: dict, sess) -> dict:
|
| 156 |
+
"""Auto-cast numpy arrays to the dtype expected by the ONNX session.
|
| 157 |
+
|
| 158 |
+
OnnxFloatToFloat16 converts all float inputs/outputs to float16. Feeding
|
| 159 |
+
float32 to such a model raises INVALID_ARGUMENT. This inspects the session
|
| 160 |
+
input metadata and casts each value to the declared type.
|
| 161 |
+
"""
|
| 162 |
+
type_map = {inp.name: _ORT_TO_NP.get(inp.type) for inp in sess.get_inputs()}
|
| 163 |
+
out = {}
|
| 164 |
+
for k, v in feed.items():
|
| 165 |
+
tgt = type_map.get(k)
|
| 166 |
+
if tgt is not None and isinstance(v, np.ndarray) and v.dtype != tgt:
|
| 167 |
+
v = v.astype(tgt)
|
| 168 |
+
out[k] = v
|
| 169 |
+
return out
|
| 170 |
+
|
| 171 |
+
|
| 172 |
+
# =============================================================================
|
| 173 |
+
# Encode: audio β codec codes
|
| 174 |
+
# =============================================================================
|
| 175 |
+
|
| 176 |
+
def encode(sessions: HiggsOnnxSessions, wav_path: str) -> np.ndarray:
|
| 177 |
+
"""Encode an audio file to RVQ codec codes.
|
| 178 |
+
|
| 179 |
+
Pipeline:
|
| 180 |
+
wav_path (24 kHz) β acoustic_encoder β (1, 256, T_a)
|
| 181 |
+
wav_path (16 kHz) β semantic_encoder β (1, 768, T_s)
|
| 182 |
+
align T_s β T_a (linear interpolation along time axis)
|
| 183 |
+
concat channels β quantizer_encoder β (8, 1, T_a) int64
|
| 184 |
+
|
| 185 |
+
Returns:
|
| 186 |
+
codes: np.ndarray shape (8, 1, T_a) dtype int64
|
| 187 |
+
T_a is the number of codec frames (25 per second of 24 kHz audio).
|
| 188 |
+
"""
|
| 189 |
+
# 1. Load audio at both sample rates
|
| 190 |
+
wav24 = load_wav(wav_path, SR_24K) # (T_24k,)
|
| 191 |
+
wav16 = load_wav(wav_path, SR_16K) # (T_16k,)
|
| 192 |
+
|
| 193 |
+
dur = len(wav24) / SR_24K
|
| 194 |
+
print(f" Audio: {dur:.2f}s "
|
| 195 |
+
f"({len(wav24)} samples @ {SR_24K} Hz, "
|
| 196 |
+
f"{len(wav16)} samples @ {SR_16K} Hz)")
|
| 197 |
+
|
| 198 |
+
# 2. Acoustic encoder β (1, 256, T_a)
|
| 199 |
+
waveform_24k = wav24[None, None, :] # (1, 1, T_24k)
|
| 200 |
+
_ae_sess = sessions["acoustic_encoder"]
|
| 201 |
+
acoustic_feat = _ae_sess.run(
|
| 202 |
+
["acoustic_features"],
|
| 203 |
+
_cast_feed({"waveform_24k": waveform_24k}, _ae_sess)
|
| 204 |
+
)[0] # (1, 256, T_a)
|
| 205 |
+
T_a = acoustic_feat.shape[2]
|
| 206 |
+
print(f" acoustic_encoder β {acoustic_feat.shape} ({T_a} frames, {T_a/dur:.1f} fps)")
|
| 207 |
+
|
| 208 |
+
# 3. Semantic encoder β (1, 768, T_s)
|
| 209 |
+
waveform_16k = wav16[None, :] # (1, T_16k)
|
| 210 |
+
_se_sess = sessions["semantic_encoder"]
|
| 211 |
+
semantic_feat = _se_sess.run(
|
| 212 |
+
["semantic_features"],
|
| 213 |
+
_cast_feed({"waveform_16k": waveform_16k}, _se_sess)
|
| 214 |
+
)[0] # (1, 768, T_s)
|
| 215 |
+
T_s = semantic_feat.shape[2]
|
| 216 |
+
print(f" semantic_encoder β {semantic_feat.shape} ({T_s} frames, {T_s/dur:.1f} fps)")
|
| 217 |
+
|
| 218 |
+
# 4. Frame alignment check
|
| 219 |
+
# The fixed semantic_encoder wrapper applies semantic_downsample_factor=2 and
|
| 220 |
+
# the (160,160) padding internally, matching _extract_semantic_features() exactly.
|
| 221 |
+
# T_s == T_a naturally for typical audio. Trim on rare off-by-one edge cases.
|
| 222 |
+
if T_s != T_a:
|
| 223 |
+
T = min(T_a, T_s)
|
| 224 |
+
acoustic_feat = acoustic_feat[:, :, :T]
|
| 225 |
+
semantic_feat = semantic_feat[:, :, :T]
|
| 226 |
+
print(f" [warn] T_a={T_a} != T_s={T_s}, trimmed both to T={T}")
|
| 227 |
+
|
| 228 |
+
# 5. Quantizer encoder β (8, 1, T_a) int64
|
| 229 |
+
_qe_sess = sessions["quantizer_encoder"]
|
| 230 |
+
codes = _qe_sess.run(
|
| 231 |
+
["codes"],
|
| 232 |
+
_cast_feed({
|
| 233 |
+
"acoustic_features": acoustic_feat, # (1, 256, T_a)
|
| 234 |
+
"semantic_features": semantic_feat, # (1, 768, T_a)
|
| 235 |
+
}, _qe_sess)
|
| 236 |
+
)[0] # (8, 1, T_a)
|
| 237 |
+
print(f" quantizer_encoder β {codes.shape} "
|
| 238 |
+
f"({N_CODEBOOKS} codebooks Γ {T_a} frames) "
|
| 239 |
+
f"value range [{codes.min()}, {codes.max()}]")
|
| 240 |
+
|
| 241 |
+
return codes
|
| 242 |
+
|
| 243 |
+
|
| 244 |
+
# =============================================================================
|
| 245 |
+
# Decode: codec codes β audio
|
| 246 |
+
# =============================================================================
|
| 247 |
+
|
| 248 |
+
def decode(sessions: HiggsOnnxSessions, codes: np.ndarray) -> np.ndarray:
|
| 249 |
+
"""Decode RVQ codec codes back to a waveform.
|
| 250 |
+
|
| 251 |
+
Args:
|
| 252 |
+
codes: np.ndarray shape (8, 1, T_frames) dtype int64
|
| 253 |
+
|
| 254 |
+
Returns:
|
| 255 |
+
waveform: np.ndarray shape (T_samples,) float32 at 24 kHz
|
| 256 |
+
"""
|
| 257 |
+
if codes.ndim != 3 or codes.shape[0] != N_CODEBOOKS:
|
| 258 |
+
raise ValueError(
|
| 259 |
+
f"codes must have shape (8, 1, T_frames), got {codes.shape}"
|
| 260 |
+
)
|
| 261 |
+
if codes.dtype != np.int64:
|
| 262 |
+
codes = codes.astype(np.int64)
|
| 263 |
+
|
| 264 |
+
T_frames = codes.shape[2]
|
| 265 |
+
expected_dur = T_frames * HOP_LENGTH / SR_24K
|
| 266 |
+
|
| 267 |
+
_hd_sess = sessions["higgs_decoder"]
|
| 268 |
+
waveform = _hd_sess.run(
|
| 269 |
+
["waveform_24k"],
|
| 270 |
+
_cast_feed({"codes": codes}, _hd_sess)
|
| 271 |
+
)[0] # (1, 1, T_samples)
|
| 272 |
+
|
| 273 |
+
waveform = waveform.squeeze() # (T_samples,)
|
| 274 |
+
actual_dur = len(waveform) / SR_24K
|
| 275 |
+
print(f" higgs_decoder β {waveform.shape} "
|
| 276 |
+
f"({actual_dur:.2f}s expected {expected_dur:.2f}s)")
|
| 277 |
+
|
| 278 |
+
return waveform
|
| 279 |
+
|
| 280 |
+
|
| 281 |
+
# =============================================================================
|
| 282 |
+
# Convenience: round-trip encode + decode
|
| 283 |
+
# =============================================================================
|
| 284 |
+
|
| 285 |
+
def encode_decode(sessions: HiggsOnnxSessions, wav_path: str) -> tuple:
|
| 286 |
+
"""Encode audio to codes then decode back to waveform.
|
| 287 |
+
|
| 288 |
+
Returns:
|
| 289 |
+
codes: np.ndarray (8, 1, T_frames) int64
|
| 290 |
+
waveform: np.ndarray (T_samples,) float32
|
| 291 |
+
"""
|
| 292 |
+
print("[Encode]")
|
| 293 |
+
codes = encode(sessions, wav_path)
|
| 294 |
+
print("[Decode]")
|
| 295 |
+
waveform = decode(sessions, codes)
|
| 296 |
+
return codes, waveform
|
| 297 |
+
|
| 298 |
+
|
| 299 |
+
# =============================================================================
|
| 300 |
+
# CLI
|
| 301 |
+
# =============================================================================
|
| 302 |
+
|
| 303 |
+
def main():
|
| 304 |
+
parser = argparse.ArgumentParser(
|
| 305 |
+
description="Higgs Audio V2 Tokenizer β standalone ONNX encode/decode"
|
| 306 |
+
)
|
| 307 |
+
parser.add_argument(
|
| 308 |
+
"--models-dir", default=str(DEFAULT_MODELS_DIR),
|
| 309 |
+
help=f"Higgs ONNX models directory (default: {DEFAULT_MODELS_DIR})"
|
| 310 |
+
)
|
| 311 |
+
parser.add_argument(
|
| 312 |
+
"--input", "-i", default=None,
|
| 313 |
+
help="Input audio file to encode (.wav or any format torchaudio/scipy supports)"
|
| 314 |
+
)
|
| 315 |
+
parser.add_argument(
|
| 316 |
+
"--output", "-o", default="output.wav",
|
| 317 |
+
help="Output WAV file for decoded audio (default: output.wav)"
|
| 318 |
+
)
|
| 319 |
+
parser.add_argument(
|
| 320 |
+
"--encode-only", action="store_true",
|
| 321 |
+
help="Only encode β save codes to --codes-out, do not decode"
|
| 322 |
+
)
|
| 323 |
+
parser.add_argument(
|
| 324 |
+
"--decode-only", action="store_true",
|
| 325 |
+
help="Only decode β load codes from --codes-in, skip encoding"
|
| 326 |
+
)
|
| 327 |
+
parser.add_argument(
|
| 328 |
+
"--codes-out", default="codes.npy",
|
| 329 |
+
help="Path to save encoded codes as .npy (default: codes.npy)"
|
| 330 |
+
)
|
| 331 |
+
parser.add_argument(
|
| 332 |
+
"--codes-in", default=None,
|
| 333 |
+
help="Path to load codes .npy for --decode-only mode"
|
| 334 |
+
)
|
| 335 |
+
parser.add_argument(
|
| 336 |
+
"--cuda", action="store_true",
|
| 337 |
+
help="Use CUDAExecutionProvider instead of CPU"
|
| 338 |
+
)
|
| 339 |
+
args = parser.parse_args()
|
| 340 |
+
|
| 341 |
+
provider = "CUDAExecutionProvider" if args.cuda else "CPUExecutionProvider"
|
| 342 |
+
|
| 343 |
+
# Validate argument combinations
|
| 344 |
+
if args.encode_only and args.decode_only:
|
| 345 |
+
parser.error("--encode-only and --decode-only are mutually exclusive")
|
| 346 |
+
if not args.decode_only and args.input is None:
|
| 347 |
+
parser.error("--input is required unless --decode-only is used")
|
| 348 |
+
if args.decode_only and args.codes_in is None:
|
| 349 |
+
parser.error("--codes-in is required when using --decode-only")
|
| 350 |
+
|
| 351 |
+
# Load ONNX sessions
|
| 352 |
+
sessions = HiggsOnnxSessions(args.models_dir, provider)
|
| 353 |
+
|
| 354 |
+
# -------------------------------------------------------------------------
|
| 355 |
+
if args.encode_only:
|
| 356 |
+
print(f"\nEncoding: {args.input}")
|
| 357 |
+
codes = encode(sessions, args.input)
|
| 358 |
+
np.save(args.codes_out, codes)
|
| 359 |
+
print(f"\nSaved codes β {args.codes_out} shape={codes.shape} dtype={codes.dtype}")
|
| 360 |
+
|
| 361 |
+
# -------------------------------------------------------------------------
|
| 362 |
+
elif args.decode_only:
|
| 363 |
+
print(f"\nLoading codes from: {args.codes_in}")
|
| 364 |
+
codes = np.load(args.codes_in)
|
| 365 |
+
print(f" codes shape={codes.shape} dtype={codes.dtype}")
|
| 366 |
+
print(f"\nDecoding...")
|
| 367 |
+
waveform = decode(sessions, codes)
|
| 368 |
+
save_wav(args.output, waveform, SR_24K)
|
| 369 |
+
print(f"Saved WAV β {args.output} ({len(waveform)/SR_24K:.2f}s @ {SR_24K} Hz)")
|
| 370 |
+
|
| 371 |
+
# -------------------------------------------------------------------------
|
| 372 |
+
else:
|
| 373 |
+
# Full round-trip
|
| 374 |
+
print(f"\nRound-trip encode β decode")
|
| 375 |
+
print(f" Input : {args.input}")
|
| 376 |
+
print(f" Output: {args.output}")
|
| 377 |
+
codes, waveform = encode_decode(sessions, args.input)
|
| 378 |
+
|
| 379 |
+
# Optionally save codes
|
| 380 |
+
np.save(args.codes_out, codes)
|
| 381 |
+
print(f"\nSaved codes β {args.codes_out}")
|
| 382 |
+
|
| 383 |
+
save_wav(args.output, waveform, SR_24K)
|
| 384 |
+
dur_in = len(load_wav(args.input, SR_24K)) / SR_24K
|
| 385 |
+
dur_out = len(waveform) / SR_24K
|
| 386 |
+
print(f"Saved WAV β {args.output} ({dur_out:.2f}s, input was {dur_in:.2f}s)")
|
| 387 |
+
print(f"\nReconstruction note: codec compression (RVQ, 8 codebooks Γ 1024 entries)")
|
| 388 |
+
print(f"at 25 fps introduces mild quality loss β this is expected.")
|
| 389 |
+
|
| 390 |
+
|
| 391 |
+
if __name__ == "__main__":
|
| 392 |
+
main()
|
model_config.json
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"type": "onnxmodel",
|
| 3 |
+
"config": {
|
| 4 |
+
"model_path": "D:\\Projects\\olive-recipes\\OmniVoice\\higgs\\models\\higgs_decoder.onnx",
|
| 5 |
+
"onnx_file_name": null,
|
| 6 |
+
"inference_settings": null,
|
| 7 |
+
"use_ort_extensions": false,
|
| 8 |
+
"external_initializers_file_name": null,
|
| 9 |
+
"constant_inputs_file_name": null,
|
| 10 |
+
"model_attributes": null
|
| 11 |
+
}
|
| 12 |
+
}
|
quantizer_encoder.onnx
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:4592311271a745da259513a33ae248f12dabc811e7942fcc0e0635da8b02ec37
|
| 3 |
+
size 12131293
|
semantic_encoder.onnx
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:1e3be47442600c7e5a29faa39b7f73b940243974848089b2ebe9717f83c1c7df
|
| 3 |
+
size 436736856
|