Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions docs/features/sleep_mode.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,21 @@ llm.wake_up(tags=["weights"])
llm.wake_up(tags=["kv_cache"])
```

#### Retaining frozen weights during RLHF updates

Set `sleep_preserve_parameter_names` (CLI: `--sleep-preserve-parameter-names`)
to runtime parameter-name glob
patterns for weights that stay frozen during training. Each pattern must match
`model.named_parameters()`; checkpoint names and `requires_grad` are not used.

Level-2 sleep backs up selected GPU parameters to pageable CPU memory; weights
wake-up restores them in place and releases the backups. CPU parameters need no
copy. Allow enough host memory for backups. Level-1 behavior is unchanged.

The trainer must omit these parameters from updates, and reload/post-processing
must preserve their values and storage (including avoiding replacement with meta
tensors). This option does not filter updates and applies only to the target model.

#### Release only KV cache memory

`LLM.release_kv_cache_memory()` discards KV cache physical memory while keeping model weights resident. It requires a completed pause and all executor memory to be resident: full sleep, partial wake-up, and repeated release without restoring memory are rejected. Requests retained with `mode="keep"` are recomputed after wake-up.
Expand Down
1 change: 1 addition & 0 deletions tests/v1/worker/test_sleep_mode_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ def resume(self, tags: list[str] | None = None) -> None:

worker = object.__new__(Worker)
worker._sleep_mode_backend = Backend()
worker._sleep_saved_parameters = {}
worker._sleep_saved_buffers = {}
worker._sleep_saved_draft_buffers = {}
worker.vllm_config = SimpleNamespace(
Expand Down
3 changes: 3 additions & 0 deletions vllm/config/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,9 @@ class ModelConfig:
enable_sleep_mode: bool = False
"""Enable sleep mode for the engine (only cuda and
hip platforms are supported)."""
sleep_preserve_parameter_names: list[str] = field(default_factory=list)
"""Parameter-name globs to preserve across level-2 sleep.
The sender must omit these parameters; loaders must preserve their storage."""
sleep_mode_backend: str = "cumem"
"""Mechanism used to free and restore GPU state for sleep mode. ``"cumem"``
(default) uses the built-in ``CuMemAllocator`` and is behavior-compatible
Expand Down
8 changes: 8 additions & 0 deletions vllm/engine/arg_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -741,6 +741,9 @@ class EngineArgs:

generation_config: str = ModelConfig.generation_config
enable_sleep_mode: bool = ModelConfig.enable_sleep_mode
sleep_preserve_parameter_names: list[str] = get_field(
ModelConfig, "sleep_preserve_parameter_names"
)
enable_cumem_allocator: bool = ModelConfig.enable_cumem_allocator
enable_nccl_comm_suspend: bool = ModelConfig.enable_nccl_comm_suspend
override_generation_config: dict[str, Any] = get_field(
Expand Down Expand Up @@ -975,6 +978,10 @@ def add_cli_args(parser: FlexibleArgumentParser) -> FlexibleArgumentParser:
model_group.add_argument(
"--enable-sleep-mode", **model_kwargs["enable_sleep_mode"]
)
model_group.add_argument(
"--sleep-preserve-parameter-names",
**model_kwargs["sleep_preserve_parameter_names"],
)
model_group.add_argument(
"--enable-cumem-allocator", **model_kwargs["enable_cumem_allocator"]
)
Expand Down Expand Up @@ -1901,6 +1908,7 @@ def create_model_config(self) -> ModelConfig:
generation_config=self.generation_config,
override_generation_config=self.override_generation_config,
enable_sleep_mode=self.enable_sleep_mode,
sleep_preserve_parameter_names=self.sleep_preserve_parameter_names,
enable_cumem_allocator=self.enable_cumem_allocator,
enable_nccl_comm_suspend=self.enable_nccl_comm_suspend,
model_impl=self.model_impl,
Expand Down
29 changes: 29 additions & 0 deletions vllm/v1/worker/gpu_worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from collections.abc import Callable
from contextlib import AbstractContextManager, contextmanager, nullcontext
from datetime import timedelta
from fnmatch import filter as fnmatch_filter
from types import NoneType
from typing import TYPE_CHECKING, Any, cast

Expand Down Expand Up @@ -208,6 +209,7 @@ def __init__(
self.worker_sentinel = WorkerSentinel(worker=self)
# Buffers saved before sleep
self._sleep_saved_buffers: dict[str, torch.Tensor] = {}
self._sleep_saved_parameters: dict[str, torch.Tensor] = {}
self._sleep_saved_draft_buffers: dict[str, torch.Tensor] = {}

# Weight transfer engine is created in `load_model` once the model
Expand Down Expand Up @@ -243,13 +245,38 @@ def sleep_mode_backend(self) -> "SleepModeBackend":
)
return self._sleep_mode_backend

def _save_sleep_parameters(self, model: nn.Module) -> None:
patterns = self.model_config.sleep_preserve_parameter_names
if not patterns:
self._sleep_saved_parameters = {}
return
parameters = dict(model.named_parameters())
names: set[str] = set()
for pattern in patterns:
matches = fnmatch_filter(parameters, pattern)
if not matches:
raise ValueError(f"No parameter matches sleep retention: {pattern}")
names.update(matches)
self._sleep_saved_parameters = {
name: param.detach().to("cpu")
for name, param in parameters.items()
if name in names and not param.is_cpu
}

@torch.no_grad()
def _restore_sleep_parameters(self, model: nn.Module) -> None:
for name, value in self._sleep_saved_parameters.items():
model.get_parameter(name).copy_(value)
self._sleep_saved_parameters.clear()

def sleep(self, level: int = 1) -> None:
torch.accelerator.synchronize()
free_bytes_before_sleep = torch.accelerator.get_memory_info()[0]

# Save the buffers before level 2 sleep
if level == 2:
model = self.model_runner.model
self._save_sleep_parameters(model)
self._sleep_saved_buffers = {
name: buffer.cpu().clone() for name, buffer in model.named_buffers()
}
Expand Down Expand Up @@ -287,6 +314,8 @@ def wake_up(self, tags: list[str] | None = None) -> None:

# Restore the buffers after level 2 sleep
wake_weights = tags is None or "weights" in tags
if wake_weights and self._sleep_saved_parameters:
self._restore_sleep_parameters(self.model_runner.model)
if wake_weights and len(self._sleep_saved_buffers):
model = self.model_runner.model
for name, buffer in model.named_buffers():
Expand Down
Loading