mirror of
https://github.com/vladmandic/automatic
synced 2026-09-19 09:14:35 +02:00
fix(offload): reclaim model memory across switches
Model switches kept most of the previous model resident, and the next load could stall in kernel reclaim while the freed memory was still held. - strip group offload hooks in disable_offload so the meta move at unload actually frees component weights; hook removal resolves wrapper components that carry hooks on the inner model - flush the torch pinned host cache in torch_gc so freed streaming buffers return to the OS instead of staying cached in-process - skip the pipe-level accelerator move for group-managed pipes: the offload engine already placed every component, and the move only dragged on-demand components to the accelerator for the trailing eviction to undo
This commit is contained in:
@@ -245,6 +245,8 @@ def torch_gc(force: bool = False, fast: bool = False, reason: str | None = None)
|
||||
torch.xpu.empty_cache()
|
||||
if hasattr(torch.xpu, "ipc_collect"):
|
||||
torch.xpu.ipc_collect()
|
||||
if torch.cuda.is_available() and hasattr(torch._C, '_host_emptyCache'): # pylint: disable=protected-access
|
||||
torch._C._host_emptyCache() # pylint: disable=protected-access # freed pinned host blocks otherwise stay cached in-process across model switches
|
||||
except Exception as e:
|
||||
log.error(f'Torch GC: {e}')
|
||||
else:
|
||||
|
||||
@@ -265,7 +265,10 @@ def move_model(model, device=None, force=False):
|
||||
if hasattr(model, 'device') and model.device == torch.device('meta'):
|
||||
set_execution_device(model, device)
|
||||
elif hasattr(model, 'to'):
|
||||
model.to(device)
|
||||
if device == devices.device and getattr(model, 'sdnext_ondemand_modules', None):
|
||||
pass # the group engine already placed every component; a pipe-level move would only drag on-demand components to the accelerator for the trailing eviction to undo
|
||||
else:
|
||||
model.to(device)
|
||||
if hasattr(model, "prior_pipe"):
|
||||
model.prior_pipe.to(device)
|
||||
if device == devices.device:
|
||||
|
||||
@@ -45,6 +45,7 @@ def get_signature(cls):
|
||||
|
||||
|
||||
def disable_offload(sd_model):
|
||||
remove_group_offload(sd_model) # group hooks block the meta move at unload, keeping component weights alive for as long as any reference to the pipe survives
|
||||
if not getattr(sd_model, 'has_accelerate', False):
|
||||
return
|
||||
for module_name in get_module_names(sd_model):
|
||||
@@ -95,11 +96,11 @@ def group_offload_config(main: bool) -> dict:
|
||||
}
|
||||
|
||||
|
||||
def remove_group_offload_component(module):
|
||||
def remove_group_offload_component(module) -> bool:
|
||||
if getattr(module, 'sdnext_group_offload_sig', None) is None:
|
||||
module = getattr(module, 'model', None) # wrapper components carry the hooks on the inner model
|
||||
if module is None or getattr(module, 'sdnext_group_offload_sig', None) is None:
|
||||
return
|
||||
return False
|
||||
from diffusers.hooks.group_offloading import _GROUP_OFFLOADING, _LAYER_EXECUTION_TRACKER, _LAZY_PREFETCH_GROUP_OFFLOADING
|
||||
from diffusers.hooks.hooks import HookRegistry
|
||||
registry = HookRegistry.check_if_exists_or_initialize(module)
|
||||
@@ -107,14 +108,14 @@ def remove_group_offload_component(module):
|
||||
registry.remove_hook(_LAYER_EXECUTION_TRACKER, recurse=True)
|
||||
registry.remove_hook(_LAZY_PREFETCH_GROUP_OFFLOADING, recurse=True)
|
||||
module.sdnext_group_offload_sig = None
|
||||
return True
|
||||
|
||||
|
||||
def remove_group_offload(sd_model):
|
||||
removed = []
|
||||
for module_name in get_module_names(sd_model):
|
||||
module = getattr(sd_model, module_name, None)
|
||||
if isinstance(module, torch.nn.Module) and getattr(module, 'sdnext_group_offload_sig', None) is not None:
|
||||
remove_group_offload_component(module)
|
||||
if isinstance(module, torch.nn.Module) and remove_group_offload_component(module):
|
||||
removed.append(module_name)
|
||||
for module_name in getattr(sd_model, 'sdnext_ondemand_modules', None) or []:
|
||||
module = getattr(sd_model, module_name, None)
|
||||
|
||||
Reference in New Issue
Block a user