Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions finetune/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
__pycache__/
*.py[cod]
.pytest_cache/
.ruff_cache/
build/
dist/
*.egg-info/
.venv/
prepared/
runs/
exports/
90 changes: 90 additions & 0 deletions finetune/CONTRACT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Inflect adaptation toolkit contract

This directory is a public, generic warm-start adaptation toolkit. It is not
the private recipe used to produce the Inflect v2 release checkpoints.

## Supported result

The toolkit produces a separate, fixed-voice checkpoint for one configured
language. The dataset speaker becomes the checkpoint voice. It does not add
runtime-selectable speakers or languages to the original checkpoint.

## Public workflow

```text
python -m inflect_finetune prepare ...
python -m inflect_finetune audit ...
python -m inflect_finetune train ...
python -m inflect_finetune export ...
```

Every command must support `--help`, fail with an actionable message, and write
machine-readable reports alongside human-readable summaries.

## Prepared dataset layout

```text
prepared/
dataset.json
symbols.json
train.jsonl
validation.jsonl
audio/
```

Each JSONL row contains:

```json
{
"audio": "audio/example.wav",
"text": "Original transcript.",
"normalized_text": "Normalized transcript.",
"phonemes": "phoneme string",
"duration_seconds": 2.34
}
```

Prepared rows may also preserve `id`, `speaker`, `group_id`, and
`group_field`. Source manifests may provide `session` as a split boundary and
`phonemes` for prephonemized preparation.

`dataset.json` records the language, sample rate, frontend, source-manifest
hash, frontend source/metadata hashes where applicable, speaker, split seed,
row counts, and aggregate diagnostics. `symbols.json` records the ordered
symbol inventory and its relationship to the base inventory.

## Checkpoint migration

Checkpoint migration copies all shape-compatible generator weights. Text
embedding rows are copied by symbol string, not by numeric index. Newly added
symbols receive deterministic initialization. Training-only discriminators,
optimizers, and schedulers are initialized from public generic defaults.

## Safety boundaries

Public code must not contain or infer:

- private corpus paths, transcripts, or generated audio;
- teacher-model names or corpus-generation prompts;
- internal filtering thresholds unrelated to generic audio validity;
- the original base-model curriculum, search history, or checkpoint ranking;
- credentials, rental identifiers, or private storage locations.

## Validation gates

At minimum, automated tests must cover:

- manifest parsing and path traversal rejection;
- deterministic splitting;
- group, duplicate-audio, and duplicate-transcript leakage prevention;
- audio-format validation;
- language/frontend failures;
- phoneme coverage and unknown-symbol reporting;
- embedding migration by symbol identity;
- checkpoint save/resume behavior;
- inference-only export loadability;
- language-aware frontend packaging and refusal of silent English fallback;
- ONNX Runtime parity when ONNX export is requested.

A release may call language adaptation experimental until at least one
non-English end-to-end run passes preparation, training, export, and inference.
227 changes: 227 additions & 0 deletions finetune/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
# Inflect adaptation toolkit

Public tools for warm-starting Inflect v2 with user-owned speech data. One run
creates one fixed voice for one configured language.

This is a generic compatible trainer, not the private process used to create
the official Inflect v2 checkpoints. It does not include the private corpus,
corpus-generation process, original curriculum, hyperparameter search, or
internal checkpoint-selection process.

## What is implemented

- JSONL and CSV manifests with strict path and audio validation
- deterministic 24 kHz mono preparation
- leakage-safe train/validation splitting by transcript and recording group
- eSpeak, prephonemized, and explicit custom Python frontends
- symbol-aware embedding migration from Micro or Nano
- staged generator/discriminator training with AMP and accumulation
- atomic checkpoints and strict same-run resume validation
- held-out waveform diagnostics and optional transcript evaluators
- inference-only PyTorch and ONNX packages
- language-aware deployment frontends with no silent English fallback

The software path has been tested end to end, including a real Nano CUDA
training step, resume, strict PyTorch load, and ONNX Runtime parity. New
language and new voice quality remain experimental: data quality, phoneme
coverage, and fluent-speaker review determine whether an adaptation is useful.

