from __future__ import annotations
import logging
from contextlib import contextmanager
from typing import cast
import torch
import torch.nn as nn
from .accelerators import AcceleratorBackend, CudaAcceleratorBackend
logger = logging.getLogger("modelexpress.tensor_utils")
def _resolve_accelerator_backend(
accelerator_backend: AcceleratorBackend | None,
) -> AcceleratorBackend:
return accelerator_backend or CudaAcceleratorBackend()
def safe_checksum(tensor: torch.Tensor) -> str:
try:
t = tensor.detach().contiguous()
if t.dim() == 0:
t = t.unsqueeze(0)
flat = t.view(torch.uint8)
idx = torch.arange(flat.numel(), device=flat.device, dtype=torch.int64)
weights = (idx * 2654435761 + 1) & 0xFFFFFFFF
mixed = (flat.to(torch.int64) * weights) & 0xFFFFFFFF
return format(mixed.sum().item() & 0xFFFFFFFF, "08x")
except Exception as e:
return f"err:{e}"
@contextmanager
def capture_tensor_attrs(accelerator_backend: AcceleratorBackend):
original_setattr = nn.Module.__setattr__
def capturing_setattr(self, name, value):
if (isinstance(value, torch.Tensor)
and not isinstance(value, nn.Parameter)
and accelerator_backend.is_accel_tensor(value)
and name not in self._parameters
and name not in self._buffers
and name not in self._modules):
if hasattr(self, name):
try:
delattr(self, name)
except AttributeError:
pass
self.register_buffer(name, value, persistent=False)
logger.debug(
"Captured bare accelerator tensor: %s.%s (shape=%s, dtype=%s)",
type(self).__name__, name, list(value.shape), value.dtype,
)
else:
original_setattr(self, name, value)
nn.Module.__setattr__ = capturing_setattr
try:
yield
finally:
nn.Module.__setattr__ = original_setattr
def _find_hidden_accel_tensors(
obj: object,
visited: set[int],
accelerator_backend: AcceleratorBackend,
depth: int = 0,
) -> list[tuple[str, torch.Tensor]]:
if depth > 20 or id(obj) in visited:
return []
visited.add(id(obj))
results: list[tuple[str, torch.Tensor]] = []
if isinstance(obj, torch.Tensor):
tensor = cast(torch.Tensor, obj)
if accelerator_backend.is_accel_tensor(tensor) and tensor.numel() > 0:
results.append(("t", tensor))
elif isinstance(obj, (list, tuple)):
for i, item in enumerate(obj):
for path, tensor in _find_hidden_accel_tensors(
item,
visited,
accelerator_backend,
depth + 1,
):
results.append((f"{i}_{path}", tensor))
elif isinstance(obj, dict):
for k, v in obj.items():
for path, tensor in _find_hidden_accel_tensors(
v,
visited,
accelerator_backend,
depth + 1,
):
results.append((f"{k}_{path}", tensor))
elif hasattr(obj, "__dict__") and not isinstance(obj, (type, nn.Module)):
for attr_name, attr_val in vars(obj).items():
if attr_name.startswith("__"):
continue
for path, tensor in _find_hidden_accel_tensors(
attr_val,
visited,
accelerator_backend,
depth + 1,
):
results.append((f"{attr_name}_{path}", tensor))
return results
def adopt_hidden_tensors(
model: nn.Module,
accelerator_backend: AcceleratorBackend | None = None,
) -> int:
import time
start = time.perf_counter()
backend = _resolve_accelerator_backend(accelerator_backend)
existing_ptrs: set[int] = set()
for _, p in model.named_parameters():
existing_ptrs.add(p.data_ptr())
for _, b in model.named_buffers():
existing_ptrs.add(b.data_ptr())
adopted = 0
for _module_name, module in model.named_modules():
for attr_name in list(vars(module)):
attr_val = getattr(module, attr_name, None)
if attr_val is None:
continue
if isinstance(attr_val, (torch.Tensor, nn.Parameter, nn.Module)):
continue
tensors = _find_hidden_accel_tensors(
attr_val,
visited=set(),
accelerator_backend=backend,
)
for tensor_path, tensor in tensors:
if tensor.data_ptr() in existing_ptrs:
continue
safe_path = (
tensor_path.replace(".", "__dot__")
.replace("[", "")
.replace("]", "")
)
buf_name = f"_mx_{attr_name}_{safe_path}"
if hasattr(module, buf_name):
suffix = 0
while hasattr(module, f"{buf_name}_{suffix}"):
suffix += 1
buf_name = f"{buf_name}_{suffix}"
module.register_buffer(buf_name, tensor, persistent=False)
existing_ptrs.add(tensor.data_ptr())
adopted += 1
logger.debug(
"Adopted hidden tensor: %s.%s "
"(shape=%s, dtype=%s, from %s.%s)",
_module_name, buf_name,
list(tensor.shape), tensor.dtype,
type(attr_val).__name__, tensor_path,
)
elapsed = time.perf_counter() - start
if adopted:
logger.info(
f"Adopted {adopted} hidden accelerator tensors as module buffers "
f"in {elapsed:.3f}s"
)
else:
logger.debug(f"No hidden accelerator tensors found ({elapsed:.3f}s)")
return adopted
def iter_module_tensors(
module: nn.Module,
accelerator_backend: AcceleratorBackend | None = None,
) -> list[tuple[str, torch.Tensor, str]]:
backend = _resolve_accelerator_backend(accelerator_backend)
results: list[tuple[str, torch.Tensor, str]] = []
for name, param in module.named_parameters():
if backend.is_accel_tensor(param):
results.append((name, param, "parameter"))
for name, buf in module.named_buffers():
if backend.is_accel_tensor(buf):
results.append((name, buf, "buffer"))
return results
def storage_view(tensor: torch.Tensor) -> torch.Tensor:
return torch.empty(0, dtype=torch.uint8, device=tensor.device).set_(
tensor.untyped_storage()
)
def collect_module_tensors(
model: nn.Module,
accelerator_backend: AcceleratorBackend | None = None,
) -> dict[str, torch.Tensor]:
backend = _resolve_accelerator_backend(accelerator_backend)
tensors: dict[str, torch.Tensor] = {}
seen_ptrs: set[int] = set()
storage_view_count = 0
skipped_duplicate = 0
for name, tensor, _tensor_type in iter_module_tensors(model, backend):
t = tensor.data if hasattr(tensor, "data") else tensor
if t.numel() == 0:
tensors[name] = t
continue
if t.is_contiguous():
ptr = t.data_ptr()
if ptr in seen_ptrs:
logger.debug(f"Skipping duplicate tensor '{name}' (same data_ptr)")
skipped_duplicate += 1
continue
seen_ptrs.add(ptr)
tensors[name] = t
else:
sv = storage_view(t)
ptr = sv.data_ptr()
if ptr in seen_ptrs:
skipped_duplicate += 1
continue
seen_ptrs.add(ptr)
tensors[f"{name}.__storage"] = sv
storage_view_count += 1
if storage_view_count:
logger.info(
f"Registered {storage_view_count} non-contiguous tensors "
f"via storage-level byte transfer"
)
if skipped_duplicate:
logger.info(f"Skipped {skipped_duplicate} duplicate tensors (tied weights)")
return tensors
def log_tensor_summary(
tensors: dict[str, torch.Tensor], global_rank: int, label: str
) -> None:
total_size = sum(t.numel() * t.element_size() for t in tensors.values())
logger.info(
f"[Worker {global_rank}] {label}: {len(tensors)} tensors ({total_size / 1e9:.2f} GB)"
)
if logger.isEnabledFor(logging.DEBUG):
for name, t in tensors.items():
checksum = safe_checksum(t)
logger.debug(
f"[Worker {global_rank}] [CHECKSUM] {label} | {name} | "
f"shape={list(t.shape)} dtype={t.dtype} | {checksum}"
)