coarse-grained-forecasting-benchmark's picture
Add anonymous reproduction code
41dd7e0 verified
Raw History Blame Contribute Delete
2.62 kB
"""EDMMethod — wraps the math in core.py."""
import torch
from ..base import Method
from . import core
class EDMMethod(Method):
"""EDM (Karras et al. 2022) for conditional endpoint prediction.
Hyperparameters
---------------
sigma_data : float
EDM σ_data; matches the empirical per-feature std of the (normalized)
training x_T. For data normalized to unit variance per feature this is
1.0.
P_mean, P_std : float
Log-normal training-σ sampler (Table 1 of the EDM paper).
sampling : dict
Keys: n_steps, sigma_min, sigma_max, rho. Used by Heun's sampler.
"""
def __init__(self, sigma_data: float, P_mean: float, P_std: float, sampling: dict,
optimizer_cfg: dict | None = None):
self.sigma_data = float(sigma_data)
self.P_mean = float(P_mean)
self.P_std = float(P_std)
self.n_steps = int(sampling["n_steps"])
self.sigma_min = float(sampling["sigma_min"])
self.sigma_max = float(sampling["sigma_max"])
self.rho = float(sampling["rho"])
# Picked up by base Method.configure_optimizer; defaults to plain Adam.
self.optimizer_cfg = optimizer_cfg or {}
@classmethod
def from_config(cls, cfg: dict) -> "EDMMethod":
return cls(
sigma_data=cfg["sigma_data"],
P_mean=cfg["P_mean"],
P_std=cfg["P_std"],
sampling=cfg["sampling"],
optimizer_cfg=cfg.get("optimizer"),
)
def loss(self, model: torch.nn.Module, batch) -> torch.Tensor:
x_0, x_T = batch
return core.edm_loss(model, x_T, x_0, self.sigma_data, self.P_mean, self.P_std)
def sample(self, model: torch.nn.Module, x_0: torch.Tensor, n_samples: int) -> torch.Tensor:
"""Return Heun-sampled clouds, shape [B, n_samples, D].
x_0 may be either a single conditioning vector of shape (D,) or a
batch of shape (B, D). The output is always (B, n_samples, D).
"""
device = next(model.parameters()).device
if x_0.ndim == 1:
x_0 = x_0.unsqueeze(0)
B = x_0.shape[0]
clouds = []
for i in range(B):
cloud = core.heun_sample(
model,
x_0[i],
n_samples=n_samples,
N=self.n_steps,
sigma_min=self.sigma_min,
sigma_max=self.sigma_max,
rho=self.rho,
sigma_data=self.sigma_data,
device=device,
)
clouds.append(cloud)
return torch.stack(clouds, dim=0)