chore: import upstream snapshot with attribution
PR Test (NPU) / check-changes (push) Has been cancelled
PR Test (NPU) / pr-gate (push) Has been cancelled
PR Test (NPU) / set-image-config (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-4-npu-a3 (push) Has been cancelled
PR Test (NPU) / stage-b-test-16-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-1-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-2-npu-a3 (push) Has been cancelled
PR Test (Arm64) / pr-gate (push) Has been cancelled
PR Test (Arm64) / check-changes (push) Has been cancelled
PR Test (Arm64) / build-test (push) Has been cancelled
PR Test (sgl-router) / gate (push) Has been cancelled
PR Test (sgl-router) / tier-1 — lint (push) Has been cancelled
PR Test (sgl-router) / tier-2 — build + test (push) Has been cancelled
PR Test (sgl-router) / tier-3 — docker (placeholder) (push) Has been cancelled
PR Test (sgl-router) / tier-3 — k8s integration (push) Has been cancelled
PR Test (sgl-router) / tier-3 — e2e (push) Has been cancelled
PR Test (sgl-router) / finish (push) Has been cancelled
PR Test (NPU) / single-node-poc (map[name:qwen3_6_27b_w8a8_1p_in64k_out1k_50ms runner:linux-aarch64-a3-2 test_case:test/registered/ascend/performance/qwen3_6_27b/test_npu_qwen3_6_27b_w8a8_1p_in64k_out1k_50ms.py test_type:perf]) (push) Has been cancelled
PR Test (NPU) / pr-test-npu-finish (push) Has been cancelled
PR Test (Xeon) / pr-gate (push) Has been cancelled
PR Test (Xeon) / check-changes (push) Has been cancelled
PR Test (Xeon) / build-test (, xeon-gnr, base-b-test-cpu) (push) Has been cancelled
PR Test (XPU) / check-changes (push) Has been cancelled
PR Test (XPU) / pr-gate (push) Has been cancelled
PR Test (XPU) / stage-a-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / wait-for-stage-a (push) Has been cancelled
PR Test (XPU) / stage-b-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / finish (push) Has been cancelled
CI Model Inventory / build-inventory (push) Has been cancelled
Lint / lint (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Compilation Check (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Manual Policy (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Request Processing (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Summary (push) Has been cancelled
PR Test (SMG) / build-wheel (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on windows (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (x86_64 - auto) (push) Has been cancelled
PR Test (SMG) / python-unit-tests (push) Has been cancelled
PR Test (SMG) / unit-tests (push) Has been cancelled
PR Test (SMG) / benchmarks (push) Has been cancelled
PR Test (SMG) / chat-completions (push) Has been cancelled
PR Test (SMG) / chat-completions-4gpu (push) Has been cancelled
PR Test (SMG) / e2e (push) Has been cancelled
PR Test (SMG) / docker-build-test (push) Has been cancelled
PR Test (SMG) / k8s-integration (push) Has been cancelled
PR Test (SMG) / finish (push) Has been cancelled
PR Test (SMG) / summarize-benchmarks (push) Has been cancelled
Release SGLang Model Gateway Docker Image / publish (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Build SDist (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Upload to PyPI (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (aarch64, 12.9, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (x86_64, 12.9, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu129 (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (aarch64, 13.0, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (x86_64, 13.0, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu130 (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 700) (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 720) (push) Has been cancelled
Release SGLang Kernels / release-rocm700 (push) Has been cancelled
Release SGLang Kernels / release-rocm720 (push) Has been cancelled
Release SGLang Kernels / build-musa43 (43, 3.10) (push) Has been cancelled
Release SGLang Kernels / release-musa43 (push) Has been cancelled
PR Test (NPU) / check-changes (push) Has been cancelled
PR Test (NPU) / pr-gate (push) Has been cancelled
PR Test (NPU) / set-image-config (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-4-npu-a3 (push) Has been cancelled
PR Test (NPU) / stage-b-test-16-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-1-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-2-npu-a3 (push) Has been cancelled
PR Test (Arm64) / pr-gate (push) Has been cancelled
PR Test (Arm64) / check-changes (push) Has been cancelled
PR Test (Arm64) / build-test (push) Has been cancelled
PR Test (sgl-router) / gate (push) Has been cancelled
PR Test (sgl-router) / tier-1 — lint (push) Has been cancelled
PR Test (sgl-router) / tier-2 — build + test (push) Has been cancelled
PR Test (sgl-router) / tier-3 — docker (placeholder) (push) Has been cancelled
PR Test (sgl-router) / tier-3 — k8s integration (push) Has been cancelled
PR Test (sgl-router) / tier-3 — e2e (push) Has been cancelled
PR Test (sgl-router) / finish (push) Has been cancelled
PR Test (NPU) / single-node-poc (map[name:qwen3_6_27b_w8a8_1p_in64k_out1k_50ms runner:linux-aarch64-a3-2 test_case:test/registered/ascend/performance/qwen3_6_27b/test_npu_qwen3_6_27b_w8a8_1p_in64k_out1k_50ms.py test_type:perf]) (push) Has been cancelled
PR Test (NPU) / pr-test-npu-finish (push) Has been cancelled
PR Test (Xeon) / pr-gate (push) Has been cancelled
PR Test (Xeon) / check-changes (push) Has been cancelled
PR Test (Xeon) / build-test (, xeon-gnr, base-b-test-cpu) (push) Has been cancelled
PR Test (XPU) / check-changes (push) Has been cancelled
PR Test (XPU) / pr-gate (push) Has been cancelled
PR Test (XPU) / stage-a-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / wait-for-stage-a (push) Has been cancelled
PR Test (XPU) / stage-b-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / finish (push) Has been cancelled
CI Model Inventory / build-inventory (push) Has been cancelled
Lint / lint (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Compilation Check (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Manual Policy (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Request Processing (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Summary (push) Has been cancelled
PR Test (SMG) / build-wheel (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on windows (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (x86_64 - auto) (push) Has been cancelled
PR Test (SMG) / python-unit-tests (push) Has been cancelled
PR Test (SMG) / unit-tests (push) Has been cancelled
PR Test (SMG) / benchmarks (push) Has been cancelled
PR Test (SMG) / chat-completions (push) Has been cancelled
PR Test (SMG) / chat-completions-4gpu (push) Has been cancelled
PR Test (SMG) / e2e (push) Has been cancelled
PR Test (SMG) / docker-build-test (push) Has been cancelled
PR Test (SMG) / k8s-integration (push) Has been cancelled
PR Test (SMG) / finish (push) Has been cancelled
PR Test (SMG) / summarize-benchmarks (push) Has been cancelled
Release SGLang Model Gateway Docker Image / publish (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Build SDist (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Upload to PyPI (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (aarch64, 12.9, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (x86_64, 12.9, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu129 (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (aarch64, 13.0, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (x86_64, 13.0, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu130 (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 700) (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 720) (push) Has been cancelled
Release SGLang Kernels / release-rocm700 (push) Has been cancelled
Release SGLang Kernels / release-rocm720 (push) Has been cancelled
Release SGLang Kernels / build-musa43 (43, 3.10) (push) Has been cancelled
Release SGLang Kernels / release-musa43 (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,558 @@
|
||||
from contextlib import nullcontext
|
||||
from types import SimpleNamespace
|
||||
|
||||
import torch
|
||||
|
||||
from sglang.multimodal_gen.runtime.layers.quantization.fp8 import Fp8Config
|
||||
from sglang.multimodal_gen.runtime.layers.quantization.modelopt_quant import (
|
||||
ModelOptFp8Config,
|
||||
)
|
||||
from sglang.multimodal_gen.runtime.loader.transformer_load_utils import (
|
||||
_ModelOptFp8OffloadAdapter,
|
||||
)
|
||||
from sglang.multimodal_gen.runtime.managers.memory_managers import (
|
||||
component_resident_strategies as component_resident_strategies_mod,
|
||||
)
|
||||
from sglang.multimodal_gen.runtime.managers.memory_managers import (
|
||||
layerwise_offload as layerwise_offload_mod,
|
||||
)
|
||||
from sglang.multimodal_gen.runtime.managers.memory_managers.component_manager import (
|
||||
ComponentUse,
|
||||
build_component_residency_strategy,
|
||||
)
|
||||
from sglang.multimodal_gen.runtime.managers.memory_managers.component_resident_strategies import (
|
||||
LayerwiseOffloadStrategy,
|
||||
ResidentStrategy,
|
||||
VanillaD2HStrategy,
|
||||
)
|
||||
from sglang.multimodal_gen.runtime.managers.memory_managers.layerwise_offload import (
|
||||
LayerwiseOffloadableModuleMixin,
|
||||
LayerwiseOffloadManager,
|
||||
configure_layerwise_offload_modules,
|
||||
get_layerwise_offload_component_names_for_pipeline,
|
||||
is_layerwise_offloaded_module,
|
||||
)
|
||||
|
||||
|
||||
class _FakeStream:
|
||||
def wait_stream(self, _stream) -> None:
|
||||
return None
|
||||
|
||||
def wait_event(self, _event) -> None:
|
||||
return None
|
||||
|
||||
|
||||
class _FakeEvent:
|
||||
def record(self, _stream) -> None:
|
||||
return None
|
||||
|
||||
|
||||
class _FakeDeviceModule:
|
||||
Stream = _FakeStream
|
||||
Event = _FakeEvent
|
||||
|
||||
@staticmethod
|
||||
def is_available() -> bool:
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def current_device() -> int:
|
||||
return 0
|
||||
|
||||
@staticmethod
|
||||
def current_stream() -> _FakeStream:
|
||||
return _FakeStream()
|
||||
|
||||
@staticmethod
|
||||
def stream(_stream):
|
||||
return nullcontext()
|
||||
|
||||
|
||||
class _DummyBlock(torch.nn.Module):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
base = torch.arange(12, dtype=torch.float32).reshape(3, 4)
|
||||
self.weight = torch.nn.Parameter(base.t())
|
||||
self.bias = torch.nn.Parameter(torch.arange(3, dtype=torch.float32))
|
||||
|
||||
|
||||
class _DummyModel(torch.nn.Module):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.blocks = torch.nn.ModuleList([_DummyBlock()])
|
||||
|
||||
|
||||
class _NestedDummyModel(torch.nn.Module, LayerwiseOffloadableModuleMixin):
|
||||
layer_names = ["encoder.blocks"]
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.encoder = _DummyModel()
|
||||
|
||||
|
||||
class _SharedBuffer(torch.nn.Module):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.register_buffer(
|
||||
"cache", torch.arange(12, dtype=torch.float32).reshape(6, 2)
|
||||
)
|
||||
|
||||
|
||||
class _SharedBufferLayer(torch.nn.Module):
|
||||
def __init__(self, shared: _SharedBuffer) -> None:
|
||||
super().__init__()
|
||||
self.shared = shared
|
||||
self.weight = torch.nn.Parameter(torch.ones(2, 2, dtype=torch.float32))
|
||||
|
||||
|
||||
class _SharedBufferModel(torch.nn.Module):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
shared = _SharedBuffer()
|
||||
self.blocks = torch.nn.ModuleList(
|
||||
[_SharedBufferLayer(shared), _SharedBufferLayer(shared)]
|
||||
)
|
||||
|
||||
|
||||
class _OrderedLinearLayer(torch.nn.Module):
|
||||
def __init__(self, scale: float) -> None:
|
||||
super().__init__()
|
||||
self.weight = torch.nn.Parameter(torch.eye(2, dtype=torch.float32) * scale)
|
||||
|
||||
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
||||
return x @ self.weight
|
||||
|
||||
|
||||
class _ReverseLayerwiseModel(torch.nn.Module):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.blocks = torch.nn.ModuleList(
|
||||
[
|
||||
_OrderedLinearLayer(2.0),
|
||||
_OrderedLinearLayer(3.0),
|
||||
_OrderedLinearLayer(5.0),
|
||||
]
|
||||
)
|
||||
|
||||
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
||||
for block in reversed(self.blocks):
|
||||
x = block(x)
|
||||
return x
|
||||
|
||||
|
||||
class _NestedEncoderDummyModel(_NestedDummyModel):
|
||||
layerwise_offload_dit_group_enabled = False
|
||||
|
||||
|
||||
class _LayerwiseComponent(torch.nn.Module, LayerwiseOffloadableModuleMixin):
|
||||
layer_names = ["blocks"]
|
||||
|
||||
def __init__(self, enabled: bool) -> None:
|
||||
super().__init__()
|
||||
self.blocks = torch.nn.ModuleList([_DummyBlock()])
|
||||
self.layerwise_offload_managers = [SimpleNamespace(enabled=enabled)]
|
||||
|
||||
|
||||
def _server_args(**kwargs):
|
||||
defaults = dict(
|
||||
use_fsdp_inference=False,
|
||||
dit_cpu_offload=False,
|
||||
text_encoder_cpu_offload=False,
|
||||
image_encoder_cpu_offload=False,
|
||||
vae_cpu_offload=False,
|
||||
dit_offload_prefetch_size=1,
|
||||
pin_cpu_memory=False,
|
||||
)
|
||||
defaults.update(kwargs)
|
||||
return SimpleNamespace(**defaults)
|
||||
|
||||
|
||||
def test_layerwise_offload_preserves_non_contiguous_stride(monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
layerwise_offload_mod.torch, "get_device_module", lambda: _FakeDeviceModule
|
||||
)
|
||||
monkeypatch.setattr(layerwise_offload_mod.current_platform, "device_type", "cpu")
|
||||
|
||||
model = _DummyModel()
|
||||
original_weight = model.blocks[0].weight.detach().clone()
|
||||
original_stride = model.blocks[0].weight.stride()
|
||||
assert not model.blocks[0].weight.is_contiguous()
|
||||
|
||||
manager = LayerwiseOffloadManager(
|
||||
model=model,
|
||||
layers_attr_str="blocks",
|
||||
num_layers=1,
|
||||
enabled=True,
|
||||
pin_cpu_memory=False,
|
||||
prefetch_size=1,
|
||||
)
|
||||
|
||||
meta = manager._weight_metadata[0]["blocks.0.weight"]
|
||||
assert meta["preserve_strides"] is True
|
||||
|
||||
restored_weight = model.blocks[0].weight.data
|
||||
assert restored_weight.shape == original_weight.shape
|
||||
assert restored_weight.stride() == original_stride
|
||||
assert not restored_weight.is_contiguous()
|
||||
assert torch.equal(restored_weight, original_weight)
|
||||
|
||||
manager.release_layer(0)
|
||||
manager.prefetch_layer(0, non_blocking=False)
|
||||
|
||||
reloaded_weight = model.blocks[0].weight.data
|
||||
assert reloaded_weight.stride() == original_stride
|
||||
assert not reloaded_weight.is_contiguous()
|
||||
assert torch.equal(reloaded_weight, original_weight)
|
||||
|
||||
|
||||
def test_layerwise_offload_uses_normal_tensors_under_inference_mode(monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
layerwise_offload_mod.torch, "get_device_module", lambda: _FakeDeviceModule
|
||||
)
|
||||
monkeypatch.setattr(layerwise_offload_mod.current_platform, "device_type", "cpu")
|
||||
|
||||
model = _DummyModel()
|
||||
manager = LayerwiseOffloadManager(
|
||||
model=model,
|
||||
layers_attr_str="blocks",
|
||||
num_layers=1,
|
||||
enabled=True,
|
||||
pin_cpu_memory=False,
|
||||
prefetch_size=1,
|
||||
)
|
||||
|
||||
with torch.inference_mode():
|
||||
manager.release_layer(0)
|
||||
manager.prefetch_layer(0, non_blocking=False)
|
||||
|
||||
assert model.blocks[0].weight._version >= 0
|
||||
assert model.blocks[0].bias._version >= 0
|
||||
|
||||
|
||||
def test_layerwise_offload_keeps_shared_buffers_resident(monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
layerwise_offload_mod.torch, "get_device_module", lambda: _FakeDeviceModule
|
||||
)
|
||||
monkeypatch.setattr(layerwise_offload_mod.current_platform, "device_type", "cpu")
|
||||
|
||||
model = _SharedBufferModel()
|
||||
original_cache = model.blocks[0].shared.cache.detach().clone()
|
||||
|
||||
manager = LayerwiseOffloadManager(
|
||||
model=model,
|
||||
layers_attr_str="blocks",
|
||||
num_layers=2,
|
||||
enabled=True,
|
||||
pin_cpu_memory=False,
|
||||
prefetch_size=1,
|
||||
)
|
||||
|
||||
assert not any(
|
||||
"cache" in name
|
||||
for metadata in manager._weight_metadata.values()
|
||||
for name in metadata
|
||||
)
|
||||
manager.release_layer(0)
|
||||
|
||||
cache = model.blocks[1].shared.cache
|
||||
assert torch.equal(cache, original_cache)
|
||||
assert torch.equal(cache.index_select(0, torch.tensor([2])), original_cache[2:3])
|
||||
|
||||
|
||||
def test_layerwise_offload_loads_current_layer_for_reverse_execution(monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
layerwise_offload_mod.torch, "get_device_module", lambda: _FakeDeviceModule
|
||||
)
|
||||
monkeypatch.setattr(layerwise_offload_mod.current_platform, "device_type", "cpu")
|
||||
|
||||
model = _ReverseLayerwiseModel()
|
||||
x = torch.ones(1, 2, dtype=torch.float32)
|
||||
expected = model(x)
|
||||
|
||||
LayerwiseOffloadManager(
|
||||
model=model,
|
||||
layers_attr_str="blocks",
|
||||
num_layers=3,
|
||||
enabled=True,
|
||||
pin_cpu_memory=False,
|
||||
prefetch_size=1,
|
||||
)
|
||||
|
||||
assert torch.equal(model(x), expected)
|
||||
|
||||
|
||||
def test_modelopt_fp8_adapter_keeps_layerwise_offload_enabled():
|
||||
server_args = SimpleNamespace(
|
||||
dit_cpu_offload=True,
|
||||
dit_layerwise_offload=True,
|
||||
)
|
||||
quant_config = ModelOptFp8Config(is_checkpoint_fp8_serialized=True)
|
||||
|
||||
_ModelOptFp8OffloadAdapter._maybe_disable_incompatible_dit_offload_modes(
|
||||
server_args=server_args,
|
||||
quant_config=quant_config,
|
||||
)
|
||||
|
||||
assert server_args.dit_cpu_offload is False
|
||||
assert server_args.dit_layerwise_offload is True
|
||||
|
||||
|
||||
def test_modelopt_fp8_adapter_does_not_change_online_fp8_offload():
|
||||
server_args = SimpleNamespace(
|
||||
dit_cpu_offload=True,
|
||||
dit_layerwise_offload=False,
|
||||
quantization="fp8",
|
||||
)
|
||||
|
||||
_ModelOptFp8OffloadAdapter._maybe_disable_incompatible_dit_offload_modes(
|
||||
server_args=server_args,
|
||||
quant_config=Fp8Config(),
|
||||
)
|
||||
|
||||
assert server_args.dit_cpu_offload is True
|
||||
|
||||
|
||||
def test_layerwise_capability_selects_layerwise_strategy_for_any_component():
|
||||
module = _LayerwiseComponent(enabled=True)
|
||||
|
||||
assert is_layerwise_offloaded_module(module)
|
||||
strategy = build_component_residency_strategy(
|
||||
"text_encoder", module, _server_args(text_encoder_cpu_offload=True)
|
||||
)
|
||||
|
||||
assert isinstance(strategy, LayerwiseOffloadStrategy)
|
||||
|
||||
|
||||
def test_layerwise_pipeline_selection_uses_dit_group(monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
layerwise_offload_mod.torch, "get_device_module", lambda: _FakeDeviceModule
|
||||
)
|
||||
monkeypatch.setattr(layerwise_offload_mod.current_platform, "device_type", "cpu")
|
||||
layerwise_module = _NestedDummyModel()
|
||||
modules = {
|
||||
"text_encoder": layerwise_module,
|
||||
"text_encoder_alias": layerwise_module,
|
||||
"scheduler": object(),
|
||||
}
|
||||
|
||||
selected = get_layerwise_offload_component_names_for_pipeline(modules)
|
||||
configured = configure_layerwise_offload_modules(modules, _server_args())
|
||||
|
||||
assert selected == ["text_encoder", "text_encoder_alias"]
|
||||
assert configured == ["text_encoder"]
|
||||
assert is_layerwise_offloaded_module(layerwise_module)
|
||||
|
||||
|
||||
def test_layerwise_configuration_filters_by_component_name(monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
layerwise_offload_mod.torch, "get_device_module", lambda: _FakeDeviceModule
|
||||
)
|
||||
monkeypatch.setattr(layerwise_offload_mod.current_platform, "device_type", "cpu")
|
||||
text_encoder = _NestedEncoderDummyModel()
|
||||
transformer = _NestedDummyModel()
|
||||
vae = _NestedDummyModel()
|
||||
modules = {
|
||||
"custom_encoder_name": text_encoder,
|
||||
"custom_transformer_name": transformer,
|
||||
"custom_vae_name": vae,
|
||||
}
|
||||
|
||||
configured = configure_layerwise_offload_modules(
|
||||
modules, _server_args(), component_names=["custom_encoder_name"]
|
||||
)
|
||||
|
||||
assert configured == ["custom_encoder_name"]
|
||||
assert is_layerwise_offloaded_module(text_encoder)
|
||||
assert not is_layerwise_offloaded_module(transformer)
|
||||
assert not is_layerwise_offloaded_module(vae)
|
||||
|
||||
|
||||
def test_layerwise_configuration_default_group_selects_non_dit_defaults(monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
layerwise_offload_mod.torch, "get_device_module", lambda: _FakeDeviceModule
|
||||
)
|
||||
monkeypatch.setattr(layerwise_offload_mod.current_platform, "device_type", "cpu")
|
||||
text_encoder = _NestedEncoderDummyModel()
|
||||
text_encoder_2 = _NestedEncoderDummyModel()
|
||||
transformer = _NestedDummyModel()
|
||||
image_encoder = _NestedEncoderDummyModel()
|
||||
vae = _NestedEncoderDummyModel()
|
||||
audio_vae = _NestedEncoderDummyModel()
|
||||
vocoder = _NestedEncoderDummyModel()
|
||||
spatial_upsampler = _NestedEncoderDummyModel()
|
||||
condition_image_encoder = _NestedEncoderDummyModel()
|
||||
modules = {
|
||||
"text_encoder": text_encoder,
|
||||
"text_encoder_2": text_encoder_2,
|
||||
"transformer": transformer,
|
||||
"image_encoder": image_encoder,
|
||||
"vae": vae,
|
||||
"audio_vae": audio_vae,
|
||||
"vocoder": vocoder,
|
||||
"spatial_upsampler": spatial_upsampler,
|
||||
"condition_image_encoder": condition_image_encoder,
|
||||
}
|
||||
|
||||
configured = configure_layerwise_offload_modules(
|
||||
modules, _server_args(), component_names=["default"]
|
||||
)
|
||||
|
||||
assert get_layerwise_offload_component_names_for_pipeline(modules, ["default"]) == [
|
||||
"text_encoder",
|
||||
"text_encoder_2",
|
||||
"image_encoder",
|
||||
"vae",
|
||||
"condition_image_encoder",
|
||||
]
|
||||
assert configured == [
|
||||
"text_encoder",
|
||||
"text_encoder_2",
|
||||
"image_encoder",
|
||||
"vae",
|
||||
"condition_image_encoder",
|
||||
]
|
||||
assert is_layerwise_offloaded_module(text_encoder)
|
||||
assert is_layerwise_offloaded_module(text_encoder_2)
|
||||
assert not is_layerwise_offloaded_module(transformer)
|
||||
assert is_layerwise_offloaded_module(image_encoder)
|
||||
assert is_layerwise_offloaded_module(vae)
|
||||
assert not is_layerwise_offloaded_module(audio_vae)
|
||||
assert not is_layerwise_offloaded_module(vocoder)
|
||||
assert not is_layerwise_offloaded_module(spatial_upsampler)
|
||||
assert is_layerwise_offloaded_module(condition_image_encoder)
|
||||
|
||||
for component_name, module in (
|
||||
("audio_vae", audio_vae),
|
||||
("vocoder", vocoder),
|
||||
("spatial_upsampler", spatial_upsampler),
|
||||
):
|
||||
configured = configure_layerwise_offload_modules(
|
||||
modules, _server_args(), component_names=[component_name]
|
||||
)
|
||||
assert configured == [component_name]
|
||||
assert is_layerwise_offloaded_module(module)
|
||||
|
||||
|
||||
def test_layerwise_configuration_all_selects_every_capable_component(monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
layerwise_offload_mod.torch, "get_device_module", lambda: _FakeDeviceModule
|
||||
)
|
||||
monkeypatch.setattr(layerwise_offload_mod.current_platform, "device_type", "cpu")
|
||||
text_encoder = _NestedEncoderDummyModel()
|
||||
transformer = _NestedDummyModel()
|
||||
modules = {
|
||||
"custom_encoder_name": text_encoder,
|
||||
"custom_transformer_name": transformer,
|
||||
"scheduler": object(),
|
||||
}
|
||||
|
||||
configured = configure_layerwise_offload_modules(
|
||||
modules, _server_args(), component_names=["all"]
|
||||
)
|
||||
|
||||
assert configured == ["custom_encoder_name", "custom_transformer_name"]
|
||||
assert is_layerwise_offloaded_module(text_encoder)
|
||||
assert is_layerwise_offloaded_module(transformer)
|
||||
|
||||
|
||||
def test_component_cpu_offload_strategy_remains_flag_driven():
|
||||
strategy = build_component_residency_strategy(
|
||||
"text_encoder", _DummyModel(), _server_args(text_encoder_cpu_offload=True)
|
||||
)
|
||||
assert isinstance(strategy, VanillaD2HStrategy)
|
||||
|
||||
strategy = build_component_residency_strategy(
|
||||
"unknown_component", _DummyModel(), _server_args(text_encoder_cpu_offload=True)
|
||||
)
|
||||
assert isinstance(strategy, ResidentStrategy)
|
||||
|
||||
|
||||
def test_resident_strategy_prepares_local_device_without_dtype(monkeypatch):
|
||||
calls = []
|
||||
|
||||
def fake_module_to_local_device(module, *, dtype=None):
|
||||
calls.append((module, dtype))
|
||||
|
||||
monkeypatch.setattr(
|
||||
component_resident_strategies_mod,
|
||||
"_module_to_local_device",
|
||||
fake_module_to_local_device,
|
||||
)
|
||||
module = _DummyModel()
|
||||
|
||||
ResidentStrategy().prepare_for_use(
|
||||
module,
|
||||
ComponentUse(stage_name="DenoisingStage", component_name="transformer"),
|
||||
SimpleNamespace(),
|
||||
)
|
||||
|
||||
assert calls == [(module, None)]
|
||||
|
||||
|
||||
def test_resident_strategy_keeps_fsdp_managed_module_owned_by_fsdp(monkeypatch):
|
||||
calls = []
|
||||
|
||||
def fake_module_to_local_device(module, *, dtype=None):
|
||||
calls.append((module, dtype))
|
||||
|
||||
monkeypatch.setattr(
|
||||
component_resident_strategies_mod,
|
||||
"_module_to_local_device",
|
||||
fake_module_to_local_device,
|
||||
)
|
||||
module = type("FSDPDummyModel", (_DummyModel,), {})()
|
||||
|
||||
ResidentStrategy().prepare_for_use(
|
||||
module,
|
||||
ComponentUse(stage_name="TextEncodingStage", component_name="text_encoder"),
|
||||
SimpleNamespace(),
|
||||
)
|
||||
|
||||
assert calls == []
|
||||
|
||||
|
||||
def test_layerwise_offload_aligns_contiguous_tensor_offsets(monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
layerwise_offload_mod.torch, "get_device_module", lambda: _FakeDeviceModule
|
||||
)
|
||||
monkeypatch.setattr(layerwise_offload_mod.current_platform, "device_type", "cpu")
|
||||
|
||||
class _AlignedDummyBlock(torch.nn.Module):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.weight = torch.nn.Parameter(
|
||||
torch.arange(9, dtype=torch.float32).reshape(3, 3)
|
||||
)
|
||||
self.bias = torch.nn.Parameter(torch.arange(3, dtype=torch.float32))
|
||||
|
||||
class _AlignedDummyModel(torch.nn.Module):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.blocks = torch.nn.ModuleList([_AlignedDummyBlock()])
|
||||
|
||||
model = _AlignedDummyModel()
|
||||
original_weight = model.blocks[0].weight.detach().clone()
|
||||
original_bias = model.blocks[0].bias.detach().clone()
|
||||
|
||||
manager = LayerwiseOffloadManager(
|
||||
model=model,
|
||||
layers_attr_str="blocks",
|
||||
num_layers=1,
|
||||
enabled=True,
|
||||
pin_cpu_memory=False,
|
||||
prefetch_size=1,
|
||||
)
|
||||
|
||||
weight_meta = manager._weight_metadata[0]["blocks.0.weight"]
|
||||
bias_meta = manager._weight_metadata[0]["blocks.0.bias"]
|
||||
assert weight_meta["preserve_strides"] is False
|
||||
assert bias_meta["preserve_strides"] is False
|
||||
assert weight_meta["offset"] == 0
|
||||
assert bias_meta["offset"] % 8 == 0
|
||||
|
||||
restored_weight = model.blocks[0].weight.data
|
||||
restored_bias = model.blocks[0].bias.data
|
||||
assert restored_weight.data_ptr() % 32 == 0
|
||||
assert restored_bias.data_ptr() % 32 == 0
|
||||
assert torch.equal(restored_weight, original_weight)
|
||||
assert torch.equal(restored_bias, original_bias)
|
||||
Reference in New Issue
Block a user