Skip to content

tools/paradee: memory-map the F32 GGUF; record the F16 and v1.1 evaluation - #85

Merged
lalalune merged 1 commit into
mainfrom
paradee/f16-v11-eval
Oct 21, 2026
Merged

lalalune merged 1 commit into
mainfrom
paradee/f16-v11-eval

Conversation

@lalalune

Copy link
Copy Markdown
Member

What

  1. paradee_load_model memory-maps an all-F32 GGUF.
    • That covers the converter's default and the pinned file. It is mapped read-only and the layers read the weights in place.
    • Until now the loader read the whole file into private memory: 32 MB that stays resident for as long as the voice is loaded.
    • PARADEE_USE_MMAP=0 restores the read. Non-F32 files are still read and widened, and Windows falls back to the read.
  2. README: the evaluation of --outtype f16 and of Paradee-8M v1.1 that was asked for, with the numbers below.

Mapping: evidence

  • test-paradee-parity against a fresh reference dump (pinned torch 2.14.0 / kokoro 0.9.4 / misaki 0.9.4, paradee 9c8b4d75): OK, mapped and read.
    • The native waveforms are byte-identical between the two modes (cmp, all 5 sentences).
  • Also OK: test-paradee-api (mapped, read, and an F16 file through the widening path), test-paradee-phase-lock, and eliza-inference-test-paradee-asr (558 checks).
  • TB336FU (4 GB, Android, arm64), paradee-tts on 19.8 s of speech, two runs each:
peak RssAnon peak RssFile RTF
mapped (new default) 170 MB 34 MB (clean) 0.29–0.34
PARADEE_USE_MMAP=0 (old behaviour) 202 MB 3 MB 0.28–0.32

F16: keep F32

Pinned v1.0 GGUF, this directory's parity test, and 40 more sentences (20 assistant prompts and 20 Harvard sentences):

  • The sentences were phonemized with tools/misaki-g2p, synthesized with paradee-tts, and transcribed with Phonon-2 (tools/parakeet) and whisper.cpp base.en.
  • "Mixed" means an F16 decoder with an F32 BERT and predictor. It was an experiment and is not in the converter.
File Size (deflate) Parity test Durations WER Phonon-2 / whisper RTF tablet / M4
F32 (pinned) 32.1 MB (29.7) pass (end to end 58–76 dB) – 3.90% / 3.90% ~0.30 / 0.024
--outtype f16 16.2 MB (14.9) fail (end to end 9.8–23 dB) 1 of 40 changed by 25 ms 3.90% / 3.90% ~0.32 / 0.024
mixed 22.1 MB (20.4) end to end 56–61 dB, but asr/dec exceed the 1e-3 × RMS stage gate identical 3.90% / 3.90% ~0.30 / 0.024
  • The F16 error is in the BERT and the duration/F0 predictor. With those in F32, the end-to-end SNR rises to 56–61 dB. The low SNR of full F16 is mostly accumulated harmonic phase from F0 errors near 1e-3: the log-mel difference is small and WER is unchanged.
  • F16 is not faster, because the runtime computes in F32.
  • F16 costs more RAM. It cannot be mapped and is widened at load, which adds 16–22 MB of private memory (measured on the tablet: 218–223 MB peak vs 202 MB for F32 read, and 170 MB for F32 mapped).
  • So F32, mapped, is the right file today. F16 would only pay off with layers that read F16 weights in place. The ggml conv1d path already keeps a private F16 copy of its weights (cached_f16_weight, up to ~10 MB for the 3-D weights). That is where a follow-up could save memory.
  • The published "8 MB" is upstream's int8 ONNX graph (onnx/paradee_int8.onnx, 9.0 MB). This runtime does not use it.

v1.1: needs a native port, not a pin move

  • sahilmahendrakar/Paradee-8M-v1.1 at 330617ad keeps the text side (identical text_side.pt) and the decoder's AdaIN trunk.
  • It replaces the iSTFTNet generator and the phase lock with a frame-rate source-filter head (training/scripts/vhead.py, paradee 606e16e1): ConvNeXt blocks at 80 fps shaping the STFT of a 64-harmonic sine bank and of random noise, plus a 3 ms noise burst path.
  • The current converter and runtime cannot load it. Its output is also not deterministic (it draws noise), so the parity gate would need a seeded noise input.

Upstream's ONNX graphs, one onnxruntime thread on the M4 Max, the same 40 sentences:

Graph Size RTF WER Phonon-2 / whisper
v1.0 fp32 37.0 MB 0.051 4.16% / 3.90%
v1.0 int8 9.0 MB 0.054 3.90% / 3.12%
v1.1 fp32 34.8 MB 0.010 3.90% / 3.12%
v1.1 int8 8.5 MB 0.011 4.16% / 3.12%

v1.1 is about 5x faster at the same WER (one word in 385 is the resolution here). Upstream reports less buzz (2–4 kHz harmonic contrast 3.9 dB vs 1.3 dB); that was not re-measured here. On the 4 GB tablet, where v1.0 runs at RTF ~0.3, a native v1.1 head is the TTS change worth doing next.

Not covered

  • No APK and no in-app run.
  • The tablet RTF figures were taken while the device was busy with other work (load average ~17), so treat them as relative.

AI-assisted change.

🤖 Generated with Claude Code

…ation

paradee_load_model read the whole GGUF into private memory (32 MB that stays
resident while the voice is loaded). An all-F32 file, the converter's default
and the pinned one, is now mapped read-only and the layers read the weights
in place; PARADEE_USE_MMAP=0 restores the read. Other files are still read
and widened. Output is byte-identical; on a 4 GB TB336FU peak private memory
for a 19.8 s utterance drops from 202 MB to 170 MB.

README: F16 halves the file but fails the parity gate (the BERT and F0
predictor carry the error), changes a duration in 1 of 40 sentences, is no
faster, and costs more RAM because it is widened at load; WER is unchanged.
Paradee-8M v1.1 replaces the generator with a new frame-rate head, which this
runtime cannot load; its upstream ONNX graph is ~5x faster than v1.0's with
the same WER.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added documentation Improvements or additions to documentation examples labels Oct 20, 2026
@lalalune
lalalune merged commit 5c3a3a7 into main Oct 21, 2026
2 of 23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation examples

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant