Audio-to-Audio
PyTorch
ONNX
Safetensors
TensorRT
English
fast_oobleck_decoder
ace-step
audio
vae
knowledge-distillation
music-generation
streaming
dreamvae
custom_code
Instructions to use daydreamlive/DreamVAE with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- TensorRT
How to use daydreamlive/DreamVAE with TensorRT:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
| #!/usr/bin/env python3 | |
| """Export FastOobleckDecoder checkpoint to ONNX and build a TRT engine. | |
| The student decoder has the exact same I/O contract as the teacher | |
| (latents [B, 64, T] -> audio [B, 2, samples]), so we reuse the existing | |
| VAE TRT build pipeline. The resulting engine is a drop-in replacement. | |
| Usage: | |
| uv run python research_program/vae_distillation/export_trt.py \ | |
| --ckpt research_program/vae_distillation/checkpoints/student_step620000.pt | |
| # FP32 engine (if FP16 has Snake1d issues): | |
| uv run python research_program/vae_distillation/export_trt.py \ | |
| --ckpt research_program/vae_distillation/checkpoints/student_step620000.pt \ | |
| --no-fp16 | |
| # Custom output directory: | |
| uv run python research_program/vae_distillation/export_trt.py \ | |
| --ckpt ... --output-dir trt_engines | |
| """ | |
| import argparse | |
| import logging | |
| import math | |
| import sys | |
| from pathlib import Path | |
| import torch | |
| import torch.nn as nn | |
| from torch.nn.utils import weight_norm | |
| logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s") | |
| logger = logging.getLogger(__name__) | |
| # ========================================================================= | |
| # Student model definition (must match training script exactly) | |
| # ========================================================================= | |
| class Snake1d(nn.Module): | |
| def __init__(self, hidden_dim, logscale=True): | |
| super().__init__() | |
| self.alpha = nn.Parameter(torch.zeros(1, hidden_dim, 1)) | |
| self.beta = nn.Parameter(torch.zeros(1, hidden_dim, 1)) | |
| self.alpha.requires_grad = True | |
| self.beta.requires_grad = True | |
| self.logscale = logscale | |
| def forward(self, hidden_states): | |
| shape = hidden_states.shape | |
| alpha = self.alpha if not self.logscale else torch.exp(self.alpha) | |
| beta = self.beta if not self.logscale else torch.exp(self.beta) | |
| hidden_states = hidden_states.reshape(shape[0], shape[1], -1) | |
| hidden_states = hidden_states + (beta + 1e-9).reciprocal() * torch.sin(alpha * hidden_states).pow(2) | |
| hidden_states = hidden_states.reshape(shape) | |
| return hidden_states | |
| class FastResidualUnit(nn.Module): | |
| def __init__(self, dim: int, dilation: int = 1): | |
| super().__init__() | |
| pad = ((7 - 1) * dilation) // 2 | |
| self.snake1 = Snake1d(dim) | |
| self.conv1 = weight_norm(nn.Conv1d(dim, dim, kernel_size=7, dilation=dilation, padding=pad)) | |
| self.snake2 = Snake1d(dim) | |
| self.conv2 = weight_norm(nn.Conv1d(dim, dim, kernel_size=1)) | |
| def forward(self, x): | |
| h = self.conv1(self.snake1(x)) | |
| h = self.conv2(self.snake2(h)) | |
| pad = (x.shape[-1] - h.shape[-1]) // 2 | |
| if pad > 0: | |
| x = x[..., pad:-pad] | |
| return x + h | |
| class FastDecoderBlock(nn.Module): | |
| def __init__(self, in_dim: int, out_dim: int, stride: int = 1): | |
| super().__init__() | |
| self.snake1 = Snake1d(in_dim) | |
| self.conv_t = weight_norm(nn.ConvTranspose1d( | |
| in_dim, out_dim, kernel_size=2 * stride, stride=stride, | |
| padding=math.ceil(stride / 2), | |
| )) | |
| self.res1 = FastResidualUnit(out_dim, dilation=1) | |
| self.res2 = FastResidualUnit(out_dim, dilation=3) | |
| def forward(self, x): | |
| x = self.snake1(x) | |
| x = self.conv_t(x) | |
| x = self.res1(x) | |
| x = self.res2(x) | |
| return x | |
| class FastOobleckDecoder(nn.Module): | |
| def __init__(self, channels=128, input_channels=64, audio_channels=2, | |
| upsampling_ratios=None, channel_multiples=None): | |
| super().__init__() | |
| if upsampling_ratios is None: | |
| upsampling_ratios = [10, 6, 4, 4, 2] | |
| if channel_multiples is None: | |
| channel_multiples = [1, 2, 4, 8, 8] | |
| cm = [1] + channel_multiples | |
| self.conv1 = weight_norm(nn.Conv1d(input_channels, channels * cm[-1], kernel_size=7, padding=3)) | |
| blocks = [] | |
| for i, stride in enumerate(upsampling_ratios): | |
| in_dim = channels * cm[len(upsampling_ratios) - i] | |
| out_dim = channels * cm[len(upsampling_ratios) - i - 1] | |
| blocks.append(FastDecoderBlock(in_dim, out_dim, stride=stride)) | |
| self.blocks = nn.ModuleList(blocks) | |
| self.final_snake = Snake1d(channels) | |
| self.conv2 = weight_norm(nn.Conv1d(channels, audio_channels, kernel_size=7, padding=3, bias=False)) | |
| def forward(self, latents: torch.Tensor) -> torch.Tensor: | |
| x = self.conv1(latents) | |
| for block in self.blocks: | |
| x = block(x) | |
| x = self.final_snake(x) | |
| x = self.conv2(x) | |
| return x | |
| # ========================================================================= | |
| # Export | |
| # ========================================================================= | |
| def export_onnx(student: nn.Module, onnx_path: Path, device: str = "cuda"): | |
| """Export student decoder to ONNX with dynamic latent length.""" | |
| onnx_path.parent.mkdir(parents=True, exist_ok=True) | |
| # Trace with 30s worth of latent frames (750 = 30s * 25 fps) | |
| example = torch.randn(1, 64, 750, device=device, dtype=torch.float32) | |
| logger.info("Tracing student decoder for ONNX export...") | |
| with torch.no_grad(): | |
| torch.onnx.export( | |
| student, | |
| (example,), | |
| str(onnx_path), | |
| input_names=["latents"], | |
| output_names=["audio"], | |
| dynamic_axes={ | |
| "latents": {0: "batch", 2: "latent_frames"}, | |
| "audio": {0: "batch", 2: "samples"}, | |
| }, | |
| opset_version=18, | |
| do_constant_folding=True, | |
| dynamo=False, | |
| ) | |
| logger.info("ONNX saved to %s (%.1f MB)", onnx_path, onnx_path.stat().st_size / (1 << 20)) | |
| return onnx_path | |
| def build_engine(onnx_path: Path, engine_path: Path, fp16: bool = True): | |
| """Build TRT engine using the same config as the teacher VAE decoder.""" | |
| # Import the existing build infrastructure | |
| sys.path.insert(0, str(Path(__file__).resolve().parents[2])) | |
| from acestep.engine.trt.vae_export import VAETRTBuildConfig, build_vae_decode_engine | |
| config = VAETRTBuildConfig(fp16=fp16) | |
| return build_vae_decode_engine(str(onnx_path), str(engine_path), config=config) | |
| def verify_engine(engine_path: Path, device: str = "cuda"): | |
| """Quick sanity check: run a dummy input through the engine.""" | |
| from polygraphy.backend.common import bytes_from_path | |
| from polygraphy.backend.trt import engine_from_bytes | |
| from polygraphy import cuda as pg_cuda | |
| engine = engine_from_bytes(bytes_from_path(str(engine_path))) | |
| ctx = engine.create_execution_context() | |
| stream = pg_cuda.Stream() | |
| # 10s of audio = 250 latent frames | |
| T = 250 | |
| latents = torch.randn(1, 64, T, device=device, dtype=torch.float32).contiguous() | |
| ctx.set_input_shape("latents", (1, 64, T)) | |
| ctx.set_tensor_address("latents", latents.data_ptr()) | |
| out_shape = tuple(ctx.get_tensor_shape("audio")) | |
| audio_buf = torch.empty(out_shape, dtype=torch.float32, device=device) | |
| ctx.set_tensor_address("audio", audio_buf.data_ptr()) | |
| ok = ctx.execute_async_v3(stream.ptr) | |
| stream.synchronize() | |
| expected_samples = T * 1920 # hop length | |
| assert ok, "TRT execution failed" | |
| assert out_shape == (1, 2, expected_samples), f"Shape mismatch: {out_shape} vs (1, 2, {expected_samples})" | |
| assert not torch.isnan(audio_buf).any(), "NaN in output" | |
| assert audio_buf.abs().max() > 1e-6, "Output is all zeros" | |
| logger.info("Engine verification passed: input [1, 64, %d] -> output %s, range [%.4f, %.4f]", | |
| T, list(out_shape), audio_buf.min().item(), audio_buf.max().item()) | |
| # Quick speed check | |
| import time | |
| torch.cuda.synchronize() | |
| times = [] | |
| for _ in range(20): | |
| torch.cuda.synchronize() | |
| t0 = time.time() | |
| ctx.execute_async_v3(stream.ptr) | |
| stream.synchronize() | |
| times.append(time.time() - t0) | |
| avg_ms = sum(times) / len(times) * 1000 | |
| logger.info("TRT speed (10s audio, 20 trials): %.1f ms avg", avg_ms) | |
| def main(): | |
| parser = argparse.ArgumentParser(description="Export FastOobleckDecoder to ONNX + TRT") | |
| parser.add_argument("--ckpt", type=str, required=True, help="Path to student checkpoint .pt") | |
| parser.add_argument("--output-dir", type=str, default=None, | |
| help="Output directory (default: trt_engines/ in project root)") | |
| parser.add_argument("--no-fp16", action="store_true", help="Build FP32 engine instead of FP16") | |
| parser.add_argument("--skip-engine", action="store_true", help="Only export ONNX, skip TRT build") | |
| parser.add_argument("--skip-verify", action="store_true", help="Skip engine verification") | |
| parser.add_argument("--device", type=str, default="cuda") | |
| args = parser.parse_args() | |
| ckpt_path = Path(args.ckpt) | |
| step = "unknown" | |
| # Determine output paths | |
| project_root = Path(__file__).resolve().parents[2] | |
| if args.output_dir: | |
| out_dir = Path(args.output_dir) | |
| else: | |
| out_dir = project_root / "trt_engines" | |
| # Load student | |
| logger.info("Loading checkpoint: %s", ckpt_path) | |
| ckpt = torch.load(ckpt_path, map_location=args.device, weights_only=False) | |
| config = ckpt.get("config", {}) | |
| student = FastOobleckDecoder( | |
| channels=config.get("channels", 128), | |
| input_channels=config.get("input_channels", 64), | |
| audio_channels=config.get("audio_channels", 2), | |
| upsampling_ratios=config.get("upsampling_ratios", [10, 6, 4, 4, 2]), | |
| channel_multiples=config.get("channel_multiples", [1, 2, 4, 8, 8]), | |
| ).to(args.device).eval() | |
| student.load_state_dict(ckpt["student_state_dict"]) | |
| step = ckpt.get("step", "unknown") | |
| params_m = sum(p.numel() for p in student.parameters()) / 1e6 | |
| logger.info("Student loaded: step %s, %.1fM params", step, params_m) | |
| # ONNX export | |
| onnx_dir = out_dir / "_onnx" / "dreamvae_decode" | |
| onnx_path = onnx_dir / "dreamvae_decode.onnx" | |
| export_onnx(student, onnx_path, device=args.device) | |
| if args.skip_engine: | |
| logger.info("Skipping TRT engine build (--skip-engine)") | |
| return | |
| # TRT engine build | |
| fp16 = not args.no_fp16 | |
| prec = "fp16" if fp16 else "fp32" | |
| engine_name = f"dreamvae_decode_{prec}_240s" | |
| engine_dir = out_dir / engine_name | |
| engine_path = engine_dir / f"{engine_name}.engine" | |
| logger.info("Building TRT engine (%s)...", prec) | |
| build_engine(onnx_path, engine_path, fp16=fp16) | |
| if not args.skip_verify: | |
| logger.info("Verifying engine...") | |
| verify_engine(engine_path, device=args.device) | |
| logger.info("Done. Engine: %s", engine_path) | |
| logger.info("To use as drop-in replacement, pass this engine path where vae_decode engine is expected.") | |
| if __name__ == "__main__": | |
| main() | |