diffrhythm-1.2-p100a / code /models /tt_dit /layers /audio_resample.py
sunandbean's picture
Add files using upload-large-folder tool
629b123 verified
Raw History Blame Contribute Delete
13.1 kB
# SPDX-FileCopyrightText: © 2025 Tenstorrent AI ULC
# SPDX-License-Identifier: Apache-2.0
"""Anti-aliased 1D resampling layers for LTX-2 audio (BigVGAN-v2 style).
Device equivalents of the reference's ``LowPassFilter1d`` / ``UpSample1d`` /
``DownSample1d`` / ``Activation1d``. The transposed-conv upsample is expressed as
zero-stuff + zero-pad + a depthwise tap filter (bit-equivalent to
``F.conv_transpose1d`` for the symmetric sinc kernel). ``UpSample1d`` is shared
by the vocoder (kaiser window, T-shard/halo aware) and the BWE resampler (hann
window, single-device).
"""
from __future__ import annotations
import math
import torch
import ttnn
from ..parallel.config import ParallelFactor
from ..parallel.manager import CCLManager
from .audio_ops import (
_make_kaiser_sinc_kernel_1d,
_replicate_pad_t,
_t_neighbor_pad,
_zero_pad_t,
_zero_stuff_t,
depthwise_tap_filter,
)
from .module import Module
def _make_hann_sinc_kernel_1d(*, ratio: int) -> tuple[torch.Tensor, int, int, int, int]:
"""Return ``(kernel, kernel_size, pad, pad_left_crop, pad_right_crop)`` for the
Hann-window sinc resampler (torchaudio-equivalent), used by the BWE skip path."""
rolloff = 0.99
lowpass_filter_width = 6
width = math.ceil(lowpass_filter_width / rolloff)
kernel_size = 2 * width * ratio + 1
pad = width
pad_left = 2 * width * ratio
pad_right = kernel_size - ratio
time_axis = (torch.arange(kernel_size, dtype=torch.float64) / ratio - width) * rolloff
time_clamped = time_axis.clamp(-lowpass_filter_width, lowpass_filter_width)
window = torch.cos(time_clamped * math.pi / lowpass_filter_width / 2) ** 2
sinc_filter = torch.sinc(time_axis) * window * rolloff / ratio
return sinc_filter.float().reshape(kernel_size), kernel_size, pad, pad_left, pad_right
class LowPassFilter1d(Module):
"""Depthwise low-pass conv1d with a fixed kaiser-sinc kernel.
The kernel is constant (baked at __init__), so ``_prepare_torch_state`` only
absorbs a checkpoint-provided kernel if present (BigVGAN convention).
"""
def __init__(
self,
*,
cutoff: float = 0.5,
half_width: float = 0.6,
stride: int = 1,
kernel_size: int = 12,
padding: bool = True,
padding_mode: str = "replicate",
mesh_device: ttnn.MeshDevice,
dtype: ttnn.DataType = ttnn.float32,
parallel_config: ParallelFactor | None = None,
ccl_manager: CCLManager | None = None,
) -> None:
super().__init__()
if cutoff < 0.0 or cutoff > 0.5:
raise ValueError("cutoff must be in [0, 0.5]")
if padding_mode not in ("replicate", "zeros"):
raise ValueError(f"padding_mode must be replicate or zeros, got {padding_mode!r}")
sharded = parallel_config is not None and parallel_config.factor > 1
if sharded:
assert ccl_manager is not None, "T-sharding requires ccl_manager"
self.kernel_size = kernel_size
self.even = kernel_size % 2 == 0
self.pad_left = kernel_size // 2 - int(self.even)
self.pad_right = kernel_size // 2
self.stride = stride
self.padding = padding
self.padding_mode = padding_mode
self.mesh_device = mesh_device
self.dtype = dtype
self.parallel_config = parallel_config
self.ccl_manager = ccl_manager
kernel = _make_kaiser_sinc_kernel_1d(cutoff, half_width, kernel_size)
self._taps_cpu = kernel.tolist()
self._conv1d_cache: dict = {}
def _prepare_torch_state(self, state: dict[str, torch.Tensor]) -> None:
if "filter" in state:
t = state.pop("filter")
assert tuple(t.shape) == (1, 1, self.kernel_size)
self._taps_cpu = t.reshape(self.kernel_size).float().tolist()
def forward(self, x_BTC: ttnn.Tensor) -> ttnn.Tensor:
"""``x_BTC``: ``(B, T, C)`` ROW_MAJOR. Returns ``(B, T_out, C)``.
When ``parallel_config.factor > 1``, ``T`` is the *per-device* extent and
the replicate/zero pad becomes a halo exchange via ``_t_neighbor_pad``.
"""
assert x_BTC.layout == ttnn.ROW_MAJOR_LAYOUT
sharded = self.parallel_config is not None and self.parallel_config.factor > 1
if self.padding:
if sharded:
x = _t_neighbor_pad(
x_BTC,
pad_left=self.pad_left,
pad_right=self.pad_right,
parallel_config=self.parallel_config,
ccl_manager=self.ccl_manager,
padding_mode=self.padding_mode,
)
elif self.padding_mode == "replicate":
x = _replicate_pad_t(x_BTC, self.pad_left, self.pad_right, self.mesh_device)
else:
x = _zero_pad_t(x_BTC, self.pad_left, self.pad_right, self.mesh_device)
else:
x = x_BTC
return depthwise_tap_filter(
x,
self._taps_cpu,
self.stride,
mesh_device=self.mesh_device,
dtype=self.dtype,
cache=self._conv1d_cache,
)
class UpSample1d(Module):
"""Anti-aliased sinc upsampler (zero-stuff + depthwise lowpass).
``window="kaiser"`` is the BigVGAN anti-alias upsampler (T-shard/halo aware);
``window="hann"`` is the torchaudio-equivalent resampler for the BWE skip path
(single-device). The depthwise Conv1d formulation is bit-equivalent to
``F.conv_transpose1d`` for the symmetric sinc kernel.
"""
def __init__(
self,
*,
ratio: int = 2,
window: str = "kaiser",
kernel_size: int | None = None,
mesh_device: ttnn.MeshDevice,
dtype: ttnn.DataType = ttnn.float32,
parallel_config: ParallelFactor | None = None,
ccl_manager: CCLManager | None = None,
) -> None:
super().__init__()
sharded = parallel_config is not None and parallel_config.factor > 1
if sharded:
assert ccl_manager is not None, "T-sharding requires ccl_manager"
self.ratio = ratio
self.stride = ratio
self.window = window
self.mesh_device = mesh_device
self.dtype = dtype
self.parallel_config = parallel_config
self.ccl_manager = ccl_manager
if window == "hann":
kernel, self.kernel_size, self.pad, self.pad_left_crop, self.pad_right_crop = _make_hann_sinc_kernel_1d(
ratio=ratio
)
self._taps_cpu = kernel.tolist()
elif window == "kaiser":
self.kernel_size = int(6 * ratio // 2) * 2 if kernel_size is None else kernel_size
self.pad = self.kernel_size // ratio - 1
self.pad_left_crop = self.pad * self.stride + (self.kernel_size - self.stride) // 2
self.pad_right_crop = self.pad * self.stride + (self.kernel_size - self.stride + 1) // 2
kernel = _make_kaiser_sinc_kernel_1d(
cutoff=0.5 / ratio, half_width=0.6 / ratio, kernel_size=self.kernel_size
)
self._taps_cpu = kernel.tolist()
else:
raise ValueError(f"window must be kaiser or hann, got {window!r}")
self._conv1d_cache: dict = {}
self._use_polyphase = (self.kernel_size % ratio) == 0
if self._use_polyphase:
self._poly_K_sub = self.kernel_size // ratio
def _prepare_torch_state(self, state: dict[str, torch.Tensor]) -> None:
if "filter" in state:
t = state.pop("filter")
assert tuple(t.shape) == (1, 1, self.kernel_size)
self._taps_cpu = t.reshape(self.kernel_size).float().tolist()
def forward(self, x_BTC: ttnn.Tensor) -> ttnn.Tensor:
assert x_BTC.layout == ttnn.ROW_MAJOR_LAYOUT
B, T, C = x_BTC.shape
sharded = self.parallel_config is not None and self.parallel_config.factor > 1
poly2 = self._use_polyphase and self.ratio == 2
# ratio-2 polyphase reads only x_pad[2:T_pad-2]; pad two fewer rows per side when possible.
crop = 2 if (poly2 and self.pad >= 2) else 0
eff_pad = self.pad - crop
if sharded and eff_pad > 0:
x_pad = _t_neighbor_pad(
x_BTC,
pad_left=eff_pad,
pad_right=eff_pad,
parallel_config=self.parallel_config,
ccl_manager=self.ccl_manager,
padding_mode="replicate",
)
else:
x_pad = _replicate_pad_t(x_BTC, eff_pad, eff_pad, self.mesh_device)
if poly2:
B_, T_pad, C_ = x_pad.shape
# Zero-pad sub-taps (sub0 trailing, sub1 leading) so both phases convolve the same input.
if crop:
base = x_pad
else:
base = ttnn.slice(x_pad, [0, 2, 0], [B_, T_pad - 2, C_])
scaled_taps = [t * self.ratio for t in self._taps_cpu]
sub0 = [scaled_taps[2 * j + 0] for j in range(self._poly_K_sub)] + [0.0]
sub1 = [0.0] + [scaled_taps[2 * j + 1] for j in range(self._poly_K_sub)]
ph0 = depthwise_tap_filter(
base,
sub0,
1,
mesh_device=self.mesh_device,
dtype=self.dtype,
cache=self._conv1d_cache,
)
ph1 = depthwise_tap_filter(
base,
sub1,
1,
mesh_device=self.mesh_device,
dtype=self.dtype,
cache=self._conv1d_cache,
)
if base is not x_pad:
ttnn.deallocate(base)
T_out = ph0.shape[1]
ph0_b = ttnn.reshape(ph0, (B_, T_out, 1, C_))
ph1_b = ttnn.reshape(ph1, (B_, T_out, 1, C_))
stacked = ttnn.concat([ph0_b, ph1_b], dim=2)
return ttnn.reshape(stacked, (B_, T_out * 2, C_))
x_zs = _zero_stuff_t(x_pad, stride=self.stride, mesh_device=self.mesh_device)
x_padded = _zero_pad_t(x_zs, self.kernel_size - 1, self.kernel_size - 1, self.mesh_device)
y = depthwise_tap_filter(
x_padded,
[t * self.ratio for t in self._taps_cpu],
1,
mesh_device=self.mesh_device,
dtype=self.dtype,
cache=self._conv1d_cache,
)
T_y = y.shape[1]
y_cropped = ttnn.slice(y, [0, self.pad_left_crop, 0], [B, T_y - self.pad_right_crop, C])
ttnn.deallocate(y)
return y_cropped
class DownSample1d(Module):
"""Strided kaiser-sinc lowpass downsampler wrapping ``LowPassFilter1d``."""
def __init__(
self,
*,
ratio: int = 2,
kernel_size: int | None = None,
mesh_device: ttnn.MeshDevice,
dtype: ttnn.DataType = ttnn.float32,
parallel_config: ParallelFactor | None = None,
ccl_manager: CCLManager | None = None,
) -> None:
super().__init__()
self.ratio = ratio
self.kernel_size = int(6 * ratio // 2) * 2 if kernel_size is None else kernel_size
self.lowpass = LowPassFilter1d(
cutoff=0.5 / ratio,
half_width=0.6 / ratio,
stride=ratio,
kernel_size=self.kernel_size,
padding=True,
padding_mode="replicate",
mesh_device=mesh_device,
dtype=dtype,
parallel_config=parallel_config,
ccl_manager=ccl_manager,
)
def forward(self, x_BTC: ttnn.Tensor) -> ttnn.Tensor:
return self.lowpass(x_BTC)
class Activation1d(Module):
"""Anti-aliased activation: ``UpSample1d(2x) → activation → DownSample1d(2x)``."""
def __init__(
self,
*,
channels: int,
activation: Module,
up_ratio: int = 2,
down_ratio: int = 2,
up_kernel_size: int = 12,
down_kernel_size: int = 12,
mesh_device: ttnn.MeshDevice,
dtype: ttnn.DataType = ttnn.float32,
parallel_config: ParallelFactor | None = None,
ccl_manager: CCLManager | None = None,
) -> None:
super().__init__()
self.channels = channels
self.act = activation
self.upsample = UpSample1d(
ratio=up_ratio,
window="kaiser",
kernel_size=up_kernel_size,
mesh_device=mesh_device,
dtype=dtype,
parallel_config=parallel_config,
ccl_manager=ccl_manager,
)
self.downsample = DownSample1d(
ratio=down_ratio,
kernel_size=down_kernel_size,
mesh_device=mesh_device,
dtype=dtype,
parallel_config=parallel_config,
ccl_manager=ccl_manager,
)
def forward(self, x_BTC: ttnn.Tensor) -> ttnn.Tensor:
y = self.upsample(x_BTC)
y = self.act(y)
if y.layout != ttnn.ROW_MAJOR_LAYOUT:
y = ttnn.to_layout(y, ttnn.ROW_MAJOR_LAYOUT)
y = self.downsample(y)
return y