Compare commits

...
Author SHA1 Message Date
Isotr0py a2a5ab003b revert doc deletion
Signed-off-by: Isotr0py <mozf@mail2.sysu.edu.cn>
2025-11-19 00:04:21 +08:00
Isotr0py f8e948de9e code format
Signed-off-by: Isotr0py <mozf@mail2.sysu.edu.cn>
2025-11-18 23:56:39 +08:00
Isotr0py 1c8a31821f expose ode_solver_class
Signed-off-by: Isotr0py <mozf@mail2.sysu.edu.cn>
2025-11-18 23:56:22 +08:00
Isotr0py 219c5a1987 oops
Signed-off-by: Isotr0py <mozf@mail2.sysu.edu.cn>
2025-11-18 23:29:17 +08:00
Isotr0py 4541e51ccf move ode_solver outside model impl
Signed-off-by: Isotr0py <mozf@mail2.sysu.edu.cn>
2025-11-18 23:19:27 +08:00
6 changed files with 141 additions and 104 deletions

No files matched your search

+1
View File
@@ -15,6 +15,7 @@ class OmniModelConfig(ModelConfig):
stage_id: int = 0 stage_id: int = 0
model_stage: str = "thinker" model_stage: str = "thinker"
model_arch: str = "Qwen2_5OmniForConditionalGeneration" model_arch: str = "Qwen2_5OmniForConditionalGeneration"
ode_solver_class: Optional[str] = None
engine_output_type: Optional[str] = None engine_output_type: Optional[str] = None
@property @property
+2
View File
@@ -12,6 +12,7 @@ class OmniEngineArgs(EngineArgs):
stage_id: int = 0 stage_id: int = 0
model_stage: str = "thinker" model_stage: str = "thinker"
model_arch: str = "Qwen2_5OmniForConditionalGeneration" model_arch: str = "Qwen2_5OmniForConditionalGeneration"
ode_solver_class: Optional[str] = None
engine_output_type: Optional[str] = None engine_output_type: Optional[str] = None
def create_model_config(self) -> OmniModelConfig: def create_model_config(self) -> OmniModelConfig:
@@ -27,6 +28,7 @@ class OmniEngineArgs(EngineArgs):
config_dict["model_stage"] = self.model_stage config_dict["model_stage"] = self.model_stage
config_dict["model_arch"] = self.model_arch config_dict["model_arch"] = self.model_arch
config_dict["engine_output_type"] = self.engine_output_type config_dict["engine_output_type"] = self.engine_output_type
config_dict["ode_solver_class"] = self.ode_solver_class
# Create and return the OmniModelConfig instance # Create and return the OmniModelConfig instance
omni_config = OmniModelConfig(**config_dict) omni_config = OmniModelConfig(**config_dict)
@@ -23,6 +23,7 @@ from transformers.models.qwen2_5_omni.modeling_qwen2_5_omni import Qwen2_5OmniPr
from transformers.utils.logging import get_logger as _hf_get_logger from transformers.utils.logging import get_logger as _hf_get_logger
from vllm.config import VllmConfig from vllm.config import VllmConfig
from vllm.logger import init_logger from vllm.logger import init_logger
from vllm.model_executor.model_loader.utils import set_default_torch_dtype
from vllm.model_executor.models.interfaces import SupportsPP from vllm.model_executor.models.interfaces import SupportsPP
from vllm.model_executor.models.utils import AutoWeightsLoader as _Vllm_AutoWeightsLoader from vllm.model_executor.models.utils import AutoWeightsLoader as _Vllm_AutoWeightsLoader
from vllm.model_executor.models.utils import WeightsMapper as _Vllm_WeightsMapper from vllm.model_executor.models.utils import WeightsMapper as _Vllm_WeightsMapper
@@ -33,6 +34,8 @@ from vllm.v1.outputs import SamplerOutput
from vllm.v1.sample.metadata import SamplingMetadata from vllm.v1.sample.metadata import SamplingMetadata
from vllm.v1.sample.sampler import Sampler from vllm.v1.sample.sampler import Sampler
from vllm_omni.model_executor.ode_solver import get_ode_solver_class
# Provide a no-op auto_docstring decorator to satisfy annotations if missing # Provide a no-op auto_docstring decorator to satisfy annotations if missing
def auto_docstring(func=None, **_kwargs): def auto_docstring(func=None, **_kwargs):
@@ -569,7 +572,8 @@ class DiTAttention(nn.Module):
cos, sin = position_embeddings cos, sin = position_embeddings
query[:, :1], key[:, :1] = apply_rotary_pos_emb(query[:, :1], key[:, :1], cos, sin) query[:, :1], key[:, :1] = apply_rotary_pos_emb(query[:, :1], key[:, :1], cos, sin)
attention_interface = ALL_ATTENTION_FUNCTIONS[self.config._attn_implementation] attn_impl = self.config._attn_implementation or "sdpa"
attention_interface = ALL_ATTENTION_FUNCTIONS[attn_impl]
attention_weights, _ = attention_interface( attention_weights, _ = attention_interface(
self, self,
query, query,
@@ -1014,100 +1018,19 @@ class Qwen2_5OmniToken2WavBigVGANModel(Qwen2_5OmniPreTrainedModel):
return torch.clamp(output_waveform, min=-1.0, max=1.0).squeeze().cpu() return torch.clamp(output_waveform, min=-1.0, max=1.0).squeeze().cpu()
class RungeKutta4ODESolver:
def __init__(self, function, initial_value):
self.function = function
self.initial_value = initial_value
self._one_third = 1 / 3
self._two_thirds = 2 / 3
def _rk4_step(
self,
function,
time_start,
time_step,
time_end,
value_start,
function_value_start=None,
):
k1 = function_value_start if function_value_start is not None else function(time_start, value_start)
k2 = function(
time_start + time_step * self._one_third,
value_start + time_step * k1 * self._one_third,
)
k3 = function(
time_start + time_step * self._two_thirds,
value_start + time_step * (k2 - k1 * self._one_third),
)
k4 = function(time_end, value_start + time_step * (k1 - k2 + k3))
return (k1 + 3 * (k2 + k3) + k4) * time_step / 8
def _compute_step(self, function, time_start, time_step, time_end, value_start):
function_value_start = function(time_start, value_start)
return (
self._rk4_step(
function,
time_start,
time_step,
time_end,
value_start,
function_value_start=function_value_start,
),
function_value_start,
)
def _linear_interpolation(self, time_start, time_end, value_start, value_end, time_point):
if time_point == time_start:
return value_start
if time_point == time_end:
return value_end
weight = (time_point - time_start) / (time_end - time_start)
return value_start + weight * (value_end - value_start)
def integrate(self, time_points):
solution = torch.empty(
len(time_points),
*self.initial_value.shape,
dtype=self.initial_value.dtype,
device=self.initial_value.device,
)
solution[0] = self.initial_value
current_index = 1
current_value = self.initial_value
for time_start, time_end in zip(time_points[:-1], time_points[1:]):
time_step = time_end - time_start
delta_value, _ = self._compute_step(self.function, time_start, time_step, time_end, current_value)
next_value = current_value + delta_value
while current_index < len(time_points) and time_end >= time_points[current_index]:
solution[current_index] = self._linear_interpolation(
time_start,
time_end,
current_value,
next_value,
time_points[current_index],
)
current_index += 1
current_value = next_value
return solution
@auto_docstring( @auto_docstring(
custom_intro=""" custom_intro="""
The full Qwen2.5Omni Token2WavDiT model. Which take speech tokens as The full Qwen2.5Omni Token2WavDiT model. Which take speech tokens as
input and predict mel spectrogram. input and predict mel spectrogram.
""" """
) )
class Qwen2_5OmniToken2WavDiTModel(Qwen2_5OmniPreTrainedModel): class Qwen2_5OmniToken2WavDiTModel(nn.Module):
config: Qwen2_5OmniDiTConfig def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
_no_split_modules = ["DiTDecoderLayer"] super().__init__()
model_config = vllm_config.model_config
config: Qwen2_5OmniDiTConfig = model_config.hf_config
def __init__(self, config: Qwen2_5OmniDiTConfig):
super().__init__(config)
self.mel_dim = config.mel_dim self.mel_dim = config.mel_dim
self.repeats = config.repeats self.repeats = config.repeats
self.time_embed = DiTTimestepEmbedding(config.hidden_size) self.time_embed = DiTTimestepEmbedding(config.hidden_size)
@@ -1135,6 +1058,10 @@ class Qwen2_5OmniToken2WavDiTModel(Qwen2_5OmniPreTrainedModel):
self.norm_out = Qwen2_5_OmniAdaLayerNormZero_Final(config.hidden_size) # final modulation self.norm_out = Qwen2_5_OmniAdaLayerNormZero_Final(config.hidden_size) # final modulation
self.proj_out = nn.Linear(config.hidden_size, config.mel_dim) self.proj_out = nn.Linear(config.hidden_size, config.mel_dim)
self.ode_solver = get_ode_solver_class(vllm_config.model_config.ode_solver_class)(
function=None, initial_value=None
) # placeholder
def _create_block_diff(self, hidden_states): def _create_block_diff(self, hidden_states):
batch, seq_len = hidden_states.shape[0], hidden_states.shape[1] batch, seq_len = hidden_states.shape[0], hidden_states.shape[1]
block_indices = torch.arange(seq_len, device=hidden_states.device) // self.block_size # [seq_length] block_indices = torch.arange(seq_len, device=hidden_states.device) // self.block_size # [seq_length]
@@ -1248,8 +1175,8 @@ class Qwen2_5OmniToken2WavDiTModel(Qwen2_5OmniPreTrainedModel):
if sway_coefficient is not None: if sway_coefficient is not None:
time_embedding += sway_coefficient * (torch.cos(torch.pi / 2 * time_embedding) - 1 + time_embedding) time_embedding += sway_coefficient * (torch.cos(torch.pi / 2 * time_embedding) - 1 + time_embedding)
ode_solver = RungeKutta4ODESolver(function=ode_function, initial_value=initial_state) self.ode_solver.reset_ode_solver(function=ode_function, initial_value=initial_state)
solution_trajectory = ode_solver.integrate(time_embedding) solution_trajectory = self.ode_solver.integrate(time_embedding)
generated_waveform = solution_trajectory[-1] generated_waveform = solution_trajectory[-1]
generated_mel_spectrogram = generated_waveform.permute(0, 2, 1) generated_mel_spectrogram = generated_waveform.permute(0, 2, 1)
@@ -1320,8 +1247,8 @@ class Qwen2_5OmniToken2WavDiTModel(Qwen2_5OmniPreTrainedModel):
if sway_coefficient is not None: if sway_coefficient is not None:
time_embedding += sway_coefficient * (torch.cos(torch.pi / 2 * time_embedding) - 1 + time_embedding) time_embedding += sway_coefficient * (torch.cos(torch.pi / 2 * time_embedding) - 1 + time_embedding)
ode_solver = RungeKutta4ODESolver(function=ode_function, initial_value=initial_state) self.ode_solver.reset_ode_solver(function=ode_function, initial_value=initial_state)
solution_trajectory = ode_solver.integrate(time_embedding) solution_trajectory = self.ode_solver.integrate(time_embedding)
generated_waveform = solution_trajectory[-1] generated_waveform = solution_trajectory[-1]
generated_mel_spectrogram = generated_waveform.permute(0, 2, 1) generated_mel_spectrogram = generated_waveform.permute(0, 2, 1)
@@ -1335,16 +1262,13 @@ class Qwen2_5OmniToken2WavDiTModel(Qwen2_5OmniPreTrainedModel):
mel spectrogram as input and predict waveform. mel spectrogram as input and predict waveform.
""" """
) )
class Qwen2_5OmniToken2WavModel(Qwen2_5OmniPreTrainedModel): class Qwen2_5OmniToken2WavModel(nn.Module):
config: Qwen2_5OmniToken2WavConfig def __init__(self, *, vllm_config: VllmConfig, prefix=""):
base_model_prefix = "model" super().__init__()
_no_split_modules = [
"Qwen2_5OmniToken2WavDiTModel", self.model_config = vllm_config.model_config
"Qwen2_5OmniToken2WavBigVGANModel", config: Qwen2_5OmniToken2WavConfig = self.model_config.hf_config
]
def __init__(self, config: Qwen2_5OmniToken2WavConfig):
super().__init__(config)
attn_impl = config._attn_implementation attn_impl = config._attn_implementation
if config._attn_implementation == "flash_attention_2": if config._attn_implementation == "flash_attention_2":
logger.warning_once( logger.warning_once(
@@ -1359,9 +1283,10 @@ class Qwen2_5OmniToken2WavModel(Qwen2_5OmniPreTrainedModel):
"Qwen2_5OmniToken2WavModel does not support eager attention implementation, fall back to sdpa" "Qwen2_5OmniToken2WavModel does not support eager attention implementation, fall back to sdpa"
) )
attn_impl = "sdpa" attn_impl = "sdpa"
self.code2wav_dit_model = Qwen2_5OmniToken2WavDiTModel._from_config( with set_default_torch_dtype(torch.float32):
config.dit_config, attn_implementation=attn_impl self.code2wav_dit_model = Qwen2_5OmniToken2WavDiTModel(
) vllm_config=vllm_config.with_hf_config(config.dit_config),
)
self.code2wav_bigvgan_model = Qwen2_5OmniToken2WavBigVGANModel._from_config( self.code2wav_bigvgan_model = Qwen2_5OmniToken2WavBigVGANModel._from_config(
config.bigvgan_config, attn_implementation=attn_impl config.bigvgan_config, attn_implementation=attn_impl
) )
@@ -1394,6 +1319,10 @@ class Qwen2_5OmniToken2WavModel(Qwen2_5OmniPreTrainedModel):
# fallback to commonly used value # fallback to commonly used value
self.vocoder_hop = 240 self.vocoder_hop = 240
@property
def dtype(self):
return next(self.parameters()).dtype
def forward( def forward(
self, self,
code, code,
@@ -0,0 +1,15 @@
from vllm_omni.model_executor.ode_solver.runger_kutta_4 import RungeKutta4ODESolver
_ODE_SOLVERS = {
"RungeKutta4ODESolver": RungeKutta4ODESolver,
}
def get_ode_solver_class(class_name: str):
solver = _ODE_SOLVERS.get(class_name)
if solver is None:
raise ValueError(f"ODE solver class '{class_name}' not found.")
return solver
__all__ = ["RungeKutta4ODESolver"]
@@ -0,0 +1,89 @@
from typing import Callable
import torch
class RungeKutta4ODESolver:
def __init__(self, function: Callable[[torch.Tensor, torch.Tensor], torch.Tensor], initial_value: torch.Tensor):
self.function = function
self.initial_value = initial_value
self._one_third = 1 / 3
self._two_thirds = 2 / 3
def reset_ode_solver(self, function, initial_value):
self.function = function
self.initial_value = initial_value
def _rk4_step(
self,
function,
time_start,
time_step,
time_end,
value_start,
function_value_start=None,
):
k1 = function_value_start if function_value_start is not None else function(time_start, value_start)
k2 = function(
time_start + time_step * self._one_third,
value_start + time_step * k1 * self._one_third,
)
k3 = function(
time_start + time_step * self._two_thirds,
value_start + time_step * (k2 - k1 * self._one_third),
)
k4 = function(time_end, value_start + time_step * (k1 - k2 + k3))
return (k1 + 3 * (k2 + k3) + k4) * time_step / 8
def _compute_step(self, function, time_start, time_step, time_end, value_start):
function_value_start = function(time_start, value_start)
return (
self._rk4_step(
function,
time_start,
time_step,
time_end,
value_start,
function_value_start=function_value_start,
),
function_value_start,
)
def _linear_interpolation(self, time_start, time_end, value_start, value_end, time_point):
if time_point == time_start:
return value_start
if time_point == time_end:
return value_end
weight = (time_point - time_start) / (time_end - time_start)
return value_start + weight * (value_end - value_start)
def integrate(self, time_points: torch.Tensor) -> torch.Tensor:
solution = torch.empty(
len(time_points),
*self.initial_value.shape,
dtype=self.initial_value.dtype,
device=self.initial_value.device,
)
solution[0] = self.initial_value
current_index = 1
current_value = self.initial_value
for time_start, time_end in zip(time_points[:-1], time_points[1:]):
time_step = time_end - time_start
delta_value, _ = self._compute_step(self.function, time_start, time_step, time_end, current_value)
next_value = current_value + delta_value
while current_index < len(time_points) and time_end >= time_points[current_index]:
solution[current_index] = self._linear_interpolation(
time_start,
time_end,
current_value,
next_value,
time_points[current_index],
)
current_index += 1
current_value = next_value
return solution
@@ -60,6 +60,7 @@ stage_args:
engine_args: engine_args:
model_stage: code2wav model_stage: code2wav
model_arch: Qwen2_5OmniForConditionalGeneration model_arch: Qwen2_5OmniForConditionalGeneration
ode_solver_class: RungeKutta4ODESolver
worker_cls: vllm_omni.worker.gpu_diffusion_worker.GPUDiffusionWorker worker_cls: vllm_omni.worker.gpu_diffusion_worker.GPUDiffusionWorker
scheduler_cls: vllm_omni.core.sched.diffusion_scheduler.DiffusionScheduler scheduler_cls: vllm_omni.core.sched.diffusion_scheduler.DiffusionScheduler
gpu_memory_utilization: 0.15 gpu_memory_utilization: 0.15