[Model] Add Ming-omni-tts dense 0.5B pipeline (#2906)

Signed-off-by: akshatvishu <akshatnayak197@gmail.com>
Co-authored-by: Hongsheng Liu <liuhongsheng4@huawei.com>
This commit is contained in:
akshatvishuandHongsheng Liu authored and GitHub committed 2026-06-10 20:11:04 +08:00
1 parent 39ae6e12f8
commit 2fa4c7a4a9
55 files changed
+6263 -549

No files matched your search

@@ -0,0 +1,2 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
@@ -0,0 +1,209 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
# Adopted from https://github.com/inclusionAI/Ming-omni-tts/blob/main/audio_tokenizer/istft.py
import torch
import torch.nn as nn
class ISTFT(nn.Module):
"""
Custom implementation of ISTFT since torch.istft doesn't allow custom padding (other than `center=True`) with
windowing. This is because the NOLA (Nonzero Overlap Add) check fails at the edges.
See issue: https://github.com/pytorch/pytorch/issues/62323
Specifically, in the context of neural vocoding we are interested in "same" padding analogous to CNNs.
The NOLA constraint is met as we trim padded samples anyway.
Args:
n_fft (int): Size of Fourier transform.
hop_length (int): The distance between neighboring sliding window frames.
win_length (int): The size of window frame and STFT filter.
padding (str, optional): Type of padding. Options are "center" or "same". Defaults to "same".
"""
def __init__(self, n_fft: int, hop_length: int, win_length: int, padding: str = "same"):
super().__init__()
if padding not in ["center", "same"]:
raise ValueError("Padding must be 'center' or 'same'.")
self.padding = padding
self.n_fft = n_fft
self.hop_length = hop_length
self.win_length = win_length
window = torch.hann_window(win_length)
self.register_buffer("window", window)
self.buffer_len = self.win_length - self.hop_length
def _buffer_process(
self,
x: torch.Tensor,
buffer: torch.Tensor | None,
pad: int,
last_chunk: bool = False,
streaming: bool = False,
) -> tuple[torch.Tensor, torch.Tensor | None]:
if streaming:
if buffer is None:
# first chunk
x = x[:, pad:]
if buffer is not None:
# next chunk
x[:, : self.buffer_len] += buffer
buffer = x[:, -self.buffer_len :]
if not last_chunk:
x = x[:, : -self.buffer_len]
else:
x = x[:, :-pad]
else:
x = x[:, pad:-pad]
return x, buffer
def forward(
self,
spec: torch.Tensor,
audio_buffer: torch.Tensor | None = None,
window_buffer: torch.Tensor | None = None,
streaming: bool = False,
last_chunk: bool = False,
) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor | None, torch.Tensor | None]:
"""
Compute the Inverse Short Time Fourier Transform (ISTFT) of a complex spectrogram.
Args:
spec (Tensor): Input complex spectrogram of shape (B, N, T), where B is the batch size,
N is the number of frequency bins, and T is the number of time frames.
audio_buffer (Tensor): [Streaming Input/State] The audio overlap buffer from the previous chunk.
Shape: (B, win_length - hop_length)
window_buffer (Tensor): [Streaming Input/State] The window overlap buffer from the previous chunk.
streaming: If `True`, the function operates in streaming mode, processing `spec` as a single chunk.
last_chunk: When `streaming=True` and `last_chunk=True`, the function can perform final "flush" operations
Returns:
Reconstructed signal, plus streaming buffers when `padding="same"`.
"""
if self.padding == "center":
# Fallback to pytorch native implementation
return torch.istft(spec, self.n_fft, self.hop_length, self.win_length, self.window, center=True)
elif self.padding == "same":
pad = (self.win_length - self.hop_length) // 2
else:
raise ValueError("Padding must be 'center' or 'same'.")
if spec.dim() != 3:
raise ValueError(f"Expected spec rank-3 [Batch, Freq, Time], got {tuple(spec.shape)}")
_, _, T = spec.shape
# Inverse FFT
ifft = torch.fft.irfft(spec, self.n_fft, dim=1, norm="backward")
ifft = ifft * self.window[None, :, None]
# Overlap and Add
output_size = (T - 1) * self.hop_length + self.win_length
y = torch.nn.functional.fold(
ifft,
output_size=(1, output_size),
kernel_size=(1, self.win_length),
stride=(1, self.hop_length),
)[:, 0, 0, :]
y, audio_buffer = self._buffer_process(y, audio_buffer, pad, last_chunk=last_chunk, streaming=streaming)
# Window envelope
window_sq = self.window.square().expand(1, T, -1).transpose(1, 2)
window_envelope = (
torch.nn.functional.fold(
window_sq,
output_size=(1, output_size),
kernel_size=(1, self.win_length),
stride=(1, self.hop_length),
)
.squeeze(0)
.squeeze(0)
)
window_envelope, window_buffer = self._buffer_process(
window_envelope, window_buffer, pad, last_chunk=last_chunk, streaming=streaming
)
window_envelope = window_envelope.squeeze()
# Normalize
if not (window_envelope > 1e-11).all():
raise RuntimeError("ISTFT window envelope underflowed; invalid overlap-add state.")
y = y / window_envelope
return y, audio_buffer, window_buffer
class FourierHead(nn.Module):
"""Base class for inverse fourier modules."""
def forward(self, x: torch.Tensor) -> torch.Tensor:
"""
Args:
x (Tensor): Input tensor of shape (B, L, H), where B is the batch size,
L is the sequence length, and H denotes the model dimension.
Returns:
Tensor: Reconstructed time-domain audio signal of shape (B, T), where T is the length of the output signal.
"""
raise NotImplementedError("Subclasses must implement the forward method.")
class ISTFTHead(FourierHead):
"""
ISTFT Head module for predicting STFT complex coefficients.
Args:
dim (int): Hidden dimension of the model.
n_fft (int): Size of Fourier transform.
hop_length (int): The distance between neighboring sliding window frames, which should align with
the resolution of the input features.
padding (str, optional): Type of padding. Options are "center" or "same". Defaults to "same".
"""
def __init__(self, dim: int, n_fft: int, hop_length: int, padding: str = "same"):
super().__init__()
out_dim = n_fft + 2
self.out = torch.nn.Linear(dim, out_dim)
self.istft = ISTFT(n_fft=n_fft, hop_length=hop_length, win_length=n_fft, padding=padding)
def forward(
self,
x: torch.Tensor,
audio_buffer: torch.Tensor | None = None,
window_buffer: torch.Tensor | None = None,
streaming: bool = False,
last_chunk: bool = False,
) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor | None, torch.Tensor | None]:
"""
Forward pass of the ISTFTHead module.
Args:
x (Tensor): Input tensor of shape (B, L, H), where B is the batch size,
L is the sequence length, and H denotes the model dimension.
Returns:
Audio, predicted spectrogram coefficients, and streaming buffers.
"""
x_pred = self.out(x)
x_pred = x_pred.transpose(1, 2)
mag, p = x_pred.chunk(2, dim=1)
mag = torch.exp(mag)
mag = torch.clip(mag, max=1e2) # safeguard to prevent excessively large magnitudes
# wrapping happens here. These two lines produce real and imaginary value
x = torch.cos(p)
y = torch.sin(p)
# recalculating phase here does not produce anything new
# only costs time
# phase = torch.atan2(y, x)
# S = mag * torch.exp(phase * 1j)
# better directly produce the complex value
S = mag * (x + 1j * y)
audio, audio_buffer, window_buffer = self.istft(
S, audio_buffer=audio_buffer, window_buffer=window_buffer, streaming=streaming, last_chunk=last_chunk
)
return audio.unsqueeze(1), x_pred, audio_buffer, window_buffer
__all__ = ["FourierHead", "ISTFT", "ISTFTHead"]
@@ -0,0 +1,379 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
import torch
import torch.nn as nn
import torch.nn.functional as F
from transformers import PretrainedConfig, PreTrainedModel, Qwen2Config, Qwen2Model
from transformers.utils import is_flash_attn_2_available
from vllm.logger import init_logger
from .audio_dsp import ISTFTHead
logger = init_logger(__name__)
class AudioVAEConfig(PretrainedConfig):
model_type = "audio_vae"
def __init__(
self,
sample_rate=44100,
enc_kwargs=None,
semantic_module_kwargs=None,
dec_kwargs=None,
hifi_gan_disc_kwargs=None,
spec_disc_kwargs=None,
lambda_disc=1.0,
lambda_mel_loss=15,
lambda_adv=1.0,
lambda_feat_match_loss=1.0,
lambda_semantic=5.0,
init_method="kaiming",
patch_size=4,
**kwargs,
):
self.sample_rate = sample_rate
self.enc_kwargs = enc_kwargs or {}
self.semantic_module_kwargs = semantic_module_kwargs
self.dec_kwargs = dec_kwargs or {}
self.hifi_gan_disc_kwargs = hifi_gan_disc_kwargs
self.spec_disc_kwargs = spec_disc_kwargs
self.lambda_disc = lambda_disc
self.lambda_mel_loss = lambda_mel_loss
self.lambda_adv = lambda_adv
self.lambda_feat_match_loss = lambda_feat_match_loss
self.lambda_semantic = lambda_semantic
self.init_method = init_method
self.patch_size = patch_size
super().__init__(**kwargs)
def _qwen2_config(backbone):
config = Qwen2Config.from_dict(config_dict=backbone)
if (getattr(config, "_attn_implementation", None) or getattr(config, "attn_implementation", None)) not in (
None,
"flash_attention_2",
):
return config
if is_flash_attn_2_available():
config._attn_implementation_autoset = True
config._attn_implementation = "flash_attention_2"
else:
config._attn_implementation = "sdpa"
return config
class StreamingLinearUpsample(nn.Module):
def __init__(self, scale_factor=4):
super().__init__()
self.scale_factor = scale_factor
self.upsampler = nn.Upsample(scale_factor=scale_factor, mode="linear", align_corners=False)
def forward(self, x, state=None, is_last=False):
if x is None and is_last and (state is None or state.get("prev_chunk") is None):
raise ValueError("Received end-of-stream without any latent chunk to upsample.")
if state is None:
state = {"prev_chunk": None, "history_last": None, "is_first": True}
if x is None and not is_last:
return None, state
if state["is_first"] and is_last:
out = self.upsampler(x.transpose(1, 2)).transpose(1, 2)
return out, None
output_chunks = []
if state["is_first"]:
state["prev_chunk"] = x
state["is_first"] = False
if not is_last:
return None, state
if state["prev_chunk"] is not None:
p = state["prev_chunk"].transpose(1, 2)
if state["history_last"] is None:
lookahead = x[:, :1, :].transpose(1, 2)
inp = torch.cat([p, lookahead], dim=2)
up = self.upsampler(inp)
out_prev = up[:, :, : p.size(2) * self.scale_factor]
else:
lookahead = x[:, :1, :].transpose(1, 2)
inp = torch.cat([state["history_last"], p, lookahead], dim=2)
up = self.upsampler(inp)
start = self.scale_factor
end = start + p.size(2) * self.scale_factor
out_prev = up[:, :, start:end]
output_chunks.append(out_prev.transpose(1, 2))
state["history_last"] = p[:, :, -1:]
state["prev_chunk"] = x
if is_last:
p = state["prev_chunk"].transpose(1, 2)
inp = torch.cat([state["history_last"], p], dim=2)
up = self.upsampler(inp)
out_last = up[:, :, self.scale_factor :]
output_chunks.append(out_last.transpose(1, 2))
state = None
final_out = torch.cat(output_chunks, dim=1) if output_chunks else None
return final_out, state
class Encoder(nn.Module):
def __init__(self, encoder_args, input_dim=320, hop_size=320, latent_dim=64, patch_size=-1):
super().__init__()
config = _qwen2_config(encoder_args)
logger.info("AudioVAE Encoder: using attn_implementation=%r", config._attn_implementation)
self.encoder = Qwen2Model(config)
self.input_dim = input_dim
self.hop_size = hop_size
self.latent_dim = latent_dim
self.fc1 = nn.Linear(input_dim, config.hidden_size, bias=False)
self.fc2 = nn.Linear(config.hidden_size, config.hidden_size)
self.fc3 = nn.Linear(config.hidden_size, latent_dim * 2)
self.norm = nn.LayerNorm(config.hidden_size)
self.patch_size = patch_size
if patch_size != -1:
aggregator_config = _qwen2_config({**encoder_args, "num_hidden_layers": 4})
self.aggregator = Qwen2Model(aggregator_config)
self.cls_embed = nn.Parameter(torch.rand(1, 1, config.hidden_size))
self.cls_embed.data.normal_(0, 0.02)
def get_frames(self, x):
num_frames_total = (x.size(-1) + self.hop_size - 1) // self.hop_size
expected_len = (num_frames_total - 1) * self.hop_size + self.input_dim
padding_needed = expected_len - x.size(-1)
waveform = F.pad(x, (0, padding_needed), value=0.0)
frames = waveform.unfold(dimension=-1, size=self.input_dim, step=self.hop_size)
return frames
def pad_patch_insert_cls(self, x):
bsz, _, dim = x.size()
num_frame = x.size(1)
r = num_frame % self.patch_size
pad_num = self.patch_size - r if r else 0
x = F.pad(x, (0, 0, 0, pad_num), value=0.0)
# [Batch, Time, Dimension] -> [Batch*PatchGroups, Patch, Dimension].
x = x.reshape(-1, self.patch_size, dim)
x = torch.cat((x, self.cls_embed.expand(x.size(0), -1, -1)), dim=1)
# [Batch*PatchGroups, Patch+1, Dimension] -> [Batch, Time, Dimension].
x = x.reshape(bsz, -1, dim)
return x
def forward(self, waveform):
x = self.get_frames(waveform)
x = self.fc1(x)
x = self.fc2(x)
x = self.encoder(inputs_embeds=x)
x = x.last_hidden_state
if self.patch_size != -1:
x = self.pad_patch_insert_cls(x)
x = self.aggregator(inputs_embeds=x)
x = x.last_hidden_state
bsz, _, dim = x.size()
# [Batch, Time, Dimension] -> [Batch*PatchGroups, Patch+1, Dimension].
x = x.reshape(-1, self.patch_size + 1, dim)
# [Batch*PatchGroups, 1, Dimension] -> [Batch, PatchGroups, Dimension].
x = x[:, -1:, :].reshape(bsz, -1, dim)
x = self.fc3(x)
return x, waveform.unsqueeze(1)
class Decoder(nn.Module):
def __init__(self, decoder_args, output_dim=320, latent_dim=64, patch_size=-1):
super().__init__()
config = _qwen2_config(decoder_args)
logger.info("AudioVAE Decoder: using attn_implementation=%r", config._attn_implementation)
self.decoder = Qwen2Model(config)
self.output_dim = output_dim
self.latent_dim = latent_dim
self.fc1 = nn.Linear(latent_dim, config.hidden_size)
self.hop_length = output_dim
self.head = ISTFTHead(
dim=config.hidden_size, n_fft=self.hop_length * 4, hop_length=self.hop_length, padding="same"
)
self.patch_size = patch_size
if self.patch_size != -1:
self.upsampling = StreamingLinearUpsample(scale_factor=patch_size)
def forward(self, x):
x = self.fc1(x)
if self.patch_size != -1:
# [Batch, Time, Dimension] -> [Batch, Dimension, Time] -> [Batch, Time, Dimension].
x = self.upsampling.upsampler(x.transpose(1, 2)).transpose(1, 2)
x = self.decoder(inputs_embeds=x)
x = x.last_hidden_state
x, _ = self.head(x)
return x, None
def low_level_reconstruct(self, x, past_key_values=None, use_cache=False, stream_state=None, last_chunk=False):
if stream_state is None:
stream_state = (None, None, None)
upsample_state, audio_buffer, window_buffer = stream_state
bsz, device, dtype = x.size(0), x.device, x.dtype
x = self.fc1(x)
if self.patch_size != -1:
if use_cache:
x, upsample_state = self.upsampling(x, state=upsample_state, is_last=last_chunk)
if x is None:
stream_state = (upsample_state, audio_buffer, window_buffer)
return torch.empty(bsz, 1, 0, device=device, dtype=dtype), stream_state, past_key_values
else:
# [Batch, Time, Dimension] -> [Batch, Dimension, Time] -> [Batch, Time, Dimension].
x = self.upsampling.upsampler(x.transpose(1, 2)).transpose(1, 2)
hidden_states_list = []
if use_cache and getattr(self.decoder.config, "sliding_window", None) is not None:
sw_size = self.decoder.config.sliding_window
target_len = sw_size - 1
if past_key_values is None:
past_len = 0
elif hasattr(past_key_values, "get_seq_length"):
past_len = past_key_values.get_seq_length()
elif isinstance(past_key_values, tuple) and len(past_key_values) > 0:
past_len = past_key_values[0][0].shape[-2]
else:
past_len = 0
curr_len = x.shape[1]
if past_len < target_len and (past_len + curr_len) >= sw_size:
fill_len = target_len - past_len
x_fill = x[:, :fill_len, :]
outputs = self.decoder(inputs_embeds=x_fill, past_key_values=past_key_values, use_cache=use_cache)
hidden_states_list.append(outputs.last_hidden_state)
past_key_values = outputs.past_key_values
x = x[:, fill_len:, :]
outputs = self.decoder(inputs_embeds=x, past_key_values=past_key_values, use_cache=use_cache)
hidden_states_list.append(outputs.last_hidden_state)
past_key_values = outputs.past_key_values
if len(hidden_states_list) > 1:
full_hidden_state = torch.cat(hidden_states_list, dim=1)
else:
full_hidden_state = hidden_states_list[0]
x_out, _, audio_buffer, window_buffer = self.head(
full_hidden_state,
streaming=use_cache,
audio_buffer=audio_buffer,
window_buffer=window_buffer,
last_chunk=last_chunk,
)
stream_state = (upsample_state, audio_buffer, window_buffer)
return x_out, stream_state, past_key_values
class AudioVAE(PreTrainedModel):
config_class = AudioVAEConfig
def __init__(self, config):
super().__init__(config)
self.config = config
enc_kwargs = config.enc_kwargs
dec_kwargs = config.dec_kwargs
for key in ("backbone", "input_dim", "latent_dim"):
if key not in enc_kwargs:
raise ValueError(f"AudioVAE.enc_kwargs missing required key: {key}")
for key in ("backbone", "output_dim", "latent_dim"):
if key not in dec_kwargs:
raise ValueError(f"AudioVAE.dec_kwargs missing required key: {key}")
hop_size = enc_kwargs.get("hop_size", enc_kwargs["input_dim"])
if enc_kwargs["input_dim"] != hop_size:
raise ValueError(f"AudioVAE encoder input_dim ({enc_kwargs['input_dim']}) != hop_size ({hop_size}).")
if hop_size != dec_kwargs["output_dim"]:
raise ValueError(
f"AudioVAE encoder hop_size ({hop_size}) != decoder output_dim ({dec_kwargs['output_dim']})."
)
self.encoder = Encoder(
encoder_args=enc_kwargs["backbone"],
input_dim=enc_kwargs["input_dim"],
hop_size=hop_size,
latent_dim=enc_kwargs["latent_dim"],
patch_size=config.patch_size,
)
self.decoder = Decoder(
decoder_args=dec_kwargs["backbone"],
output_dim=dec_kwargs["output_dim"],
latent_dim=dec_kwargs["latent_dim"],
patch_size=config.patch_size,
)
self.post_init()
def _init_weights(self, module):
std = 0.02
if isinstance(module, nn.Linear):
if self.config.init_method == "kaiming":
nn.init.kaiming_normal_(module.weight, mode="fan_in", nonlinearity="relu")
else:
module.weight.data.normal_(mean=0.0, std=std)
if module.bias is not None:
module.bias.data.zero_()
elif isinstance(module, nn.Embedding):
module.weight.data.normal_(mean=0.0, std=std)
if module.padding_idx is not None:
module.weight.data[module.padding_idx].zero_()
@torch.inference_mode()
def encode_latent(self, waveform, waveform_length):
if waveform.ndim != 2:
raise ValueError(f"Expected waveform rank-2 [Batch, Time], got {tuple(waveform.shape)}")
if waveform_length.ndim != 1:
raise ValueError(f"Expected waveform_length rank-1 [Batch], got {tuple(waveform_length.shape)}")
if waveform.shape[0] != waveform_length.shape[0]:
raise ValueError(
"Batch mismatch: "
f"waveform batch={waveform.shape[0]} vs "
f"waveform_length batch={waveform_length.shape[0]}"
)
if torch.any(waveform_length <= 0):
raise ValueError("waveform_length must be strictly positive.")
frame_num = torch.ceil(waveform_length / self.config.enc_kwargs["input_dim"]).to(torch.int32)
if self.config.patch_size != -1:
frame_num = torch.ceil(frame_num / self.config.patch_size)
h, _ = self.encoder(waveform)
h = h.transpose(1, 2)
mean, logvar = torch.chunk(h, 2, dim=1)
logvar = torch.clamp(logvar, -30.0, 20.0)
std = torch.exp(0.5 * logvar)
latent = mean + std * torch.randn_like(mean)
latent = latent.transpose(1, 2)
return latent, frame_num
@torch.inference_mode()
def decode(self, latent, past_key_values=None, use_cache=False, stream_state=(None, None, None), last_chunk=False):
if latent.dim() != 3:
raise ValueError(f"Expected latent rank-3 [B,T,D], got shape={tuple(latent.shape)}")
if latent.shape[0] <= 0:
raise ValueError("latent batch size must be positive.")
target_dtype = next(self.decoder.parameters()).dtype
target_device = next(self.decoder.parameters()).device
if latent.dtype != target_dtype or latent.device != target_device:
latent = latent.to(device=target_device, dtype=target_dtype)
expected_latent_dim = self.config.dec_kwargs["latent_dim"]
if latent.shape[-1] != expected_latent_dim:
raise ValueError(f"Latent dim mismatch in decode(): got {latent.shape[-1]}, expected {expected_latent_dim}")
waveform, stream_state, past_key_values = self.decoder.low_level_reconstruct(
latent,
past_key_values=past_key_values,
use_cache=use_cache,
stream_state=stream_state,
last_chunk=last_chunk,
)
return waveform, stream_state, past_key_values
@@ -0,0 +1,193 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
import torch
import torch.nn.functional as F
from torch import nn
from x_transformers.x_transformers import apply_rotary_pos_emb
class RMSNorm(nn.Module):
def __init__(self, dim, eps=1e-6):
super().__init__()
self.eps = eps
self.weight = nn.Parameter(torch.ones(dim))
def forward(self, x):
if self.weight.dtype in [torch.float16, torch.bfloat16]:
x = x.to(self.weight.dtype)
x = F.rms_norm(x, normalized_shape=(x.shape[-1],), weight=self.weight, eps=self.eps)
return x
class FeedForward(nn.Module):
def __init__(self, dim, dim_out=None, mult=4, dropout=0.0, approximate="none"):
super().__init__()
inner_dim = int(dim * mult)
dim_out = dim_out if dim_out is not None else dim
activation = nn.GELU(approximate=approximate)
project_in = nn.Sequential(nn.Linear(dim, inner_dim), activation)
self.ff = nn.Sequential(project_in, nn.Dropout(dropout), nn.Linear(inner_dim, dim_out))
def forward(self, x):
return self.ff(x)
class Attention(nn.Module):
def __init__(
self,
dim,
heads=8,
dim_head=64,
dropout=0.0,
qk_norm=None,
pe_attn_head=None,
attn_mask_enabled=True,
):
super().__init__()
self.dim = dim
self.heads = heads
self.inner_dim = dim_head * heads
self.dropout = dropout
self.to_q = nn.Linear(dim, self.inner_dim)
self.to_k = nn.Linear(dim, self.inner_dim)
self.to_v = nn.Linear(dim, self.inner_dim)
if qk_norm is None:
self.q_norm = None
self.k_norm = None
elif qk_norm == "rms_norm":
self.q_norm = RMSNorm(dim_head)
self.k_norm = RMSNorm(dim_head)
else:
raise ValueError(f"Unimplemented qk_norm: {qk_norm}")
self.to_out = nn.ModuleList([])
self.to_out.append(nn.Linear(self.inner_dim, dim))
self.to_out.append(nn.Dropout(dropout))
self.pe_attn_head = pe_attn_head
self.attn_mask_enabled = attn_mask_enabled
def forward(self, x, mask=None, rope=None):
batch_size = x.shape[0]
query = self.to_q(x)
key = self.to_k(x)
value = self.to_v(x)
inner_dim = key.shape[-1]
head_dim = inner_dim // self.heads
query = query.view(batch_size, -1, self.heads, head_dim).transpose(1, 2)
key = key.view(batch_size, -1, self.heads, head_dim).transpose(1, 2)
value = value.view(batch_size, -1, self.heads, head_dim).transpose(1, 2)
if self.q_norm is not None:
query = self.q_norm(query)
if self.k_norm is not None:
key = self.k_norm(key)
if rope is not None:
freqs, xpos_scale = rope
q_xpos_scale, k_xpos_scale = (xpos_scale, xpos_scale**-1.0) if xpos_scale is not None else (1.0, 1.0)
if self.pe_attn_head is not None:
on = self.pe_attn_head
query[:, :on, :, :] = apply_rotary_pos_emb(query[:, :on, :, :], freqs, q_xpos_scale)
key[:, :on, :, :] = apply_rotary_pos_emb(key[:, :on, :, :], freqs, k_xpos_scale)
else:
query = apply_rotary_pos_emb(query, freqs, q_xpos_scale)
key = apply_rotary_pos_emb(key, freqs, k_xpos_scale)
if self.attn_mask_enabled and mask is not None:
valid_sample_indices = mask.any(dim=1)
final_output = torch.zeros_like(query).to(query.device)
attn_mask = mask[valid_sample_indices]
query = query[valid_sample_indices]
key = key[valid_sample_indices]
value = value[valid_sample_indices]
attn_mask = attn_mask.unsqueeze(1).unsqueeze(1)
attn_mask = attn_mask.expand(valid_sample_indices.sum().item(), self.heads, query.shape[-2], key.shape[-2])
else:
attn_mask = None
x = F.scaled_dot_product_attention(query, key, value, attn_mask=attn_mask, dropout_p=0.0, is_causal=False)
if self.attn_mask_enabled and mask is not None:
final_output[valid_sample_indices] = x
x = final_output
x = x.transpose(1, 2).reshape(batch_size, -1, self.heads * head_dim)
x = x.to(query.dtype)
x = self.to_out[0](x)
x = self.to_out[1](x)
if mask is not None:
mask = mask.unsqueeze(-1)
x = x.masked_fill(~mask, 0.0)
return x
class DiTBlock(nn.Module):
def __init__(
self,
hidden_size,
num_heads,
mlp_ratio=4.0,
dropout=0.1,
qk_norm=None,
pe_attn_head=None,
attn_mask_enabled=True,
**kwargs,
):
super().__init__()
self.norm1 = RMSNorm(hidden_size)
self.attn = Attention(
dim=hidden_size,
heads=num_heads,
dim_head=hidden_size // num_heads,
dropout=dropout,
qk_norm=qk_norm,
pe_attn_head=pe_attn_head,
attn_mask_enabled=attn_mask_enabled,
)
self.norm2 = RMSNorm(hidden_size)
self.mlp = FeedForward(dim=hidden_size, mult=mlp_ratio, dropout=dropout, approximate="tanh")
def forward(self, x, mask, rope):
x = x + self.attn(self.norm1(x), mask=mask, rope=rope)
x = x + self.mlp(self.norm2(x))
return x
class FinalLayer(nn.Module):
def __init__(self, hidden_size, out_channels):
super().__init__()
self.norm_final = RMSNorm(hidden_size)
self.linear = nn.Linear(hidden_size, out_channels, bias=True)
def forward(self, x):
x = self.norm_final(x)
x = self.linear(x)
return x
class CondEmbedder(nn.Module):
def __init__(self, input_feature_size, hidden_size):
super().__init__()
self.cond_embedder = nn.Linear(input_feature_size, hidden_size)
def forward(self, llm_cond):
return self.cond_embedder(llm_cond)
def get_epss_timesteps(n, device, dtype):
dt = 1 / 32
predefined_timesteps = {
5: [0, 2, 4, 8, 16, 32],
6: [0, 2, 4, 6, 8, 16, 32],
7: [0, 2, 4, 6, 8, 16, 24, 32],
10: [0, 2, 4, 6, 8, 12, 16, 20, 24, 28, 32],
12: [0, 2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32],
16: [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32],
}
t = predefined_timesteps.get(n, [])
if not t:
return torch.linspace(0, 1, n + 1, device=device, dtype=dtype)
return dt * torch.tensor(t, device=device, dtype=dtype)
@@ -0,0 +1,68 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
import torch
from .dit import get_epss_timesteps
def apply_sway_sampling(t, sway_sampling_coef):
if sway_sampling_coef is None:
return t
return t + sway_sampling_coef * (torch.cos(torch.pi / 2 * t) - 1 + t)
def build_timesteps(steps, device, dtype, use_epss=True, sway_sampling_coef=-1.0):
if steps <= 0:
raise ValueError(f"steps must be positive, got {steps}")
if use_epss:
t = get_epss_timesteps(steps, device=device, dtype=dtype)
else:
t = torch.linspace(0, 1, steps + 1, device=device, dtype=dtype)
return apply_sway_sampling(t, sway_sampling_coef)
class Solver:
def __init__(self, func, y0, sigma=0.25, temperature=1.5) -> None:
self.func = func
self.y0 = y0
self.sigma = sigma
self.temperature = temperature
def integrate(self, t):
solution = torch.empty(len(t), *self.y0.shape, dtype=self.y0.dtype, device=self.y0.device)
solution[0] = self.y0
j = 1
y0 = self.y0
for t0, t1 in zip(t[:-1], t[1:]):
dt = t1 - t0
f0 = self.func(t0, y0)
dy = dt * f0
y1 = y0 + dy
while j < len(t) and t1 >= t[j]:
solution[j] = self._linear_interp(t0, t1, y0, y1, t[j])
j += 1
noise = torch.randn_like(y0)
shift = self.sigma * (self.temperature**0.5) * (abs(dt) ** 0.5) * noise
y0 = y1 + shift
return solution
def _linear_interp(self, t0, t1, y0, y1, t):
if t == t0:
return y0
if t == t1:
return y1
slope = (t - t0) / (t1 - t0)
return y0 + slope * (y1 - y0)
def integrate_cfm_steps(fn, y0, t, sde_args, sde_rnd, steps):
for step in range(steps):
dt = t[step + 1] - t[step]
y0 = y0 + fn(t[step], y0) * dt
y0 = y0 + sde_args[1] * (sde_args[2] ** 0.5) * (dt.abs() ** 0.5) * sde_rnd[step]
return y0