Read [CONTRACT.md](CONTRACT.md) and [scope](docs/SCOPE.md) before starting.

## Install

From this directory:

```bash
python -m venv .venv
python -m pip install --upgrade pip
python -m pip install -e .
```

Activate on PowerShell with:

```powershell
.\.venv\Scripts\Activate.ps1
```

For ONNX export and parity checks:

```bash
python -m pip install -e ".[onnx]"
```

Every command is available as either `inflect-adapt` or
`python -m inflect_finetune`.

## 1. Create a manifest

JSONL and CSV are supported. A minimal JSONL row is:

```json
{"audio":"session01/000001.wav","text":"Buenos dias.","speaker":"voice-a","session":"session01"}
```

`audio` and `text` are required. `speaker`, `session`, `group_id`, `id`, and
`phonemes` are documented in [MANIFESTS.md](docs/MANIFESTS.md).

Use one consenting speaker per dataset. Put clips cut from the same source
recording in the same `group_id` or `session` so they cannot leak across
splits.

## 2. Prepare and audit

For an eSpeak-supported language:

```bash
inflect-adapt prepare \
--manifest data/metadata.jsonl \
--audio-root data/audio \
--language es \
--frontend espeak \
--output prepared/es

inflect-adapt audit --dataset prepared/es
```

Preparation writes converted audio, ordered symbols, frontend identity, hashes,
and deterministic nonempty train/validation splits. Do not train until audit
passes and a fluent speaker has inspected representative normalized text and
phonemes.

If eSpeak is unsuitable, use prephonemized rows or the documented
[custom frontend hook](docs/CUSTOM_G2P.md).

## 3. Train

Start with Micro unless minimum footprint is the primary goal:

```bash
inflect-adapt train \
--base owensong/Inflect-Micro-v2 \
--dataset prepared/es \
--preset micro-12gb \
--output runs/es-micro
```

Available presets are `balanced`, `micro-12gb`, and `nano-8gb`. They are
starting points, not memory or quality guarantees. CLI flags override preset
values exactly:

```bash
inflect-adapt train \
--base nano \
--dataset prepared/es \
--preset nano-8gb \
--batch-size 1 \
--gradient-accumulation-steps 12 \
--output runs/es-nano
```

The public release checkpoint contains inference weights only. Training-only
posterior and discriminator components are initialized by this toolkit, and
new symbol embeddings are initialized deterministically.

## 4. Resume safely

```bash
inflect-adapt train \
--base owensong/Inflect-Micro-v2 \
--dataset prepared/es \
--preset micro-12gb \
--output runs/es-micro \
--resume runs/es-micro/checkpoints/latest.pth
```

Resume is accepted only for the same run identity. Changes to the base model,
prepared data, symbols, frontend, public optimizer schema, or relevant
configuration are rejected.

The final resumable checkpoint is
`runs/es-micro/checkpoints/adaptation-final.pth`. Step checkpoints and held-out
audio are written at the configured intervals. The toolkit does not label a
checkpoint "best"; select one using a declared held-out process.

## 5. Export

Export the selected training checkpoint together with the exact prepared
frontend metadata:

```bash
inflect-adapt export \
--checkpoint runs/es-micro/checkpoints/adaptation-final.pth \
--prepared-dataset prepared/es \
--format pytorch \
--output exports/es-micro
```

For ONNX:

```bash
inflect-adapt export \
--checkpoint runs/es-micro/checkpoints/adaptation-final.pth \
--prepared-dataset prepared/es \
--format onnx \
--output exports/es-micro-onnx
```

For a custom frontend, also pass the same source file:

```bash
inflect-adapt export \
--checkpoint runs/custom/checkpoints/adaptation-final.pth \
--prepared-dataset prepared/custom \
--frontend-hook my_frontend.py \
--format onnx \
--output exports/custom
```

