coarse-grained-forecasting-benchmark's picture
Add anonymous reproduction code
41dd7e0 verified
Raw History Blame Contribute Delete
2.79 kB
from __future__ import annotations
import torch
from ..base import Method
from . import core
class CascadedSIMethod(Method):
def __init__(self, sigma_train, t_eps, sampling, beta_power=1,
eval_noise_scales=None, optimizer_cfg=None):
self.sigma_train = float(sigma_train)
self.t_eps = float(t_eps)
self.beta_power = int(beta_power)
self.n_sde_steps_per_seg = int(sampling["n_sde_steps_per_seg"])
self.n_segments = int(sampling.get("n_segments", 10))
self.noise_scale = float(sampling.get("noise_scale", 1.0))
# Segment boundaries — uniform partition of [0, 1] by default, matching
# the normalized physical forecast horizon.
if "t_values" in sampling:
self.t_values = list(sampling["t_values"])
else:
self.t_values = [k / self.n_segments for k in range(self.n_segments + 1)]
self.eval_noise_scales = ([float(s) for s in eval_noise_scales]
if eval_noise_scales is not None else [self.noise_scale])
self.optimizer_cfg = optimizer_cfg or {}
@classmethod
def from_config(cls, cfg):
if cfg.get("anchor_ic", False):
raise ValueError("This release supports the paper's SI models without retained initial-state inputs")
return cls(
sigma_train=cfg["sigma_train"],
t_eps=cfg.get("t_eps", 0.0),
sampling=cfg["sampling"],
beta_power=cfg.get("beta_power", 1),
eval_noise_scales=cfg.get("eval_noise_scales"),
optimizer_cfg=cfg.get("optimizer"),
)
def variants_for_eval(self):
return {f"noise_scale_{_fmt(s)}": {"noise_scale": s} for s in self.eval_noise_scales}
def loss(self, model, batch):
x_tk, x_tk1, t_k, t_k1 = batch
return core.local_si_loss(model, x_tk, x_tk1, t_k, t_k1,
sigma=self.sigma_train, t_eps=self.t_eps,
beta_power=self.beta_power)
def sample(self, model, x_0, n_samples, noise_scale=None):
if noise_scale is None:
noise_scale = self.noise_scale
if x_0.ndim == 1:
x_0 = x_0.unsqueeze(0)
B = x_0.shape[0]
out = []
for i in range(B):
cloud = core.rollout(model, x_0[i], n_samples=n_samples,
t_values=self.t_values,
n_sde_steps_per_seg=self.n_sde_steps_per_seg,
sigma=self.sigma_train,
noise_scale=noise_scale)
out.append(cloud)
return torch.stack(out, dim=0)
def _fmt(s):
if s == int(s):
return f"{int(s)}p0"
return f"{s}".replace(".", "p")