feat: enhance model loading with prefetching and retry logic

- Introduced `from_pretrained_with_prefetch` to handle racy cache scenarios by re-prefetching and retrying on failures.
- Updated various model pipelines to utilize the new prefetching mechanism, ensuring robust loading of model components.
- Prefetch logic added to multiple models, including HunyuanVideo, LongCatImage, and QwenImage, to mitigate issues with incomplete cache states.
This commit is contained in:
tzhouam committed 2026-06-02 09:01:47 +00:00
1 parent b550709bba
commit 617c6ca55f
20 files changed
+678 -194

No files matched your search

@@ -39,7 +39,7 @@ from vllm_omni.diffusion.data import DiffusionOutput, OmniDiffusionConfig
from vllm_omni.diffusion.distributed.cfg_parallel import CFGParallelMixin
from vllm_omni.diffusion.distributed.utils import get_local_device
from vllm_omni.diffusion.model_loader.diffusers_loader import DiffusersPipelineLoader
from vllm_omni.diffusion.model_loader.hub_prefetch import prefetch_subfolders
from vllm_omni.diffusion.model_loader.hub_prefetch import from_pretrained_with_prefetch, prefetch_subfolders
from vllm_omni.diffusion.models.flux2_klein.flux2_klein_transformer import (
Flux2Transformer2DModel,
)
@@ -213,9 +213,10 @@ class Flux2KleinPipeline(nn.Module, CFGParallelMixin, SupportImageInput, Diffusi
# Avoid the transformers v5 multi-worker subfolder race (see
# ``vllm_omni/diffusion/model_loader/hub_prefetch.py`` for the full
# analysis; L4 build #1043 hit this on FLUX.2-klein-4B's text_encoder).
flux2_subfolders = ["scheduler", "text_encoder", "tokenizer", "vae"]
prefetch_subfolders(
model,
["scheduler", "text_encoder", "tokenizer", "vae"],
flux2_subfolders,
local_files_only=local_files_only,
)
@@ -224,9 +225,15 @@ class Flux2KleinPipeline(nn.Module, CFGParallelMixin, SupportImageInput, Diffusi
subfolder="scheduler",
local_files_only=local_files_only,
)
self.text_encoder = Qwen3ForCausalLM.from_pretrained(
# ``from_pretrained_with_prefetch`` re-prefetches and retries if a peer
# worker left the cache half-written (missing-shard ``OSError`` or the
# default-config size-mismatch ``RuntimeError``) instead of crashing
# the worker - FLUX.2-klein-4B's sharded text_encoder hit this on #1043.
self.text_encoder = from_pretrained_with_prefetch(
Qwen3ForCausalLM.from_pretrained,
model,
subfolder="text_encoder",
prefetch_list=flux2_subfolders,
local_files_only=local_files_only,
).to(self._execution_device)
self.tokenizer = Qwen2TokenizerFast.from_pretrained(
@@ -234,9 +241,11 @@ class Flux2KleinPipeline(nn.Module, CFGParallelMixin, SupportImageInput, Diffusi
subfolder="tokenizer",
local_files_only=local_files_only,
)
self.vae = AutoencoderKLFlux2.from_pretrained(
self.vae = from_pretrained_with_prefetch(
AutoencoderKLFlux2.from_pretrained,
model,
subfolder="vae",
prefetch_list=flux2_subfolders,
local_files_only=local_files_only,
).to(self._execution_device)
@@ -31,6 +31,7 @@ from vllm_omni.diffusion.distributed.cfg_parallel import CFGParallelMixin
from vllm_omni.diffusion.distributed.parallel_state import get_classifier_free_guidance_world_size
from vllm_omni.diffusion.distributed.utils import get_local_device
from vllm_omni.diffusion.model_loader.diffusers_loader import DiffusersPipelineLoader
from vllm_omni.diffusion.model_loader.hub_prefetch import from_pretrained_with_prefetch, prefetch_subfolders
from vllm_omni.diffusion.models.hidream_image import HiDreamImageTransformer2DModel
from vllm_omni.diffusion.models.progress_bar import ProgressBarMixin
from vllm_omni.diffusion.profiler.diffusion_pipeline_profiler import DiffusionPipelineProfilerMixin
@@ -177,24 +178,55 @@ class HiDreamI1ImagePipeline(nn.Module, CFGParallelMixin, DiffusionPipelineProfi
# Check if model is a local path
local_files_only = os.path.exists(model)
# See ``hub_prefetch.py`` for the transformers v5 multi-worker subfolder
# race; prefetch the in-repo component set before any from_pretrained
# (``text_encoder_4`` lives in a separate Llama repo and is unaffected).
hidream_subfolders = [
"scheduler",
"vae",
"text_encoder",
"tokenizer",
"text_encoder_2",
"tokenizer_2",
"text_encoder_3",
"tokenizer_3",
]
prefetch_subfolders(model, hidream_subfolders, local_files_only=local_files_only)
self.scheduler = FlowMatchEulerDiscreteScheduler.from_pretrained(
model, subfolder="scheduler", local_files_only=local_files_only
)
self.vae = AutoencoderKL.from_pretrained(model, subfolder="vae", local_files_only=local_files_only).to(
self.device
)
self.text_encoder = CLIPTextModelWithProjection.from_pretrained(
model, subfolder="text_encoder", local_files_only=local_files_only
self.vae = from_pretrained_with_prefetch(
AutoencoderKL.from_pretrained,
model,
subfolder="vae",
prefetch_list=hidream_subfolders,
local_files_only=local_files_only,
).to(self.device)
self.text_encoder = from_pretrained_with_prefetch(
CLIPTextModelWithProjection.from_pretrained,
model,
subfolder="text_encoder",
prefetch_list=hidream_subfolders,
local_files_only=local_files_only,
)
self.tokenizer = CLIPTokenizer.from_pretrained(model, subfolder="tokenizer", local_files_only=local_files_only)
self.text_encoder_2 = CLIPTextModelWithProjection.from_pretrained(
model, subfolder="text_encoder_2", local_files_only=local_files_only
self.text_encoder_2 = from_pretrained_with_prefetch(
CLIPTextModelWithProjection.from_pretrained,
model,
subfolder="text_encoder_2",
prefetch_list=hidream_subfolders,
local_files_only=local_files_only,
)
self.tokenizer_2 = CLIPTokenizer.from_pretrained(
model, subfolder="tokenizer_2", local_files_only=local_files_only
)
self.text_encoder_3 = T5EncoderModel.from_pretrained(
model, subfolder="text_encoder_3", local_files_only=local_files_only
self.text_encoder_3 = from_pretrained_with_prefetch(
T5EncoderModel.from_pretrained,
model,
subfolder="text_encoder_3",
prefetch_list=hidream_subfolders,
local_files_only=local_files_only,
)
self.tokenizer_3 = T5Tokenizer.from_pretrained(
model, subfolder="tokenizer_3", local_files_only=local_files_only
@@ -31,6 +31,7 @@ from vllm_omni.diffusion.distributed.cfg_parallel import CFGParallelMixin
from vllm_omni.diffusion.distributed.parallel_state import get_classifier_free_guidance_world_size
from vllm_omni.diffusion.distributed.utils import get_local_device
from vllm_omni.diffusion.model_loader.diffusers_loader import DiffusersPipelineLoader
from vllm_omni.diffusion.model_loader.hub_prefetch import from_pretrained_with_prefetch, prefetch_subfolders
from vllm_omni.diffusion.models.hidream_image import HiDreamImageTransformer2DModel
from vllm_omni.diffusion.models.progress_bar import ProgressBarMixin
from vllm_omni.diffusion.profiler.diffusion_pipeline_profiler import DiffusionPipelineProfilerMixin
@@ -177,24 +178,55 @@ class HiDreamImagePipeline(nn.Module, CFGParallelMixin, DiffusionPipelineProfile
# Check if model is a local path
local_files_only = os.path.exists(model)
# See ``hub_prefetch.py`` for the transformers v5 multi-worker subfolder
# race; prefetch the in-repo component set before any from_pretrained
# (``text_encoder_4`` lives in a separate Llama repo and is unaffected).
hidream_subfolders = [
"scheduler",
"vae",
"text_encoder",
"tokenizer",
"text_encoder_2",
"tokenizer_2",
"text_encoder_3",
"tokenizer_3",
]
prefetch_subfolders(model, hidream_subfolders, local_files_only=local_files_only)
self.scheduler = FlowMatchEulerDiscreteScheduler.from_pretrained(
model, subfolder="scheduler", local_files_only=local_files_only
)
self.vae = AutoencoderKL.from_pretrained(model, subfolder="vae", local_files_only=local_files_only).to(
self.device
)
self.text_encoder = CLIPTextModelWithProjection.from_pretrained(
model, subfolder="text_encoder", local_files_only=local_files_only
self.vae = from_pretrained_with_prefetch(
AutoencoderKL.from_pretrained,
model,
subfolder="vae",
prefetch_list=hidream_subfolders,
local_files_only=local_files_only,
).to(self.device)
self.text_encoder = from_pretrained_with_prefetch(
CLIPTextModelWithProjection.from_pretrained,
model,
subfolder="text_encoder",
prefetch_list=hidream_subfolders,
local_files_only=local_files_only,
)
self.tokenizer = CLIPTokenizer.from_pretrained(model, subfolder="tokenizer", local_files_only=local_files_only)
self.text_encoder_2 = CLIPTextModelWithProjection.from_pretrained(
model, subfolder="text_encoder_2", local_files_only=local_files_only
self.text_encoder_2 = from_pretrained_with_prefetch(
CLIPTextModelWithProjection.from_pretrained,
model,
subfolder="text_encoder_2",
prefetch_list=hidream_subfolders,
local_files_only=local_files_only,
)
self.tokenizer_2 = CLIPTokenizer.from_pretrained(
model, subfolder="tokenizer_2", local_files_only=local_files_only
)
self.text_encoder_3 = T5EncoderModel.from_pretrained(
model, subfolder="text_encoder_3", local_files_only=local_files_only
self.text_encoder_3 = from_pretrained_with_prefetch(
T5EncoderModel.from_pretrained,
model,
subfolder="text_encoder_3",
prefetch_list=hidream_subfolders,
local_files_only=local_files_only,
)
self.tokenizer_3 = T5Tokenizer.from_pretrained(
model, subfolder="tokenizer_3", local_files_only=local_files_only
@@ -25,6 +25,7 @@ from vllm_omni.diffusion.distributed.autoencoders.autoencoder_kl_hunyuan_video_1
from vllm_omni.diffusion.distributed.cfg_parallel import CFGParallelMixin
from vllm_omni.diffusion.distributed.utils import get_local_device
from vllm_omni.diffusion.model_loader.diffusers_loader import DiffusersPipelineLoader
from vllm_omni.diffusion.model_loader.hub_prefetch import from_pretrained_with_prefetch, prefetch_subfolders
from vllm_omni.diffusion.models.hunyuan_video.hunyuan_video_15_transformer import HunyuanVideo15Transformer3DModel
from vllm_omni.diffusion.models.progress_bar import ProgressBarMixin
from vllm_omni.diffusion.models.t5_encoder import T5EncoderModel
@@ -101,9 +102,20 @@ class HunyuanVideo15Pipeline(nn.Module, CFGParallelMixin, ProgressBarMixin, Diff
model = od_config.model
local_files_only = os.path.exists(model)
# See ``hub_prefetch.py`` for the transformers v5 multi-worker subfolder
# race; prefetch the whole component set before any from_pretrained so
# peer workers load from a warm, complete cache.
hv_subfolders = ["tokenizer", "text_encoder", "tokenizer_2", "text_encoder_2", "vae", "scheduler"]
prefetch_subfolders(model, hv_subfolders, local_files_only=local_files_only)
self.tokenizer = Qwen2Tokenizer.from_pretrained(model, subfolder="tokenizer", local_files_only=local_files_only)
self.text_encoder = Qwen2_5_VLTextModel.from_pretrained(
model, subfolder="text_encoder", torch_dtype=dtype, local_files_only=local_files_only
self.text_encoder = from_pretrained_with_prefetch(
Qwen2_5_VLTextModel.from_pretrained,
model,
subfolder="text_encoder",
prefetch_list=hv_subfolders,
local_files_only=local_files_only,
torch_dtype=dtype,
).to(self.device)
self.tokenizer_2 = ByT5Tokenizer.from_pretrained(
@@ -112,8 +124,13 @@ class HunyuanVideo15Pipeline(nn.Module, CFGParallelMixin, ProgressBarMixin, Diff
t5_config = AutoConfig.from_pretrained(model, subfolder="text_encoder_2", local_files_only=local_files_only)
self.text_encoder_2 = T5EncoderModel(t5_config, prefix="text_encoder_2").to(dtype=dtype, device=self.device)
self.vae = DistributedAutoencoderKLHunyuanVideo15.from_pretrained(
model, subfolder="vae", torch_dtype=torch.float32, local_files_only=local_files_only
self.vae = from_pretrained_with_prefetch(
DistributedAutoencoderKLHunyuanVideo15.from_pretrained,
model,
subfolder="vae",
prefetch_list=hv_subfolders,
local_files_only=local_files_only,
torch_dtype=torch.float32,
).to(self.device)
self.scheduler = FlowMatchEulerDiscreteScheduler.from_pretrained(
@@ -32,6 +32,7 @@ from vllm_omni.diffusion.distributed.autoencoders.autoencoder_kl_hunyuan_video_1
from vllm_omni.diffusion.distributed.cfg_parallel import CFGParallelMixin
from vllm_omni.diffusion.distributed.utils import get_local_device
from vllm_omni.diffusion.model_loader.diffusers_loader import DiffusersPipelineLoader
from vllm_omni.diffusion.model_loader.hub_prefetch import from_pretrained_with_prefetch, prefetch_subfolders
from vllm_omni.diffusion.models.hunyuan_video.hunyuan_video_15_transformer import HunyuanVideo15Transformer3DModel
from vllm_omni.diffusion.models.hunyuan_video.pipeline_hunyuan_video_1_5 import (
extract_glyph_texts,
@@ -123,9 +124,29 @@ class HunyuanVideo15I2VPipeline(
model = od_config.model
local_files_only = os.path.exists(model)
# See ``hub_prefetch.py`` for the transformers v5 multi-worker subfolder
# race; prefetch the whole component set before any from_pretrained so
# peer workers load from a warm, complete cache.
hv_subfolders = [
"tokenizer",
"text_encoder",
"tokenizer_2",
"text_encoder_2",
"image_encoder",
"feature_extractor",
"vae",
"scheduler",
]
prefetch_subfolders(model, hv_subfolders, local_files_only=local_files_only)
self.tokenizer = Qwen2Tokenizer.from_pretrained(model, subfolder="tokenizer", local_files_only=local_files_only)
self.text_encoder = Qwen2_5_VLTextModel.from_pretrained(
model, subfolder="text_encoder", torch_dtype=dtype, local_files_only=local_files_only
self.text_encoder = from_pretrained_with_prefetch(
Qwen2_5_VLTextModel.from_pretrained,
model,
subfolder="text_encoder",
prefetch_list=hv_subfolders,
local_files_only=local_files_only,
torch_dtype=dtype,
).to(self.device)
self.tokenizer_2 = ByT5Tokenizer.from_pretrained(
@@ -134,15 +155,25 @@ class HunyuanVideo15I2VPipeline(
t5_config = AutoConfig.from_pretrained(model, subfolder="text_encoder_2", local_files_only=local_files_only)
self.text_encoder_2 = T5EncoderModel(t5_config, prefix="text_encoder_2").to(dtype=dtype, device=self.device)
self.image_encoder = SiglipVisionModel.from_pretrained(
model, subfolder="image_encoder", torch_dtype=dtype, local_files_only=local_files_only
self.image_encoder = from_pretrained_with_prefetch(
SiglipVisionModel.from_pretrained,
model,
subfolder="image_encoder",
prefetch_list=hv_subfolders,
local_files_only=local_files_only,
torch_dtype=dtype,
).to(self.device)
self.feature_extractor = SiglipImageProcessor.from_pretrained(
model, subfolder="feature_extractor", local_files_only=local_files_only
)
self.vae = DistributedAutoencoderKLHunyuanVideo15.from_pretrained(
model, subfolder="vae", torch_dtype=torch.float32, local_files_only=local_files_only
self.vae = from_pretrained_with_prefetch(
DistributedAutoencoderKLHunyuanVideo15.from_pretrained,
model,
subfolder="vae",
prefetch_list=hv_subfolders,
local_files_only=local_files_only,
torch_dtype=torch.float32,
).to(self.device)
self.scheduler = FlowMatchEulerDiscreteScheduler.from_pretrained(
@@ -27,6 +27,7 @@ from vllm_omni.diffusion.data import DiffusionOutput, OmniDiffusionConfig
from vllm_omni.diffusion.distributed.cfg_parallel import CFGParallelMixin
from vllm_omni.diffusion.distributed.utils import get_local_device
from vllm_omni.diffusion.model_loader.diffusers_loader import DiffusersPipelineLoader
from vllm_omni.diffusion.model_loader.hub_prefetch import from_pretrained_with_prefetch, prefetch_subfolders
from vllm_omni.diffusion.models.longcat_image.longcat_image_transformer import LongCatImageTransformer2DModel
from vllm_omni.diffusion.profiler.diffusion_pipeline_profiler import DiffusionPipelineProfilerMixin
from vllm_omni.diffusion.request import OmniDiffusionRequest
@@ -223,19 +224,32 @@ class LongCatImagePipeline(nn.Module, CFGParallelMixin, DiffusionPipelineProfile
model = od_config.model
local_files_only = os.path.exists(model)
# See ``hub_prefetch.py`` for the transformers v5 multi-worker subfolder
# race; prefetch the whole component set before any from_pretrained.
longcat_subfolders = ["scheduler", "text_encoder", "tokenizer", "vae"]
prefetch_subfolders(model, longcat_subfolders, local_files_only=local_files_only)
self.scheduler = FlowMatchEulerDiscreteScheduler.from_pretrained(
model, subfolder="scheduler", local_files_only=local_files_only
)
self.text_encoder = Qwen2_5_VLForConditionalGeneration.from_pretrained(
model, subfolder="text_encoder", local_files_only=local_files_only
self.text_encoder = from_pretrained_with_prefetch(
Qwen2_5_VLForConditionalGeneration.from_pretrained,
model,
subfolder="text_encoder",
prefetch_list=longcat_subfolders,
local_files_only=local_files_only,
)
self.text_processor = Qwen2VLProcessor.from_pretrained(
model, subfolder="tokenizer", local_files_only=local_files_only
)
self.vae = AutoencoderKL.from_pretrained(model, subfolder="vae", local_files_only=local_files_only).to(
self.device
)
self.vae = from_pretrained_with_prefetch(
AutoencoderKL.from_pretrained,
model,
subfolder="vae",
prefetch_list=longcat_subfolders,
local_files_only=local_files_only,
).to(self.device)
self.transformer = LongCatImageTransformer2DModel(od_config=od_config)
self.tokenizer = AutoTokenizer.from_pretrained(model, subfolder="tokenizer", local_files_only=local_files_only)
@@ -29,6 +29,7 @@ from vllm_omni.diffusion.data import DiffusionOutput, OmniDiffusionConfig
from vllm_omni.diffusion.distributed.cfg_parallel import CFGParallelMixin
from vllm_omni.diffusion.distributed.utils import get_local_device
from vllm_omni.diffusion.model_loader.diffusers_loader import DiffusersPipelineLoader
from vllm_omni.diffusion.model_loader.hub_prefetch import from_pretrained_with_prefetch, prefetch_subfolders
from vllm_omni.diffusion.models.interface import SupportImageInput
from vllm_omni.diffusion.models.longcat_image.longcat_image_transformer import (
LongCatImageTransformer2DModel,
@@ -244,19 +245,32 @@ class LongCatImageEditPipeline(nn.Module, CFGParallelMixin, SupportImageInput, D
model = od_config.model
local_files_only = os.path.exists(model)
# See ``hub_prefetch.py`` for the transformers v5 multi-worker subfolder
# race; prefetch the whole component set before any from_pretrained.
longcat_subfolders = ["scheduler", "text_encoder", "text_processor", "tokenizer", "vae"]
prefetch_subfolders(model, longcat_subfolders, local_files_only=local_files_only)
self.scheduler = FlowMatchEulerDiscreteScheduler.from_pretrained(
model, subfolder="scheduler", local_files_only=local_files_only
)
self.text_encoder = Qwen2_5_VLForConditionalGeneration.from_pretrained(
model, subfolder="text_encoder", local_files_only=local_files_only
self.text_encoder = from_pretrained_with_prefetch(
Qwen2_5_VLForConditionalGeneration.from_pretrained,
model,
subfolder="text_encoder",
prefetch_list=longcat_subfolders,
local_files_only=local_files_only,
)
self.text_processor = Qwen2VLProcessor.from_pretrained(
model, subfolder="text_processor", local_files_only=local_files_only
)
self.vae = AutoencoderKL.from_pretrained(model, subfolder="vae", local_files_only=local_files_only).to(
self.device
)
self.vae = from_pretrained_with_prefetch(
AutoencoderKL.from_pretrained,
model,
subfolder="vae",
prefetch_list=longcat_subfolders,
local_files_only=local_files_only,
).to(self.device)
self.transformer = LongCatImageTransformer2DModel(od_config=od_config)
self.tokenizer = AutoTokenizer.from_pretrained(model, subfolder="tokenizer", local_files_only=local_files_only)
@@ -36,6 +36,7 @@ from vllm_omni.diffusion.distributed.parallel_state import (
from vllm_omni.diffusion.distributed.utils import get_local_device
from vllm_omni.diffusion.lora.manager import DiffusionLoRAManager
from vllm_omni.diffusion.model_loader.diffusers_loader import DiffusersPipelineLoader
from vllm_omni.diffusion.model_loader.hub_prefetch import from_pretrained_with_prefetch, prefetch_subfolders
from vllm_omni.diffusion.models.dmd2 import DMD2PipelineMixin
from vllm_omni.diffusion.models.interface import SupportsComponentDiscovery
from vllm_omni.diffusion.models.progress_bar import ProgressBarMixin
@@ -185,6 +186,19 @@ class LTX2Pipeline(nn.Module, CFGParallelMixin, ProgressBarMixin):
),
]
# See ``hub_prefetch.py`` for the transformers v5 multi-worker subfolder
# race; prefetch the whole component set before any from_pretrained.
ltx2_subfolders = [
"tokenizer",
"text_encoder",
"connectors",
"vae",
"audio_vae",
"vocoder",
"scheduler",
]
prefetch_subfolders(model, ltx2_subfolders, local_files_only=local_files_only)
self.tokenizer = AutoTokenizer.from_pretrained(
model,
subfolder="tokenizer",
@@ -193,36 +207,46 @@ class LTX2Pipeline(nn.Module, CFGParallelMixin, ProgressBarMixin):
# prefer mmap loading as default device is cuda, and the output of text encoder
# could be deterministic.
with torch.device("cpu"):
self.text_encoder = Gemma3ForConditionalGeneration.from_pretrained(
self.text_encoder = from_pretrained_with_prefetch(
Gemma3ForConditionalGeneration.from_pretrained,
model,
subfolder="text_encoder",
torch_dtype=dtype,
prefetch_list=ltx2_subfolders,
local_files_only=local_files_only,
torch_dtype=dtype,
).to(self.device)
self.connectors = LTX2TextConnectors.from_pretrained(
self.connectors = from_pretrained_with_prefetch(
LTX2TextConnectors.from_pretrained,
model,
subfolder="connectors",
torch_dtype=dtype,
prefetch_list=ltx2_subfolders,
local_files_only=local_files_only,
torch_dtype=dtype,
).to(self.device)
self.vae = AutoencoderKLLTX2Video.from_pretrained(
self.vae = from_pretrained_with_prefetch(
AutoencoderKLLTX2Video.from_pretrained,
model,
subfolder="vae",
torch_dtype=dtype,
prefetch_list=ltx2_subfolders,
local_files_only=local_files_only,
torch_dtype=dtype,
).to(self.device)
self.audio_vae = AutoencoderKLLTX2Audio.from_pretrained(
self.audio_vae = from_pretrained_with_prefetch(
AutoencoderKLLTX2Audio.from_pretrained,
model,
subfolder="audio_vae",
torch_dtype=dtype,
prefetch_list=ltx2_subfolders,
local_files_only=local_files_only,
torch_dtype=dtype,
).to(self.device)
self.vocoder = LTX2Vocoder.from_pretrained(
self.vocoder = from_pretrained_with_prefetch(
LTX2Vocoder.from_pretrained,
model,
subfolder="vocoder",
torch_dtype=dtype,
prefetch_list=ltx2_subfolders,
local_files_only=local_files_only,
torch_dtype=dtype,
).to(self.device)
transformer_config = load_transformer_config(model, "transformer", local_files_only)
@@ -45,6 +45,7 @@ from vllm_omni.diffusion.distributed.parallel_state import (
)
from vllm_omni.diffusion.distributed.utils import get_local_device
from vllm_omni.diffusion.model_loader.diffusers_loader import DiffusersPipelineLoader
from vllm_omni.diffusion.model_loader.hub_prefetch import from_pretrained_with_prefetch, prefetch_subfolders
from vllm_omni.diffusion.models.progress_bar import ProgressBarMixin
from vllm_omni.diffusion.request import OmniDiffusionRequest
@@ -149,26 +150,59 @@ class LTX23Pipeline(nn.Module, CFGParallelMixin, ProgressBarMixin):
),
]
# See ``hub_prefetch.py`` for the transformers v5 multi-worker subfolder
# race; prefetch the whole component set before any from_pretrained.
ltx2_subfolders = [
"tokenizer",
"text_encoder",
"connectors",
"vae",
"audio_vae",
"vocoder",
"scheduler",
]
prefetch_subfolders(model, ltx2_subfolders, local_files_only=local_files_only)
# --- Tokenizer (lightweight, stays wherever) ---
self.tokenizer = AutoTokenizer.from_pretrained(model, subfolder="tokenizer", local_files_only=local_files_only)
# --- Text encoder: load on CPU, move to GPU only during encoding ---
with torch.device("cpu"):
self.text_encoder = Gemma3ForConditionalGeneration.from_pretrained(
model, subfolder="text_encoder", torch_dtype=dtype, local_files_only=local_files_only
self.text_encoder = from_pretrained_with_prefetch(
Gemma3ForConditionalGeneration.from_pretrained,
model,
subfolder="text_encoder",
prefetch_list=ltx2_subfolders,
local_files_only=local_files_only,
torch_dtype=dtype,
)
# --- Connectors: CPU (LTX-2.3 connectors include caption projection) ---
self.connectors = LTX2TextConnectors.from_pretrained(
model, subfolder="connectors", torch_dtype=dtype, local_files_only=local_files_only
self.connectors = from_pretrained_with_prefetch(
LTX2TextConnectors.from_pretrained,
model,
subfolder="connectors",
prefetch_list=ltx2_subfolders,
local_files_only=local_files_only,
torch_dtype=dtype,
)
# --- VAE, Audio VAE: CPU ---
self.vae = AutoencoderKLLTX2Video.from_pretrained(
model, subfolder="vae", torch_dtype=dtype, local_files_only=local_files_only
self.vae = from_pretrained_with_prefetch(
AutoencoderKLLTX2Video.from_pretrained,
model,
subfolder="vae",
prefetch_list=ltx2_subfolders,
local_files_only=local_files_only,
torch_dtype=dtype,
)
self.audio_vae = AutoencoderKLLTX2Audio.from_pretrained(
model, subfolder="audio_vae", torch_dtype=dtype, local_files_only=local_files_only
self.audio_vae = from_pretrained_with_prefetch(
AutoencoderKLLTX2Audio.from_pretrained,
model,
subfolder="audio_vae",
prefetch_list=ltx2_subfolders,
local_files_only=local_files_only,
torch_dtype=dtype,
)
# --- Vocoder: prefer BWE vocoder (48kHz) for LTX-2.3 ---
@@ -32,6 +32,7 @@ from vllm_omni.diffusion.data import DiffusionOutput, OmniDiffusionConfig
from vllm_omni.diffusion.distributed.cfg_parallel import CFGParallelMixin
from vllm_omni.diffusion.distributed.utils import get_local_device
from vllm_omni.diffusion.model_loader.diffusers_loader import DiffusersPipelineLoader
from vllm_omni.diffusion.model_loader.hub_prefetch import from_pretrained_with_prefetch, prefetch_subfolders
from vllm_omni.diffusion.models.interface import SupportsComponentDiscovery
from vllm_omni.diffusion.models.omnigen2.omnigen2_transformer import (
OmniGen2RotaryPosEmbed,
@@ -673,23 +674,40 @@ class OmniGen2Pipeline(CFGParallelMixin, nn.Module, SupportsComponentDiscovery):
)
]
# See ``hub_prefetch.py`` for the transformers v5 multi-worker subfolder
# race; prefetch the whole component set before any from_pretrained.
omnigen2_subfolders = ["scheduler", "vae", "mllm", "processor"]
prefetch_subfolders(model, omnigen2_subfolders, local_files_only=local_files_only)
self.scheduler = FlowMatchEulerDiscreteScheduler.from_pretrained(
model, subfolder="scheduler", local_files_only=local_files_only
)
self.vae = AutoencoderKL.from_pretrained(model, subfolder="vae", local_files_only=local_files_only).to(
self.device
)
self.vae = from_pretrained_with_prefetch(
AutoencoderKL.from_pretrained,
model,
subfolder="vae",
prefetch_list=omnigen2_subfolders,
local_files_only=local_files_only,
).to(self.device)
transformer_kwargs = get_transformer_config_kwargs(od_config.tf_model_config, OmniGen2Transformer2DModel)
self.transformer = OmniGen2Transformer2DModel(
**transformer_kwargs,
quant_config=od_config.quantization_config,
)
self.mllm = Qwen2_5_VLForConditionalGeneration.from_pretrained(
model, subfolder="mllm", local_files_only=local_files_only
self.mllm = from_pretrained_with_prefetch(
Qwen2_5_VLForConditionalGeneration.from_pretrained,
model,
subfolder="mllm",
prefetch_list=omnigen2_subfolders,
local_files_only=local_files_only,
).to(self.device)
self.processor = Qwen2_5_VLProcessor.from_pretrained(
model, subfolder="processor", local_files_only=local_files_only
self.processor = from_pretrained_with_prefetch(
Qwen2_5_VLProcessor.from_pretrained,
model,
subfolder="processor",
prefetch_list=omnigen2_subfolders,
local_files_only=local_files_only,
)
self.vae_scale_factor = (
2 ** (len(self.vae.config.block_out_channels) - 1) if hasattr(self, "vae") and self.vae is not None else 8
@@ -38,6 +38,7 @@ from vllm_omni.diffusion.data import DiffusionOutput, OmniDiffusionConfig
from vllm_omni.diffusion.distributed.cfg_parallel import CFGParallelMixin
from vllm_omni.diffusion.distributed.utils import get_local_device
from vllm_omni.diffusion.model_loader.diffusers_loader import DiffusersPipelineLoader
from vllm_omni.diffusion.model_loader.hub_prefetch import from_pretrained_with_prefetch, prefetch_subfolders
from vllm_omni.diffusion.models.ovis_image.ovis_image_transformer import OvisImageTransformer2DModel
from vllm_omni.diffusion.profiler.diffusion_pipeline_profiler import DiffusionPipelineProfilerMixin
from vllm_omni.diffusion.request import OmniDiffusionRequest
@@ -163,20 +164,32 @@ class OvisImagePipeline(nn.Module, CFGParallelMixin, DiffusionPipelineProfilerMi
self._execution_device = get_local_device()
model = od_config.model
local_files_only = os.path.exists(model)
# See ``hub_prefetch.py`` for the transformers v5 multi-worker subfolder
# race; prefetch the whole component set before any from_pretrained.
ovis_subfolders = ["scheduler", "text_encoder", "vae", "tokenizer"]
prefetch_subfolders(model, ovis_subfolders, local_files_only=local_files_only)
self.scheduler = FlowMatchEulerDiscreteScheduler.from_pretrained(
model, subfolder="scheduler", local_files_only=local_files_only
)
self.text_encoder = Qwen3Model.from_pretrained(
self.text_encoder = from_pretrained_with_prefetch(
Qwen3Model.from_pretrained,
model,
subfolder="text_encoder",
prefetch_list=ovis_subfolders,
local_files_only=local_files_only,
torch_dtype=od_config.dtype,
)
self.vae = AutoencoderKL.from_pretrained(model, subfolder="vae", local_files_only=local_files_only).to(
self._execution_device
)
self.vae = from_pretrained_with_prefetch(
AutoencoderKL.from_pretrained,
model,
subfolder="vae",
prefetch_list=ovis_subfolders,
local_files_only=local_files_only,
).to(self._execution_device)
self.tokenizer = Qwen2TokenizerFast.from_pretrained(
model, subfolder="tokenizer", local_files_only=local_files_only
@@ -26,7 +26,7 @@ from vllm_omni.diffusion.data import DiffusionOutput, OmniDiffusionConfig
from vllm_omni.diffusion.distributed.autoencoders.autoencoder_kl_qwenimage import DistributedAutoencoderKLQwenImage
from vllm_omni.diffusion.distributed.utils import get_local_device
from vllm_omni.diffusion.model_loader.diffusers_loader import DiffusersPipelineLoader
from vllm_omni.diffusion.model_loader.hub_prefetch import prefetch_subfolders, retry_on_missing_shard
from vllm_omni.diffusion.model_loader.hub_prefetch import from_pretrained_with_prefetch, prefetch_subfolders
from vllm_omni.diffusion.models.dmd2 import DMD2PipelineMixin
from vllm_omni.diffusion.models.qwen_image.cfg_parallel import (
QwenImageCFGParallelMixin,
@@ -279,18 +279,25 @@ class QwenImagePipeline(nn.Module, QwenImageCFGParallelMixin, DiffusionPipelineP
# See pipeline_qwen_image_edit_plus: guard against transformers v5
# multi-worker race on partial subfolder shard sets (Buildkite #1043).
qwen_subfolders = ["scheduler", "text_encoder", "vae", "tokenizer"]
prefetch_subfolders(
model,
["scheduler", "text_encoder", "vae", "tokenizer"],
qwen_subfolders,
)
self.scheduler = FlowMatchEulerDiscreteScheduler.from_pretrained(
model, subfolder="scheduler", local_files_only=local_files_only
)
self.text_encoder = retry_on_missing_shard(
lambda: Qwen2_5_VLForConditionalGeneration.from_pretrained(
model, subfolder="text_encoder", local_files_only=local_files_only
)
# ``from_pretrained_with_prefetch`` re-prefetches and retries on a
# half-written cache (missing-shard ``OSError`` *and* the default
# -config size-mismatch ``RuntimeError`` that ``retry_on_missing_shard``
# could not recover) instead of crashing the worker.
self.text_encoder = from_pretrained_with_prefetch(
Qwen2_5_VLForConditionalGeneration.from_pretrained,
model,
subfolder="text_encoder",
prefetch_list=qwen_subfolders,
local_files_only=local_files_only,
)
# Qwen2.5-VL ships a vision tower that text-to-image does not use.
# Drop it while the model is still on CPU, before moving to GPU, so
@@ -307,8 +314,12 @@ class QwenImagePipeline(nn.Module, QwenImageCFGParallelMixin, DiffusionPipelineP
else:
logger.warning("Qwen-Image: vision tower not found on text encoder; skipping drop")
self.text_encoder = self.text_encoder.to(self.device)
self.vae = DistributedAutoencoderKLQwenImage.from_pretrained(
model, subfolder="vae", local_files_only=local_files_only
self.vae = from_pretrained_with_prefetch(
DistributedAutoencoderKLQwenImage.from_pretrained,
model,
subfolder="vae",
prefetch_list=qwen_subfolders,
local_files_only=local_files_only,
).to(self.device)
transformer_kwargs = get_transformer_config_kwargs(od_config.tf_model_config, QwenImageTransformer2DModel)
self.transformer = QwenImageTransformer2DModel(
@@ -27,7 +27,7 @@ from vllm.model_executor.models.utils import AutoWeightsLoader
from vllm_omni.diffusion.data import DiffusionOutput, OmniDiffusionConfig
from vllm_omni.diffusion.distributed.utils import get_local_device
from vllm_omni.diffusion.model_loader.diffusers_loader import DiffusersPipelineLoader
from vllm_omni.diffusion.model_loader.hub_prefetch import prefetch_subfolders, retry_on_missing_shard
from vllm_omni.diffusion.model_loader.hub_prefetch import from_pretrained_with_prefetch, prefetch_subfolders
from vllm_omni.diffusion.models.interface import SupportImageInput
from vllm_omni.diffusion.models.qwen_image.cfg_parallel import (
QwenImageCFGParallelMixin,
@@ -247,28 +247,43 @@ class QwenImageEditPipeline(nn.Module, SupportImageInput, QwenImageCFGParallelMi
# See pipeline_qwen_image_edit_plus: guard against transformers v5
# multi-worker race on partial subfolder shard sets (Buildkite #1043).
qwen_subfolders = ["scheduler", "text_encoder", "vae", "tokenizer", "processor"]
prefetch_subfolders(
model,
["scheduler", "text_encoder", "vae", "tokenizer", "processor"],
qwen_subfolders,
)
self.scheduler = FlowMatchEulerDiscreteScheduler.from_pretrained(
model, subfolder="scheduler", local_files_only=local_files_only
)
self.text_encoder = retry_on_missing_shard(
lambda: Qwen2_5_VLForConditionalGeneration.from_pretrained(
model, subfolder="text_encoder", local_files_only=local_files_only
).to(self.device)
)
# ``from_pretrained_with_prefetch`` re-prefetches and retries on a
# half-written cache (missing-shard ``OSError`` *and* the default
# -config size-mismatch ``RuntimeError`` that ``retry_on_missing_shard``
# could not recover) instead of crashing the worker.
self.text_encoder = from_pretrained_with_prefetch(
Qwen2_5_VLForConditionalGeneration.from_pretrained,
model,
subfolder="text_encoder",
prefetch_list=qwen_subfolders,
local_files_only=local_files_only,
).to(self.device)
self.vae = AutoencoderKLQwenImage.from_pretrained(model, subfolder="vae", local_files_only=local_files_only).to(
self.device
)
self.vae = from_pretrained_with_prefetch(
AutoencoderKLQwenImage.from_pretrained,
model,
subfolder="vae",
prefetch_list=qwen_subfolders,
local_files_only=local_files_only,
).to(self.device)
transformer_kwargs = get_transformer_config_kwargs(od_config.tf_model_config, QwenImageTransformer2DModel)
self.transformer = QwenImageTransformer2DModel(od_config=od_config, **transformer_kwargs)
self.tokenizer = Qwen2Tokenizer.from_pretrained(model, subfolder="tokenizer", local_files_only=local_files_only)
self.processor = retry_on_missing_shard(
lambda: Qwen2VLProcessor.from_pretrained(model, subfolder="processor", local_files_only=local_files_only)
self.processor = from_pretrained_with_prefetch(
Qwen2VLProcessor.from_pretrained,
model,
subfolder="processor",
prefetch_list=qwen_subfolders,
local_files_only=local_files_only,
)
self.stage = None
@@ -25,7 +25,7 @@ from vllm.model_executor.models.utils import AutoWeightsLoader
from vllm_omni.diffusion.data import DiffusionOutput, OmniDiffusionConfig
from vllm_omni.diffusion.distributed.utils import get_local_device
from vllm_omni.diffusion.model_loader.diffusers_loader import DiffusersPipelineLoader
from vllm_omni.diffusion.model_loader.hub_prefetch import prefetch_subfolders, retry_on_missing_shard
from vllm_omni.diffusion.model_loader.hub_prefetch import from_pretrained_with_prefetch, prefetch_subfolders
from vllm_omni.diffusion.model_metadata import QWEN_IMAGE_EDIT_PLUS_MAX_INPUT_IMAGES
from vllm_omni.diffusion.models.interface import SupportImageInput
from vllm_omni.diffusion.models.qwen_image.cfg_parallel import (
@@ -216,29 +216,44 @@ class QwenImageEditPlusPipeline(
# #1043 for Qwen/Qwen-Image-Edit-2509). snapshot_download takes a
# per-repo file lock so the first worker downloads and the rest
# wait on a warm cache before loading.
qwen_subfolders = ["scheduler", "text_encoder", "vae", "tokenizer", "processor"]
prefetch_subfolders(
model,
["scheduler", "text_encoder", "vae", "tokenizer", "processor"],
qwen_subfolders,
)
self.scheduler = FlowMatchEulerDiscreteScheduler.from_pretrained(
model, subfolder="scheduler", local_files_only=local_files_only
)
self.text_encoder = retry_on_missing_shard(
lambda: Qwen2_5_VLForConditionalGeneration.from_pretrained(
model, subfolder="text_encoder", local_files_only=local_files_only
).to(self.device)
)
# ``from_pretrained_with_prefetch`` re-prefetches and retries on a
# half-written cache (missing-shard ``OSError`` *and* the default
# -config size-mismatch ``RuntimeError`` that ``retry_on_missing_shard``
# could not recover) instead of crashing the worker.
self.text_encoder = from_pretrained_with_prefetch(
Qwen2_5_VLForConditionalGeneration.from_pretrained,
model,
subfolder="text_encoder",
prefetch_list=qwen_subfolders,
local_files_only=local_files_only,
).to(self.device)
self.vae = AutoencoderKLQwenImage.from_pretrained(model, subfolder="vae", local_files_only=local_files_only).to(
self.device
)
self.vae = from_pretrained_with_prefetch(
AutoencoderKLQwenImage.from_pretrained,
model,
subfolder="vae",
prefetch_list=qwen_subfolders,
local_files_only=local_files_only,
).to(self.device)
transformer_kwargs = get_transformer_config_kwargs(od_config.tf_model_config, QwenImageTransformer2DModel)
self.transformer = QwenImageTransformer2DModel(od_config=od_config, **transformer_kwargs)
self.tokenizer = Qwen2Tokenizer.from_pretrained(model, subfolder="tokenizer", local_files_only=local_files_only)
self.processor = retry_on_missing_shard(
lambda: Qwen2VLProcessor.from_pretrained(model, subfolder="processor", local_files_only=local_files_only)
self.processor = from_pretrained_with_prefetch(
Qwen2VLProcessor.from_pretrained,
model,
subfolder="processor",
prefetch_list=qwen_subfolders,
local_files_only=local_files_only,
)
self.stage = None
@@ -24,7 +24,7 @@ from vllm.model_executor.models.utils import AutoWeightsLoader
from vllm_omni.diffusion.data import DiffusionOutput, OmniDiffusionConfig
from vllm_omni.diffusion.distributed.utils import get_local_device
from vllm_omni.diffusion.model_loader.diffusers_loader import DiffusersPipelineLoader
from vllm_omni.diffusion.model_loader.hub_prefetch import prefetch_subfolders, retry_on_missing_shard
from vllm_omni.diffusion.model_loader.hub_prefetch import from_pretrained_with_prefetch, prefetch_subfolders
from vllm_omni.diffusion.models.interface import SupportImageInput
from vllm_omni.diffusion.models.qwen_image.autoencoder_kl_qwenimage import (
AutoencoderKLQwenImage,
@@ -220,26 +220,41 @@ class QwenImageLayeredPipeline(nn.Module, SupportImageInput, QwenImageCFGParalle
# See pipeline_qwen_image_edit_plus: guard against transformers v5
# multi-worker race on partial subfolder shard sets (Buildkite #1043).
qwen_subfolders = ["scheduler", "text_encoder", "vae", "tokenizer", "processor"]
prefetch_subfolders(
model,
["scheduler", "text_encoder", "vae", "tokenizer", "processor"],
qwen_subfolders,
)
# modules keep same as transformers & diffusers
self.scheduler = FlowMatchEulerDiscreteScheduler.from_pretrained(
model, subfolder="scheduler", local_files_only=local_files_only
)
self.text_encoder = retry_on_missing_shard(
lambda: Qwen2_5_VLForConditionalGeneration.from_pretrained(
model, subfolder="text_encoder", local_files_only=local_files_only
).to(self.device)
)
self.vae = AutoencoderKLQwenImage.from_pretrained(model, subfolder="vae", local_files_only=local_files_only).to(
self.device
)
# ``from_pretrained_with_prefetch`` re-prefetches and retries on a
# half-written cache (missing-shard ``OSError`` *and* the default
# -config size-mismatch ``RuntimeError`` that ``retry_on_missing_shard``
# could not recover) instead of crashing the worker.
self.text_encoder = from_pretrained_with_prefetch(
Qwen2_5_VLForConditionalGeneration.from_pretrained,
model,
subfolder="text_encoder",
prefetch_list=qwen_subfolders,
local_files_only=local_files_only,
).to(self.device)
self.vae = from_pretrained_with_prefetch(
AutoencoderKLQwenImage.from_pretrained,
model,
subfolder="vae",
prefetch_list=qwen_subfolders,
local_files_only=local_files_only,
).to(self.device)
self.tokenizer = Qwen2Tokenizer.from_pretrained(model, subfolder="tokenizer", local_files_only=local_files_only)
self.processor = retry_on_missing_shard(
lambda: Qwen2VLProcessor.from_pretrained(model, subfolder="processor", local_files_only=local_files_only)
self.processor = from_pretrained_with_prefetch(
Qwen2VLProcessor.from_pretrained,
model,
subfolder="processor",
prefetch_list=qwen_subfolders,
local_files_only=local_files_only,
)
# modules re-implemented for vLLM-Omni
+32 -19
View File
@@ -19,7 +19,7 @@ from vllm_omni.diffusion.distributed.autoencoders.autoencoder_kl import Distribu
from vllm_omni.diffusion.distributed.cfg_parallel import CFGParallelMixin
from vllm_omni.diffusion.distributed.utils import get_local_device
from vllm_omni.diffusion.model_loader.diffusers_loader import DiffusersPipelineLoader
from vllm_omni.diffusion.model_loader.hub_prefetch import prefetch_subfolders
from vllm_omni.diffusion.model_loader.hub_prefetch import from_pretrained_with_prefetch, prefetch_subfolders
from vllm_omni.diffusion.models.sd3.sd3_transformer import (
SD3Transformer2DModel,
)
@@ -156,18 +156,19 @@ class StableDiffusion3Pipeline(nn.Module, CFGParallelMixin, DiffusionPipelinePro
# See ``hub_prefetch.py`` for the transformers v5 subfolder race.
# SD3.5 loads six subfolders in a row, each with multi-shard
# safetensors - it is the worst-case fan-out for the race window.
sd3_subfolders = [
"scheduler",
"tokenizer",
"tokenizer_2",
"tokenizer_3",
"text_encoder",
"text_encoder_2",
"text_encoder_3",
"vae",
]
prefetch_subfolders(
model,
[
"scheduler",
"tokenizer",
"tokenizer_2",
"tokenizer_3",
"text_encoder",
"text_encoder_2",
"text_encoder_3",
"vae",
],
sd3_subfolders,
local_files_only=local_files_only,
)
@@ -198,31 +199,43 @@ class StableDiffusion3Pipeline(nn.Module, CFGParallelMixin, DiffusionPipelinePro
self.tokenizer_3 = T5Tokenizer.from_pretrained(
model, subfolder="tokenizer_3", local_files_only=local_files_only
)
self.text_encoder = CLIPTextModelWithProjection.from_pretrained(
# ``from_pretrained_with_prefetch`` re-prefetches and retries if a
# peer worker left the cache half-written (missing-shard ``OSError`` or
# the default-config size-mismatch ``RuntimeError``) instead of
# crashing the worker - critical here given the six-subfolder fan-out.
self.text_encoder = from_pretrained_with_prefetch(
CLIPTextModelWithProjection.from_pretrained,
model,
subfolder="text_encoder",
torch_dtype=dtype,
prefetch_list=sd3_subfolders,
local_files_only=local_files_only,
torch_dtype=dtype,
)
self.text_encoder_2 = CLIPTextModelWithProjection.from_pretrained(
self.text_encoder_2 = from_pretrained_with_prefetch(
CLIPTextModelWithProjection.from_pretrained,
model,
subfolder="text_encoder_2",
torch_dtype=dtype,
prefetch_list=sd3_subfolders,
local_files_only=local_files_only,
torch_dtype=dtype,
)
self.text_encoder_3 = T5EncoderModel.from_pretrained(
self.text_encoder_3 = from_pretrained_with_prefetch(
T5EncoderModel.from_pretrained,
model,
subfolder="text_encoder_3",
torch_dtype=dtype,
prefetch_list=sd3_subfolders,
local_files_only=local_files_only,
torch_dtype=dtype,
)
self.transformer = SD3Transformer2DModel(od_config=od_config)
self.vae = DistributedAutoencoderKL.from_pretrained(
self.vae = from_pretrained_with_prefetch(
DistributedAutoencoderKL.from_pretrained,
model,
subfolder="vae",
torch_dtype=dtype,
prefetch_list=sd3_subfolders,
local_files_only=local_files_only,
torch_dtype=dtype,
).to(self.device)
self.vae_scale_factor = 2 ** (len(self.vae.config.block_out_channels) - 1) if getattr(self, "vae", None) else 8
@@ -28,6 +28,7 @@ from vllm.model_executor.models.utils import AutoWeightsLoader
from vllm_omni.diffusion.data import DiffusionOutput, OmniDiffusionConfig
from vllm_omni.diffusion.distributed.utils import get_local_device
from vllm_omni.diffusion.model_loader.diffusers_loader import DiffusersPipelineLoader
from vllm_omni.diffusion.model_loader.hub_prefetch import from_pretrained_with_prefetch, prefetch_subfolders
from vllm_omni.diffusion.models.interface import SupportAudioOutput
from vllm_omni.diffusion.models.stable_audio.stable_audio_transformer import (
StableAudioDiTModel,
@@ -109,6 +110,11 @@ class StableAudioPipeline(nn.Module, SupportAudioOutput, DiffusionPipelineProfil
),
]
# See ``hub_prefetch.py`` for the transformers v5 multi-worker subfolder
# race; prefetch the whole component set before any from_pretrained.
sa_subfolders = ["tokenizer", "text_encoder", "vae", "projection_model", "scheduler"]
prefetch_subfolders(model, sa_subfolders, local_files_only=local_files_only)
# Load tokenizer
self.tokenizer = T5TokenizerFast.from_pretrained(
model,
@@ -117,27 +123,33 @@ class StableAudioPipeline(nn.Module, SupportAudioOutput, DiffusionPipelineProfil
)
# Load text encoder
self.text_encoder = T5EncoderModel.from_pretrained(
self.text_encoder = from_pretrained_with_prefetch(
T5EncoderModel.from_pretrained,
model,
subfolder="text_encoder",
torch_dtype=dtype,
prefetch_list=sa_subfolders,
local_files_only=local_files_only,
torch_dtype=dtype,
).to(self.device)
# Load VAE (AutoencoderOobleck for audio)
self.vae = AutoencoderOobleck.from_pretrained(
self.vae = from_pretrained_with_prefetch(
AutoencoderOobleck.from_pretrained,
model,
subfolder="vae",
torch_dtype=torch.float32,
prefetch_list=sa_subfolders,
local_files_only=local_files_only,
torch_dtype=torch.float32,
).to(self.device)
# Load projection model (using diffusers implementation)
self.projection_model = StableAudioProjectionModel.from_pretrained(
self.projection_model = from_pretrained_with_prefetch(
StableAudioProjectionModel.from_pretrained,
model,
subfolder="projection_model",
torch_dtype=dtype,
prefetch_list=sa_subfolders,
local_files_only=local_files_only,
torch_dtype=dtype,
).to(self.device)
# Initialize transformer from HF config to keep architecture aligned with checkpoint.
@@ -26,7 +26,7 @@ from vllm_omni.diffusion.distributed.pipeline_parallel import AsyncLatents, Pipe
from vllm_omni.diffusion.distributed.utils import get_local_device
from vllm_omni.diffusion.forward_context import set_forward_context_denoise_step_idx
from vllm_omni.diffusion.model_loader.diffusers_loader import DiffusersPipelineLoader
from vllm_omni.diffusion.model_loader.hub_prefetch import prefetch_subfolders
from vllm_omni.diffusion.model_loader.hub_prefetch import from_pretrained_with_prefetch, prefetch_subfolders
from vllm_omni.diffusion.models.dmd2 import DMD2PipelineMixin
from vllm_omni.diffusion.models.progress_bar import ProgressBarMixin, _is_rank_zero
from vllm_omni.diffusion.models.schedulers import FlowUniPCMultistepScheduler
@@ -336,18 +336,39 @@ class Wan22Pipeline(
)
# See ``hub_prefetch.py`` for the transformers v5 subfolder race.
component_subfolders = ["tokenizer", "text_encoder", "vae"]
prefetch_subfolders(
model,
["tokenizer", "text_encoder", "vae"],
component_subfolders,
local_files_only=local_files_only,
)
self.tokenizer = AutoTokenizer.from_pretrained(model, subfolder="tokenizer", local_files_only=local_files_only)
self.text_encoder = UMT5EncoderModel.from_pretrained(
model, subfolder="text_encoder", torch_dtype=dtype, local_files_only=local_files_only
# ``from_pretrained_with_prefetch`` re-prefetches and retries if the
# cache is still half-written (the missing-shard ``OSError`` and the
# default-``UMT5Config`` size-mismatch ``RuntimeError`` seen on multi
# -worker HSDP / ring launches), instead of crashing the worker.
self.tokenizer = from_pretrained_with_prefetch(
AutoTokenizer.from_pretrained,
model,
subfolder="tokenizer",
prefetch_list=component_subfolders,
local_files_only=local_files_only,
)
self.text_encoder = from_pretrained_with_prefetch(
UMT5EncoderModel.from_pretrained,
model,
subfolder="text_encoder",
prefetch_list=component_subfolders,
local_files_only=local_files_only,
torch_dtype=dtype,
).to(self.device)
self.vae = DistributedAutoencoderKLWan.from_pretrained(
model, subfolder="vae", torch_dtype=dtype, local_files_only=local_files_only
self.vae = from_pretrained_with_prefetch(
DistributedAutoencoderKLWan.from_pretrained,
model,
subfolder="vae",
prefetch_list=component_subfolders,
local_files_only=local_files_only,
torch_dtype=dtype,
).to(self.device)
# Initialize transformers with correct config (weights loaded via load_weights)
@@ -26,7 +26,7 @@ from vllm_omni.diffusion.distributed.pipeline_parallel import AsyncLatents, Pipe
from vllm_omni.diffusion.distributed.utils import get_local_device
from vllm_omni.diffusion.forward_context import set_forward_context_denoise_step_idx
from vllm_omni.diffusion.model_loader.diffusers_loader import DiffusersPipelineLoader
from vllm_omni.diffusion.model_loader.hub_prefetch import prefetch_subfolders
from vllm_omni.diffusion.model_loader.hub_prefetch import from_pretrained_with_prefetch, prefetch_subfolders
from vllm_omni.diffusion.models.dmd2 import DMD2PipelineMixin
from vllm_omni.diffusion.models.interface import SupportImageInput
from vllm_omni.diffusion.models.progress_bar import ProgressBarMixin, _is_rank_zero
@@ -197,35 +197,64 @@ class Wan22I2VPipeline(
)
)
# Text encoder
self.tokenizer = AutoTokenizer.from_pretrained(model, subfolder="tokenizer", local_files_only=local_files_only)
self.text_encoder = UMT5EncoderModel.from_pretrained(
model, subfolder="text_encoder", torch_dtype=dtype, local_files_only=local_files_only
).to(self.device)
# Image encoder (CLIP) - optional, for Wan2.1-style I2V
self.has_image_encoder = "image_encoder" in model_index and model_index["image_encoder"][0] is not None
# See ``hub_prefetch.py`` for the transformers v5 subfolder race.
# See ``hub_prefetch.py`` for the transformers v5 subfolder race. The
# prefetch MUST run before any ``from_pretrained`` below - previously
# the tokenizer / text_encoder were loaded ahead of this call, so they
# never benefited from the prefetch and could hit the half-written
# cache directly.
subfolders = ["tokenizer", "text_encoder", "vae"]
if self.has_image_encoder:
subfolders.extend(["image_processor", "image_encoder"])
prefetch_subfolders(model, subfolders, local_files_only=local_files_only)
# Text encoder
self.tokenizer = from_pretrained_with_prefetch(
AutoTokenizer.from_pretrained,
model,
subfolder="tokenizer",
prefetch_list=subfolders,
local_files_only=local_files_only,
)
self.text_encoder = from_pretrained_with_prefetch(
UMT5EncoderModel.from_pretrained,
model,
subfolder="text_encoder",
prefetch_list=subfolders,
local_files_only=local_files_only,
torch_dtype=dtype,
).to(self.device)
if self.has_image_encoder:
self.image_processor = CLIPImageProcessor.from_pretrained(
model, subfolder="image_processor", local_files_only=local_files_only
self.image_processor = from_pretrained_with_prefetch(
CLIPImageProcessor.from_pretrained,
model,
subfolder="image_processor",
prefetch_list=subfolders,
local_files_only=local_files_only,
)
self.image_encoder = CLIPVisionModel.from_pretrained(
model, subfolder="image_encoder", torch_dtype=dtype, local_files_only=local_files_only
self.image_encoder = from_pretrained_with_prefetch(
CLIPVisionModel.from_pretrained,
model,
subfolder="image_encoder",
prefetch_list=subfolders,
local_files_only=local_files_only,
torch_dtype=dtype,
).to(self.device)
else:
self.image_processor = None
self.image_encoder = None
# VAE
self.vae = DistributedAutoencoderKLWan.from_pretrained(
model, subfolder="vae", torch_dtype=dtype, local_files_only=local_files_only
self.vae = from_pretrained_with_prefetch(
DistributedAutoencoderKLWan.from_pretrained,
model,
subfolder="vae",
prefetch_list=subfolders,
local_files_only=local_files_only,
torch_dtype=dtype,
).to(self.device)
# Transformers (weights loaded via load_weights)