Export strips posterior, discriminator, optimizer, scheduler, scaler, RNG, and
other training-only state. It writes `frontend.json`, `symbols.json`,
checksums, a report, a deployable runtime, and optional ONNX graphs. Adapted
checkpoints without frontend metadata are rejected instead of silently using
the release English frontend.

## 6. Evaluate the exported package

Use original text for eSpeak/custom packages or include `phonemes` in each
evaluation row for a prephonemized package:

```bash
inflect-adapt evaluate \
--model-dir exports/es-micro \
--manifest prepared/es/validation.jsonl \
--output evaluations/es-micro \
--max-samples 100
```

The report covers waveform duration, silence, clipping, peak, RMS, DC offset,
and non-finite values. An optional transcript-evaluator hook can add ASR or
other metrics. These diagnostics do not replace blind listening or
fluent-speaker review.

## Documentation

- [Supported scope](docs/SCOPE.md)
- [Manifests and split safety](docs/MANIFESTS.md)
- [Data quality](docs/DATA_QUALITY.md)
- [Languages and symbols](docs/LANGUAGES.md)
- [Training, checkpoints, evaluation, and export](docs/TRAINING.md)
- [Custom G2P/frontend hooks](docs/CUSTOM_G2P.md)
- [Troubleshooting](docs/TROUBLESHOOTING.md)
- [Consent and responsible use](docs/RESPONSIBLE_USE.md)

## Release gate

Before publishing an adapted checkpoint:

1. Re-run preparation and audit from the source manifest.
2. Confirm groups and duplicate transcripts do not cross the split.
3. Compare several checkpoints on untouched held-out text.
4. Load the exported package in a clean environment.
5. Run its checksum, inference, and ONNX parity checks where applicable.
6. Have fluent speakers review pronunciation and naturalness.
7. Publish data provenance, consent, language, voice, frontend, base model,
toolkit version, evaluation method, and limitations.

Passing the software checks does not establish naturalness, voice identity, or
acceptable pronunciation.
68 changes: 68 additions & 0 deletions finetune/docs/CUSTOM_G2P.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Custom G2P and frontend hooks

Use a custom frontend when eSpeak does not provide acceptable normalization or
phonemization. A frontend controls normalization, punctuation, word
boundaries, and the exact symbol stream consumed by the generator.

## Hook contract

Pass a trusted factory as either `module:callable` or `file.py:function`:

```bash
python -m inflect_finetune prepare \
--manifest data/metadata.jsonl \
--audio-root data/audio \
--language my-language \
--frontend custom \
--frontend-hook ./my_frontend.py:create_frontend \
--output prepared/my-language
```

The factory may accept no arguments or the keyword argument `language`. It
must return an object with:

```python
normalize(text: str) -> str
phonemize(normalized_text: str) -> str
symbols() -> list[str]
metadata() -> dict
```

`symbols()` must return a nonempty ordered list of unique, one-character
strings. `metadata()` must contain `name`, `version`, `language`, and
`configuration`.

The hook is trusted Python code and executes during preparation. Do not run a
hook from an untrusted source.

## Reproducibility checks

Preparation calls normalization and phonemization twice and rejects
nondeterministic output. It also rejects empty text, control characters, and
symbols not declared by the hook.

The prepared dataset stores hashes of the hook source and declared metadata.
Export requires the matching hook source for custom frontends, verifies those
hashes, and copies the hook into the deployment package. It will not silently
replace a custom or non-English frontend with the release English frontend.

## Frontend validation

Before training, test:

- ordinary sentences and every target phoneme;
- punctuation and sentence boundaries;
- numbers, dates, currencies, and abbreviations;
- names, loanwords, and mixed scripts;
- unsupported and empty input;
- repeated calls for exact determinism.

Have fluent speakers inspect both normalized text and phonemes. A technically
valid symbol stream can still encode the wrong pronunciation.

## Deployment requirements

An adapted package must include the exact frontend needed for inference.
Third-party dictionaries or models remain subject to their own licenses and
must be packaged or documented separately. Do not describe an export as
self-contained if its frontend requires an external artifact.
Loading
Loading