# SPDX-License-Identifier: Apache-2.0 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project """Cosmos3 sound tokenizer integration. The tokenizer decodes model-generated sound latents for video+audio output. It does not encode or condition on ``multi_modal_data["audio"]``; request-side sound generation is enabled by ``generate_sound`` or ``sound_gen``. """ from __future__ import annotations import json import os from pathlib import Path from typing import Any import torch from vllm.logger import init_logger from vllm_omni.diffusion.data import OmniDiffusionConfig from vllm_omni.diffusion.distributed.utils import get_local_device from vllm_omni.diffusion.models.progress_bar import _is_rank_zero from .audio_tokenizer import Cosmos3AVAEAudioTokenizer logger = init_logger(__name__) DEFAULT_SOUND_SAMPLE_RATE = 48000 DEFAULT_SOUND_CHANNELS = 2 DEFAULT_SOUND_DIM = 64 DEFAULT_SOUND_HOP_SIZE = 1920 DEFAULT_SOUND_LATENT_FPS = DEFAULT_SOUND_SAMPLE_RATE / DEFAULT_SOUND_HOP_SIZE DEFAULT_SOUND_NORMALIZE_LATENTS = False DEFAULT_SOUND_NORMALIZATION_TYPE = "none" DEFAULT_SOUND_TANH_INPUT_SCALE = 1.5 DEFAULT_SOUND_TANH_OUTPUT_SCALE = 3.5 DEFAULT_SOUND_TANH_CLAMP = 0.995 SOUND_TOKENIZER_COMPONENT_NAME = "sound_tokenizer" SOUND_TOKENIZER_CHECKPOINT_NAME = "diffusion_pytorch_model.safetensors" def _pipeline_args(od_config: OmniDiffusionConfig) -> dict[str, Any]: return dict(getattr(od_config, "custom_pipeline_args", None) or {}) def _config_get(config: Any, key: str, default: Any = None) -> Any: if config is None: return default if isinstance(config, dict): return config.get(key, default) if hasattr(config, "get"): value = config.get(key, None) return default if value is None else value return getattr(config, key, default) def _config_path_get(config: Any, *keys: str) -> Any: value = config for key in keys: value = _config_get(value, key, None) if value is None: return None return value def _sound_tokenizer_config_from(config: Any) -> Any: """Return nested ``sound_tokenizer`` config from Cosmos3 config shapes.""" for path in ( ("sound_tokenizer",), ("model", "config", "sound_tokenizer"), ("config", "sound_tokenizer"), ("model_config", "sound_tokenizer"), ): value = _config_path_get(config, *path) if value is not None: return value return None def _nested_sound_tokenizer_configs(od_config: OmniDiffusionConfig | None) -> tuple[Any, ...]: if od_config is None: return () configs = [] for source in ( getattr(od_config, "model_config", None), getattr(od_config, "tf_model_config", None), ): config = _sound_tokenizer_config_from(source) if config is not None: configs.append(config) return tuple(configs) def _first_value_from_configs(configs: tuple[Any, ...], keys: tuple[str, ...]) -> Any: for config in configs: for key in keys: value = _config_get(config, key, None) if value is not None: return value return None def _top_level_model_value(od_config: OmniDiffusionConfig | None, keys: tuple[str, ...]) -> Any: if od_config is None: return None for source in ( getattr(od_config, "model_config", None), getattr(od_config, "tf_model_config", None), ): for key in keys: for path in ((key,), ("model", "config", key), ("config", key), ("model_config", key)): value = _config_path_get(source, *path) if value is not None: return value return None def _custom_arg_value(args: dict[str, Any], keys: tuple[str, ...]) -> Any: for key in keys: value = args.get(key) if value is not None: return value return None def _as_bool(value: Any) -> bool: if isinstance(value, str): return value.strip().lower() in {"1", "true", "yes", "on"} return bool(value) def _as_audio_channels(value: Any) -> int: if isinstance(value, bool): return 2 if value else 1 if isinstance(value, str) and value.strip().lower() in { "1", "0", "true", "false", "yes", "no", "on", "off", }: return 2 if _as_bool(value) else 1 return int(value) def _resolve_model_file(path: Any, model_root: str | None) -> str | None: if not path: return None path = str(path) if "://" in path or os.path.isabs(path) or os.path.exists(path) or not model_root: return path return str(Path(model_root) / path) def _load_sound_tokenizer_component_config(config_path: str | None) -> dict[str, Any]: if not config_path: return {} with open(config_path, encoding="utf-8") as f: config = json.load(f) if not isinstance(config, dict): raise TypeError(f"Cosmos3 sound tokenizer config must be a JSON object, got {type(config)!r}.") return config def _component_audio_channels(config: dict[str, Any]) -> Any: if config.get("dec_out_channels") is not None: return config["dec_out_channels"] if config.get("audio_channels") is not None: return config["audio_channels"] if config.get("stereo") is not None: return 2 if _as_bool(config["stereo"]) else 1 return None def _component_arch_values(config: dict[str, Any]) -> dict[str, Any]: values = { "sample_rate": config.get("sampling_rate", config.get("sample_rate")), "audio_channels": _component_audio_channels(config), "io_channels": config.get("vocoder_input_dim", config.get("io_channels", config.get("latent_ch"))), "hop_size": config.get("hop_size"), } return {key: value for key, value in values.items() if value is not None} def _resolve_arch_value( od_config: OmniDiffusionConfig, args: dict[str, Any], component_values: dict[str, Any], *, field: str, custom_keys: tuple[str, ...], nested_keys: tuple[str, ...], top_level_keys: tuple[str, ...], default: Any, cast, ) -> Any: custom_value = _custom_arg_value(args, custom_keys) component_value = component_values.get(field) if component_value is not None: resolved = cast(component_value) if custom_value is not None and cast(custom_value) != resolved: raise ValueError( "Conflicting Cosmos3 sound tokenizer architecture override for " f"{field}: component config has {resolved!r}, custom args have {cast(custom_value)!r}." ) return resolved if custom_value is not None: return cast(custom_value) nested_value = _first_value_from_configs(_nested_sound_tokenizer_configs(od_config), nested_keys) if nested_value is not None: return cast(nested_value) top_value = _top_level_model_value(od_config, top_level_keys) if top_value is not None: return cast(top_value) return cast(default) def _resolve_normalization_value( od_config: OmniDiffusionConfig, args: dict[str, Any], *, name: str, default: Any, aliases: tuple[str, ...] = (), ) -> Any: keys = (f"sound_{name}", name, *aliases) custom_value = _custom_arg_value(args, keys) if custom_value is not None: return custom_value nested_value = _first_value_from_configs(_nested_sound_tokenizer_configs(od_config), (name, *aliases)) return default if nested_value is None else nested_value def get_sound_config_value( od_config: OmniDiffusionConfig, name: str, default: Any, aliases: tuple[str, ...] = (), ) -> Any: # Backward-compatible generic accessor. Prefer the more specific helpers # below for Cosmos3 sound tokenizer fields so precedence stays explicit. keys = (name, *aliases) for config in ( _pipeline_args(od_config), getattr(od_config, "model_config", None), getattr(od_config, "tf_model_config", None), ): if config is None: continue for key in keys: if hasattr(config, "get"): value = config.get(key, None) else: value = getattr(config, key, None) if value is not None: return value return default def get_sound_sample_rate(od_config: OmniDiffusionConfig) -> int: args = _pipeline_args(od_config) return _resolve_arch_value( od_config, args, {}, field="sample_rate", custom_keys=("sound_sample_rate", "sample_rate"), nested_keys=("sample_rate", "sampling_rate"), top_level_keys=("sound_sample_rate", "sample_rate"), default=DEFAULT_SOUND_SAMPLE_RATE, cast=int, ) def get_sound_channels(od_config: OmniDiffusionConfig) -> int: args = _pipeline_args(od_config) return _resolve_arch_value( od_config, args, {}, field="audio_channels", custom_keys=("sound_audio_channels", "audio_channels", "stereo"), nested_keys=("audio_channels", "dec_out_channels", "stereo"), top_level_keys=("sound_audio_channels", "audio_channels", "stereo"), default=DEFAULT_SOUND_CHANNELS, cast=_as_audio_channels, ) def get_sound_hop_size(od_config: OmniDiffusionConfig) -> int: args = _pipeline_args(od_config) return _resolve_arch_value( od_config, args, {}, field="hop_size", custom_keys=("sound_hop_size", "hop_size"), nested_keys=("hop_size",), top_level_keys=("sound_hop_size", "hop_size"), default=DEFAULT_SOUND_HOP_SIZE, cast=int, ) class Cosmos3SoundTokenizer: """Thin adapter around the local AVAE tokenizer implementation.""" def __init__(self, tokenizer: Any) -> None: self.tokenizer = tokenizer self.sample_rate = int(getattr(tokenizer, "sample_rate", DEFAULT_SOUND_SAMPLE_RATE)) self.audio_channels = int(getattr(tokenizer, "audio_channels", DEFAULT_SOUND_CHANNELS)) self.latent_ch = int(getattr(tokenizer, "latent_ch", DEFAULT_SOUND_DIM)) self.hop_size = int(getattr(tokenizer, "temporal_compression_factor", DEFAULT_SOUND_HOP_SIZE)) if self.hop_size <= 0: raise ValueError(f"Cosmos3 sound tokenizer hop_size must be positive, got {self.hop_size}.") self.latent_fps = float(self.sample_rate) / float(self.hop_size) @classmethod def from_config(cls, od_config: OmniDiffusionConfig) -> Cosmos3SoundTokenizer: args = _pipeline_args(od_config) model_path = getattr(od_config, "model", None) explicit_avae_path = ( args.get("sound_tokenizer_path") or args.get("avae_path") or args.get("cosmos3_avae_path") or os.environ.get("COSMOS3_SOUND_TOKENIZER_PATH") ) explicit_config_path = args.get("sound_tokenizer_config_path") or os.environ.get( "COSMOS3_SOUND_TOKENIZER_CONFIG_PATH" ) model_root = str(model_path) if model_path and os.path.isdir(model_path) else None if model_root is None and model_path and not explicit_avae_path: from huggingface_hub import snapshot_download model_root = snapshot_download( repo_id=str(model_path), revision=getattr(od_config, "revision", None), allow_patterns=[ f"{SOUND_TOKENIZER_COMPONENT_NAME}/config.json", f"{SOUND_TOKENIZER_COMPONENT_NAME}/{SOUND_TOKENIZER_CHECKPOINT_NAME}", ], ) if explicit_avae_path: avae_path = _resolve_model_file(explicit_avae_path, model_root) else: tokenizer_dir = Path(model_root) / SOUND_TOKENIZER_COMPONENT_NAME if model_root else None candidate = tokenizer_dir / SOUND_TOKENIZER_CHECKPOINT_NAME if tokenizer_dir else None avae_path = str(candidate) if candidate and candidate.exists() else None if not avae_path: raise ValueError( "Cosmos3 sound generation was requested, but no AVAE sound " "tokenizer checkpoint was provided. Set " "custom_pipeline_args['sound_tokenizer_path'] or " "COSMOS3_SOUND_TOKENIZER_PATH, or include " f"{SOUND_TOKENIZER_COMPONENT_NAME}/{SOUND_TOKENIZER_CHECKPOINT_NAME} under the model path." ) config_path = _resolve_model_file(explicit_config_path, model_root) if config_path is None and model_root: candidate = Path(model_root) / SOUND_TOKENIZER_COMPONENT_NAME / "config.json" config_path = str(candidate) if candidate.exists() else None component_config = _load_sound_tokenizer_component_config(config_path) component_values = _component_arch_values(component_config) sample_rate = _resolve_arch_value( od_config, args, component_values, field="sample_rate", custom_keys=("sound_sample_rate", "sample_rate"), nested_keys=("sample_rate", "sampling_rate"), top_level_keys=("sound_sample_rate", "sample_rate"), default=DEFAULT_SOUND_SAMPLE_RATE, cast=int, ) audio_channels = _resolve_arch_value( od_config, args, component_values, field="audio_channels", custom_keys=("sound_audio_channels", "audio_channels", "stereo"), nested_keys=("audio_channels", "dec_out_channels", "stereo"), top_level_keys=("sound_audio_channels", "audio_channels", "stereo"), default=DEFAULT_SOUND_CHANNELS, cast=_as_audio_channels, ) sound_dim = _resolve_arch_value( od_config, args, component_values, field="io_channels", custom_keys=("sound_dim", "io_channels", "latent_ch"), nested_keys=("io_channels", "vocoder_input_dim", "latent_ch"), top_level_keys=("sound_dim",), default=DEFAULT_SOUND_DIM, cast=int, ) hop_size = _resolve_arch_value( od_config, args, component_values, field="hop_size", custom_keys=("sound_hop_size", "hop_size"), nested_keys=("hop_size",), top_level_keys=("sound_hop_size", "hop_size"), default=DEFAULT_SOUND_HOP_SIZE, cast=int, ) normalize_latents = _as_bool( _resolve_normalization_value( od_config, args, name="normalize_latents", default=DEFAULT_SOUND_NORMALIZE_LATENTS, ) ) normalization_type = str( _resolve_normalization_value( od_config, args, name="normalization_type", default=DEFAULT_SOUND_NORMALIZATION_TYPE, ) ) tanh_input_scale = float( _resolve_normalization_value( od_config, args, name="tanh_input_scale", default=DEFAULT_SOUND_TANH_INPUT_SCALE, ) ) tanh_output_scale = float( _resolve_normalization_value( od_config, args, name="tanh_output_scale", default=DEFAULT_SOUND_TANH_OUTPUT_SCALE, ) ) tanh_clamp = float( _resolve_normalization_value( od_config, args, name="tanh_clamp", default=DEFAULT_SOUND_TANH_CLAMP, ) ) tokenizer = Cosmos3AVAEAudioTokenizer( checkpoint_path=str(avae_path), config_path=config_path, sample_rate=sample_rate, audio_channels=audio_channels, io_channels=sound_dim, hop_size=hop_size, normalize_latents=normalize_latents, normalization_type=normalization_type, tanh_input_scale=tanh_input_scale, tanh_output_scale=tanh_output_scale, tanh_clamp=tanh_clamp, dtype=getattr(od_config, "dtype", torch.bfloat16), device=get_local_device(), ) if _is_rank_zero(): logger.info( "Loaded Cosmos3 AVAE sound tokenizer from %s " "(sr=%d, channels=%d, latent_ch=%d, hop=%d, latent_fps=%.3f)", avae_path, sample_rate, audio_channels, sound_dim, hop_size, float(sample_rate) / float(hop_size), ) return cls(tokenizer) def get_latent_num_samples(self, num_audio_samples: int) -> int: return int(self.tokenizer.get_latent_num_samples(num_audio_samples)) def get_audio_num_samples(self, num_latent_samples: int) -> int: return int(self.tokenizer.get_audio_num_samples(num_latent_samples)) @torch.no_grad() def decode(self, latents: torch.Tensor) -> torch.Tensor: """Decode sound latents. Args: latents: ``[B, C, T]`` or ``[C, T]`` tensor. Returns: ``[B, audio_channels, N]`` tensor for batched input, or ``[audio_channels, N]`` for unbatched input. """ squeeze = latents.ndim == 2 if squeeze: latents = latents.unsqueeze(0) audio = self.tokenizer.decode(latents) audio = audio.clamp(-1.0, 1.0) return audio.squeeze(0) if squeeze else audio