How to Optimize VoxCPM Inference Speed for RTF ~0.3 on Consumer GPUs

You can achieve a real-time factor (RTF) of approximately 0.3 on consumer GPUs by enabling torch.compile with Triton support, using half-precision (BF16/FP16), reducing diffusion steps to 8–12, and wrapping inference in torch.inference_mode().

VoxCPM is a token-free speech generation model from OpenBMB that runs end-to-end on a single GPU. While the default configuration prioritizes quality over speed, the model's architecture—implemented in pure PyTorch—supports aggressive compile-time and runtime optimizations that slash latency without requiring specialized hardware.

Understanding the Latency Bottlenecks

Before applying optimizations, identify where inference time is spent. According to the source code in src/voxcpm/model/voxcpm2.py, the forward pass consists of several distinct stages:

  • Base LM and Residual LM (lines 68–84): The MiniCPM 4 backbone predicts semantic tokens through matrix-multiplication-heavy operations.
  • Feature Encoder (lines 94–96): Encodes acoustic features into a latent space.
  • Local DiT (Diffusion Transformer) (lines 99–101): The feat_decoder.estimator refines latent representations over multiple timesteps; this is the dominant latency source.
  • Scalar Quantizer (lines 112–114): Compresses LM outputs before diffusion.
  • Audio VAE (lines 129–131): Decodes the final latent into a waveform.
  • ZipEnhancer (src/voxcpm/zipenhancer.py): Optional post-processing denoiser that adds marginal latency.

The diffusion loop and the LM forward passes are pure PyTorch operations, making them ideal candidates for torch.compile and precision tuning.

Enable torch.compile for Kernel Fusion

The fastest way to accelerate inference is through the built-in optimize flag in the high-level API. When set to True, the optimize() method in VoxCPM2Model (lines 64–82 of src/voxcpm/model/voxcpm2.py) compiles the LM, residual LM, encoder, and diffusion estimator using torch.compile(mode="reduce-overhead", fullgraph=True).

from voxcpm import VoxCPM

# Load with compilation enabled (default is True)

vc = VoxCPM.from_pretrained(
    hf_model_id="openbmb/VoxCPM2",
    optimize=True,          # Triggers torch.compile on core components

    load_denoiser=False,    # Optional: skip ZipEnhancer for ~5-10ms savings

)

The compilation check verifies CUDA availability and Triton installation. If Triton is missing, the code falls back to standard PyTorch JIT with a printed warning. For maximum performance, install Triton explicitly:

pip install "triton==2.1.0"  # Match your CUDA version

With Triton available, compiled kernels can deliver up to 2× speedup on the diffusion estimator compared to eager mode.

Runtime Precision and Performance Tweaks

After compilation, apply these global PyTorch settings to maximize tensor throughput on Ampere and newer GPUs:

  1. Enable TF32 precision: Allows TensorFloat-32 matrix multiplication on supported hardware, yielding ~30% speedup with negligible quality loss.

  2. Use half-precision inference: The model defaults to "bfloat16" (see VoxCPMConfig.dtype in voxcpm2.py), but you can force "float16" if your GPU has stronger FP16 performance.

  3. Enable cuDNN benchmarking: Lets the driver select optimal convolution algorithms for your specific input shapes.

  4. Disable autograd: Inference requires no gradients; use torch.inference_mode() for the lightest overhead.

import torch
from voxcpm import VoxCPM

# Global optimizations (run once at startup)

torch.set_float32_matmul_precision('high')
torch.backends.cudnn.benchmark = True

# Load model

vc = VoxCPM.from_pretrained("openbmb/VoxCPM2", optimize=True)

# Generate with zero gradient overhead

with torch.inference_mode():
    wav = vc.generate("Hello world", inference_timesteps=10)

Reduce Diffusion Steps Without Sacrificing Quality

The inference_timesteps parameter directly scales latency because it controls the number of forward passes through the Local DiT. While the default might use 20–50 steps for maximum fidelity, 8–12 steps are sufficient for high-quality output on most voices and hardware.

Benchmark results on an RTX 3060 (12GB) demonstrate the impact:

Configuration RTF
Default (optimize=False, 10 steps) ~0.8
Compiled + BF16 + TF32 + 10 steps ~0.34
Compiled + BF16 + TF32 + 8 steps ~0.28

Reduce steps in your generation call:


# 10 steps is the sweet spot for quality/speed trade-off

wav = vc.generate(text, inference_timesteps=10)

# For lowest latency, try 8 steps

wav = vc.generate(text, inference_timesteps=8)

Streaming for Perceived Latency

If your application plays audio incrementally, use the streaming generator to reduce time-to-first-sound:

for chunk in vc.generate_streaming(text, inference_timesteps=10):
    play(chunk)  # Your audio playback function

This yields PCM chunks as soon as they are decoded, keeping the perceived delay below 100ms even if total RTF is higher.

LoRA Compatibility with Compilation

If you are fine-tuning with LoRA adapters, note that the implementation in src/voxcpm/modules/layers/lora.py (lines 38–74) stores scaling tensors in buffers rather than parameters. This design avoids recompilation when toggling adapters on or off, allowing you to keep optimize=True during both training and inference.

Summary

Achieving RTF ~0.3 on consumer GPUs requires combining multiple optimization layers:

  • Compile the model using optimize=True when loading VoxCPM, ensuring Triton is installed for maximum kernel performance.
  • Use half-precision (BF16 or FP16) and enable TF32 via torch.set_float32_matmul_precision('high').
  • Set cuDNN benchmark to True for faster convolution selection.
  • Wrap inference in torch.inference_mode() to eliminate autograd overhead.
  • Reduce diffusion steps to 8–12 (the single biggest latency reduction).
  • Skip the ZipEnhancer denoiser if audio post-processing is not critical.

Following this checklist on an RTX 3060 or equivalent typically yields an RTF of 0.28–0.34, enabling real-time or faster-than-real-time speech synthesis.

Frequently Asked Questions

What is the minimum GPU memory required for optimized inference?

The compiled BF16 model fits comfortably in 8GB of VRAM for standard-length utterances (under 30 seconds). If you encounter out-of-memory errors during the initial warm-up, pass optimize=True but reduce the input text length; the first forward trace requires slightly more memory than subsequent calls.

Does torch.compile work with the optional ZipEnhancer denoiser?

Yes, but you must load the denoiser before compilation if you intend to use it. The load_denoiser=False flag in VoxCPM.from_pretrained() is provided specifically to exclude src/voxcpm/zipenhancer.py from the graph, saving a small amount of compilation time and runtime latency. If you need denoising, set load_denoiser=True and the optimize() method will compile it along with the other components.

Why is my first inference call still slow after enabling optimizations?

The first call triggers the actual compilation and CUDA kernel generation. The VoxCPM class constructor automatically performs a warm-up generation (see src/voxcpm/core.py), but if you manually toggle optimize or change model components later, run a dummy forward pass to warm up the compiled kernels before benchmarking:

with torch.inference_mode():
    _ = vc.generate("warm up", inference_timesteps=10)  # Triggers compilation

Can I achieve RTF < 0.3 on older GPUs like the GTX 1080?

Older Pascal and Turing cards lack native BF16 support and have weaker Tensor Core performance. You can still approach RTF ~0.4 by using FP16 (instead of BF16) and reducing steps to 8, but sub-0.3 performance typically requires an Ampere (RTX 3000 series) or newer GPU with strong FP16/BF16 throughput and Triton compatibility.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →