[Diffusion][Quantization] Enable MiniMax-H3 global FP8 with DLO (#5910)

Signed-off-by: lishunyang12 <lishunyang12@163.com>
Co-authored-by: Hongsheng Liu <liuhongsheng4@huawei.com>
This commit is contained in:
SYLARandHongsheng Liu authored and GitHub committed 2026-08-15 23:01:26 +08:00
1 parent 09b6a1604a
commit d1e230c95b
18 files changed
+833 -165

No files matched your search

@@ -298,6 +298,60 @@ class DiffusersPipelineLoader:
for source in sources:
yield from self._get_weights_iterator(source, model=model)
@staticmethod
def _stream_online_quant_weights_to_cpu(
model: nn.Module,
weights: Iterable[tuple[str, torch.Tensor]],
) -> Generator[tuple[str, torch.Tensor], None, None]:
"""Offload each online-quantized layer as soon as it is complete.
Upstream vLLM's online layerwise loader materializes and quantizes a
layer synchronously while consuming ``weights``. Generator execution
resumes after that weight has been consumed, which gives us a safe
point to move completed layers to CPU before the next layer is loaded.
This bounds accelerator residency during CPU-offloaded model startup
instead of retaining the entire quantized model until loading ends.
"""
from vllm.model_executor.model_loader.reload.layerwise import (
get_layerwise_info,
)
pending = {
module
for module in model.modules()
if getattr(getattr(module, "quant_method", None), "uses_meta_device", False)
and get_layerwise_info(module).can_load()
}
offloaded = 0
def offload_completed() -> None:
nonlocal offloaded
for module in tuple(pending):
if get_layerwise_info(module).can_load():
continue
module.to("cpu")
pending.remove(module)
offloaded += 1
for weight in weights:
# This runs after the consumer has handled the previous yield.
offload_completed()
yield weight
offload_completed()
# Quantization workspaces and the old accelerator-side parameter
# storages are now reusable cache blocks. Release them before the
# remaining (unquantized) model tensors are copied to CPU; otherwise
# the cached quantization footprint and final offload overlap in the
# process-level startup peak.
if offloaded:
torch.accelerator.empty_cache()
logger.info(
"Stream-offloaded %d online-quantized layers to CPU during weight loading",
offloaded,
)
def _get_weight_sources(self, model: nn.Module) -> tuple["ComponentSource", ...]:
return tuple(
cast(
@@ -403,7 +457,10 @@ class DiffusersPipelineLoader:
if load_format == "diffusers":
cast(DiffusersAdapterPipeline, model).load_weights()
else:
self.load_weights(model)
if offload_after_quant:
self.load_weights(model, stream_online_quant_to_cpu=True)
else:
self.load_weights(model)
self._process_weights_after_loading(model, target_device)
if offload_after_quant:
@@ -498,6 +555,14 @@ class DiffusersPipelineLoader:
continue
if has_online_quant:
# finalize_layerwise_processing() and the synchronous online
# loader already processed these layers. Avoid moving their
# quantized CPU weights back to the accelerator merely to call
# an idempotent no-op; doing so rebuilds a large CUDA allocator
# cache and defeats streaming CPU offload's startup-memory bound.
if getattr(module, "_already_called_process_weights_after_loading", False):
continue
# Online quant may leave straggler params on the ``meta`` device.
# Move only real (non-meta) params onto the target device for
# processing and restore them afterward, mirroring upstream vLLM's
@@ -535,9 +600,17 @@ class DiffusersPipelineLoader:
if needs_device_move:
module.to(module_device)
def load_weights(self, model: nn.Module) -> None:
def load_weights(
self,
model: nn.Module,
*,
stream_online_quant_to_cpu: bool = False,
) -> None:
weights_to_load = self._get_expected_parameter_names(model)
loaded_weights = model.load_weights(self.get_all_weights(model))
weights = self.get_all_weights(model)
if stream_online_quant_to_cpu:
weights = self._stream_online_quant_weights_to_cpu(model, weights)
loaded_weights = model.load_weights(weights)
self.counter_after_loading_weights = time.perf_counter()
logger.info_once(