coarse-grained-forecasting-benchmark's picture
Add anonymous reproduction code
41dd7e0 verified
Raw History Blame Contribute Delete
4.62 kB
"""Two-component U-Net for nonlinear Klein-Gordon forecasts.
The state contains 196 coarse displacement coordinates and 196 scaled velocity
coordinates. The segment head receives both components of the noisy state and
conditioning state, together with interpolation time and segment boundaries.
It emits both components through the shared periodic U-Net and frozen spectral
normalization wrappers. Internal parameter names are retained for checkpoint loading."""
from __future__ import annotations
import torch
from ..registry import register_model
from .unet2 import K_C, _broadcast_scalar, _PeriodicUNet2Core, _require_packaged, _SpectralFieldWrapper
class _TwoComponent(_PeriodicUNet2Core):
"""Shared plumbing: one frozen wrapper applied to each half of the 2*D_c state vector."""
def __init__(self, D: int = 392, base_channels: int = 64, n_grid: int = 32, k_c: int = K_C,
packaged: str | None = None, dropout: float = 0.0, in_channels: int = 7):
super().__init__(in_channels=in_channels, base_channels=base_channels, dropout=dropout,
out_channels=2)
self.D = int(D)
if packaged is None:
raise ValueError("unet2_2comp needs the training dataset's normalization: pass packaged")
# one wrapper per component, each with that component's slice of the frozen normalization
self.wrap = _SpectralFieldWrapper(packaged, n_grid, k_c, component=0)
self.wrap_im = _SpectralFieldWrapper(packaged, n_grid, k_c, component=1)
if self.wrap.D * 2 != self.D:
raise ValueError(f"two-component state needs D = 2 * {self.wrap.D}, got {self.D}")
self.Dc = self.wrap.D
def _fields(self, v: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]:
"""(B, 2*Dc) -> two (B, 1, Ng, Ng) field channels."""
return (self.wrap.inv(v[:, :self.Dc]).unsqueeze(1),
self.wrap_im.inv(v[:, self.Dc:]).unsqueeze(1))
def _vec(self, field2: torch.Tensor) -> torch.Tensor:
"""(B, 2, Ng, Ng) -> (B, 2*Dc)."""
return torch.cat([self.wrap.fwd(field2[:, 0]), self.wrap_im.fwd(field2[:, 1])], dim=1)
class LocalDrift2Comp(_TwoComponent):
"""forward(x_tau, tau, x_tk, t_k, t_k1) -> (B, D); channels [Re/Im x_tau, Re/Im x_tk, tau, t_k, t_k1]."""
def forward(self, x_tau: torch.Tensor, tau: torch.Tensor, x_tk: torch.Tensor,
t_k: torch.Tensor, t_k1: torch.Tensor) -> torch.Tensor:
B, ng = x_tau.shape[0], self.wrap.n_grid
a_re, a_im = self._fields(x_tau)
b_re, b_im = self._fields(x_tk)
tau_bc = _broadcast_scalar(tau, B, ng)
tk_bc = t_k.view(B, 1, 1, 1).expand(B, 1, ng, ng)
tk1_bc = t_k1.view(B, 1, 1, 1).expand(B, 1, ng, ng)
out = self._forward_core(torch.cat([a_re, a_im, b_re, b_im, tau_bc, tk_bc, tk1_bc], dim=1))
return self._vec(out)
@classmethod
def from_config(cls, cfg: dict) -> "LocalDrift2Comp":
return cls(D=int(cfg.get("D", 392)), base_channels=int(cfg.get("base_channels", 64)),
n_grid=int(cfg.get("n_grid", 32)), k_c=int(cfg.get("k_c", K_C)),
packaged=_require_packaged(cfg), dropout=float(cfg.get("dropout", 0.0)))
class Conditional2Comp(LocalDrift2Comp):
"""Endpoint head with the segment head's interface (t_k = t_start, t_k1 = t_end), as unet2_5ch."""
def __init__(self, *args, t_start: float = 0.0, t_end: float = 1.0, **kwargs):
super().__init__(*args, **kwargs)
self.t_start, self.t_end = float(t_start), float(t_end)
def forward(self, x: torch.Tensor, sigma_embedded: torch.Tensor, x_0: torch.Tensor) -> torch.Tensor: # type: ignore[override]
B = x.shape[0]
tk = torch.full((B,), self.t_start, dtype=x.dtype, device=x.device)
tk1 = torch.full((B,), self.t_end, dtype=x.dtype, device=x.device)
return super().forward(x, sigma_embedded, x_0, tk, tk1)
@classmethod
def from_config(cls, cfg: dict) -> "Conditional2Comp":
return cls(D=int(cfg.get("D", 392)), base_channels=int(cfg.get("base_channels", 64)),
n_grid=int(cfg.get("n_grid", 32)), k_c=int(cfg.get("k_c", K_C)),
packaged=_require_packaged(cfg), dropout=float(cfg.get("dropout", 0.0)),
t_start=float(cfg.get("t_start", 0.0)), t_end=float(cfg.get("t_end", 1.0)))
register_model("unet2_2comp", endpoint_cls=Conditional2Comp, segment_cls=LocalDrift2Comp,
needs_dataset_norm=True,
description="two-component (Re,Im) coarse complex state; unet2 core, per-component FFT wrapper")