Skip to content

feat: VAD-only GGUF files (head, front end, subsampler) and a slicer - #87

Merged
mudler merged 2 commits into
masterfrom
feat/vad-only-gguf
Oct 4, 2026
Merged

mudler merged 2 commits into
masterfrom
feat/vad-only-gguf

Conversation

@localai-org-maint-bot

Copy link
Copy Markdown
Collaborator

What and why

Ultra and Redux have a built-in VAD head, but using it meant loading the whole model, 213 MB to 1.4 GB. The head reads only the log-mel front end, the subsampler and itself. This PR adds a script that cuts those parts out into a 6 to 10 MB GGUF, and loaders that run VAD from it.

How

  • scripts/slice_vad_gguf.py copies 20 tensors byte for byte from an Ultra or Redux GGUF, plus the encoder, preprocessor and parakeet.vad.* keys. It does not requantize. It records the parent (name, file, size, architecture, SHA-256) as provenance metadata.
  • The slice sets parakeet.arch=vad. A normal file has a vocabulary and a decoder, and the slice has neither, so the loader needs the marker.
  • ModelLoader::load accepts the marker without a vocabulary. New Model::load_vad_only serves it. parakeet-cli vad (via gguf_is_vad_only) and the parakeet_capi_vad_* functions use it through a separate context slot.
  • Every other call refuses the slice with a clear message: Model::load, DiarizationModel::load, and the other C-API entry points ("context holds a VAD-only model"). Files that are not slices load as before.

Results

Compared with the parent model on three clips and four slices (Ultra Q8_0, Ultra F16, Redux packed, Redux dequantized F16):

  • Output is byte-identical to the parent.
  • Load time is a few ms, against 0.1 to 0.7 s.
  • Peak memory is about 245 MiB, against 0.6 to 1.6 GiB, for a 33 s clip.
  • Speed is unchanged. VAD at 1 thread runs at about 92x real time, against 736x for Silero. The machine was busy, so the 8-thread numbers are only indicative.

I also ran parakeet-cli vad on the two published files below and compared with the full parent output on two_speakers.wav: identical.

Tests

  • New tests/test_vad_only.cpp (label model; needs PARAKEET_TEST_VAD_ONLY_GGUF and PARAKEET_TEST_GGUF_ULTRA): the slice gives the parent's VAD output, and the slice is refused by the other calls.
  • ctest -LE model: 35 of 35 pass (5 skipped for missing fixtures). With the model GGUFs set, everything passes except test_relpos_attention_local_chunked and test_capi_timestamps, which fail without this change too.
  • CED and voice-detect were off in my build because their submodules were not checked out.

Limits

  • CPU only. Streaming and GPU were not tested.
  • The C ABI is unchanged.
  • No accuracy rerun, since the output is identical to the parent.
  • A slice cannot transcribe, diarize or stream.
  • The bundle work (feat: bundle GGUF format (ASR, VAD, diarization, sound events and voice in one file) #85, if it lands) touches the same loader and C-API code. The two features do not depend on each other: a slice is its own file kind, and a bundle does not need to hold one.

Published files

Both are on https://huggingface.co/mudler/parakeet-cpp-gguf, CC-BY-4.0. They are cut out of Moondream's models, not trained here: credit Moondream and NVIDIA. docs/vad.md, the README and models/MANIFEST.md link them with sizes and checksums.

File Size (bytes) SHA-256
redux-vad.gguf 9,939,488 588e1d6e2ee5b6cdfd9ec5ea98dc0993d5bea498d9cc4ec8d6077041eef8a34f
ultra-vad-q8_0.gguf 6,007,328 8b891a4435e97438104ca07c72530d0c5fe62b986baee48b2dd4e1500c1d4758
parakeet-cli vad --model redux-vad.gguf --input audio.wav

Assisted-by: Claude:claude-sonnet-5-5 [Claude Code]

🤖 Generated with Claude Code

mudler added 2 commits October 4, 2026 01:28
scripts/slice_vad_gguf.py copies from an Ultra or Redux GGUF only what
the VAD path reads: the mel filterbank and window, the subsampler, the
vad_head tensors and the encoder, preprocessor and vad config keys. It
does not requantize, sets parakeet.arch to "vad" and records the parent
name, file, size, architecture and SHA-256.

The marker is needed because the loader expects a vocabulary and
decoder. ModelLoader accepts arch "vad" without a vocabulary. The new
Model::load_vad_only serves the slice, and parakeet-cli vad and the
C-API VAD calls use it through a separate context slot. Model::load and
DiarizationModel::load refuse the slice with a log message, and every
other C-API call reports that the context holds a VAD-only model.
Existing files load as before.

Assisted-by: Claude:claude-sonnet-5-5 [Claude Code]
Add the two published slice files, redux-vad.gguf and
ultra-vad-q8_0.gguf, with sizes and SHA-256 to docs/vad.md, the
README and models/MANIFEST.md. Note that they are cut out of
Moondream's models (CC-BY-4.0) and cannot transcribe.

Assisted-by: Claude:claude-sonnet-5-5 [Claude Code]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants