Files
MOSS-Image/inference_runtime.py
T
2026-10-16 03:00:54 +00:00

85 lines
2.9 KiB
Python

"""Application device placement, optional compilation, and progress reporting."""
from __future__ import annotations
from pathlib import Path
import diffusers
import torch
from huggingface_hub.utils import validate_repo_id
DEFAULT_MODEL = "OpenMOSS-Team/MOSS-Image-Base"
def model_source(model):
"""Resolve local bundles without turning Hub IDs into filesystem paths."""
model = str(model).strip()
path = Path(model).expanduser()
if path.is_dir():
if not (path / "pipeline_moss_image.py").is_file():
raise ValueError("The local bundle must include pipeline_moss_image.py from the HF repository.")
return str(path.resolve())
if model.startswith(("/", ".", "~")):
raise FileNotFoundError(f"Model directory does not exist: {model}")
validate_repo_id(model)
return model
def load_pipeline(model, local_files_only=False):
return diffusers.DiffusionPipeline.from_pretrained(
model_source(model),
custom_pipeline="pipeline_moss_image",
trust_remote_code=True,
local_files_only=local_files_only,
torch_dtype={"default": torch.bfloat16, "vae": torch.float32},
)
def set_scheduler(pipe, shift):
pipe.scheduler = type(pipe.scheduler).from_config(pipe.scheduler.config, shift=shift)
def cuda_budget_gib():
if not torch.cuda.is_available():
return 0.0
total = torch.cuda.get_device_properties(0).total_memory
return total * torch.cuda.get_per_process_memory_fraction(0) / 1024**3
def configure_pipeline(pipe, offload="auto", compile_transformer=False):
device = "cuda" if torch.cuda.is_available() else "cpu"
if offload == "auto":
offload = "none" if device == "cpu" or cuda_budget_gib() >= 40 else "model"
if compile_transformer and offload == "sequential":
raise ValueError("Compilation is incompatible with sequential offload.")
if offload == "model":
pipe.enable_model_cpu_offload(device=device)
elif offload == "sequential":
pipe.enable_sequential_cpu_offload(device=device)
elif offload == "none":
pipe.to(device)
else:
raise ValueError(f"Unknown offload mode: {offload}")
if compile_transformer:
for block in (*pipe.transformer.layers, *pipe.transformer.text_embedder.blocks):
block.compile(backend="inductor", fullgraph=True, dynamic=True, mode="default")
return pipe
def generate_with_progress(pipe, report_stage, report_step, **kwargs):
progress_bar = pipe.progress_bar
def progress(items):
report_stage("denoise")
for index, timestep in enumerate(progress_bar(items)):
yield timestep
report_step(pipe, index, timestep, {})
if kwargs.get("output_type", "pil") != "latent":
report_stage("decode")
pipe.progress_bar = progress
try:
report_stage("encode")
return pipe(**kwargs)
finally:
pipe.progress_bar = progress_bar