Add verified FP32 ONNX Runtime export
Browse filesAdds dynamic-length ONNX graphs, a torch-free runner, reproducible exporter, provenance, parity reports, checksums, and updated documentation.
- CHANGELOG.md +9 -2
- README.md +28 -1
- docs/EXPORTS.md +27 -7
- onnx/README.md +120 -0
- onnx/SOURCE.json +16 -0
- onnx/checksums.sha256 +8 -0
- onnx/decode.onnx +3 -0
- onnx/duration.onnx +3 -0
- onnx/export_onnx.py +261 -0
- onnx/inference_onnx.py +229 -0
- onnx/parity_report.json +31 -0
- onnx/requirements.txt +7 -0
- release_manifest.json +126 -35
CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
| 1 |
-
# Changelog
|
| 2 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
## 2.0.0 - 2026-07-24
|
| 4 |
|
| 5 |
- Release Inflect-Micro-v2 as a complete 24 kHz English text-to-waveform package.
|
|
|
|
| 1 |
+
# Changelog
|
| 2 |
+
|
| 3 |
+
## 2.1.0 - 2026-07-25
|
| 4 |
+
|
| 5 |
+
- Add verified FP32 ONNX graphs with dynamic text and waveform lengths.
|
| 6 |
+
- Add a torch-free ONNX Runtime API and CLI with CPU, CUDA, and DirectML provider selection.
|
| 7 |
+
- Add a reproducible exporter, checkpoint provenance, parity reports, and SHA-256 checksums.
|
| 8 |
+
- Credit Robert Bak's original ONNX conversion and browser implementation.
|
| 9 |
+
|
| 10 |
## 2.0.0 - 2026-07-24
|
| 11 |
|
| 12 |
- Release Inflect-Micro-v2 as a complete 24 kHz English text-to-waveform package.
|
README.md
CHANGED
|
@@ -14,6 +14,8 @@ tags:
|
|
| 14 |
- edge-ai
|
| 15 |
- small-model
|
| 16 |
- pytorch
|
|
|
|
|
|
|
| 17 |
- vits
|
| 18 |
- 24khz
|
| 19 |
thumbnail: assets/inflect-v2-repository-hero.png
|
|
@@ -171,7 +173,9 @@ equal-work pooled across their two tested voices.
|
|
| 171 |
Because Inflect uses the larger 100-prompt steady-state run while comparator
|
| 172 |
rows use the shorter 50-prompt confirmation pass, this table is deployment
|
| 173 |
context rather than a perfectly matched speed leaderboard. Several comparators
|
| 174 |
-
also use optimized ONNX runtimes while
|
|
|
|
|
|
|
| 175 |
|
| 176 |
</details>
|
| 177 |
|
|
@@ -257,6 +261,28 @@ sample_rate, waveform = tts.synthesize("The complete model runs locally.")
|
|
| 257 |
|
| 258 |
The result is a 24 kHz mono `float32` waveform. Long input is split at punctuation-aware boundaries, synthesized chunk by chunk, and joined with controlled pauses.
|
| 259 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 260 |
## Release profile
|
| 261 |
|
| 262 |
| **Local runtime** | **Long-text handling** |
|
|
@@ -317,6 +343,7 @@ This release is inference-first. New-voice and new-language adaptation are **not
|
|
| 317 |
| `inference.py` | Public Python API and CLI |
|
| 318 |
| `inflect_vits_frontend.py` | English normalization, phonemization, and punctuation frontend |
|
| 319 |
| `runtime/` | Self-contained model implementation |
|
|
|
|
| 320 |
| `samples/` | Held-out example generations |
|
| 321 |
| `evaluation/final/` | Frozen benchmark prompts, reports, and protocol artifacts |
|
| 322 |
| `docs/` | API, deployment, evaluation, adaptation, and export documentation |
|
|
|
|
| 14 |
- edge-ai
|
| 15 |
- small-model
|
| 16 |
- pytorch
|
| 17 |
+
- onnx
|
| 18 |
+
- onnxruntime
|
| 19 |
- vits
|
| 20 |
- 24khz
|
| 21 |
thumbnail: assets/inflect-v2-repository-hero.png
|
|
|
|
| 173 |
Because Inflect uses the larger 100-prompt steady-state run while comparator
|
| 174 |
rows use the shorter 50-prompt confirmation pass, this table is deployment
|
| 175 |
context rather than a perfectly matched speed leaderboard. Several comparators
|
| 176 |
+
also use optimized ONNX runtimes, while the published Inflect benchmark above
|
| 177 |
+
uses the canonical PyTorch runtime. The separately released Inflect ONNX path
|
| 178 |
+
has not been substituted into those benchmark numbers.
|
| 179 |
|
| 180 |
</details>
|
| 181 |
|
|
|
|
| 261 |
|
| 262 |
The result is a 24 kHz mono `float32` waveform. Long input is split at punctuation-aware boundaries, synthesized chunk by chunk, and joined with controlled pauses.
|
| 263 |
|
| 264 |
+
### ONNX Runtime
|
| 265 |
+
|
| 266 |
+
A verified FP32 ONNX export is included under [`onnx/`](https://huggingface.co/owensong/Inflect-Micro-v2/tree/main/onnx).
|
| 267 |
+
It supports dynamic lengths, CPU/CUDA/DirectML provider selection, deterministic
|
| 268 |
+
seeds, and the same long-text wrapper without importing PyTorch:
|
| 269 |
+
|
| 270 |
+
```bash
|
| 271 |
+
python -m pip install -r onnx/requirements.txt
|
| 272 |
+
python onnx/inference_onnx.py \
|
| 273 |
+
--text "The complete model now runs through ONNX Runtime." \
|
| 274 |
+
--output sample-onnx.wav \
|
| 275 |
+
--provider cpu \
|
| 276 |
+
--seed 7
|
| 277 |
+
```
|
| 278 |
+
|
| 279 |
+
The neural model is split into `duration.onnx` and `decode.onnx`; together they
|
| 280 |
+
contain the complete learned text-to-waveform path. The English eSpeak-ng
|
| 281 |
+
frontend remains CPU-side code. See the
|
| 282 |
+
[`ONNX guide`](https://huggingface.co/owensong/Inflect-Micro-v2/blob/main/onnx/README.md)
|
| 283 |
+
for graph contracts, provenance, parity measurements, browser deployment, and
|
| 284 |
+
re-export instructions.
|
| 285 |
+
|
| 286 |
## Release profile
|
| 287 |
|
| 288 |
| **Local runtime** | **Long-text handling** |
|
|
|
|
| 343 |
| `inference.py` | Public Python API and CLI |
|
| 344 |
| `inflect_vits_frontend.py` | English normalization, phonemization, and punctuation frontend |
|
| 345 |
| `runtime/` | Self-contained model implementation |
|
| 346 |
+
| `onnx/` | Verified FP32 ONNX graphs, torch-free runner, parity report, checksums, and exporter |
|
| 347 |
| `samples/` | Held-out example generations |
|
| 348 |
| `evaluation/final/` | Frozen benchmark prompts, reports, and protocol artifacts |
|
| 349 |
| `docs/` | API, deployment, evaluation, adaptation, and export documentation |
|
docs/EXPORTS.md
CHANGED
|
@@ -6,19 +6,38 @@
|
|
| 6 |
| --- | --- | --- |
|
| 7 |
| PyTorch FP32 | Supported | Canonical weights and the fully tested runtime. |
|
| 8 |
| PyTorch FP16/BF16 | Not released | Smaller in memory, but not validated for waveform quality or CPU compatibility. |
|
| 9 |
-
| ONNX |
|
| 10 |
| INT8 / INT4 | Not released | Naive weight quantization can audibly damage the integrated waveform decoder. |
|
| 11 |
| GGUF | Not applicable today | GGUF targets transformer/LLM runtimes and is not a drop-in container for this VITS-family convolutional waveform model. |
|
| 12 |
| Core ML / TFLite | Not released | Requires separate conversion and target-device validation. |
|
| 13 |
|
| 14 |
-
##
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
|
| 16 |
The model is already small: 37.53 MB for Micro and 15.97 MB for Nano. A format
|
| 17 |
is useful only if it is smaller or faster **and** preserves pronunciation,
|
| 18 |
stability, and waveform quality. An export that loads but produces degraded
|
| 19 |
speech is not release-ready.
|
| 20 |
|
| 21 |
-
The canonical `model.pth` remains the source of truth. Future
|
|
|
|
| 22 |
|
| 23 |
1. reproduce deterministic fixed-seed outputs within a declared tolerance;
|
| 24 |
2. pass matched semantic-WER and signal-diagnostic gates;
|
|
@@ -28,7 +47,8 @@ The canonical `model.pth` remains the source of truth. Future exports must:
|
|
| 28 |
|
| 29 |
## Practical deployment today
|
| 30 |
|
| 31 |
-
Use the
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
|
|
|
|
|
| 6 |
| --- | --- | --- |
|
| 7 |
| PyTorch FP32 | Supported | Canonical weights and the fully tested runtime. |
|
| 8 |
| PyTorch FP16/BF16 | Not released | Smaller in memory, but not validated for waveform quality or CPU compatibility. |
|
| 9 |
+
| ONNX FP32 | Supported | Verified dynamic-length graphs, torch-free Python runner, and reproducible exporter under `onnx/`. |
|
| 10 |
| INT8 / INT4 | Not released | Naive weight quantization can audibly damage the integrated waveform decoder. |
|
| 11 |
| GGUF | Not applicable today | GGUF targets transformer/LLM runtimes and is not a drop-in container for this VITS-family convolutional waveform model. |
|
| 12 |
| Core ML / TFLite | Not released | Requires separate conversion and target-device validation. |
|
| 13 |
|
| 14 |
+
## Supported ONNX package
|
| 15 |
+
|
| 16 |
+
The official ONNX package contains:
|
| 17 |
+
|
| 18 |
+
- `onnx/duration.onnx`: token sequence to aligned acoustic distribution;
|
| 19 |
+
- `onnx/decode.onnx`: aligned distribution and seeded noise to waveform;
|
| 20 |
+
- `onnx/inference_onnx.py`: ONNX Runtime API and CLI;
|
| 21 |
+
- `onnx/export_onnx.py`: reproducible export from the canonical checkpoint;
|
| 22 |
+
- machine-readable provenance, parity results, and SHA-256 checksums.
|
| 23 |
+
|
| 24 |
+
Dynamic text and waveform lengths are supported. The public wrapper implements
|
| 25 |
+
seeded latent sampling, speed and variation controls, punctuation-aware
|
| 26 |
+
long-text chunking, and CPU/CUDA/DirectML provider selection. eSpeak-ng remains
|
| 27 |
+
the non-neural English frontend and is not embedded in the ONNX graphs.
|
| 28 |
+
|
| 29 |
+
See [`onnx/README.md`](https://huggingface.co/owensong/Inflect-Micro-v2/blob/main/onnx/README.md)
|
| 30 |
+
for installation and verified parity measurements.
|
| 31 |
+
|
| 32 |
+
## Why only verified FP32 ships
|
| 33 |
|
| 34 |
The model is already small: 37.53 MB for Micro and 15.97 MB for Nano. A format
|
| 35 |
is useful only if it is smaller or faster **and** preserves pronunciation,
|
| 36 |
stability, and waveform quality. An export that loads but produces degraded
|
| 37 |
speech is not release-ready.
|
| 38 |
|
| 39 |
+
The canonical `model.pth` remains the source of truth. Future quantized or
|
| 40 |
+
platform-specific exports must:
|
| 41 |
|
| 42 |
1. reproduce deterministic fixed-seed outputs within a declared tolerance;
|
| 43 |
2. pass matched semantic-WER and signal-diagnostic gates;
|
|
|
|
| 47 |
|
| 48 |
## Practical deployment today
|
| 49 |
|
| 50 |
+
Use either the canonical PyTorch runtime or the verified FP32 ONNX Runtime
|
| 51 |
+
package and keep one engine instance loaded. Nano is the recommended
|
| 52 |
+
footprint-first deployment; Micro is the quality-first deployment. Choose ONNX
|
| 53 |
+
for C/C++ bindings, browser work, DirectML, or other ONNX Runtime execution
|
| 54 |
+
providers. Choose PyTorch when integrating with the original Python model code.
|
onnx/README.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Inflect-Micro-v2 ONNX
|
| 2 |
+
|
| 3 |
+
Official, verified FP32 ONNX Runtime export of
|
| 4 |
+
[Inflect-Micro-v2](https://huggingface.co/owensong/Inflect-Micro-v2).
|
| 5 |
+
The neural model is split into two graphs:
|
| 6 |
+
|
| 7 |
+
| File | Purpose | Size |
|
| 8 |
+
| --- | --- | ---: |
|
| 9 |
+
| `duration.onnx` | Text tokens to aligned acoustic distribution | 7.32 MB |
|
| 10 |
+
| `decode.onnx` | Acoustic distribution and seeded noise to 24 kHz waveform | 30.43 MB |
|
| 11 |
+
|
| 12 |
+
The complete ONNX neural weights are about **37.75 MB**. The original FP32
|
| 13 |
+
PyTorch checkpoint remains the canonical source of truth.
|
| 14 |
+
|
| 15 |
+
## Install
|
| 16 |
+
|
| 17 |
+
```bash
|
| 18 |
+
python -m pip install -r onnx/requirements.txt
|
| 19 |
+
```
|
| 20 |
+
|
| 21 |
+
ONNX Runtime CPU is installed by default. For another execution provider, use
|
| 22 |
+
the appropriate ONNX Runtime package for the target platform.
|
| 23 |
+
|
| 24 |
+
## Generate speech
|
| 25 |
+
|
| 26 |
+
From the repository root:
|
| 27 |
+
|
| 28 |
+
```bash
|
| 29 |
+
python onnx/inference_onnx.py \
|
| 30 |
+
--text "A compact voice can still sound clear and expressive." \
|
| 31 |
+
--output sample.wav \
|
| 32 |
+
--provider cpu \
|
| 33 |
+
--speed 1.0 \
|
| 34 |
+
--variation 0.667 \
|
| 35 |
+
--seed 7
|
| 36 |
+
```
|
| 37 |
+
|
| 38 |
+
Python:
|
| 39 |
+
|
| 40 |
+
```python
|
| 41 |
+
import sys
|
| 42 |
+
|
| 43 |
+
sys.path.insert(0, "onnx")
|
| 44 |
+
from inference_onnx import InflectONNX
|
| 45 |
+
|
| 46 |
+
tts = InflectONNX(".", provider="cpu")
|
| 47 |
+
sample_rate, waveform = tts.synthesize(
|
| 48 |
+
"Inflect runs through ONNX Runtime.",
|
| 49 |
+
speed=1.0,
|
| 50 |
+
variation=0.667,
|
| 51 |
+
seed=7,
|
| 52 |
+
)
|
| 53 |
+
```
|
| 54 |
+
|
| 55 |
+
Accepted provider aliases are `cpu`, `cuda`, and `directml`. The corresponding
|
| 56 |
+
provider must exist in the installed ONNX Runtime build.
|
| 57 |
+
|
| 58 |
+
## What the export includes
|
| 59 |
+
|
| 60 |
+
- Dynamic text and waveform lengths
|
| 61 |
+
- The duration predictor, acoustic generator, flow, and waveform decoder
|
| 62 |
+
- Seeded stochastic latent sampling in the Python wrapper
|
| 63 |
+
- The same punctuation-aware long-text chunking used by the PyTorch package
|
| 64 |
+
- 24 kHz mono `float32` waveform output
|
| 65 |
+
|
| 66 |
+
The English normalization and phonemization frontend remains Python code and
|
| 67 |
+
uses eSpeak-ng on the CPU. The ONNX files contain the learned neural graphs,
|
| 68 |
+
not eSpeak-ng itself.
|
| 69 |
+
|
| 70 |
+
## Verification
|
| 71 |
+
|
| 72 |
+
The packaged graphs pass:
|
| 73 |
+
|
| 74 |
+
- ONNX checker validation at opset 17
|
| 75 |
+
- Dynamic-length inference tests
|
| 76 |
+
- Short- and long-form end-to-end synthesis
|
| 77 |
+
- Same-seed determinism and different-seed variation checks
|
| 78 |
+
- Direct numerical comparison with the canonical PyTorch checkpoint
|
| 79 |
+
- Independent re-export comparison from the published `model.pth`
|
| 80 |
+
|
| 81 |
+
The direct PyTorch comparison measured a maximum absolute waveform error of
|
| 82 |
+
`1.7583e-05`, mean absolute error of `2.2595e-07`, and correlation above
|
| 83 |
+
`0.9999999999`. An independent re-export matched this package within
|
| 84 |
+
`1.0617e-07` maximum waveform error.
|
| 85 |
+
|
| 86 |
+
See [`parity_report.json`](parity_report.json), [`SOURCE.json`](SOURCE.json),
|
| 87 |
+
and [`checksums.sha256`](checksums.sha256) for machine-readable details.
|
| 88 |
+
|
| 89 |
+
## Re-export
|
| 90 |
+
|
| 91 |
+
The export script is included for reproducibility:
|
| 92 |
+
|
| 93 |
+
```bash
|
| 94 |
+
python -m pip install torch==2.4.1 onnx==1.19.1
|
| 95 |
+
python onnx/export_onnx.py \
|
| 96 |
+
--model-dir . \
|
| 97 |
+
--output-dir onnx-reexport \
|
| 98 |
+
--model-name Inflect-Micro-v2 \
|
| 99 |
+
--source-repository owensong/Inflect-Micro-v2 \
|
| 100 |
+
--source-revision 3e8c567f9bce1a309eea12d38ca9fbf7050df72e
|
| 101 |
+
```
|
| 102 |
+
|
| 103 |
+
Serialization hashes can differ across exporter versions even when numerical
|
| 104 |
+
outputs match. Validate outputs rather than expecting byte-identical files.
|
| 105 |
+
|
| 106 |
+
## Browser implementation and credit
|
| 107 |
+
|
| 108 |
+
Robert Bak produced the original ONNX conversion and a complete browser runner:
|
| 109 |
+
[robertbak/webtts-inflect](https://github.com/robertbak/webtts-inflect).
|
| 110 |
+
The official package preserves that conversion credit and adds checkpoint
|
| 111 |
+
provenance, metadata, reproducible export tooling, and Python ONNX Runtime
|
| 112 |
+
validation. The browser project is Apache-2.0 and runs synthesis locally with
|
| 113 |
+
ONNX Runtime Web and an eSpeak-ng WASM frontend.
|
| 114 |
+
|
| 115 |
+
## Quantization status
|
| 116 |
+
|
| 117 |
+
Only verified FP32 ONNX graphs are released. INT8 and INT4 are not included:
|
| 118 |
+
naive quantization of the flow and waveform decoder can produce audible
|
| 119 |
+
degradation, and no quantized build has passed matched listening and
|
| 120 |
+
intelligibility validation yet.
|
onnx/SOURCE.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"format": "inflect_v2_onnx_source_v1",
|
| 3 |
+
"model": "Inflect-Micro-v2",
|
| 4 |
+
"source_repository": "owensong/Inflect-Micro-v2",
|
| 5 |
+
"source_revision": "3e8c567f9bce1a309eea12d38ca9fbf7050df72e",
|
| 6 |
+
"source_model_file": "model.pth",
|
| 7 |
+
"source_model_sha256": "3eede065c9ccfa88ade0a5a9a5c23de34afcbbb32213e59aad44d5cf100fdee8",
|
| 8 |
+
"conversion_repository": "https://github.com/robertbak/webtts-inflect",
|
| 9 |
+
"conversion_commit": "60832b1978115e4ed7fdddce4d9b9fd9161f9fe7",
|
| 10 |
+
"conversion_author": "Robert Bak",
|
| 11 |
+
"official_packaging": "Owen Song",
|
| 12 |
+
"precision": "FP32",
|
| 13 |
+
"onnx_opset": 17,
|
| 14 |
+
"sample_rate_hz": 24000,
|
| 15 |
+
"license": "Apache-2.0"
|
| 16 |
+
}
|
onnx/checksums.sha256
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
7940923add86f76e7fa78d910b0632ca1779f8cc9a2ca2b49236381a9ca77183 decode.onnx
|
| 2 |
+
b728ca2564b9e5b7d6cf5e446f65e02a6fe2f1880ba281466fec93a667dd2388 duration.onnx
|
| 3 |
+
77bd27277861c8cae670247e3c9e3b976134a4886506fb069331aa6828752be6 export_onnx.py
|
| 4 |
+
cf48c4812f68e8315d80568e93650c64a7ad3fdfb9a0051c61a0d1d0746df274 inference_onnx.py
|
| 5 |
+
10c88564d24fe65ea730dc6ec98aa19ec74d3590efa427595a3c122c4c0f7039 parity_report.json
|
| 6 |
+
ecfaf6a3edca6ffc3152a61ccc6c27240f42daaa0ddf6efc08e1f9b277295734 README.md
|
| 7 |
+
43abd2c128e4296f1f0171f12946f3fc7dee3f8c8e2bb1858bcae6b43b62b3c9 requirements.txt
|
| 8 |
+
e950bf44034b011a64bba3773b388e386418ef952c3cd17ceefda5bfa94a3aaa SOURCE.json
|
onnx/decode.onnx
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:7940923add86f76e7fa78d910b0632ca1779f8cc9a2ca2b49236381a9ca77183
|
| 3 |
+
size 30427790
|
onnx/duration.onnx
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b728ca2564b9e5b7d6cf5e446f65e02a6fe2f1880ba281466fec93a667dd2388
|
| 3 |
+
size 7322687
|
onnx/export_onnx.py
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import argparse
|
| 4 |
+
import hashlib
|
| 5 |
+
import json
|
| 6 |
+
import logging
|
| 7 |
+
import sys
|
| 8 |
+
from pathlib import Path
|
| 9 |
+
|
| 10 |
+
import onnx
|
| 11 |
+
import torch
|
| 12 |
+
from torch import nn
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
PACKAGE_ROOT = Path(__file__).resolve().parents[1]
|
| 16 |
+
commons = None
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
class DurationGraph(nn.Module):
|
| 20 |
+
def __init__(self, model: nn.Module) -> None:
|
| 21 |
+
super().__init__()
|
| 22 |
+
self.enc_p = model.enc_p
|
| 23 |
+
self.dp = model.dp
|
| 24 |
+
|
| 25 |
+
def forward(
|
| 26 |
+
self,
|
| 27 |
+
tokens: torch.Tensor,
|
| 28 |
+
lengths: torch.Tensor,
|
| 29 |
+
length_scale: torch.Tensor,
|
| 30 |
+
) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
|
| 31 |
+
hidden, m_p, logs_p, x_mask = self.enc_p(tokens, lengths)
|
| 32 |
+
logw = self.dp(hidden, x_mask, g=None)
|
| 33 |
+
durations = torch.ceil(torch.exp(logw) * x_mask * length_scale)
|
| 34 |
+
y_lengths = torch.clamp_min(torch.sum(durations, [1, 2]), 1).long()
|
| 35 |
+
if commons is None:
|
| 36 |
+
raise RuntimeError("Runtime helpers were not initialized.")
|
| 37 |
+
y_mask = torch.unsqueeze(commons.sequence_mask(y_lengths, None), 1).to(
|
| 38 |
+
x_mask.dtype
|
| 39 |
+
)
|
| 40 |
+
attention_mask = torch.unsqueeze(x_mask, 2) * torch.unsqueeze(y_mask, -1)
|
| 41 |
+
attention = commons.generate_path(durations, attention_mask)
|
| 42 |
+
m_p_exp = torch.matmul(
|
| 43 |
+
attention.squeeze(1),
|
| 44 |
+
m_p.transpose(1, 2),
|
| 45 |
+
).transpose(1, 2)
|
| 46 |
+
logs_p_exp = torch.matmul(
|
| 47 |
+
attention.squeeze(1),
|
| 48 |
+
logs_p.transpose(1, 2),
|
| 49 |
+
).transpose(1, 2)
|
| 50 |
+
return m_p_exp, logs_p_exp, y_mask
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
class DecodeGraph(nn.Module):
|
| 54 |
+
def __init__(self, model: nn.Module) -> None:
|
| 55 |
+
super().__init__()
|
| 56 |
+
self.flow = model.flow
|
| 57 |
+
self.decoder = model.dec
|
| 58 |
+
|
| 59 |
+
def forward(
|
| 60 |
+
self,
|
| 61 |
+
m_p_exp: torch.Tensor,
|
| 62 |
+
logs_p_exp: torch.Tensor,
|
| 63 |
+
y_mask: torch.Tensor,
|
| 64 |
+
zp_noise: torch.Tensor,
|
| 65 |
+
noise_scale: torch.Tensor,
|
| 66 |
+
) -> torch.Tensor:
|
| 67 |
+
z_p = m_p_exp + zp_noise * torch.exp(logs_p_exp) * noise_scale
|
| 68 |
+
z = self.flow(z_p, y_mask, g=None, reverse=True)
|
| 69 |
+
return self.decoder(z * y_mask, g=None)
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
def sha256(path: Path) -> str:
|
| 73 |
+
digest = hashlib.sha256()
|
| 74 |
+
with path.open("rb") as handle:
|
| 75 |
+
for block in iter(lambda: handle.read(1024 * 1024), b""):
|
| 76 |
+
digest.update(block)
|
| 77 |
+
return digest.hexdigest()
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
def load_model(root: Path) -> nn.Module:
|
| 81 |
+
global commons
|
| 82 |
+
runtime_root = root / "runtime"
|
| 83 |
+
sys.path.insert(0, str(runtime_root))
|
| 84 |
+
sys.path.insert(0, str(root))
|
| 85 |
+
import commons as runtime_commons
|
| 86 |
+
import utils
|
| 87 |
+
from models import SynthesizerTrn
|
| 88 |
+
from text.symbols import symbols
|
| 89 |
+
|
| 90 |
+
commons = runtime_commons
|
| 91 |
+
hps = utils.get_hparams_from_file(str(root / "config.json"))
|
| 92 |
+
model = SynthesizerTrn(
|
| 93 |
+
len(symbols),
|
| 94 |
+
hps.data.filter_length // 2 + 1,
|
| 95 |
+
hps.train.segment_size // hps.data.hop_length,
|
| 96 |
+
**hps.model,
|
| 97 |
+
).cpu().eval()
|
| 98 |
+
logger = logging.getLogger()
|
| 99 |
+
previous_level = logger.level
|
| 100 |
+
try:
|
| 101 |
+
logger.setLevel(logging.WARNING)
|
| 102 |
+
utils.load_checkpoint(str(root / "model.pth"), model, None)
|
| 103 |
+
finally:
|
| 104 |
+
logger.setLevel(previous_level)
|
| 105 |
+
return model
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
def attach_metadata(
|
| 109 |
+
path: Path,
|
| 110 |
+
*,
|
| 111 |
+
model_name: str,
|
| 112 |
+
source_repository: str,
|
| 113 |
+
source_revision: str,
|
| 114 |
+
source_model_sha256: str,
|
| 115 |
+
) -> None:
|
| 116 |
+
graph = onnx.load(path)
|
| 117 |
+
metadata = {
|
| 118 |
+
"model_name": model_name,
|
| 119 |
+
"source_repository": source_repository,
|
| 120 |
+
"source_revision": source_revision,
|
| 121 |
+
"source_model_sha256": source_model_sha256,
|
| 122 |
+
"license": "Apache-2.0",
|
| 123 |
+
"sample_rate_hz": "24000",
|
| 124 |
+
"precision": "FP32",
|
| 125 |
+
"onnx_opset": "17",
|
| 126 |
+
"conversion_author": "Robert Bak (github.com/robertbak)",
|
| 127 |
+
"official_packaging": "Owen Song (huggingface.co/owensong)",
|
| 128 |
+
}
|
| 129 |
+
del graph.metadata_props[:]
|
| 130 |
+
for key, value in metadata.items():
|
| 131 |
+
item = graph.metadata_props.add()
|
| 132 |
+
item.key = key
|
| 133 |
+
item.value = value
|
| 134 |
+
onnx.checker.check_model(graph)
|
| 135 |
+
onnx.save(graph, path)
|
| 136 |
+
|
| 137 |
+
|
| 138 |
+
def export(
|
| 139 |
+
root: Path,
|
| 140 |
+
output_dir: Path,
|
| 141 |
+
*,
|
| 142 |
+
model_name: str,
|
| 143 |
+
source_repository: str,
|
| 144 |
+
source_revision: str,
|
| 145 |
+
) -> None:
|
| 146 |
+
torch.manual_seed(7)
|
| 147 |
+
model = load_model(root)
|
| 148 |
+
duration = DurationGraph(model).eval()
|
| 149 |
+
decode = DecodeGraph(model).eval()
|
| 150 |
+
|
| 151 |
+
output_dir.mkdir(parents=True, exist_ok=True)
|
| 152 |
+
duration_path = output_dir / "duration.onnx"
|
| 153 |
+
decode_path = output_dir / "decode.onnx"
|
| 154 |
+
|
| 155 |
+
tokens = torch.tensor(
|
| 156 |
+
[[0, 18, 0, 61, 0, 55, 0, 48, 0, 44, 0, 46, 0]],
|
| 157 |
+
dtype=torch.long,
|
| 158 |
+
)
|
| 159 |
+
lengths = torch.tensor([tokens.shape[1]], dtype=torch.long)
|
| 160 |
+
length_scale = torch.tensor(1.0, dtype=torch.float32)
|
| 161 |
+
|
| 162 |
+
torch.onnx.export(
|
| 163 |
+
duration,
|
| 164 |
+
(tokens, lengths, length_scale),
|
| 165 |
+
duration_path,
|
| 166 |
+
input_names=["tokens", "lengths", "length_scale"],
|
| 167 |
+
output_names=["m_p_exp", "logs_p_exp", "y_mask"],
|
| 168 |
+
dynamic_axes={
|
| 169 |
+
"tokens": {1: "text_len"},
|
| 170 |
+
"m_p_exp": {2: "mel_len"},
|
| 171 |
+
"logs_p_exp": {2: "mel_len"},
|
| 172 |
+
"y_mask": {2: "mel_len"},
|
| 173 |
+
},
|
| 174 |
+
opset_version=17,
|
| 175 |
+
do_constant_folding=True,
|
| 176 |
+
dynamo=False,
|
| 177 |
+
)
|
| 178 |
+
|
| 179 |
+
with torch.no_grad():
|
| 180 |
+
m_p_exp, logs_p_exp, y_mask = duration(tokens, lengths, length_scale)
|
| 181 |
+
zp_noise = torch.randn_like(m_p_exp)
|
| 182 |
+
noise_scale = torch.tensor(0.667, dtype=torch.float32)
|
| 183 |
+
torch.onnx.export(
|
| 184 |
+
decode,
|
| 185 |
+
(m_p_exp, logs_p_exp, y_mask, zp_noise, noise_scale),
|
| 186 |
+
decode_path,
|
| 187 |
+
input_names=[
|
| 188 |
+
"m_p_exp",
|
| 189 |
+
"logs_p_exp",
|
| 190 |
+
"y_mask",
|
| 191 |
+
"zp_noise",
|
| 192 |
+
"noise_scale",
|
| 193 |
+
],
|
| 194 |
+
output_names=["waveform"],
|
| 195 |
+
dynamic_axes={
|
| 196 |
+
"m_p_exp": {2: "mel_len"},
|
| 197 |
+
"logs_p_exp": {2: "mel_len"},
|
| 198 |
+
"y_mask": {2: "mel_len"},
|
| 199 |
+
"zp_noise": {2: "mel_len"},
|
| 200 |
+
"waveform": {2: "wav_len"},
|
| 201 |
+
},
|
| 202 |
+
opset_version=17,
|
| 203 |
+
do_constant_folding=True,
|
| 204 |
+
dynamo=False,
|
| 205 |
+
)
|
| 206 |
+
|
| 207 |
+
source_hash = sha256(root / "model.pth")
|
| 208 |
+
for path in (duration_path, decode_path):
|
| 209 |
+
attach_metadata(
|
| 210 |
+
path,
|
| 211 |
+
model_name=model_name,
|
| 212 |
+
source_repository=source_repository,
|
| 213 |
+
source_revision=source_revision,
|
| 214 |
+
source_model_sha256=source_hash,
|
| 215 |
+
)
|
| 216 |
+
|
| 217 |
+
manifest = {
|
| 218 |
+
"format": "inflect_v2_onnx_export_v1",
|
| 219 |
+
"model_name": model_name,
|
| 220 |
+
"source_repository": source_repository,
|
| 221 |
+
"source_revision": source_revision,
|
| 222 |
+
"source_model_sha256": source_hash,
|
| 223 |
+
"torch_version": torch.__version__,
|
| 224 |
+
"onnx_version": onnx.__version__,
|
| 225 |
+
"opset": 17,
|
| 226 |
+
"files": {
|
| 227 |
+
duration_path.name: {
|
| 228 |
+
"bytes": duration_path.stat().st_size,
|
| 229 |
+
"sha256": sha256(duration_path),
|
| 230 |
+
},
|
| 231 |
+
decode_path.name: {
|
| 232 |
+
"bytes": decode_path.stat().st_size,
|
| 233 |
+
"sha256": sha256(decode_path),
|
| 234 |
+
},
|
| 235 |
+
},
|
| 236 |
+
}
|
| 237 |
+
(output_dir / "export_manifest.json").write_text(
|
| 238 |
+
json.dumps(manifest, indent=2) + "\n",
|
| 239 |
+
encoding="utf-8",
|
| 240 |
+
)
|
| 241 |
+
|
| 242 |
+
|
| 243 |
+
def main() -> None:
|
| 244 |
+
parser = argparse.ArgumentParser(description="Export Inflect v2 to ONNX.")
|
| 245 |
+
parser.add_argument("--model-dir", type=Path, default=PACKAGE_ROOT)
|
| 246 |
+
parser.add_argument("--output-dir", type=Path, required=True)
|
| 247 |
+
parser.add_argument("--model-name", required=True)
|
| 248 |
+
parser.add_argument("--source-repository", required=True)
|
| 249 |
+
parser.add_argument("--source-revision", required=True)
|
| 250 |
+
args = parser.parse_args()
|
| 251 |
+
export(
|
| 252 |
+
args.model_dir.resolve(),
|
| 253 |
+
args.output_dir.resolve(),
|
| 254 |
+
model_name=args.model_name,
|
| 255 |
+
source_repository=args.source_repository,
|
| 256 |
+
source_revision=args.source_revision,
|
| 257 |
+
)
|
| 258 |
+
|
| 259 |
+
|
| 260 |
+
if __name__ == "__main__":
|
| 261 |
+
main()
|
onnx/inference_onnx.py
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import argparse
|
| 4 |
+
import re
|
| 5 |
+
import sys
|
| 6 |
+
from pathlib import Path
|
| 7 |
+
|
| 8 |
+
import numpy as np
|
| 9 |
+
import onnxruntime as ort
|
| 10 |
+
import soundfile as sf
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
PACKAGE_ROOT = Path(__file__).resolve().parents[1]
|
| 14 |
+
RUNTIME_ROOT = PACKAGE_ROOT / "runtime"
|
| 15 |
+
sys.path.insert(0, str(RUNTIME_ROOT))
|
| 16 |
+
sys.path.insert(0, str(PACKAGE_ROOT))
|
| 17 |
+
|
| 18 |
+
from inflect_vits_frontend import run_vits_frontend # noqa: E402
|
| 19 |
+
from text.symbols import symbols # noqa: E402
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
SAMPLE_RATE = 24_000
|
| 23 |
+
SYMBOL_TO_ID = {symbol: index for index, symbol in enumerate(symbols)}
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def split_text(text: str, limit: int = 280) -> list[str]:
|
| 27 |
+
normalized = " ".join(text.split())
|
| 28 |
+
sentences = [
|
| 29 |
+
part.strip()
|
| 30 |
+
for part in re.split(r"(?<=[.!?;:])\s+", normalized)
|
| 31 |
+
if part.strip()
|
| 32 |
+
]
|
| 33 |
+
chunks: list[str] = []
|
| 34 |
+
for sentence in sentences or [normalized]:
|
| 35 |
+
while len(sentence) > limit:
|
| 36 |
+
search = sentence[: limit + 1]
|
| 37 |
+
punctuation = max(search.rfind(mark) for mark in (",", ";", ":"))
|
| 38 |
+
split_at = (
|
| 39 |
+
punctuation + 1
|
| 40 |
+
if punctuation >= limit // 2
|
| 41 |
+
else sentence.rfind(" ", 0, limit + 1)
|
| 42 |
+
)
|
| 43 |
+
if split_at < limit // 2:
|
| 44 |
+
split_at = limit
|
| 45 |
+
chunks.append(sentence[:split_at].strip())
|
| 46 |
+
sentence = sentence[split_at:].strip()
|
| 47 |
+
if sentence:
|
| 48 |
+
chunks.append(sentence)
|
| 49 |
+
return chunks
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def boundary_pause_seconds(chunk: str) -> float:
|
| 53 |
+
ending = chunk.rstrip()[-1:] if chunk.strip() else ""
|
| 54 |
+
return {
|
| 55 |
+
"?": 0.28,
|
| 56 |
+
"!": 0.24,
|
| 57 |
+
".": 0.22,
|
| 58 |
+
";": 0.16,
|
| 59 |
+
":": 0.13,
|
| 60 |
+
",": 0.09,
|
| 61 |
+
}.get(ending, 0.08)
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
def edge_fade(
|
| 65 |
+
waveform: np.ndarray,
|
| 66 |
+
sample_rate: int = SAMPLE_RATE,
|
| 67 |
+
milliseconds: float = 5.0,
|
| 68 |
+
) -> np.ndarray:
|
| 69 |
+
frames = min(round(sample_rate * milliseconds / 1000.0), waveform.size // 2)
|
| 70 |
+
if frames <= 0:
|
| 71 |
+
return waveform
|
| 72 |
+
output = waveform.copy()
|
| 73 |
+
ramp = np.linspace(0.0, 1.0, frames, endpoint=True, dtype=np.float32)
|
| 74 |
+
output[:frames] *= ramp
|
| 75 |
+
output[-frames:] *= ramp[::-1]
|
| 76 |
+
return output
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
def phonemes_to_tokens(phoneme_text: str) -> np.ndarray:
|
| 80 |
+
sequence = [SYMBOL_TO_ID[symbol] for symbol in phoneme_text]
|
| 81 |
+
if not sequence:
|
| 82 |
+
raise ValueError("The text frontend produced no speakable tokens.")
|
| 83 |
+
with_blanks = np.zeros(len(sequence) * 2 + 1, dtype=np.int64)
|
| 84 |
+
with_blanks[1::2] = sequence
|
| 85 |
+
return with_blanks[None, :]
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
def available_provider(name: str) -> str:
|
| 89 |
+
aliases = {
|
| 90 |
+
"cpu": "CPUExecutionProvider",
|
| 91 |
+
"cuda": "CUDAExecutionProvider",
|
| 92 |
+
"directml": "DmlExecutionProvider",
|
| 93 |
+
}
|
| 94 |
+
provider = aliases.get(name.lower(), name)
|
| 95 |
+
available = ort.get_available_providers()
|
| 96 |
+
if provider not in available:
|
| 97 |
+
raise ValueError(
|
| 98 |
+
f"Provider {provider!r} is unavailable. Installed providers: {available}"
|
| 99 |
+
)
|
| 100 |
+
return provider
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
class InflectONNX:
|
| 104 |
+
"""Torch-free Inflect v2 inference through ONNX Runtime."""
|
| 105 |
+
|
| 106 |
+
def __init__(
|
| 107 |
+
self,
|
| 108 |
+
model_dir: str | Path = PACKAGE_ROOT,
|
| 109 |
+
provider: str = "cpu",
|
| 110 |
+
) -> None:
|
| 111 |
+
root = Path(model_dir).resolve()
|
| 112 |
+
onnx_dir = root / "onnx"
|
| 113 |
+
selected_provider = available_provider(provider)
|
| 114 |
+
providers = [selected_provider]
|
| 115 |
+
if selected_provider != "CPUExecutionProvider":
|
| 116 |
+
providers.append("CPUExecutionProvider")
|
| 117 |
+
self.duration = ort.InferenceSession(
|
| 118 |
+
str(onnx_dir / "duration.onnx"),
|
| 119 |
+
providers=providers,
|
| 120 |
+
)
|
| 121 |
+
self.decode = ort.InferenceSession(
|
| 122 |
+
str(onnx_dir / "decode.onnx"),
|
| 123 |
+
providers=providers,
|
| 124 |
+
)
|
| 125 |
+
|
| 126 |
+
def _synthesize_chunk(
|
| 127 |
+
self,
|
| 128 |
+
text: str,
|
| 129 |
+
*,
|
| 130 |
+
speed: float,
|
| 131 |
+
variation: float,
|
| 132 |
+
seed: int,
|
| 133 |
+
) -> np.ndarray:
|
| 134 |
+
phoneme_text = run_vits_frontend(text).phoneme_text
|
| 135 |
+
tokens = phonemes_to_tokens(phoneme_text)
|
| 136 |
+
duration_outputs = self.duration.run(
|
| 137 |
+
["m_p_exp", "logs_p_exp", "y_mask"],
|
| 138 |
+
{
|
| 139 |
+
"tokens": tokens,
|
| 140 |
+
"lengths": np.asarray([tokens.shape[1]], dtype=np.int64),
|
| 141 |
+
"length_scale": np.asarray(1.0 / speed, dtype=np.float32),
|
| 142 |
+
},
|
| 143 |
+
)
|
| 144 |
+
m_p_exp, logs_p_exp, y_mask = duration_outputs
|
| 145 |
+
rng = np.random.default_rng(seed)
|
| 146 |
+
latent_noise = rng.standard_normal(m_p_exp.shape, dtype=np.float32)
|
| 147 |
+
waveform = self.decode.run(
|
| 148 |
+
["waveform"],
|
| 149 |
+
{
|
| 150 |
+
"m_p_exp": m_p_exp,
|
| 151 |
+
"logs_p_exp": logs_p_exp,
|
| 152 |
+
"y_mask": y_mask,
|
| 153 |
+
"zp_noise": latent_noise,
|
| 154 |
+
"noise_scale": np.asarray(variation, dtype=np.float32),
|
| 155 |
+
},
|
| 156 |
+
)[0]
|
| 157 |
+
return edge_fade(np.asarray(waveform, dtype=np.float32).reshape(-1))
|
| 158 |
+
|
| 159 |
+
def synthesize(
|
| 160 |
+
self,
|
| 161 |
+
text: str,
|
| 162 |
+
*,
|
| 163 |
+
speed: float = 1.0,
|
| 164 |
+
variation: float = 0.667,
|
| 165 |
+
seed: int = 0,
|
| 166 |
+
) -> tuple[int, np.ndarray]:
|
| 167 |
+
normalized = " ".join(text.split())
|
| 168 |
+
if not normalized:
|
| 169 |
+
raise ValueError("Text must not be empty.")
|
| 170 |
+
if not 0.5 <= speed <= 2.0:
|
| 171 |
+
raise ValueError("speed must be between 0.5 and 2.0")
|
| 172 |
+
if not 0.0 <= variation <= 1.0:
|
| 173 |
+
raise ValueError("variation must be between 0.0 and 1.0")
|
| 174 |
+
|
| 175 |
+
chunks = split_text(normalized)
|
| 176 |
+
pieces: list[np.ndarray] = []
|
| 177 |
+
for index, chunk in enumerate(chunks):
|
| 178 |
+
if index:
|
| 179 |
+
pause = boundary_pause_seconds(chunks[index - 1])
|
| 180 |
+
pieces.append(
|
| 181 |
+
np.zeros(round(SAMPLE_RATE * pause), dtype=np.float32)
|
| 182 |
+
)
|
| 183 |
+
pieces.append(
|
| 184 |
+
self._synthesize_chunk(
|
| 185 |
+
chunk,
|
| 186 |
+
speed=speed,
|
| 187 |
+
variation=variation,
|
| 188 |
+
seed=seed + index,
|
| 189 |
+
)
|
| 190 |
+
)
|
| 191 |
+
waveform = np.clip(np.concatenate(pieces), -1.0, 1.0)
|
| 192 |
+
return SAMPLE_RATE, waveform
|
| 193 |
+
|
| 194 |
+
def save(self, text: str, output: str | Path, **kwargs: object) -> Path:
|
| 195 |
+
destination = Path(output)
|
| 196 |
+
destination.parent.mkdir(parents=True, exist_ok=True)
|
| 197 |
+
sample_rate, waveform = self.synthesize(text, **kwargs)
|
| 198 |
+
sf.write(destination, waveform, sample_rate)
|
| 199 |
+
return destination
|
| 200 |
+
|
| 201 |
+
|
| 202 |
+
def main() -> None:
|
| 203 |
+
parser = argparse.ArgumentParser(description="Run Inflect v2 through ONNX Runtime.")
|
| 204 |
+
parser.add_argument("--model-dir", type=Path, default=PACKAGE_ROOT)
|
| 205 |
+
parser.add_argument("--text", required=True)
|
| 206 |
+
parser.add_argument("--output", type=Path, required=True)
|
| 207 |
+
parser.add_argument(
|
| 208 |
+
"--provider",
|
| 209 |
+
default="cpu",
|
| 210 |
+
help="cpu, cuda, directml, or an ONNX Runtime provider name",
|
| 211 |
+
)
|
| 212 |
+
parser.add_argument("--speed", type=float, default=1.0)
|
| 213 |
+
parser.add_argument("--variation", type=float, default=0.667)
|
| 214 |
+
parser.add_argument("--seed", type=int, default=0)
|
| 215 |
+
args = parser.parse_args()
|
| 216 |
+
|
| 217 |
+
engine = InflectONNX(args.model_dir, provider=args.provider)
|
| 218 |
+
engine.save(
|
| 219 |
+
args.text,
|
| 220 |
+
args.output,
|
| 221 |
+
speed=args.speed,
|
| 222 |
+
variation=args.variation,
|
| 223 |
+
seed=args.seed,
|
| 224 |
+
)
|
| 225 |
+
print(f"wrote {args.output} at {SAMPLE_RATE} Hz")
|
| 226 |
+
|
| 227 |
+
|
| 228 |
+
if __name__ == "__main__":
|
| 229 |
+
main()
|
onnx/parity_report.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"format": "inflect_v2_onnx_parity_v1",
|
| 3 |
+
"model": "Inflect-Micro-v2",
|
| 4 |
+
"onnx_checker": "pass",
|
| 5 |
+
"dynamic_lengths": "pass",
|
| 6 |
+
"end_to_end_short_text": "pass",
|
| 7 |
+
"end_to_end_long_text": "pass",
|
| 8 |
+
"same_seed_determinism": "pass",
|
| 9 |
+
"different_seed_variation": "pass",
|
| 10 |
+
"pytorch_parity": {
|
| 11 |
+
"duration_m_p_exp_max_abs_error": 9.5367431640625e-07,
|
| 12 |
+
"duration_logs_p_exp_max_abs_error": 3.5762786865234375e-07,
|
| 13 |
+
"duration_mask_exact": true,
|
| 14 |
+
"waveform_max_abs_error": 1.75834e-05,
|
| 15 |
+
"waveform_mean_abs_error": 2.2595e-07,
|
| 16 |
+
"waveform_correlation": 0.9999999999394602
|
| 17 |
+
},
|
| 18 |
+
"independent_reexport_parity": {
|
| 19 |
+
"duration_outputs_max_abs_error": [0.0, 0.0, 0.0],
|
| 20 |
+
"waveform_max_abs_error": 1.0617077350616455e-07,
|
| 21 |
+
"waveform_mean_abs_error": 4.823611288173879e-09,
|
| 22 |
+
"waveform_correlation": 0.9999999999995599
|
| 23 |
+
},
|
| 24 |
+
"validation_environment": {
|
| 25 |
+
"python": "3.12",
|
| 26 |
+
"onnx": "1.19.1",
|
| 27 |
+
"onnxruntime": "1.22.1",
|
| 28 |
+
"torch_for_reference": "2.4.1+cpu",
|
| 29 |
+
"provider": "CPUExecutionProvider"
|
| 30 |
+
}
|
| 31 |
+
}
|
onnx/requirements.txt
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
numpy>=1.26,<3
|
| 2 |
+
onnxruntime>=1.18,<2
|
| 3 |
+
soundfile>=0.13
|
| 4 |
+
phonemizer>=3.3
|
| 5 |
+
espeakng-loader>=0.2.4
|
| 6 |
+
num2words>=0.5.14
|
| 7 |
+
Unidecode>=1.3.8
|
release_manifest.json
CHANGED
|
@@ -7,6 +7,36 @@
|
|
| 7 |
"smoke_audio_seconds": 3.968,
|
| 8 |
"standalone_cpu_smoke_audio_seconds": 3.616,
|
| 9 |
"files": [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
{
|
| 11 |
"path": "assets/evidence/asr-consensus.svg",
|
| 12 |
"bytes": 3225,
|
|
@@ -22,6 +52,11 @@
|
|
| 22 |
"bytes": 6123,
|
| 23 |
"sha256": "1a2218e0bbe726167a5b0201736a82947edbd7c6803df3f5689e7a711026758e"
|
| 24 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
{
|
| 26 |
"path": "assets/evidence/evidence-summary.json",
|
| 27 |
"bytes": 52605,
|
|
@@ -42,6 +77,11 @@
|
|
| 42 |
"bytes": 7934,
|
| 43 |
"sha256": "9086575f7d11395255f4cf4ae67e30bf92d60042c6b4bdc58ee6045595cb5420"
|
| 44 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
{
|
| 46 |
"path": "assets/evidence/quality-vs-footprint.svg",
|
| 47 |
"bytes": 5852,
|
|
@@ -49,18 +89,33 @@
|
|
| 49 |
},
|
| 50 |
{
|
| 51 |
"path": "assets/inflect-v2-repository-hero.png",
|
| 52 |
-
"bytes":
|
| 53 |
-
"sha256": "
|
| 54 |
},
|
| 55 |
{
|
| 56 |
-
"path": "
|
| 57 |
-
"bytes":
|
| 58 |
-
"sha256": "
|
| 59 |
},
|
| 60 |
{
|
| 61 |
-
"path": "
|
| 62 |
-
"bytes":
|
| 63 |
-
"sha256": "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
},
|
| 65 |
{
|
| 66 |
"path": "config.json",
|
|
@@ -74,8 +129,8 @@
|
|
| 74 |
},
|
| 75 |
{
|
| 76 |
"path": "docs/DATA_AND_VOICE.md",
|
| 77 |
-
"bytes":
|
| 78 |
-
"sha256": "
|
| 79 |
},
|
| 80 |
{
|
| 81 |
"path": "docs/DEPLOYMENT.md",
|
|
@@ -84,13 +139,13 @@
|
|
| 84 |
},
|
| 85 |
{
|
| 86 |
"path": "docs/EVALUATION.md",
|
| 87 |
-
"bytes":
|
| 88 |
-
"sha256": "
|
| 89 |
},
|
| 90 |
{
|
| 91 |
"path": "docs/EXPORTS.md",
|
| 92 |
-
"bytes":
|
| 93 |
-
"sha256": "
|
| 94 |
},
|
| 95 |
{
|
| 96 |
"path": "docs/FINETUNING.md",
|
|
@@ -259,8 +314,8 @@
|
|
| 259 |
},
|
| 260 |
{
|
| 261 |
"path": "inference.py",
|
| 262 |
-
"bytes":
|
| 263 |
-
"sha256": "
|
| 264 |
},
|
| 265 |
{
|
| 266 |
"path": "inflect_nano_v2_frontend.py",
|
|
@@ -272,11 +327,6 @@
|
|
| 272 |
"bytes": 2031,
|
| 273 |
"sha256": "70eb4cdb96b2752015f72be984f5e62e0f26d7dc80e708875601702057b95cc2"
|
| 274 |
},
|
| 275 |
-
{
|
| 276 |
-
"path": "LICENSE",
|
| 277 |
-
"bytes": 10455,
|
| 278 |
-
"sha256": "12c48c640d1d0baf158d45175a4238b9227c71c77f50b0d15791b8efc08cd793"
|
| 279 |
-
},
|
| 280 |
{
|
| 281 |
"path": "model.pth",
|
| 282 |
"bytes": 37529995,
|
|
@@ -288,9 +338,49 @@
|
|
| 288 |
"sha256": "f796d72aabd080d1232032c219dc39bbb2f5b517fe8a33a76df2a53c720bdb23"
|
| 289 |
},
|
| 290 |
{
|
| 291 |
-
"path": "README.md",
|
| 292 |
-
"bytes":
|
| 293 |
-
"sha256": "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 294 |
},
|
| 295 |
{
|
| 296 |
"path": "requirements-tested.txt",
|
|
@@ -332,6 +422,11 @@
|
|
| 332 |
"bytes": 206,
|
| 333 |
"sha256": "16ca4890f3e0107250b4a522c0127779994a5a2b99fc35d6a27f93496a72153a"
|
| 334 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 335 |
{
|
| 336 |
"path": "runtime/text/__init__.py",
|
| 337 |
"bytes": 1572,
|
|
@@ -342,11 +437,6 @@
|
|
| 342 |
"bytes": 2880,
|
| 343 |
"sha256": "11dc7325547290e529c597e620f3aaf8d0bd8a2a2987d48eb42d2289534e42d1"
|
| 344 |
},
|
| 345 |
-
{
|
| 346 |
-
"path": "runtime/text/LICENSE",
|
| 347 |
-
"bytes": 1053,
|
| 348 |
-
"sha256": "f89accd9d66f6a011f19997d7a21cf71a35ffe2e2d0911b5460cbd0cab52a581"
|
| 349 |
-
},
|
| 350 |
{
|
| 351 |
"path": "runtime/text/symbols.py",
|
| 352 |
"bytes": 642,
|
|
@@ -401,12 +491,13 @@
|
|
| 401 |
"path": "third_party/VITS_LICENSE.txt",
|
| 402 |
"bytes": 1090,
|
| 403 |
"sha256": "1cdf858b4d555567398b378b4a0166e97f7908c56607101b8bf9bb6754cdff3f"
|
| 404 |
-
},
|
| 405 |
-
{
|
| 406 |
-
"path": "THIRD_PARTY_NOTICES.md",
|
| 407 |
-
"bytes": 1233,
|
| 408 |
-
"sha256": "2ead63b7d9cddd6c1d12a96d88de0ade6fd3eabd1278825c0a3a2c1d3647ab4b"
|
| 409 |
}
|
| 410 |
],
|
| 411 |
-
"format": "inflect_v2_release_manifest_v1"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 412 |
}
|
|
|
|
| 7 |
"smoke_audio_seconds": 3.968,
|
| 8 |
"standalone_cpu_smoke_audio_seconds": 3.616,
|
| 9 |
"files": [
|
| 10 |
+
{
|
| 11 |
+
"path": ".gitattributes",
|
| 12 |
+
"bytes": 1519,
|
| 13 |
+
"sha256": "11ad7efa24975ee4b0c3c3a38ed18737f0658a5f75a0a96787b576a78a023361"
|
| 14 |
+
},
|
| 15 |
+
{
|
| 16 |
+
"path": "CHANGELOG.md",
|
| 17 |
+
"bytes": 792,
|
| 18 |
+
"sha256": "742ddc2b7990ffa3e205f686e9c8dcb8e6e98eb3b910b411e72cfb2a3120b104"
|
| 19 |
+
},
|
| 20 |
+
{
|
| 21 |
+
"path": "CITATION.cff",
|
| 22 |
+
"bytes": 289,
|
| 23 |
+
"sha256": "8150876b279aec0438cb25851c12375522c07521261645368565febeaff22408"
|
| 24 |
+
},
|
| 25 |
+
{
|
| 26 |
+
"path": "LICENSE",
|
| 27 |
+
"bytes": 10455,
|
| 28 |
+
"sha256": "12c48c640d1d0baf158d45175a4238b9227c71c77f50b0d15791b8efc08cd793"
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"path": "README.md",
|
| 32 |
+
"bytes": 20101,
|
| 33 |
+
"sha256": "3250258e2ec7b8e7e312da1579dda93ff68334ed803561f4ac3dcc26a5f2d644"
|
| 34 |
+
},
|
| 35 |
+
{
|
| 36 |
+
"path": "THIRD_PARTY_NOTICES.md",
|
| 37 |
+
"bytes": 1233,
|
| 38 |
+
"sha256": "2ead63b7d9cddd6c1d12a96d88de0ade6fd3eabd1278825c0a3a2c1d3647ab4b"
|
| 39 |
+
},
|
| 40 |
{
|
| 41 |
"path": "assets/evidence/asr-consensus.svg",
|
| 42 |
"bytes": 3225,
|
|
|
|
| 52 |
"bytes": 6123,
|
| 53 |
"sha256": "1a2218e0bbe726167a5b0201736a82947edbd7c6803df3f5689e7a711026758e"
|
| 54 |
},
|
| 55 |
+
{
|
| 56 |
+
"path": "assets/evidence/cpu-throughput.svg",
|
| 57 |
+
"bytes": 3198,
|
| 58 |
+
"sha256": "4a74b4f19c87c5da9e8f368dd0117ac2840c437976c677572e3f65d1be785b8b"
|
| 59 |
+
},
|
| 60 |
{
|
| 61 |
"path": "assets/evidence/evidence-summary.json",
|
| 62 |
"bytes": 52605,
|
|
|
|
| 77 |
"bytes": 7934,
|
| 78 |
"sha256": "9086575f7d11395255f4cf4ae67e30bf92d60042c6b4bdc58ee6045595cb5420"
|
| 79 |
},
|
| 80 |
+
{
|
| 81 |
+
"path": "assets/evidence/quality-vs-cpu-speed.svg",
|
| 82 |
+
"bytes": 3887,
|
| 83 |
+
"sha256": "023e0a4a86c71eefea19a4fdab7404b8710ead4045ae3964928f149af1cc04b4"
|
| 84 |
+
},
|
| 85 |
{
|
| 86 |
"path": "assets/evidence/quality-vs-footprint.svg",
|
| 87 |
"bytes": 5852,
|
|
|
|
| 89 |
},
|
| 90 |
{
|
| 91 |
"path": "assets/inflect-v2-repository-hero.png",
|
| 92 |
+
"bytes": 1911877,
|
| 93 |
+
"sha256": "ca59256690b4ce1b11f27e51ee4aa21c30883d58c1e5c87cccae553898afe884"
|
| 94 |
},
|
| 95 |
{
|
| 96 |
+
"path": "assets/nav/collection.svg",
|
| 97 |
+
"bytes": 652,
|
| 98 |
+
"sha256": "85387a74b68b0b7b735f4ce3527f32ddd5ca084dfd49dc81fa96ebf816b153e6"
|
| 99 |
},
|
| 100 |
{
|
| 101 |
+
"path": "assets/nav/github.svg",
|
| 102 |
+
"bytes": 517,
|
| 103 |
+
"sha256": "d55949cc700715bb152b0380799b314631f442414e81b83a6f3553df18dbef6f"
|
| 104 |
+
},
|
| 105 |
+
{
|
| 106 |
+
"path": "assets/nav/micro.svg",
|
| 107 |
+
"bytes": 529,
|
| 108 |
+
"sha256": "f56b72a293acdf8e9fed93893f75acf760a20a2fe09b316646a627db2ada741a"
|
| 109 |
+
},
|
| 110 |
+
{
|
| 111 |
+
"path": "assets/nav/nano.svg",
|
| 112 |
+
"bytes": 726,
|
| 113 |
+
"sha256": "69275d0d9277144c098b3dce66db5e870ebd113d97ca55cc6912242bda520643"
|
| 114 |
+
},
|
| 115 |
+
{
|
| 116 |
+
"path": "assets/nav/playground.svg",
|
| 117 |
+
"bytes": 624,
|
| 118 |
+
"sha256": "fa05ff68190baf290f3d1e9c9b8a7bc89af033fd03066cf7d3e828089b194953"
|
| 119 |
},
|
| 120 |
{
|
| 121 |
"path": "config.json",
|
|
|
|
| 129 |
},
|
| 130 |
{
|
| 131 |
"path": "docs/DATA_AND_VOICE.md",
|
| 132 |
+
"bytes": 1739,
|
| 133 |
+
"sha256": "8a504473b8377493256d435124851479ebee7f74432671ed0e0dff4e4509d8ba"
|
| 134 |
},
|
| 135 |
{
|
| 136 |
"path": "docs/DEPLOYMENT.md",
|
|
|
|
| 139 |
},
|
| 140 |
{
|
| 141 |
"path": "docs/EVALUATION.md",
|
| 142 |
+
"bytes": 3246,
|
| 143 |
+
"sha256": "4041e56250564366ff80ef9278d66bac5139d8833d368264931ba28ffbad7991"
|
| 144 |
},
|
| 145 |
{
|
| 146 |
"path": "docs/EXPORTS.md",
|
| 147 |
+
"bytes": 2808,
|
| 148 |
+
"sha256": "bcb70436c88e92d2926941e76f141498d63e2432e3584e921a9682785c474392"
|
| 149 |
},
|
| 150 |
{
|
| 151 |
"path": "docs/FINETUNING.md",
|
|
|
|
| 314 |
},
|
| 315 |
{
|
| 316 |
"path": "inference.py",
|
| 317 |
+
"bytes": 6346,
|
| 318 |
+
"sha256": "bb8b5302b16c35ee04d6729fd73caa95d1e72b2fc50420b1cdec120327f8b672"
|
| 319 |
},
|
| 320 |
{
|
| 321 |
"path": "inflect_nano_v2_frontend.py",
|
|
|
|
| 327 |
"bytes": 2031,
|
| 328 |
"sha256": "70eb4cdb96b2752015f72be984f5e62e0f26d7dc80e708875601702057b95cc2"
|
| 329 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 330 |
{
|
| 331 |
"path": "model.pth",
|
| 332 |
"bytes": 37529995,
|
|
|
|
| 338 |
"sha256": "f796d72aabd080d1232032c219dc39bbb2f5b517fe8a33a76df2a53c720bdb23"
|
| 339 |
},
|
| 340 |
{
|
| 341 |
+
"path": "onnx/README.md",
|
| 342 |
+
"bytes": 3907,
|
| 343 |
+
"sha256": "ecfaf6a3edca6ffc3152a61ccc6c27240f42daaa0ddf6efc08e1f9b277295734"
|
| 344 |
+
},
|
| 345 |
+
{
|
| 346 |
+
"path": "onnx/SOURCE.json",
|
| 347 |
+
"bytes": 633,
|
| 348 |
+
"sha256": "e950bf44034b011a64bba3773b388e386418ef952c3cd17ceefda5bfa94a3aaa"
|
| 349 |
+
},
|
| 350 |
+
{
|
| 351 |
+
"path": "onnx/checksums.sha256",
|
| 352 |
+
"bytes": 653,
|
| 353 |
+
"sha256": "d74c3c8d3a148f240d795dc603e18ac2c152a3f7ad3e45dcd66d3e14ee335b6b"
|
| 354 |
+
},
|
| 355 |
+
{
|
| 356 |
+
"path": "onnx/decode.onnx",
|
| 357 |
+
"bytes": 30427790,
|
| 358 |
+
"sha256": "7940923add86f76e7fa78d910b0632ca1779f8cc9a2ca2b49236381a9ca77183"
|
| 359 |
+
},
|
| 360 |
+
{
|
| 361 |
+
"path": "onnx/duration.onnx",
|
| 362 |
+
"bytes": 7322687,
|
| 363 |
+
"sha256": "b728ca2564b9e5b7d6cf5e446f65e02a6fe2f1880ba281466fec93a667dd2388"
|
| 364 |
+
},
|
| 365 |
+
{
|
| 366 |
+
"path": "onnx/export_onnx.py",
|
| 367 |
+
"bytes": 7884,
|
| 368 |
+
"sha256": "77bd27277861c8cae670247e3c9e3b976134a4886506fb069331aa6828752be6"
|
| 369 |
+
},
|
| 370 |
+
{
|
| 371 |
+
"path": "onnx/inference_onnx.py",
|
| 372 |
+
"bytes": 7333,
|
| 373 |
+
"sha256": "cf48c4812f68e8315d80568e93650c64a7ad3fdfb9a0051c61a0d1d0746df274"
|
| 374 |
+
},
|
| 375 |
+
{
|
| 376 |
+
"path": "onnx/parity_report.json",
|
| 377 |
+
"bytes": 1026,
|
| 378 |
+
"sha256": "10c88564d24fe65ea730dc6ec98aa19ec74d3590efa427595a3c122c4c0f7039"
|
| 379 |
+
},
|
| 380 |
+
{
|
| 381 |
+
"path": "onnx/requirements.txt",
|
| 382 |
+
"bytes": 126,
|
| 383 |
+
"sha256": "43abd2c128e4296f1f0171f12946f3fc7dee3f8c8e2bb1858bcae6b43b62b3c9"
|
| 384 |
},
|
| 385 |
{
|
| 386 |
"path": "requirements-tested.txt",
|
|
|
|
| 422 |
"bytes": 206,
|
| 423 |
"sha256": "16ca4890f3e0107250b4a522c0127779994a5a2b99fc35d6a27f93496a72153a"
|
| 424 |
},
|
| 425 |
+
{
|
| 426 |
+
"path": "runtime/text/LICENSE",
|
| 427 |
+
"bytes": 1053,
|
| 428 |
+
"sha256": "f89accd9d66f6a011f19997d7a21cf71a35ffe2e2d0911b5460cbd0cab52a581"
|
| 429 |
+
},
|
| 430 |
{
|
| 431 |
"path": "runtime/text/__init__.py",
|
| 432 |
"bytes": 1572,
|
|
|
|
| 437 |
"bytes": 2880,
|
| 438 |
"sha256": "11dc7325547290e529c597e620f3aaf8d0bd8a2a2987d48eb42d2289534e42d1"
|
| 439 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 440 |
{
|
| 441 |
"path": "runtime/text/symbols.py",
|
| 442 |
"bytes": 642,
|
|
|
|
| 491 |
"path": "third_party/VITS_LICENSE.txt",
|
| 492 |
"bytes": 1090,
|
| 493 |
"sha256": "1cdf858b4d555567398b378b4a0166e97f7908c56607101b8bf9bb6754cdff3f"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 494 |
}
|
| 495 |
],
|
| 496 |
+
"format": "inflect_v2_release_manifest_v1",
|
| 497 |
+
"onnx_release": {
|
| 498 |
+
"format": "FP32 ONNX opset 17",
|
| 499 |
+
"path": "onnx/",
|
| 500 |
+
"verified": true,
|
| 501 |
+
"released": "2026-07-25"
|
| 502 |
+
}
|
| 503 |
}
|