Files
vllm-omni/vllm_omni/entrypoints/omni_diffusion.py
T
汪志鹏andwzliu 7f821be57b Support Bagel Model (#726)
Signed-off-by: princepride <wangzhipeng628@gmail.com>
Co-authored-by: wzliu <wzliu@connect.hku.hk>
2026-01-22 23:09:55 +13:00

171 lines
6.2 KiB
Python

# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
import logging
import uuid
from dataclasses import fields
from vllm.logger import init_logger
from vllm.transformers_utils.config import get_hf_file_to_dict
from vllm_omni.diffusion.data import OmniDiffusionConfig, TransformerConfig
from vllm_omni.diffusion.diffusion_engine import DiffusionEngine
from vllm_omni.diffusion.request import OmniDiffusionRequest
# TODO configure logging properly
logging.basicConfig(level=logging.INFO)
logger = init_logger(__name__)
def prepare_requests(prompt: str | list[str], **kwargs):
field_names = {f.name for f in fields(OmniDiffusionRequest)}
init_kwargs = {"prompt": prompt}
for key, value in kwargs.items():
if key in field_names:
init_kwargs[key] = value
if "guidance_scale" in kwargs:
init_kwargs["guidance_scale_provided"] = True
return OmniDiffusionRequest(**init_kwargs)
class OmniDiffusion:
"""
It is the main class to interact with vLLM-Omni diffusion models.
It acts as a high-level interface that prepares requests and
delegates the actual diffusion process to the DiffusionEngine.
You can pass either an `OmniDiffusionConfig` via `od_config`, or
pass kwargs such as `model="Qwen/Qwen-Image"`,
which will be forwarded to `OmniDiffusionConfig.from_kwargs`.
"""
def __init__(self, od_config: OmniDiffusionConfig | None = None, **kwargs):
# Capture stage info from kwargs before they might be filtered out
stage_id = kwargs.get("stage_id")
engine_input_source = kwargs.get("engine_input_source")
if od_config is None:
od_config = OmniDiffusionConfig.from_kwargs(**kwargs)
elif isinstance(od_config, dict):
# If config is dict, check it too (priority to kwargs if both exist)
if stage_id is None:
stage_id = od_config.get("stage_id")
if engine_input_source is None:
engine_input_source = od_config.get("engine_input_source")
od_config = OmniDiffusionConfig.from_kwargs(**od_config)
self.od_config = od_config
# Inject stage info into omni_kv_config if present
if stage_id is not None:
self.od_config.omni_kv_config.setdefault("stage_id", stage_id)
if engine_input_source is not None:
self.od_config.omni_kv_config.setdefault("engine_input_source", engine_input_source)
# Diffusers-style models expose `model_index.json` with `_class_name`.
# Bagel models (and other non-diffusers) typically expose `config.json`.
try:
config_dict = get_hf_file_to_dict(
"model_index.json",
od_config.model,
)
od_config.model_class_name = config_dict.get("_class_name", None)
od_config.update_multimodal_support()
tf_config_dict = get_hf_file_to_dict(
"transformer/config.json",
od_config.model,
)
od_config.tf_model_config = TransformerConfig.from_dict(tf_config_dict)
except (AttributeError, OSError, ValueError):
cfg = get_hf_file_to_dict("config.json", od_config.model)
if cfg is None:
raise ValueError(f"Could not find config.json or model_index.json for model {od_config.model}")
model_type = cfg.get("model_type")
architectures = cfg.get("architectures") or []
if model_type == "bagel" or "BagelForConditionalGeneration" in architectures:
od_config.model_class_name = "BagelPipeline"
od_config.tf_model_config = TransformerConfig()
od_config.update_multimodal_support()
else:
raise
self.engine: DiffusionEngine = DiffusionEngine.make_engine(od_config)
def generate(
self,
prompt: str | list[str],
**kwargs,
):
prompts = []
if isinstance(prompt, str):
prompts.append(prompt)
elif isinstance(prompt, list):
prompts.extend(prompt)
else:
raise ValueError("Prompt must be a string or a list of strings")
requests: list[OmniDiffusionRequest] = []
# Check if request_id is provided in kwargs
request_id = kwargs.get("request_id")
request_ids = kwargs.pop("request_ids", None)
for i, p in enumerate(prompts):
req_kwargs = kwargs.copy()
if request_ids and isinstance(request_ids, list) and i < len(request_ids):
req_kwargs["request_id"] = request_ids[i]
elif request_id is None:
# Generate default ID consistent with OmniLLM: "{i}_{uuid}"
req_kwargs["request_id"] = f"{i}_{uuid.uuid4()}"
requests.append(
prepare_requests(
p,
**req_kwargs,
)
)
logger.info(f"Prepared {len(requests)} requests for generation.")
return self._run_engine(requests)
def _run_engine(self, requests: list[OmniDiffusionRequest]):
return self.engine.step(requests)
def close(self) -> None:
self.engine.close()
def __del__(self): # pragma: no cover - best effort cleanup
try:
self.close()
except Exception:
pass
def start_profile(self, trace_filename: str | None = None) -> None:
"""Start profiling for the diffusion model.
Args:
trace_filename: Optional base filename for trace files.
If None, a timestamp-based name will be generated.
"""
if hasattr(self, "engine") and self.engine:
self.engine.start_profile(trace_filename)
else:
raise RuntimeError("Diffusion engine not initialized")
def stop_profile(self) -> dict:
"""Stop profiling and return profiling results.
Returns:
Dictionary containing paths to trace and table files.
"""
if hasattr(self, "engine") and self.engine:
return self.engine.stop_profile()
else:
raise RuntimeError("Diffusion engine not initialized")