Files

153 lines
4.2 KiB
Python

def is_tensor_like(x):
return hasattr(x, "shape") and hasattr(x, "dtype")
def safe_shape(x):
try:
return list(x.shape)
except Exception:
return None
def safe_dtype(x):
try:
return str(x.dtype)
except Exception:
return None
def safe_device(x):
try:
return str(x.device)
except Exception:
return None
def safe_tensor_stats(x):
"""Return compact stats for tensor-like values without storing raw tensors."""
stats = {
"python_type": type(x).__name__,
"shape": safe_shape(x),
"dtype": safe_dtype(x),
"device": safe_device(x),
}
try:
import torch
if isinstance(x, torch.Tensor):
y = x.detach()
stats["numel"] = int(y.numel())
if y.numel() == 0:
return stats
yf = y.float()
stats.update({
"mean": float(yf.mean().item()),
"std": float(yf.std().item()) if y.numel() > 1 else 0.0,
"min": float(yf.min().item()),
"max": float(yf.max().item()),
"norm": float(torch.linalg.vector_norm(yf).item()),
"nan_count": int(torch.isnan(yf).sum().item()),
"inf_count": int(torch.isinf(yf).sum().item()),
})
except Exception as e:
stats["stats_error"] = str(e)
return stats
def extract_latent_samples(latent):
if isinstance(latent, dict) and "samples" in latent:
return latent["samples"]
return latent
def summarize_latent(latent):
if isinstance(latent, dict) and "samples" in latent:
stats = safe_tensor_stats(latent["samples"])
stats["latent_format"] = "dict_samples"
stats["dict_keys"] = list(latent.keys())
return stats
stats = safe_tensor_stats(latent)
stats["latent_format"] = "direct_or_unknown"
return stats
def summarize_image(image):
stats = safe_tensor_stats(image)
stats["image_format"] = "tensor_like_or_unknown"
return stats
def summarize_noise(noise):
stats = safe_tensor_stats(noise)
stats["noise_format"] = "tensor_like_or_unknown"
return stats
def summarize_delta(delta, before=None):
stats = safe_tensor_stats(delta)
stats["delta_format"] = "tensor_like_or_unknown"
if stats.get("norm") is not None:
stats["delta_norm"] = stats.get("norm")
try:
before_stats = safe_tensor_stats(before) if before is not None else {}
before_norm = before_stats.get("norm")
if before_norm is not None:
eps = 1e-12
stats["before_norm"] = before_norm
stats["relative_delta"] = float(stats.get("delta_norm", 0.0) / max(abs(before_norm), eps))
except Exception as e:
stats["relative_delta_error"] = str(e)
return stats
def summarize_conditioning(cond):
summary = {
"python_type": type(cond).__name__,
"shape": safe_shape(cond),
"dtype": safe_dtype(cond),
"device": safe_device(cond),
}
try:
summary["length"] = len(cond)
except Exception:
summary["length"] = None
nested = []
try:
if isinstance(cond, (list, tuple)):
for i, item in enumerate(cond[:8]):
if isinstance(item, (list, tuple)):
nested.append({"index": i, "type": type(item).__name__, "length": len(item)})
elif isinstance(item, dict):
nested.append({"index": i, "type": "dict", "keys": list(item.keys())})
else:
nested.append({"index": i, "type": type(item).__name__, "shape": safe_shape(item)})
except Exception as e:
summary["nested_error"] = str(e)
if nested:
summary["nested_summary"] = nested
return summary
def compute_tensor_delta(before, after):
"""Try to compute after - before for tensor-like values.
Returns (delta, error_string).
"""
b = extract_latent_samples(before)
a = extract_latent_samples(after)
try:
if safe_shape(b) != safe_shape(a):
return None, f"shape mismatch: before={safe_shape(b)} after={safe_shape(a)}"
delta = a - b
return delta, ""
except Exception as e:
return None, str(e)