VALL-E-X Fork • Original Conditioning & Data Pipeline • Solo on Consumer GPUs
BedVibe-TTS: the architecture, the conditioning, and the pipeline that feeds it.
BedVibe-TTS is a VALL-E-X-family AR + NAR neural-codec language model (over EnCodec Q=8 tokens) — forked from the
open VALL-E-X architecture and trained from scratch (weights from random initialisation, not fine-tuned). The base transformer is
not my invention; the original engineering here is the conditioning design — a 6-dim emotion vector, a 13-dim voice-trait
vector, and a 2-dim speaker-blend vector, none of which exist in stock VALL-E-X — plus a custom memory-mapped .bvbean dataset
format and a Rust metadata pipeline that make a 108,076-row corpus trainable on consumer hardware.
End-to-end pipeline
Raw studio audio becomes a single memory-mapped training file through six deterministic stages. Each stage writes a typed, validated artifact consumed by the next.
The conditioning metadata — one real record
Every training record carries five conditioning channels. Below is a real (anonymised) row from metadata_B_train.jsonl,
with the three vector channels broken out and labelled with the project's own names. Click an emotion to see how the one-hot moves.
emotion_vector
6-dim one-hot— record emotion: Happytrait_vector
13-dim continuous— 9 dimensions defined from the Dataset B trait corpus (breathiness and low-high are per-gender); remaining slots not yet assigned. Training rows currently hold the whole axis at zero.blend_vector
2-dim speaker interpolationSingle-speaker rows use [1.0, 0.0]. Blended rows (e.g. [0.67, 0.33], [0.50, 0.50]) are generated by the Rust blender into 768k / 588k-row variants.
A B_BLEND row interpolates two speakers (here 0.67 / 0.33) and pairs both speakers' EnCodec token sets across all six emotional states for the same utterance — the raw material the model needs to learn the interpolation rather than memorise one voice. The Rust blender emits hundreds of thousands of these from the base corpus.
The real code
A browsable slice of the actual pipeline source. Pick a file.
The metadata generators (B metadata training/main.rs, 543 lines) and the speaker-blender
(B metadata blending/src/main.rs, 468 lines) are compiled Rust; the model itself
(valle_training/VALL-E-X/models/vallex.py) wires the emotion/trait/blend projections into the AR and NAR
heads as additive bias. Full source is in the repository.
The .bvbean binary format
One memory-mapped file packs the entire corpus — audio tokens, attention weights, text IDs, the three conditioning vectors,
a speaker index, and the speaker-embedding lookup table — behind a JSON header of byte offsets, so the loader reads any sample
with O(1) random access and no per-file open. Magic bytes: BDBEAN1\0.
uint16-safe by design (all IDs validated < 65,536 at pack time); conditioning vectors stored as float16 and upcast to float32 on read — roughly half the storage of a naive float32/uint32 layout.
Training resilience — the loop that refuses to die
A weeks-long run on a single consumer GPU will hit NaNs, out-of-memory batches, and poisoned samples. The training loop
(utils/train_epoch.py) is built to survive all of them without crashing — and, before it trusts a single step, to prove the
model is actually using the text rather than hallucinating audio. Every guard below is in the real source; the skip-counters are
returned in each epoch's summary.
isfinite(loss) drops NaN/Inf batches and zeroes grads — one poisoned sample can't sink a week of training.OutOfMemoryError, empties CUDA cache, drops the batch, and continues — one long utterance won't kill the run.train_epoch_seg.py slices long sequences into overlapping VRAM-safe windows — run as an A/B against the flat loop to confirm the loss curve held.
BF16 autocast (GradScaler disabled by design), env-selectable SDPA kernel (flash / mem-efficient / math — the same switch that surfaced the
Blackwell failure documented in the report), gradient accumulation, and a deterministic per-epoch sampler
(seed = base + epoch) for reproducible shuffles.