[Refactor] Unify Snake/SnakeBeta and alias-free activation into common modules (#3886)

Signed-off-by: BeatSeat <wendavid552@gmail.com>
This commit is contained in:
BeatSeat authored and GitHub committed 2026-05-27 23:41:35 -05:00
1 parent 2b999429c4
commit dab596e468
6 files changed
+320 -616

No files matched your search

@@ -0,0 +1,243 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
"""Alias-free activation for BigVGAN-style speech decoders.
Provides anti-aliased activation (upsample → activation → downsample) with
Kaiser-windowed sinc filters. Includes NPU bf16 workarounds for platforms
where F.pad(mode='replicate') does not support bfloat16.
Used by: Qwen2.5-Omni, Qwen3-TTS v1, CoVo-Audio, and future BigVGAN vocoders.
"""
from __future__ import annotations
import math
import torch
import torch.nn as nn
import torch.nn.functional as F
from vllm.logger import init_logger
from vllm_omni.platforms import current_omni_platform
logger = init_logger(__name__)
# ---------------------------------------------------------------------------
# Helper utilities
# ---------------------------------------------------------------------------
def kaiser_sinc_filter1d(cutoff: float, half_width: float, kernel_size: int) -> torch.Tensor:
"""Generate a 1-D Kaiser-windowed sinc low-pass filter.
Args:
cutoff: Normalized cutoff frequency (0 to 0.5).
half_width: Transition bandwidth.
kernel_size: Number of filter taps.
Returns:
Filter tensor of shape ``(1, 1, kernel_size)``.
"""
is_even = kernel_size % 2 == 0
half_size = kernel_size // 2
delta_f = 4 * half_width
attenuation = 2.285 * (half_size - 1) * math.pi * delta_f + 7.95
if attenuation > 50.0:
beta = 0.1102 * (attenuation - 8.7)
elif attenuation >= 21.0:
beta = 0.5842 * (attenuation - 21) ** 0.4 + 0.07886 * (attenuation - 21.0)
else:
beta = 0.0
# torch.kaiser_window is not supported on NPU / XPU — compute on CPU.
if current_omni_platform.is_npu():
kaiser_window = torch.kaiser_window(
kernel_size, beta=beta, periodic=False, dtype=torch.float32, device="cpu"
).to("npu")
elif current_omni_platform.is_xpu():
kaiser_window = torch.kaiser_window(
kernel_size, beta=beta, periodic=False, dtype=torch.float32, device="cpu"
).to("xpu")
else:
kaiser_window = torch.kaiser_window(kernel_size, beta=beta, periodic=False, dtype=torch.float32)
if is_even:
time_indices = torch.arange(-half_size, half_size) + 0.5
else:
time_indices = torch.arange(kernel_size) - half_size
if cutoff == 0:
return torch.zeros((1, 1, kernel_size), dtype=torch.float32)
sinc_filter = torch.sinc(2 * cutoff * time_indices)
normalized_filter = 2 * cutoff * kaiser_window * sinc_filter
normalized_filter /= normalized_filter.sum()
return normalized_filter.view(1, 1, kernel_size)
def replication_pad_1d(hidden_states: torch.Tensor, pad_left: int, pad_right: int) -> torch.Tensor:
"""Manual replicate padding for NPU bf16 compatibility.
``F.pad(mode='replicate')`` does not support bfloat16 on NPU (and older
CUDA). This expand+cat fallback produces identical results.
TODO: Remove when upstream PyTorch fixes replication_pad1d for bf16.
"""
if pad_left == 0 and pad_right == 0:
return hidden_states
segments = []
if pad_left > 0:
left = hidden_states[..., :1].expand(*hidden_states.shape[:-1], pad_left)
segments.append(left)
segments.append(hidden_states)
if pad_right > 0:
right = hidden_states[..., -1:].expand(*hidden_states.shape[:-1], pad_right)
segments.append(right)
return torch.cat(segments, dim=-1)
# ---------------------------------------------------------------------------
# Up / Down sampling with Kaiser sinc filters
# ---------------------------------------------------------------------------
class UpSample1d(nn.Module):
"""Kaiser-sinc interpolation upsample (default: 2x, 12-tap filter)."""
def __init__(self, ratio: int = 2, kernel_size: int | None = None):
super().__init__()
self.ratio = ratio
self.kernel_size = int(6 * ratio // 2) * 2 if kernel_size is None else kernel_size
self.stride = ratio
self.pad = self.kernel_size // ratio - 1
self.pad_left = self.pad * self.stride + (self.kernel_size - self.stride) // 2
self.pad_right = self.pad * self.stride + (self.kernel_size - self.stride + 1) // 2
filt = kaiser_sinc_filter1d(cutoff=0.5 / ratio, half_width=0.6 / ratio, kernel_size=self.kernel_size)
self.register_buffer("filter", filt, persistent=False)
def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
channels = hidden_states.shape[1]
if current_omni_platform.is_npu():
input_dtype = hidden_states.dtype
hidden_states = replication_pad_1d(hidden_states.to(self.filter.dtype), self.pad, self.pad)
hidden_states = self.ratio * F.conv_transpose1d(
hidden_states,
self.filter.expand(channels, -1, -1),
stride=self.stride,
groups=channels,
).to(input_dtype)
else:
input_dtype = hidden_states.dtype
hidden_states = F.pad(hidden_states, (self.pad, self.pad), mode="replicate").to(self.filter.dtype)
hidden_states = self.ratio * F.conv_transpose1d(
hidden_states,
self.filter.expand(channels, -1, -1),
stride=self.stride,
groups=channels,
).to(input_dtype)
hidden_states = hidden_states[..., self.pad_left : -self.pad_right]
return hidden_states
class DownSample1d(nn.Module):
"""Kaiser-sinc anti-aliasing downsample (default: 2x, 12-tap filter)."""
def __init__(self, ratio: int = 2, kernel_size: int | None = None):
super().__init__()
if kernel_size is None:
kernel_size = int(6 * ratio // 2) * 2
cutoff = 0.5 / ratio
half_width = 0.6 / ratio
if cutoff < 0.0:
raise ValueError("Minimum cutoff must be larger than zero.")
if cutoff > 0.5:
raise ValueError("A cutoff above 0.5 does not make sense.")
self.even = kernel_size % 2 == 0
self.pad_left = kernel_size // 2 - int(self.even)
self.pad_right = kernel_size // 2
self.stride = ratio
filt = kaiser_sinc_filter1d(cutoff, half_width, kernel_size)
self.register_buffer("filter", filt, persistent=False)
def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
channels = hidden_states.shape[1]
if current_omni_platform.is_npu():
input_dtype = hidden_states.dtype
hidden_states = replication_pad_1d(hidden_states.to(self.filter.dtype), self.pad_left, self.pad_right)
out = F.conv1d(
hidden_states,
self.filter.to(device=hidden_states.device, dtype=hidden_states.dtype).expand(channels, -1, -1),
stride=self.stride,
groups=channels,
).to(input_dtype)
else:
input_dtype = hidden_states.dtype
hidden_states = F.pad(hidden_states, (self.pad_left, self.pad_right), mode="replicate").to(
self.filter.dtype
)
out = F.conv1d(
hidden_states,
self.filter.expand(channels, -1, -1),
stride=self.stride,
groups=channels,
).to(input_dtype)
return out
# ---------------------------------------------------------------------------
# Alias-free activation: upsample → activation → downsample
# ---------------------------------------------------------------------------
class AliasFreeActivation1d(nn.Module):
"""Anti-aliased activation following BigVGAN (ICLR 2023).
Upsamples the signal, applies a pointwise activation (typically SnakeBeta),
then downsamples with a low-pass filter to suppress aliasing from the
high-frequency components introduced by the activation function.
The ``activation`` should be an ``nn.Module`` instance — typically
``SnakeBeta`` from ``common.snake_activation``, which already dispatches
between Triton and eager PyTorch internally.
Args:
activation: Pointwise activation module (e.g. ``SnakeBeta(channels)``).
up_ratio: Upsample factor before activation.
down_ratio: Downsample factor after activation.
up_kernel_size: Kaiser sinc filter taps for upsampling.
down_kernel_size: Kaiser sinc filter taps for downsampling.
"""
def __init__(
self,
activation: nn.Module,
up_ratio: int = 2,
down_ratio: int = 2,
up_kernel_size: int = 12,
down_kernel_size: int = 12,
):
super().__init__()
if not callable(activation):
raise TypeError("Activation function must be callable")
self.act = activation
self.upsample = UpSample1d(up_ratio, up_kernel_size)
self.downsample = DownSample1d(down_ratio, down_kernel_size)
def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
hidden_states = self.upsample(hidden_states)
hidden_states = self.act(hidden_states)
hidden_states = self.downsample(hidden_states)
return hidden_states
@@ -1,7 +1,10 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
# Copyright 2025 The Qwen team.
"""Shared SnakeBeta activation for speech decoders (Qwen3-TTS, Qwen3-Omni Code2Wav)."""
"""Shared Snake/SnakeBeta activations for speech decoders.
Used by: Qwen3-TTS, Qwen3-Omni Code2Wav, Qwen2.5-Omni, CoVo-Audio, CosyVoice3.
"""
import torch
from torch import nn
@@ -70,12 +73,17 @@ class SnakeBeta(nn.Module):
SnakeBeta._triton_kernel = _kernel
return True
def __init__(self, in_features, alpha=1.0):
def __init__(self, in_features, alpha=1.0, alpha_logscale=True):
super().__init__()
self.in_features = in_features
self.alpha_logscale = alpha_logscale
self.alpha = Parameter(torch.zeros(in_features) * alpha)
self.beta = Parameter(torch.zeros(in_features) * alpha)
if alpha_logscale:
self.alpha = Parameter(torch.zeros(in_features) * alpha)
self.beta = Parameter(torch.zeros(in_features) * alpha)
else:
self.alpha = Parameter(torch.ones(in_features) * alpha)
self.beta = Parameter(torch.ones(in_features) * alpha)
self.no_div_by_zero = 0.000000001
@@ -86,8 +94,12 @@ class SnakeBeta(nn.Module):
def precompute_exp_cache(self):
"""Materialize exp(alpha) and 1/(exp(beta)+eps) as frozen buffers."""
with torch.no_grad():
self._exp_alpha = torch.exp(self.alpha).contiguous()
self._inv_beta = (1.0 / (torch.exp(self.beta) + self.no_div_by_zero)).contiguous()
if self.alpha_logscale:
self._exp_alpha = torch.exp(self.alpha).contiguous()
self._inv_beta = (1.0 / (torch.exp(self.beta) + self.no_div_by_zero)).contiguous()
else:
self._exp_alpha = self.alpha.contiguous()
self._inv_beta = (1.0 / (self.beta + self.no_div_by_zero)).contiguous()
@property
def _cached(self):
@@ -104,12 +116,10 @@ class SnakeBeta(nn.Module):
return self._eager_forward(hidden_states)
def _eager_forward(self, hidden_states):
if self._cached:
exp_alpha = self._exp_alpha.unsqueeze(0).unsqueeze(-1)
inv_beta = self._inv_beta.unsqueeze(0).unsqueeze(-1)
else:
exp_alpha = torch.exp(self.alpha).unsqueeze(0).unsqueeze(-1)
inv_beta = (1.0 / (torch.exp(self.beta) + self.no_div_by_zero)).unsqueeze(0).unsqueeze(-1)
if not self._cached:
self.precompute_exp_cache()
exp_alpha = self._exp_alpha.unsqueeze(0).unsqueeze(-1)
inv_beta = self._inv_beta.unsqueeze(0).unsqueeze(-1)
hidden_states = hidden_states + inv_beta * torch.pow(torch.sin(hidden_states * exp_alpha), 2)
return hidden_states
@@ -134,3 +144,33 @@ class SnakeBeta(nn.Module):
block_t=block_t,
)
return out
class Snake(SnakeBeta):
"""Original Snake activation with a single parameter: x + 1/α * sin²(αx).
Unlike SnakeBeta which has separate alpha (frequency) and beta (magnitude)
parameters, Snake uses alpha for both. Only ``alpha`` appears in the
state_dict — ``beta`` is absent, keeping checkpoint compatibility with
CosyVoice3's HiFi-GAN.
The Triton kernel and precomputed-cache path from SnakeBeta are reused;
``precompute_exp_cache`` derives ``_inv_beta`` from ``alpha`` so the
forward path is identical.
"""
def __init__(self, in_features, alpha=1.0, alpha_logscale=False):
# Initialise SnakeBeta — creates both alpha and beta Parameters.
super().__init__(in_features, alpha=alpha, alpha_logscale=alpha_logscale)
# Drop beta as a Parameter so it won't appear in state_dict.
del self.beta
def precompute_exp_cache(self):
"""Derive both exp_alpha and inv_beta from the single alpha parameter."""
with torch.no_grad():
if self.alpha_logscale:
self._exp_alpha = torch.exp(self.alpha).contiguous()
self._inv_beta = (1.0 / (torch.exp(self.alpha) + self.no_div_by_zero)).contiguous()
else:
self._exp_alpha = self.alpha.contiguous()
self._inv_beta = (1.0 / (self.alpha + self.no_div_by_zero)).contiguous()
@@ -11,7 +11,6 @@ import torch
import torch.nn as nn
import torch.nn.functional as F
from scipy.signal import get_window
from torch import pow, sin
from torch.nn import Conv1d, ConvTranspose1d
from torch.nn.utils import remove_weight_norm
@@ -20,64 +19,8 @@ try:
except ImportError:
from torch.nn.utils import weight_norm
from torch.distributions.uniform import Uniform
from torch.nn import Parameter
# Implementation adapted from https://github.com/EdwardDixon/snake under the MIT license.
# LICENSE is in incl_licenses directory.
class Snake(nn.Module):
"""
Implementation of a sine-based periodic activation function
Shape:
- Input: (B, C, T)
- Output: (B, C, T), same shape as the input
Parameters:
- alpha - trainable parameter
References:
- This activation function is from this paper by Liu Ziyin, Tilman Hartwig, Masahito Ueda:
https://arxiv.org/abs/2006.08195
Examples:
>>> a1 = snake(256)
>>> x = torch.randn(256)
>>> x = a1(x)
"""
def __init__(self, in_features, alpha=1.0, alpha_trainable=True, alpha_logscale=False):
"""
Initialization.
INPUT:
- in_features: shape of the input
- alpha: trainable parameter
alpha is initialized to 1 by default, higher values = higher-frequency.
alpha will be trained along with the rest of your model.
"""
super().__init__()
self.in_features = in_features
# initialize alpha
self.alpha_logscale = alpha_logscale
if self.alpha_logscale: # log scale alphas initialized to zeros
self.alpha = Parameter(torch.zeros(in_features) * alpha)
else: # linear scale alphas initialized to ones
self.alpha = Parameter(torch.ones(in_features) * alpha)
self.alpha.requires_grad = alpha_trainable
self.no_div_by_zero = 0.000000001
def forward(self, x):
"""
Forward pass of the function.
Applies the function to the input elementwise.
Snake ∶= x + 1/a * sin^2 (xa)
"""
alpha = self.alpha.unsqueeze(0).unsqueeze(-1) # line up with x to [B, C, T]
if self.alpha_logscale:
alpha = torch.exp(alpha)
x = x + (1.0 / (alpha + self.no_div_by_zero)) * pow(sin(x * alpha), 2)
return x
from vllm_omni.model_executor.models.common.snake_activation import Snake
"""hifigan based generator implementation.
@@ -10,10 +10,11 @@ import torch
import torch.nn as nn
import torch.nn.functional as F
from einops import rearrange
from torch import pow, sin
from torch.nn import Parameter
from torch.nn.utils import weight_norm
from vllm_omni.model_executor.models.common.alias_free_activation import AliasFreeActivation1d
from vllm_omni.model_executor.models.common.snake_activation import SnakeBeta
# --------------- Utilities ---------------
@@ -93,41 +94,7 @@ def apply_rotary_pos_emb(pos, t):
return t * pos.cos() + rotate_half(t) * pos.sin()
if "sinc" in dir(torch):
sinc = torch.sinc
else:
def sinc(x: torch.Tensor):
return torch.where(
x == 0, torch.tensor(1.0, device=x.device, dtype=x.dtype), torch.sin(math.pi * x) / math.pi / x
)
def kaiser_sinc_filter1d(cutoff, half_width, kernel_size):
even = kernel_size % 2 == 0
half_size = kernel_size // 2
delta_f = 4 * half_width
A = 2.285 * (half_size - 1) * math.pi * delta_f + 7.95
if A > 50.0:
beta = 0.1102 * (A - 8.7)
elif A >= 21.0:
beta = 0.5842 * (A - 21) ** 0.4 + 0.07886 * (A - 21.0)
else:
beta = 0.0
window = torch.kaiser_window(kernel_size, beta=beta, periodic=False)
if even:
time = torch.arange(-half_size, half_size) + 0.5
else:
time = torch.arange(kernel_size) - half_size
if cutoff == 0:
filter_ = torch.zeros_like(time)
else:
filter_ = 2 * cutoff * window * sinc(2 * cutoff * time)
filter_ /= filter_.sum()
return filter_.view(1, 1, kernel_size)
# sinc, kaiser_sinc_filter1d removed — now in common.alias_free_activation
# --------------- Basic Layers ---------------
@@ -320,116 +287,14 @@ class ConvPositionEmbed(nn.Module):
# --------------- Anti-aliasing (BigVGAN) ---------------
class LowPassFilter1d(nn.Module):
def __init__(
self,
cutoff=0.5,
half_width=0.6,
stride: int = 1,
padding: bool = True,
padding_mode: str = "replicate",
kernel_size: int = 12,
):
super().__init__()
if cutoff < -0.0:
raise ValueError("Minimum cutoff must be larger than zero.")
if cutoff > 0.5:
raise ValueError("A cutoff above 0.5 does not make sense.")
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
filter = kaiser_sinc_filter1d(cutoff, half_width, kernel_size)
self.register_buffer("filter", filter)
def forward(self, x):
_, C, _ = x.shape
if self.padding:
x = F.pad(x, (self.pad_left, self.pad_right), mode=self.padding_mode)
out = F.conv1d(x, self.filter.expand(C, -1, -1), stride=self.stride, groups=C)
return out
class UpSample1d(nn.Module):
def __init__(self, ratio=2, kernel_size=None):
super().__init__()
self.ratio = ratio
self.kernel_size = int(6 * ratio // 2) * 2 if kernel_size is None else kernel_size
self.stride = ratio
self.pad = self.kernel_size // ratio - 1
self.pad_left = self.pad * self.stride + (self.kernel_size - self.stride) // 2
self.pad_right = self.pad * self.stride + (self.kernel_size - self.stride + 1) // 2
filter = kaiser_sinc_filter1d(cutoff=0.5 / ratio, half_width=0.6 / ratio, kernel_size=self.kernel_size)
self.register_buffer("filter", filter)
def forward(self, x):
_, C, _ = x.shape
x = F.pad(x, (self.pad, self.pad), mode="replicate")
x = self.ratio * F.conv_transpose1d(x, self.filter.expand(C, -1, -1), stride=self.stride, groups=C)
x = x[..., self.pad_left : -self.pad_right]
return x
class DownSample1d(nn.Module):
def __init__(self, ratio=2, kernel_size=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
)
def forward(self, x):
return self.lowpass(x)
class Activation1d(nn.Module):
def __init__(
self, activation, up_ratio: int = 2, down_ratio: int = 2, up_kernel_size: int = 12, down_kernel_size: int = 12
):
super().__init__()
self.up_ratio = up_ratio
self.down_ratio = down_ratio
self.act = activation
self.upsample = UpSample1d(up_ratio, up_kernel_size)
self.downsample = DownSample1d(down_ratio, down_kernel_size)
def forward(self, x):
x = self.upsample(x)
x = self.act(x)
x = self.downsample(x)
return x
# LowPassFilter1d, UpSample1d, DownSample1d, Activation1d removed —
# now provided by common.alias_free_activation.AliasFreeActivation1d
# --------------- Activations ---------------
class SnakeBeta(nn.Module):
def __init__(self, in_features, alpha=1.0, alpha_trainable=True, alpha_logscale=False):
super().__init__()
self.in_features = in_features
self.alpha_logscale = alpha_logscale
if self.alpha_logscale:
self.alpha = Parameter(torch.zeros(in_features) * alpha)
self.beta = Parameter(torch.zeros(in_features) * alpha)
else:
self.alpha = Parameter(torch.ones(in_features) * alpha)
self.beta = Parameter(torch.ones(in_features) * alpha)
self.alpha.requires_grad = alpha_trainable
self.beta.requires_grad = alpha_trainable
self.no_div_by_zero = 0.000000001
def forward(self, x):
alpha = self.alpha.unsqueeze(0).unsqueeze(-1)
beta = self.beta.unsqueeze(0).unsqueeze(-1)
if self.alpha_logscale:
alpha = torch.exp(alpha)
beta = torch.exp(beta)
x = x + (1.0 / (beta + self.no_div_by_zero)) * pow(sin(x * alpha), 2)
return x
# SnakeBeta removed — now in common.snake_activation (with alpha_logscale support)
# --------------- Attention ---------------
@@ -828,7 +693,7 @@ class AMPBlock1(torch.nn.Module):
self.activations = nn.ModuleList(
[
Activation1d(activation=SnakeBeta(channels, alpha_logscale=h.snake_logscale))
AliasFreeActivation1d(activation=SnakeBeta(channels, alpha_logscale=h.snake_logscale))
for _ in range(self.num_layers)
]
)
@@ -882,7 +747,7 @@ class BigVGANFlowVAE(nn.Module):
self.resblocks.append(AMPBlock1(h, ch, k, d, causal=causal))
activation_post = SnakeBeta(ch, alpha_logscale=h.snake_logscale)
self.activation_post = Activation1d(activation=activation_post)
self.activation_post = AliasFreeActivation1d(activation=activation_post)
self.conv_post = weight_norm(Conv1d(ch, 1, 7, 1, causal=causal))
@@ -2,14 +2,12 @@
# Start Token2Wav #
############################
import math
from collections.abc import Iterable
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.nn import Parameter
from transformers.modeling_utils import ALL_ATTENTION_FUNCTIONS
from transformers.models.qwen2_5_omni.configuration_qwen2_5_omni import (
Qwen2_5OmniBigVGANConfig,
@@ -35,8 +33,9 @@ from vllm.v1.sample.metadata import SamplingMetadata
from vllm.v1.sample.sampler import Sampler
from vllm_omni.model_executor.layers.timestep_embedding import DiTTimestepEmbedding
from vllm_omni.model_executor.models.common.alias_free_activation import AliasFreeActivation1d
from vllm_omni.model_executor.models.common.snake_activation import SnakeBeta
from vllm_omni.model_executor.models.qwen2_5_omni.audio_length import cap_and_align_mel_length, resolve_max_mel_frames
from vllm_omni.platforms import current_omni_platform
# Provide a no-op auto_docstring decorator to satisfy annotations if missing
@@ -634,238 +633,9 @@ class DiTDecoderLayer(nn.Module):
return hidden_states
class SnakeBeta(nn.Module):
"""
A modified Snake function which uses separate parameters for the magnitude
of the periodic components
Shape:
- Input: (B, C, T)
- Output: (B, C, T), same shape as the input
Parameters:
- alpha - trainable parameter that controls frequency
- beta - trainable parameter that controls magnitude
References:
- This activation function is a modified version based on this paper
by Liu Ziyin, Tilman Hartwig, Masahito Ueda:
https://huggingface.co/papers/2006.08195
"""
def __init__(self, in_features, alpha=1.0):
super().__init__()
self.in_features = in_features
# initialize alpha
self.alpha = Parameter(torch.zeros(in_features) * alpha)
self.beta = Parameter(torch.zeros(in_features) * alpha)
self.no_div_by_zero = 0.000000001
def forward(self, hidden_states):
"""
Forward pass of the function.
Applies the function to the input elementwise.
SnakeBeta ∶= x + 1/b * sin^2 (xa)
"""
alpha = self.alpha.unsqueeze(0).unsqueeze(-1) # line up with x to [B, C, T]
beta = self.beta.unsqueeze(0).unsqueeze(-1)
alpha = torch.exp(alpha)
beta = torch.exp(beta)
hidden_states = hidden_states + (1.0 / (beta + self.no_div_by_zero)) * torch.pow(
torch.sin(hidden_states * alpha), 2
)
return hidden_states
def kaiser_sinc_filter1d(cutoff: float, half_width: float, kernel_size: int) -> torch.Tensor:
"""Generates a 1D Kaiser-windowed sinc filter.
Args:
cutoff (float): Normalized cutoff frequency (0 to 0.5).
half_width (float): Transition bandwidth.
kernel_size (int): Number of filter taps.
Returns:
torch.Tensor: A tensor of shape (1, 1, kernel_size) representing the filter.
"""
is_even = kernel_size % 2 == 0
half_size = kernel_size // 2
# Compute Kaiser window parameters
delta_f = 4 * half_width
attenuation = 2.285 * (half_size - 1) * math.pi * delta_f + 7.95
if attenuation > 50.0:
beta = 0.1102 * (attenuation - 8.7)
elif attenuation >= 21.0:
beta = 0.5842 * (attenuation - 21) ** 0.4 + 0.07886 * (attenuation - 21.0)
else:
beta = 0.0
# TODO: When torch.kaiser_window supports NPU, remove the device="cpu" argument
if current_omni_platform.is_npu():
kaiser_window = torch.kaiser_window(
kernel_size, beta=beta, periodic=False, dtype=torch.float32, device="cpu"
).to("npu")
elif current_omni_platform.is_xpu():
kaiser_window = torch.kaiser_window(
kernel_size, beta=beta, periodic=False, dtype=torch.float32, device="cpu"
).to("xpu")
else:
kaiser_window = torch.kaiser_window(kernel_size, beta=beta, periodic=False, dtype=torch.float32)
# Compute time indices
if is_even:
time_indices = torch.arange(-half_size, half_size) + 0.5
else:
time_indices = torch.arange(kernel_size) - half_size
# Compute sinc filter
if cutoff == 0:
return torch.zeros((1, 1, kernel_size), dtype=torch.float32)
sinc_filter = torch.sinc(2 * cutoff * time_indices)
normalized_filter = 2 * cutoff * kaiser_window * sinc_filter
# Normalize to ensure sum = 1 (avoid leakage of constant component)
normalized_filter /= normalized_filter.sum()
return normalized_filter.view(1, 1, kernel_size)
def replication_pad_1d(hidden_states: torch.Tensor, pad_left: int, pad_right: int) -> torch.Tensor:
"""
Manual replicate padding to avoid replication_pad1d kernel limits on NPU.
TODO: remove when F.pad supports replicate mode on NPU.
"""
# NOTE: a immature implementation for running in NPU. Need to discuss.
if pad_left == 0 and pad_right == 0:
return hidden_states
segments = []
if pad_left > 0:
left = hidden_states[..., :1].expand(*hidden_states.shape[:-1], pad_left)
segments.append(left)
segments.append(hidden_states)
if pad_right > 0:
right = hidden_states[..., -1:].expand(*hidden_states.shape[:-1], pad_right)
segments.append(right)
return torch.cat(segments, dim=-1)
class UpSample1d(nn.Module):
def __init__(self, ratio=2, kernel_size=None):
super().__init__()
self.ratio = ratio
self.kernel_size = int(6 * ratio // 2) * 2 if kernel_size is None else kernel_size
self.stride = ratio
self.pad = self.kernel_size // ratio - 1
self.pad_left = self.pad * self.stride + (self.kernel_size - self.stride) // 2
self.pad_right = self.pad * self.stride + (self.kernel_size - self.stride + 1) // 2
filter = kaiser_sinc_filter1d(cutoff=0.5 / ratio, half_width=0.6 / ratio, kernel_size=self.kernel_size)
self.register_buffer("filter", filter, persistent=False)
def forward(self, hidden_states):
channels = hidden_states.shape[1]
if current_omni_platform.is_npu():
# TODO: When F.pad supports replicate mode on NPU, remove this branch
input_dtype = hidden_states.dtype
# F.pad in NPU doesn't support BF16 when mode is replicate.
# To ensure the accuracy, manually pad the input tensor.
hidden_states = replication_pad_1d(hidden_states.to(self.filter.dtype), self.pad, self.pad)
filter_convert_dtype = self.filter.to(hidden_states.dtype)
hidden_states = self.ratio * F.conv_transpose1d(
hidden_states,
filter_convert_dtype.expand(channels, -1, -1),
stride=self.stride,
groups=channels,
).to(input_dtype)
else:
hidden_states_dtype = hidden_states.dtype
hidden_states = F.pad(hidden_states, (self.pad, self.pad), mode="replicate").to(self.filter.dtype)
hidden_states = self.ratio * F.conv_transpose1d(
hidden_states,
self.filter.expand(channels, -1, -1),
stride=self.stride,
groups=channels,
).to(hidden_states_dtype)
hidden_states = hidden_states[..., self.pad_left : -self.pad_right]
return hidden_states
class DownSample1d(nn.Module):
def __init__(self, ratio=2, kernel_size=None):
super().__init__()
cutoff = 0.5 / ratio
half_width = 0.6 / ratio
if cutoff < 0.0:
raise ValueError("Minimum cutoff must be larger than zero.")
if cutoff > 0.5:
raise ValueError("A cutoff above 0.5 does not make sense.")
self.even = kernel_size % 2 == 0
self.pad_left = kernel_size // 2 - int(self.even)
self.pad_right = kernel_size // 2
self.stride = ratio
filter = kaiser_sinc_filter1d(cutoff, half_width, kernel_size)
self.register_buffer("filter", filter, persistent=False)
def forward(self, hidden_states):
channels = hidden_states.shape[1]
if current_omni_platform.is_npu():
input_dtype = hidden_states.dtype
# F.pad in NPU doesn't support BF16 when mode is replicate.
# To ensure the accuracy, manually pad the input tensor.
hidden_states = replication_pad_1d(hidden_states.to(self.filter.dtype), self.pad_left, self.pad_right)
filter_on_device = self.filter.to(device=hidden_states.device, dtype=hidden_states.dtype)
out = F.conv1d(
hidden_states,
filter_on_device.expand(channels, -1, -1),
stride=self.stride,
groups=channels,
).to(input_dtype)
else:
hidden_states_dtype = hidden_states.dtype
hidden_states = F.pad(hidden_states, (self.pad_left, self.pad_right), mode="replicate").to(
self.filter.dtype
)
out = F.conv1d(
hidden_states,
self.filter.expand(channels, -1, -1),
stride=self.stride,
groups=channels,
).to(hidden_states_dtype)
return out
class TorchActivation1d(nn.Module):
def __init__(
self,
activation,
up_ratio: int = 2,
down_ratio: int = 2,
up_kernel_size: int = 12,
down_kernel_size: int = 12,
):
super().__init__()
if not callable(activation):
raise TypeError("Activation function must be callable")
self.act = activation
self.upsample = UpSample1d(up_ratio, up_kernel_size)
self.downsample = DownSample1d(down_ratio, down_kernel_size)
def forward(self, hidden_states):
hidden_states = self.upsample(hidden_states)
hidden_states = self.act(hidden_states)
hidden_states = self.downsample(hidden_states)
return hidden_states
# SnakeBeta, UpSample1d, DownSample1d, AliasFreeActivation1d (formerly
# TorchActivation1d) are now provided by the shared ``common`` modules.
# See: vllm_omni/model_executor/models/common/{snake_activation,alias_free_activation}.py
class AMPBlock(torch.nn.Module):
@@ -938,7 +708,7 @@ class AMPBlock(torch.nn.Module):
self.num_layers = len(self.convs1) + len(self.convs2) # total number of conv layers
self.activations = nn.ModuleList(
[TorchActivation1d(activation=SnakeBeta(channels)) for _ in range(self.num_layers)]
[AliasFreeActivation1d(activation=SnakeBeta(channels)) for _ in range(self.num_layers)]
)
def _get_padding(self, kernel_size, dilation=1):
@@ -1002,7 +772,7 @@ class Qwen2_5OmniToken2WavBigVGANModel(Qwen2_5OmniPreTrainedModel):
]
)
self.activation_post = TorchActivation1d(
self.activation_post = AliasFreeActivation1d(
activation=SnakeBeta(config.upsample_initial_channel // (2**self.num_upsample_layers))
)
self.conv_post = nn.Conv1d(
@@ -13,13 +13,11 @@
# limitations under the License.
"""PyTorch Qwen3TTSTokenizerV1 model."""
import math
from dataclasses import dataclass
import numpy as np
import torch
from torch import nn
from torch.nn import Parameter
from torch.nn import functional as F
from torch.nn.utils.rnn import pad_sequence
from transformers.modeling_utils import ALL_ATTENTION_FUNCTIONS, PreTrainedModel
@@ -27,6 +25,8 @@ from transformers.utils import ModelOutput, auto_docstring, logging
from transformers.utils.hub import cached_file
from vllm_omni.model_executor.layers.timestep_embedding import DiTTimestepEmbedding
from vllm_omni.model_executor.models.common.alias_free_activation import AliasFreeActivation1d
from vllm_omni.model_executor.models.common.snake_activation import SnakeBeta
from .configuration_qwen3_tts_tokenizer_v1 import (
Qwen3TTSTokenizerV1Config,
@@ -663,166 +663,9 @@ class DiTDecoderLayer(nn.Module):
return hidden_states
class SnakeBeta(nn.Module):
"""
A modified Snake function which uses separate parameters for the magnitude of the periodic components
Shape:
- Input: (B, C, T)
- Output: (B, C, T), same shape as the input
Parameters:
- alpha - trainable parameter that controls frequency
- beta - trainable parameter that controls magnitude
References:
- This activation function is a modified version based on this paper
by Liu Ziyin, Tilman Hartwig, Masahito Ueda:
https://huggingface.co/papers/2006.08195
"""
def __init__(self, in_features, alpha=1.0):
super().__init__()
self.in_features = in_features
# initialize alpha
self.alpha = Parameter(torch.zeros(in_features) * alpha)
self.beta = Parameter(torch.zeros(in_features) * alpha)
self.no_div_by_zero = 0.000000001
def forward(self, hidden_states):
"""
Forward pass of the function.
Applies the function to the input elementwise.
SnakeBeta ∶= x + 1/b * sin^2 (xa)
"""
alpha = self.alpha.unsqueeze(0).unsqueeze(-1) # line up with x to [B, C, T]
beta = self.beta.unsqueeze(0).unsqueeze(-1)
alpha = torch.exp(alpha)
beta = torch.exp(beta)
hidden_states = hidden_states + (1.0 / (beta + self.no_div_by_zero)) * torch.pow(
torch.sin(hidden_states * alpha), 2
)
return hidden_states
def kaiser_sinc_filter1d(cutoff, half_width, kernel_size) -> torch.Tensor:
"""Generates a 1D Kaiser-windowed sinc filter.
Args:
cutoff (float): Normalized cutoff frequency (0 to 0.5).
half_width (float): Transition bandwidth.
kernel_size (int): Number of filter taps.
Returns:
torch.Tensor: A tensor of shape (1, 1, kernel_size) representing the filter.
"""
is_even = kernel_size % 2 == 0
half_size = kernel_size // 2
# Compute Kaiser window parameters
delta_f = 4 * half_width
attenuation = 2.285 * (half_size - 1) * math.pi * delta_f + 7.95
if attenuation > 50.0:
beta = 0.1102 * (attenuation - 8.7)
elif attenuation >= 21.0:
beta = 0.5842 * (attenuation - 21) ** 0.4 + 0.07886 * (attenuation - 21.0)
else:
beta = 0.0
kaiser_window = torch.kaiser_window(kernel_size, beta=beta, periodic=False, dtype=torch.float32)
# Compute time indices
if is_even:
time_indices = torch.arange(-half_size, half_size) + 0.5
else:
time_indices = torch.arange(kernel_size) - half_size
# Compute sinc filter
if cutoff == 0:
return torch.zeros((1, 1, kernel_size), dtype=torch.float32) # Ensures correct shape
sinc_filter = torch.sinc(2 * cutoff * time_indices)
normalized_filter = 2 * cutoff * kaiser_window * sinc_filter
# Normalize to ensure sum = 1 (avoid leakage of constant component)
normalized_filter /= normalized_filter.sum()
return normalized_filter.view(1, 1, kernel_size)
class UpSample1d(nn.Module):
def __init__(self, ratio=2, kernel_size=None):
super().__init__()
self.ratio = ratio
self.kernel_size = int(6 * ratio // 2) * 2 if kernel_size is None else kernel_size
self.stride = ratio
self.pad = self.kernel_size // ratio - 1
self.pad_left = self.pad * self.stride + (self.kernel_size - self.stride) // 2
self.pad_right = self.pad * self.stride + (self.kernel_size - self.stride + 1) // 2
filter = kaiser_sinc_filter1d(cutoff=0.5 / ratio, half_width=0.6 / ratio, kernel_size=self.kernel_size)
self.register_buffer("filter", filter, persistent=False)
def forward(self, hidden_states):
channels = hidden_states.shape[1]
hidden_states = F.pad(hidden_states, (self.pad, self.pad), mode="replicate")
hidden_states = self.ratio * F.conv_transpose1d(
hidden_states, self.filter.expand(channels, -1, -1), stride=self.stride, groups=channels
)
hidden_states = hidden_states[..., self.pad_left : -self.pad_right]
return hidden_states
class DownSample1d(nn.Module):
def __init__(self, ratio=2, kernel_size=None):
super().__init__()
cutoff = 0.5 / ratio
half_width = 0.6 / ratio
if cutoff < 0.0:
raise ValueError("Minimum cutoff must be larger than zero.")
if cutoff > 0.5:
raise ValueError("A cutoff above 0.5 does not make sense.")
self.even = kernel_size % 2 == 0
self.pad_left = kernel_size // 2 - int(self.even)
self.pad_right = kernel_size // 2
self.stride = ratio
filter = kaiser_sinc_filter1d(cutoff, half_width, kernel_size)
self.register_buffer("filter", filter, persistent=False)
def forward(self, hidden_states):
channels = hidden_states.shape[1]
hidden_states = F.pad(hidden_states, (self.pad_left, self.pad_right), mode="replicate")
out = F.conv1d(hidden_states, self.filter.expand(channels, -1, -1), stride=self.stride, groups=channels)
return out
class TorchActivation1d(nn.Module):
def __init__(
self,
activation,
up_ratio: int = 2,
down_ratio: int = 2,
up_kernel_size: int = 12,
down_kernel_size: int = 12,
):
super().__init__()
if not callable(activation):
raise TypeError("Activation function must be callable")
self.act = activation
self.upsample = UpSample1d(up_ratio, up_kernel_size)
self.downsample = DownSample1d(down_ratio, down_kernel_size)
def forward(self, hidden_states):
hidden_states = self.upsample(hidden_states)
hidden_states = self.act(hidden_states)
hidden_states = self.downsample(hidden_states)
return hidden_states
# SnakeBeta, UpSample1d, DownSample1d, AliasFreeActivation1d (formerly
# TorchActivation1d) are now provided by the shared ``common`` modules.
# See: vllm_omni/model_executor/models/common/{snake_activation,alias_free_activation}.py
class CausalConv1d(nn.Conv1d):
@@ -929,7 +772,7 @@ class AMPBlock(torch.nn.Module):
self.num_layers = len(self.convs1) + len(self.convs2) # total number of conv layers
self.activations = nn.ModuleList(
[TorchActivation1d(activation=SnakeBeta(channels)) for _ in range(self.num_layers)]
[AliasFreeActivation1d(activation=SnakeBeta(channels)) for _ in range(self.num_layers)]
)
if causal_type == "2":
@@ -940,7 +783,7 @@ class AMPBlock(torch.nn.Module):
stride=1,
padding=self._get_padding(kernel_size, 1),
)
self.pre_act = TorchActivation1d(activation=SnakeBeta(channels))
self.pre_act = AliasFreeActivation1d(activation=SnakeBeta(channels))
else:
self.pre_conv = nn.Identity()
self.pre_act = nn.Identity()
@@ -1002,7 +845,7 @@ class Qwen3TTSTokenizerV1DecoderBigVGANModel(Qwen3TTSTokenizerV1DecoderPreTraine
]
)
self.activation_post = TorchActivation1d(
self.activation_post = AliasFreeActivation1d(
activation=SnakeBeta(config.upsample_initial_channel // (2**self.num_upsample_layers))
)
self.conv_post = nn.Conv1d(