Repository navigation
feat: load ced and voice bundle components from memory (no temp file), bump ced.cpp and voice-detect.cpp - #92
Merged
Conversation
…and voice-detect.cpp ced.cpp and voice-detect.cpp can now load a model from memory, with a prefix for a model stored inside a larger GGUF. Move both submodules to the commits that add this (ced.cpp 736a4ee, voice-detect.cpp bca46bc). Use it for the ced and voice components of a bundle. The bundle is mapped read-only (mmap, MapViewOfFile on Windows) and handed to the prefixed loader, which copies only the tensors of that component during the call. No standalone copy, temporary file, memory file or environment variable is needed any more, so bundle_extract and PARAKEET_BUNDLE_NO_MEMFD are removed. Pages of the other components are never touched. Loading ced-small Q8_0 from the 1.1 GB standard bundle peaks 49 MB above an idle process and reads 24 MB from storage. Both loaders now check that the component exists and has the right kind, and add the loader's own error text to the message. The speaker encoder family is read from the prefixed keys of the bundle. The full-bundle test runs with a read-only TMPDIR, checks that the descriptor count and the working directory do not change, and measures the bytes read from storage per component with the page cache dropped. Assisted-by: Claude:claude-sonnet-5-5 [Claude Code]
mudler
approved these changes
Oct 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The
cedandvoicecomponents of a bundle are now loaded straight from memory, with no standalone copy and no temporary file.third_party/ced.cppto 736a4ee (ced_capi_load_from_memory_prefixed) andthird_party/voice-detect.cppto bca46bc (voicedetect_capi_load_from_memory_prefixed). Both are on the default branch of their repositories..gitmodulesstill points at thelocalai-orgrepositories; CMake and CI (submodules: recursive) need no change.CedTagger::loadandSpeakerEncoder::loadmap the bundle read-only (src/bundle_map.cpp:mmapon Linux and macOS,MapViewOfFileon Windows) and pass the map and the prefix (ced.,voice.) to the hook. The hook parses the header and copies only the tensors of that component, then the map is released.src/bundle_extract.*,pk::ComponentFileandPARAKEET_BUNDLE_NO_MEMFDare removed (about 250 lines). Nothing needs them on any platform.ced_capi_last_error(NULL)orvoicedetect_capi_last_load_error()to the error message. The speaker encoder family is read from the prefixed keys of the bundle header, so the fingerprint and identity are unchanged.What bytes the hooks get
The prefixed hooks need a buffer that parses as a GGUF holding the component's keys and tensor table. That is the whole bundle image, not only the component. Reading the whole image is not acceptable (1.1 GB for the standard bundle), so the buffer is a read-only map of the file: the hook touches only the header and the tensors under the prefix, and the operating system reads only those pages. The other components are never read. No sparse image or minimal GGUF writer is needed.
Memory and I/O
Standard bundle, 1100.8 MB (asr 940.5, diar 108.6, ced-small Q8_0 23.6, voice WeSpeaker ResNet34 F32 26.5, vad), one component loaded in a fresh process:
The peak is the copy of the component (kept) plus the touched pages of the map (file cache, released with the map). It depends on the component, not on the bundle: the 338 MB small bundle gives the same figures. I did not measure the old memfd path; it held one more copy of the component during the load.
Behaviour
No memfd, no temporary file, no environment variable; the bundle is opened read-only for the moment it takes to map it and closed again. The same code runs on every platform. Windows and macOS were not run (standard
mmapandMapViewOfFilecode). CED scores and speaker embeddings are bitwise equal to the standalone files.Tests
ctest -LE model: 38 of 38 pass (CED and voice-detect ON, Release).ctest -L modelwith real files (tdt_ctc-110m Q8_0, Nemotron diarization Q8_0, CED-small Q8_0, WeSpeaker ResNet34 F32, silero-vad-f16, all five in a bundle built byscripts/bundle_gguf.py): 86 of 87 pass; the only failure istest_relpos_attention_local_chunked, known and unrelated.test_bundle_full(also with the publishedparakeet-bundle-small.gguf): identical transcript, diarization JSON, CED scores (bitwise), speaker embedding (bitwise), identity, Silero probabilities and named diarization. The bundle block oftest_speaker_fingerprint,test_bundle_modelsandcheck_bundle.pypass.TMPDIR; the descriptor count, the working directory and/proc/self/mapsshow no temporary file, memory file or descriptor; the bytes read from storage per component (page cache dropped first) stay near the component size and under half of the bundle. The old bytes-read check usedrchar, which does not count mapped reads, so the expectation changed: now about 1x the component size instead of up to 3x.test_bundleadds unit checks for the map (content, missing file, empty file) and the new component and kind errors.Limits
docs/bundle.md ("ced and voice components", "Partial loading") and AGENTS.md are updated.
🤖 Generated with Claude Code