VRAM = incremental GPU memory used by inference (excluding desktop/display baseline). Decoder uses chunked decoding (~23.8s per chunk), so VRAM is constant regardless of audio length.
Quantization Strategy
Model
Method
Size Reduction
Tool
T5
INT4 (MatMul) + FP16 (Embedding)
1075→538 MB (-50%)
MNNConvert --weightQuantBits 4 --fp16
DiT
INT8 (Conv/MatMul weights)
1754→445 MB (-75%)
MNNConvert --weightQuantBits 8
Decoder
INT8 (Conv weights)
200→53 MB (-74%)
MNNConvert --weightQuantBits 8
Encoder
INT8 (Conv weights)
205→52 MB (-75%)
MNNConvert --weightQuantBits 8
NC
INT8 (MatMul weights)
~0.2 MB
MNNConvert --weightQuantBits 8
T5 Encoder
The T5Gemma text encoder runs on MNN CPU with INT4 quantization. INT4 is the default mode — use --mnn-t5-fp32 to fall back to FP32 precision.
MNN CUDA for T5 produces incorrect output (max_diff=26 vs CPU reference) — the root cause was extensively investigated but not isolated to a single CUDA kernel. MNN CPU produces identical results to ONNX Runtime.
All other models (NC, DiT, Decoder, Encoder) run on MNN CUDA with negligible differences from CPU reference.
Model Architecture
Text Prompt → T5Gemma (MNN CPU INT4) → Text Embedding
Duration → NumberConditioner (MNN CUDA INT8) → Duration Embedding
↓
DiT (MNN CUDA INT8) ← Diffusion Denoising
↓
Decoder (MNN CUDA INT8 FusedWN) → Audio Waveform
INT8 Full Pipeline: T5 INT4 + DiT INT8 + Decoder INT8 + Encoder INT8. Total model size ~1.09 GB, RTF 10-33x on RTX 2080 Ti
Chunked Decoding: Decoder processes latents in chunks of 256 timesteps, enabling pseudo-streaming output (~23.8s of audio per chunk) and constant VRAM regardless of audio length
Pre-allocated Memory: Decoder is initialized with chunk_size=256 at load time, eliminating expensive resize during inference
WeightNorm Pre-fusion: Decoder Conv1d WeightNorm is pre-fused into weights before ONNX→MNN conversion, avoiding FP16 precision issues in L2 normalization
Softmax Fix: MNN CUDA Softmax kernel patched for small axis sizes (≤64) — see MNN fork
Softmax Fix: SOFTMAX_AXIS_REDUCE kernel had a bug where idle threads in block reduction corrupted __shared__ memory for small axis sizes, causing echo artifacts in Decoder attention. Fixed by using simple per-thread SOFTMAX kernel for axis ≤ 64.
MatMul PrecisionType Fix: FP16FP32Mix mode incorrectly set precisionType=2 (always FP16), causing precision anomalies. Fixed to use precisionType=0 for FP16FP32Mix/FP32 modes.
LoopCreator Op Type Check: CUDALoop::onExecute only supports UnaryOp/MatMul/BinaryOp for non-fused commands. Other op types (LayerNorm, Softmax, Select, etc.) were silently skipped, producing garbage output. LoopCreator now rejects unsupported op types at creation time, falling back to CPU.
T5 Forced to CPU: T5 MNN CUDA produces incorrect output (root cause not isolated). T5 always runs on MNN CPU backend, producing correct results verified against ONNX Runtime.