Compare commits

...
Author SHA1 Message Date
xmarre ca8118de03 fix cpu fallback and torch remap handling 2026-04-12 05:54:14 +02:00
xmarre 752def584f load torch checkpoints on cpu before cuda remap 2026-04-12 05:42:29 +02:00
xmarre 871c144ac9 keep clip metadata tensors on cpu 2026-04-12 05:26:51 +02:00
xmarre ca0d55ce04 Merge pull request #1 from xmarre/codex/import-zip-implementation
[codex] Import GPU resident loader implementation
2026-04-12 04:52:39 +02:00
+74 -15
View File
@@ -22,6 +22,7 @@ from .residency import (
_LOG = logging.getLogger(__name__)
_PATCHED = False
_ORIGINALS: dict[str, Callable[..., Any]] = {}
_METADATA_CPU_KEY_SUFFIXES = ("spiece_model", "tekken_model", "comfy_quant")
def _normalize_device(device: Any | None) -> torch.device | None:
@@ -60,6 +61,42 @@ def _copy_tensor_if_needed(
return tensor.to(device=target_device, copy=True)
def _tensor_key_requires_cpu(key: str) -> bool:
return key.endswith(_METADATA_CPU_KEY_SUFFIXES)
def _prepare_loaded_tensor(
key: str,
tensor: torch.Tensor,
requested_device: torch.device,
*,
disable_mmap: bool,
move_to_requested_device: bool = False,
) -> torch.Tensor:
if _tensor_key_requires_cpu(key):
return _copy_tensor_if_needed(tensor, torch.device("cpu"))
if move_to_requested_device and tensor.device != requested_device:
return _copy_tensor_if_needed(tensor, requested_device)
if disable_mmap and tensor.device.type == "cpu":
return _copy_tensor_if_needed(tensor, requested_device, force_copy=True)
return tensor
def _state_dict_device_summary(sd: dict[str, Any], requested_device: torch.device) -> str:
devices: set[str] = set()
for value in sd.values():
if torch.is_tensor(value):
devices.add(str(value.device))
if not devices:
return str(requested_device)
if len(devices) == 1:
return next(iter(devices))
return ", ".join(sorted(devices))
def _resolved_context(kind: str, source_path: str | None) -> tuple[torch.device | None, str, str | None]:
ctx = REGISTRY.current_context()
if ctx is not None and ctx.explicit_device is not None:
@@ -121,15 +158,19 @@ def _patched_load_torch_file(ckpt, safe_load=False, device=None, return_metadata
safe_device = _safe_open_device_arg(requested_device)
with safe_open(ckpt, framework="pt", device=safe_device) as handle:
sd = {}
disable_mmap = getattr(comfy_utils, "DISABLE_MMAP", False)
for key in handle.keys():
tensor = handle.get_tensor(key)
if getattr(comfy_utils, "DISABLE_MMAP", False) and tensor.device.type == "cpu":
tensor = _copy_tensor_if_needed(tensor, requested_device, force_copy=True)
sd[key] = tensor
sd[key] = _prepare_loaded_tensor(
key,
tensor,
requested_device,
disable_mmap=disable_mmap,
)
if return_metadata:
metadata = handle.metadata()
actual_device = str(next(iter(sd.values())).device) if sd else str(requested_device)
actual_device = _state_dict_device_summary(sd, requested_device)
method = "safetensors_gpu_direct" if requested_device.type == "cuda" else "safetensors_cpu"
_record_generic_load(
path=ckpt,
@@ -149,14 +190,20 @@ def _patched_load_torch_file(ckpt, safe_load=False, device=None, return_metadata
with safe_open(ckpt, framework="pt", device="cpu") as handle:
sd = {}
for key in handle.keys():
sd[key] = handle.get_tensor(key).to(requested_device)
sd[key] = _prepare_loaded_tensor(
key,
handle.get_tensor(key),
requested_device,
disable_mmap=False,
move_to_requested_device=True,
)
if return_metadata:
metadata = handle.metadata()
_record_generic_load(
path=ckpt,
method="safetensors_cpu_then_copy_to_cuda",
requested_device=requested_device,
actual_device=str(requested_device),
actual_device=_state_dict_device_summary(sd, requested_device),
error=str(exc),
)
return (sd, metadata) if return_metadata else sd
@@ -198,15 +245,8 @@ def _patched_load_torch_file(ckpt, safe_load=False, device=None, return_metadata
if getattr(comfy_utils, "MMAP_TORCH_FILES", False):
torch_args["mmap"] = True
pl_sd = torch.load(ckpt, map_location=requested_device, weights_only=True, **torch_args)
method = "torch_load_cpu_first_to_cuda" if requested_device.type == "cuda" else "torch_load_cpu"
_record_generic_load(
path=ckpt,
method=method,
requested_device=requested_device,
actual_device=str(requested_device),
)
torch_load_device = torch.device("cpu") if requested_device.type == "cuda" else requested_device
pl_sd = torch.load(ckpt, map_location=torch_load_device, weights_only=True, **torch_args)
if "state_dict" in pl_sd:
sd = pl_sd["state_dict"]
else:
@@ -217,6 +257,25 @@ def _patched_load_torch_file(ckpt, safe_load=False, device=None, return_metadata
sd = pl_sd
else:
sd = pl_sd
if isinstance(sd, dict):
for key, value in list(sd.items()):
if torch.is_tensor(value):
sd[key] = _prepare_loaded_tensor(
key,
value,
requested_device,
disable_mmap=False,
move_to_requested_device=True,
)
method = "torch_load_cpu_first_to_cuda" if requested_device.type == "cuda" else "torch_load_cpu"
_record_generic_load(
path=ckpt,
method=method,
requested_device=requested_device,
actual_device=_state_dict_device_summary(sd, requested_device) if isinstance(sd, dict) else str(requested_device),
)
return (sd, metadata) if return_metadata else sd