avatar-demo / gepard_inference /codec_wrapper.py
Mike0021's picture
Build unified talking avatar Space
a1210e3 verified
Raw
History Blame Contribute Delete
2.11 kB
"""NeMo audio-codec wrapper used at inference time.
``UnfoldedCodecModel`` extends NeMo's ``AudioCodecModel`` with direct decoding
from per-dimension discrete FSQ codes (the format the Gepard model produces),
bypassing mixed-radix composition/decomposition.
"""
import torch
from omegaconf import open_dict
from nemo.collections.tts.models import AudioCodecModel
class UnfoldedCodecModel(AudioCodecModel):
"""AudioCodecModel + decoding from unfolded per-dimension FSQ codes.
Works with any GroupFiniteScalarQuantizer configuration β€” the number of
groups, dimensions per group, and FSQ levels are read from the model's
vector_quantizer at runtime.
"""
def __init__(self, cfg, trainer=None):
# SLMDiscriminator downloads microsoft/wavlm-base-plus (~360MB) and is
# only used during training β€” strip it from the config before init.
with open_dict(cfg):
disc = cfg.get("discriminator", None)
if disc is not None and "discriminators" in disc:
disc.discriminators = [
d for d in disc.discriminators if "SLM" not in d._target_
]
super().__init__(cfg, trainer)
def decode_from_codes(self, codes: torch.Tensor, codes_len: torch.Tensor):
"""Decode audio from unfolded per-dimension discrete codes.
Args:
codes: (B, D, T) β€” per-dimension discrete values, where
D = num_groups * dims_per_group.
codes_len: (B,) β€” valid frame count per batch element.
Returns:
audio: (B, T_audio) β€” decoded waveform
audio_len: (B,) β€” valid audio lengths in samples
"""
num_levels = self.vector_quantizer.fsqs[0].num_levels.squeeze()
scale = (num_levels // 2).float().to(codes.device)
groups = codes.chunk(self.vector_quantizer.num_groups, dim=1)
dequantized = torch.cat(
[(g - scale[None, :, None]) / scale[None, :, None] for g in groups],
dim=1,
)
return self.decode_audio(inputs=dequantized, input_len=codes_len)