Update dynamic_swapping_loader.py

tensor
This commit is contained in:
obisin
2025-09-02 16:45:31 +01:00
committed by GitHub
parent 42c6211666
commit eaecd28d31
+26 -139
View File
@@ -223,79 +223,31 @@ def debug_layer_locations(layers, device_cache):
# DYNAMIC LAYER SWAPPING INFERENCE for Comfy-UI - by obisin
# =============================================================================
def _has_version_counter(t: torch.Tensor) -> bool:
try:
_ = t._version
return True
except (RuntimeError, AttributeError):
return False
# def fix_inference_tensor_parameters(layer):
# """
# Ensure all tensors owned by this module have a normal version counter.
# """
# fixed = False
# with torch.inference_mode(False), torch.no_grad():
# # 1) Parameters: re-register as fresh Parameters if needed
# for name, p in list(layer.named_parameters(recurse=False)):
# if p is not None and not _has_version_counter(p):
# new_p = p.detach().to(p.device, p.dtype)
# setattr(layer, name, torch.nn.Parameter(new_p, requires_grad=False))
# fixed = True
#
# # 2) Buffers: re-register if needed
# for name, b in list(layer.named_buffers(recurse=False)):
# if b is not None and not _has_version_counter(b):
# new_b = b.detach().to(b.device, b.dtype)
# layer.register_buffer(name, new_b, persistent=True)
# fixed = True
#
# # 3) Plain tensor attributes used by WAN/Flux blocks
# tensor_attrs = ["modulation", "freqs", "pe", "vec", "norm", "scale",
# "pos_embed", "time_embed", "label_embed"]
# for attr_name in tensor_attrs:
# if hasattr(layer, attr_name):
# t = getattr(layer, attr_name)
# if isinstance(t, torch.Tensor) and not _has_version_counter(t):
# new_t = t.detach().to(t.device, t.dtype)
# setattr(layer, attr_name, new_t)
# fixed = True
#
# return fixed
#
def fix_inference_tensor_parameters(layer):
"""
Ensure all tensors owned by this module have a normal version counter.
"""
fixed = False
def needs_version_fix(t: torch.Tensor) -> bool:
try:
_ = t._version
return False # Has version counter
except Exception:
return True # Needs fixing
# Quick scan first - early exit if nothing needs fixing
for name, p in layer.named_parameters(recurse=False):
if p is not None and needs_version_fix(p):
break
else:
return False # Nothing needs fixing
# Only fix what needs fixing
with torch.inference_mode(False), torch.no_grad():
# 1) Parameters: re-register using ComfyUI's safe casting
for name, p in list(layer.named_parameters(recurse=False)):
if p is not None and not _has_version_counter(p):
new_p = comfy.model_management.cast_to_device(p, p.device, p.dtype, copy=False)
setattr(layer, name, torch.nn.Parameter(new_p, requires_grad=False))
fixed = True
# 2) Buffers: re-register using ComfyUI's safe casting
for name, b in list(layer.named_buffers(recurse=False)):
if b is not None and not _has_version_counter(b):
new_b = comfy.model_management.cast_to_device(b, b.device, b.dtype, copy=False)
layer.register_buffer(name, new_b, persistent=True)
fixed = True
# 3) Plain tensor attributes used by WAN/Flux blocks
tensor_attrs = ["modulation", "freqs", "pe", "vec", "norm", "scale",
"pos_embed", "time_embed", "label_embed"]
for attr_name in tensor_attrs:
if hasattr(layer, attr_name):
t = getattr(layer, attr_name)
if isinstance(t, torch.Tensor) and not _has_version_counter(t):
new_t = comfy.model_management.cast_to_device(t, t.device, t.dtype, copy=False)
setattr(layer, attr_name, new_t)
fixed = True
return fixed
if p is not None and needs_version_fix(p):
new_p = torch.nn.Parameter(
torch.empty_like(p).copy_(p),
requires_grad=False
)
setattr(layer, name, new_p)
return True
def get_cached_layer_size_mb(idx):
size = layer_sizes_mb.get(idx, 0)
@@ -405,10 +357,10 @@ def calculate_auto_gpu_layers(layers, args):
overhead = max_layer_size * 1.1 * (args.prefetch + 1)
if args.cpu_threading:
overhead += max_layer_size * 0.33 * (args.prefetch + 1)
overhead += max_layer_size * 0.4 * (args.prefetch + 1)
if args.cuda_streams:
overhead += max_layer_size * 0.33 * (args.prefetch + 1)
overhead += max_layer_size * 0.4 * (args.prefetch + 1)
layer_memory_budget = max(128 * 1024 * 1024, layer_memory_budget - overhead)
@@ -648,8 +600,6 @@ def add_smart_swapping_to_layer(layer, layer_idx, layers_list, gpu_resident_laye
if not hasattr(layer, '_original_forward'):
layer._original_forward = layer.forward
if not getattr(layer, "_dgls_fixed", False):
if fix_inference_tensor_parameters(layer):
pass # fixed something
@@ -807,40 +757,6 @@ def add_smart_swapping_to_layer(layer, layer_idx, layers_list, gpu_resident_laye
return x # Pass input through unchanged
# def move_to_device(tensor, target_device):
# if not isinstance(tensor, torch.Tensor):
# return tensor
# # Fix inference mode tensors BEFORE moving
# if hasattr(tensor, 'device'):
# # Check if tensor needs inference mode fix
# try:
# _ = tensor._version
# fixed_tensor = tensor
# except (RuntimeError, AttributeError):
# # Clone to get normal tensor
# with torch.inference_mode(False), torch.no_grad():
# fixed_tensor = tensor.detach()#.clone()
#
# # Move to target device
# if fixed_tensor.device != target_device:
# return fixed_tensor.to(target_device, non_blocking=True)
# else:
# return fixed_tensor
#
# return tensor
# def move_to_device(tensor, target_device):
# if isinstance(tensor, torch.Tensor) and hasattr(tensor, 'device'):
# if tensor.device != target_device:
# return tensor.to(target_device, non_blocking=True)
# return tensor
# def move_to_device(tensor, target_device):
# if isinstance(tensor, torch.Tensor) and tensor.device != target_device:
# return tensor.to(target_device, non_blocking=True)
# return tensor
def move_to_device(tensor, target_device):
if isinstance(tensor, torch.Tensor) and tensor.device != target_device:
return comfy.model_management.cast_to_device(tensor, target_device, tensor.dtype, copy=False)
@@ -884,28 +800,13 @@ def add_smart_swapping_to_layer(layer, layer_idx, layers_list, gpu_resident_laye
if args.verbose:
compute_start = time.perf_counter()
# === NEW: ensure default stream waits on H2D completion ===
# ensure default stream waits on H2D completion
if args.cuda_streams and layer_idx in cpu_swappable_layers:
if hasattr(add_smart_swapping_to_layer, 'transfer_events'):
ev = add_smart_swapping_to_layer.transfer_events.get(layer_idx)
if ev is not None:
torch.cuda.current_stream().wait_event(ev)
# if args.cuda_streams and hasattr(add_smart_swapping_to_layer, 'compute_stream'):
# with torch.cuda.stream(add_smart_swapping_to_layer.compute_stream):
# # fix_inference_tensor_parameters(layer)
# if is_flux_call:
# if fwd_args:
# result = original_forward(*new_args, **new_kwargs)
# else:
# result = original_forward(**new_kwargs)
#
# elif is_keyword_only_call:
# result = original_forward(**new_kwargs)
# else:
# result = original_forward(x, *new_args, **new_kwargs)
# else:
# fix_inference_tensor_parameters(layer)
if is_flux_call:
if fwd_args:
result = original_forward(*new_args, **new_kwargs)
@@ -1026,6 +927,7 @@ class DynamicSwappingLoader:
cast_target="", cuda_streams=False, cpu_threading=False):
global gpu_resident_layers, cpu_swappable_layers, device_cache
def _teardown_swapping_state():
"""Complete cleanup of all modified layers and global state"""
global layers, device_cache, gpu_resident_layers, cpu_swappable_layers
@@ -1041,7 +943,6 @@ class DynamicSwappingLoader:
if hasattr(layer, '_dgls_fixed'):
delattr(layer, '_dgls_fixed')
# Kill thread pool unconditionally
if hasattr(add_smart_swapping_to_layer, 'cpu_thread_pool'):
try:
@@ -1454,20 +1355,6 @@ class DynamicSwappingLoader:
gpu_resident_layers,
cpu_swappable_layers)
if args.verbose:
print("Verifying tensor fixes...")
problematic_layers = []
for i, layer in enumerate(layers):
for name, param in layer.named_parameters():
if not _has_version_counter(param):
problematic_layers.append(i)
break
if problematic_layers:
print(f"WARNING: Layers {problematic_layers} still have inference tensors")
else:
print("All layer tensors properly fixed at startup")
if args.verbose:
print("✓ Dynamic swapping successfully integrated with ComfyUI")