594 lines
20 KiB
Python
594 lines
20 KiB
Python
# PI_code_test_FNO_inference.py
|
|
# =========================================================
|
|
# ✅ Inference ONLY for Encoder+FNO (no DDP, no training)
|
|
# ✅ Can read BOTH MATLAB v7 (scipy.io.loadmat) and v7.3 (HDF5 via h5py)
|
|
# ✅ Added: accurate inference timing (CUDA synchronized) + save timing into .mat
|
|
#
|
|
# Input .mat must contain (names can vary, see candidates below):
|
|
# - Rimg : (N,1,512,512) OR (512,512,N) OR (512,512) OR (1,512,512)
|
|
# - coords: (M,2) in [-1,1] (or (1,M,2))
|
|
#
|
|
# Output .mat:
|
|
# - E_pred : (N,M,2) float32 (Re, Im)
|
|
# - coords_xy : (M,2) float32
|
|
# - Rimg : (N,1,512,512) float32
|
|
# - meta_* : timing + shapes + ckpt path
|
|
# =========================================================
|
|
|
|
import argparse
|
|
import math
|
|
import time
|
|
from pathlib import Path
|
|
|
|
import numpy as np
|
|
import torch
|
|
import torch.nn as nn
|
|
from scipy.io import loadmat, savemat
|
|
|
|
|
|
# -------------------------
|
|
# Utils
|
|
# -------------------------
|
|
def make_gn(num_channels: int, max_groups: int = 8) -> nn.GroupNorm:
|
|
for g in [max_groups, 4, 2, 1]:
|
|
if num_channels % g == 0:
|
|
return nn.GroupNorm(num_groups=g, num_channels=num_channels)
|
|
return nn.GroupNorm(num_groups=1, num_channels=num_channels)
|
|
|
|
|
|
def _pick_key(d, keys):
|
|
for k in keys:
|
|
if k in d:
|
|
return k
|
|
return None
|
|
|
|
|
|
def _as_numpy_from_h5(obj):
|
|
"""
|
|
Convert h5py dataset to numpy.
|
|
MATLAB v7.3 stores arrays in column-major and often with transposed dims;
|
|
We will reshape/transpose later in the Rimg handler.
|
|
"""
|
|
import numpy as _np
|
|
return _np.array(obj)
|
|
|
|
|
|
def load_mat_auto(mat_path: str):
|
|
"""
|
|
Load .mat file:
|
|
- MATLAB v7.2 and below: scipy.io.loadmat
|
|
- MATLAB v7.3 (HDF5): h5py
|
|
Returns: dict-like mapping name -> numpy array
|
|
"""
|
|
mat_path = str(mat_path)
|
|
try:
|
|
data = loadmat(mat_path)
|
|
# remove matlab meta keys if exist
|
|
return {k: v for k, v in data.items() if not k.startswith("__")}
|
|
except NotImplementedError:
|
|
import h5py
|
|
data = {}
|
|
with h5py.File(mat_path, "r") as f:
|
|
for k in f.keys():
|
|
data[k] = _as_numpy_from_h5(f[k])
|
|
return data
|
|
|
|
|
|
def load_meta_inference_mat(mat_in: str):
|
|
"""
|
|
Returns:
|
|
Rimg_np: (N,1,512,512) float32
|
|
coords_np: (M,2) float32
|
|
"""
|
|
data = load_mat_auto(mat_in)
|
|
|
|
# candidates (you can add more if needed)
|
|
k_r = _pick_key(data, ["Rimg", "rimg", "geom", "geometry", "M"])
|
|
k_c = _pick_key(data, ["coords", "coord", "coords_xy", "xy"])
|
|
|
|
if k_r is None or k_c is None:
|
|
raise KeyError(
|
|
f"[meta_inference] mat must contain geometry + coords.\n"
|
|
f"Found keys: {list(data.keys())}\n"
|
|
f"Geometry candidates: [Rimg,rimg,geom,geometry,M]\n"
|
|
f"Coords candidates: [coords,coord,coords_xy,xy]"
|
|
)
|
|
|
|
Rimg_np = np.array(data[k_r])
|
|
coords_np = np.array(data[k_c])
|
|
|
|
# ---- coords -> (M,2)
|
|
coords_np = np.squeeze(coords_np)
|
|
|
|
# MATLAB v7.3 (h5py) sometimes gives (2,M) for a (M,2) saved matrix
|
|
if coords_np.ndim == 2 and coords_np.shape[0] == 2 and coords_np.shape[1] != 2:
|
|
coords_np = coords_np.T
|
|
|
|
if coords_np.ndim != 2 or coords_np.shape[1] != 2:
|
|
raise ValueError(f"[meta_inference] coords must be (M,2). Got {coords_np.shape}")
|
|
coords_np = coords_np.astype(np.float32)
|
|
|
|
# ---- Rimg -> (N,1,512,512)
|
|
Rimg_np = np.squeeze(Rimg_np)
|
|
|
|
if Rimg_np.ndim == 2:
|
|
# (512,512)
|
|
Rimg_np = Rimg_np[None, None, :, :]
|
|
|
|
elif Rimg_np.ndim == 3:
|
|
# could be (512,512,N) OR (N,512,512) OR (1,512,512)
|
|
if Rimg_np.shape[0] == 1 and Rimg_np.shape[1] == 512 and Rimg_np.shape[2] == 512:
|
|
Rimg_np = Rimg_np[:, None, :, :] # (1,1,512,512)
|
|
|
|
elif Rimg_np.shape[0] == 512 and Rimg_np.shape[1] == 512:
|
|
# (512,512,N) -> (N,1,512,512)
|
|
Rimg_np = np.transpose(Rimg_np, (2, 0, 1))[:, None, :, :]
|
|
|
|
elif Rimg_np.shape[1] == 512 and Rimg_np.shape[2] == 512:
|
|
# (N,512,512) -> (N,1,512,512)
|
|
Rimg_np = Rimg_np[:, None, :, :]
|
|
|
|
else:
|
|
raise ValueError(f"[meta_inference] Unrecognized Rimg 3D shape: {Rimg_np.shape}")
|
|
|
|
elif Rimg_np.ndim == 4:
|
|
# could be (N,1,512,512) OR (1,512,512,N) OR (512,512,1,N) etc.
|
|
if Rimg_np.shape[1] == 1 and Rimg_np.shape[2] == 512 and Rimg_np.shape[3] == 512:
|
|
# (N,1,512,512)
|
|
pass
|
|
|
|
elif Rimg_np.shape[0] == 1 and Rimg_np.shape[1] == 512 and Rimg_np.shape[2] == 512:
|
|
# (1,512,512,N) -> (N,1,512,512)
|
|
Rimg_np = np.transpose(Rimg_np, (3, 0, 1, 2))
|
|
|
|
elif Rimg_np.shape[0] == 512 and Rimg_np.shape[1] == 512 and Rimg_np.shape[2] == 1:
|
|
# (512,512,1,N) -> (N,1,512,512)
|
|
Rimg_np = np.transpose(Rimg_np, (3, 2, 0, 1))
|
|
|
|
else:
|
|
raise ValueError(f"[meta_inference] Unrecognized Rimg 4D shape: {Rimg_np.shape}")
|
|
|
|
else:
|
|
raise ValueError(f"[meta_inference] Unrecognized Rimg shape: {Rimg_np.shape}")
|
|
|
|
if Rimg_np.shape[1] != 1 or Rimg_np.shape[-2:] != (512, 512):
|
|
raise ValueError(f"[meta_inference] Rimg must be (N,1,512,512). Got {Rimg_np.shape}")
|
|
|
|
return Rimg_np.astype(np.float32), coords_np.astype(np.float32)
|
|
|
|
|
|
# -------------------------
|
|
# FNO core
|
|
# -------------------------
|
|
class FFTConv2d(nn.Module):
|
|
def __init__(self, in_channels: int, out_channels: int, modes: int):
|
|
super().__init__()
|
|
self.out_channels = out_channels
|
|
self.modes = int(modes)
|
|
self.w = nn.Parameter(
|
|
torch.rand(in_channels, out_channels, 2 * self.modes, self.modes, 2)
|
|
/ (in_channels * out_channels)
|
|
)
|
|
|
|
@staticmethod
|
|
def cmul2d(a, b):
|
|
return torch.einsum("bixy,ioxy->boxy", a, b)
|
|
|
|
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
|
B, C, H, W = x.shape
|
|
device = x.device
|
|
|
|
x_ft = torch.fft.rfft2(x) # (B,C,H,Wf)
|
|
Wf = x_ft.size(-1)
|
|
|
|
my = min(self.modes, H // 2)
|
|
mx = min(self.modes, Wf)
|
|
|
|
out_ft = torch.zeros(B, self.out_channels, H, Wf, dtype=torch.cfloat, device=device)
|
|
|
|
x_ft = torch.fft.fftshift(x_ft, dim=-2)
|
|
cy = H // 2
|
|
|
|
a = x_ft[..., cy - my: cy + my, :mx] # (B,inC,2*my,mx)
|
|
w_c = torch.view_as_complex(self.w) # (inC,outC,2*modes,modes)
|
|
b = w_c[..., self.modes - my: self.modes + my, :mx]
|
|
out_ft[..., cy - my: cy + my, :mx] = self.cmul2d(a, b)
|
|
|
|
out_ft = torch.fft.ifftshift(out_ft, dim=-2)
|
|
x = torch.fft.irfft2(out_ft, s=(H, W))
|
|
return x
|
|
|
|
|
|
class FNOBlock2d(nn.Module):
|
|
def __init__(self, modes: int, width: int, norm: str = "gn", dropout: float = 0.10, layerscale=0.10):
|
|
super().__init__()
|
|
self.fftconv = FFTConv2d(width, width, modes)
|
|
self.conv = nn.Conv2d(width, width, 1, bias=False)
|
|
|
|
self.norm = nn.BatchNorm2d(width) if norm == "bn" else make_gn(width)
|
|
self.act = nn.GELU()
|
|
self.drop = nn.Dropout2d(p=float(dropout)) if dropout and dropout > 0 else nn.Identity()
|
|
self.gamma = nn.Parameter(layerscale * torch.ones(1, width, 1, 1)) if layerscale and layerscale > 0 else None
|
|
|
|
def forward(self, x):
|
|
y = self.fftconv(x) + self.conv(x)
|
|
x = x + (self.gamma * y if self.gamma is not None else y)
|
|
x = self.norm(x)
|
|
x = self.act(x)
|
|
x = self.drop(x)
|
|
return x
|
|
|
|
|
|
class FNOModel2d(nn.Module):
|
|
def __init__(
|
|
self,
|
|
modes=6,
|
|
width=24,
|
|
blocks=4,
|
|
padding=0,
|
|
in_channels=3,
|
|
out_channels=2,
|
|
norm="gn",
|
|
dropout=0.10,
|
|
layerscale=0.10,
|
|
):
|
|
super().__init__()
|
|
self.conv_in = nn.Conv2d(in_channels, width, 1, bias=True)
|
|
|
|
self.padding = int(padding)
|
|
self.pad_in = nn.ConstantPad2d(self.padding, 0.0) if self.padding > 0 else nn.Identity()
|
|
self.pad_out = nn.ConstantPad2d(-self.padding, 0.0) if self.padding > 0 else nn.Identity()
|
|
|
|
self.fno_blocks = nn.Sequential(
|
|
*[FNOBlock2d(modes, width, norm=norm, dropout=dropout, layerscale=layerscale) for _ in range(blocks)]
|
|
)
|
|
|
|
self.conv_out = nn.Sequential(
|
|
nn.Conv2d(width, width, 1),
|
|
nn.GELU(),
|
|
nn.Dropout2d(dropout),
|
|
nn.Conv2d(width, out_channels, 1),
|
|
)
|
|
|
|
def forward(self, x):
|
|
x = self.conv_in(x)
|
|
x = self.pad_in(x)
|
|
x = self.fno_blocks(x)
|
|
x = self.pad_out(x)
|
|
x = self.conv_out(x)
|
|
return x
|
|
|
|
|
|
# -------------------------
|
|
# Geometry Encoder
|
|
# -------------------------
|
|
class GeomEncoder(nn.Module):
|
|
def __init__(self, out_ch=8, drop=0.10):
|
|
super().__init__()
|
|
self.prepool = nn.AvgPool2d(kernel_size=6, stride=6) # 512 -> ~85
|
|
|
|
self.net = nn.Sequential(
|
|
nn.Conv2d(1, 16, 3, padding=1, bias=False),
|
|
make_gn(16), nn.GELU(), nn.Dropout2d(drop),
|
|
|
|
nn.Conv2d(16, 24, 3, stride=2, padding=1, bias=False), # ~85 -> ~43
|
|
make_gn(24), nn.GELU(), nn.Dropout2d(drop),
|
|
|
|
nn.Conv2d(24, 32, 3, stride=2, padding=1, bias=False), # ~43 -> ~22
|
|
make_gn(32), nn.GELU(), nn.Dropout2d(drop),
|
|
|
|
nn.Conv2d(32, out_ch, 1, bias=True),
|
|
make_gn(out_ch), nn.GELU(),
|
|
)
|
|
self.pool_to = None
|
|
|
|
def forward(self, x_img, Ny, Nx):
|
|
h = self.prepool(x_img)
|
|
h = self.net(h)
|
|
if (self.pool_to is None) or (self.pool_to.output_size != (Ny, Nx)):
|
|
self.pool_to = nn.AdaptiveAvgPool2d((Ny, Nx))
|
|
return self.pool_to(h)
|
|
|
|
|
|
# -------------------------
|
|
# Optional Fourier features (OFF by default)
|
|
# -------------------------
|
|
class FourierFeatures2D(nn.Module):
|
|
def __init__(self, K=2, scale=1.0):
|
|
super().__init__()
|
|
self.K = int(K)
|
|
self.scale = float(scale)
|
|
freqs = torch.linspace(1.0, self.K, steps=self.K) * self.scale
|
|
self.register_buffer("freqs", freqs, persistent=False)
|
|
|
|
def forward(self, xy):
|
|
x = xy[:, 0:1]
|
|
y = xy[:, 1:2]
|
|
f = self.freqs.view(1, self.K, 1, 1)
|
|
x_proj = 2 * math.pi * x * f
|
|
y_proj = 2 * math.pi * y * f
|
|
return torch.cat([torch.sin(x_proj), torch.cos(x_proj), torch.sin(y_proj), torch.cos(y_proj)], dim=1)
|
|
|
|
|
|
# -------------------------
|
|
# Regressor: Encoder + (xy [+ optional Fourier]) + FNO
|
|
# -------------------------
|
|
class FNOFieldRegressor_EncoderFNO(nn.Module):
|
|
def __init__(
|
|
self,
|
|
modes=6,
|
|
width=24,
|
|
blocks=4,
|
|
padding=0,
|
|
norm="gn",
|
|
dropout=0.10,
|
|
layerscale=0.10,
|
|
geom_ch=8,
|
|
use_fourier=False,
|
|
fourier_K=2,
|
|
fourier_scale=1.0,
|
|
dropout_xy=0.05,
|
|
):
|
|
super().__init__()
|
|
self.encoder = GeomEncoder(out_ch=geom_ch, drop=0.10)
|
|
|
|
self.use_fourier = bool(use_fourier)
|
|
self.fourier = FourierFeatures2D(K=fourier_K, scale=fourier_scale) if self.use_fourier else None
|
|
self.drop_xy = nn.Dropout2d(dropout_xy) if dropout_xy and dropout_xy > 0 else nn.Identity()
|
|
|
|
in_ch = geom_ch + 2 + (4 * fourier_K if self.use_fourier else 0)
|
|
|
|
self.fno = FNOModel2d(
|
|
modes=modes,
|
|
width=width,
|
|
blocks=blocks,
|
|
padding=padding,
|
|
in_channels=in_ch,
|
|
out_channels=2,
|
|
norm=norm,
|
|
dropout=dropout,
|
|
layerscale=layerscale,
|
|
)
|
|
|
|
self._cached_key = None
|
|
self._cached_xy = None # (1,2,Ny,Nx)
|
|
|
|
@staticmethod
|
|
def _sanitize_coords(coords: torch.Tensor) -> torch.Tensor:
|
|
if coords.dim() == 4:
|
|
coords = coords[:, 0, :, :]
|
|
return coords
|
|
|
|
@staticmethod
|
|
def _coords_to_xy_grid(coords: torch.Tensor):
|
|
coords0 = coords[0] if coords.dim() == 3 else coords # (M,2)
|
|
x = coords0[:, 0]
|
|
y = coords0[:, 1]
|
|
|
|
xs = torch.unique(x)
|
|
ys = torch.unique(y)
|
|
xs, _ = torch.sort(xs)
|
|
ys, _ = torch.sort(ys)
|
|
|
|
Ny, Nx = ys.numel(), xs.numel()
|
|
yy, xx = torch.meshgrid(ys, xs, indexing="ij")
|
|
xy = torch.stack([xx, yy], dim=0).unsqueeze(0) # (1,2,Ny,Nx)
|
|
return xy, int(Ny), int(Nx)
|
|
|
|
def forward(self, x_img: torch.Tensor, coords: torch.Tensor):
|
|
B = x_img.shape[0]
|
|
device = x_img.device
|
|
dtype = x_img.dtype
|
|
|
|
coords = self._sanitize_coords(coords).to(device=device)
|
|
xy, Ny, Nx = self._coords_to_xy_grid(coords)
|
|
|
|
key = (Ny, Nx, device.type, getattr(device, "index", None), str(dtype))
|
|
if self._cached_key != key:
|
|
self._cached_key = key
|
|
self._cached_xy = xy.to(device=device, dtype=dtype)
|
|
|
|
xy_b = self._cached_xy.expand(B, -1, -1, -1)
|
|
xy_b = self.drop_xy(xy_b)
|
|
|
|
geom_feat = self.encoder(x_img, Ny, Nx)
|
|
|
|
if self.use_fourier:
|
|
ff = self.fourier(xy_b)
|
|
inp = torch.cat([geom_feat, xy_b, ff], dim=1)
|
|
else:
|
|
inp = torch.cat([geom_feat, xy_b], dim=1)
|
|
|
|
out = self.fno(inp) # (B,2,Ny,Nx)
|
|
out = out.permute(0, 2, 3, 1).contiguous().view(B, Ny * Nx, 2)
|
|
return out
|
|
|
|
|
|
# -------------------------
|
|
# Inference
|
|
# -------------------------
|
|
@torch.no_grad()
|
|
def run_inference(
|
|
mat_in: str,
|
|
ckpt: str,
|
|
mat_out: str,
|
|
device: str,
|
|
batch_size: int,
|
|
modes: int,
|
|
width: int,
|
|
blocks: int,
|
|
padding: int,
|
|
dropout: float,
|
|
layerscale: float,
|
|
geom_ch: int,
|
|
use_fourier: bool,
|
|
fourier_K: int,
|
|
fourier_scale: float,
|
|
dropout_xy: float,
|
|
):
|
|
Rimg_np, coords_np = load_meta_inference_mat(mat_in)
|
|
N = int(Rimg_np.shape[0])
|
|
M = int(coords_np.shape[0])
|
|
|
|
dev = torch.device(device if torch.cuda.is_available() else "cpu")
|
|
|
|
model = FNOFieldRegressor_EncoderFNO(
|
|
modes=modes,
|
|
width=width,
|
|
blocks=blocks,
|
|
padding=padding,
|
|
norm="gn",
|
|
dropout=dropout,
|
|
layerscale=layerscale,
|
|
geom_ch=geom_ch,
|
|
use_fourier=use_fourier,
|
|
fourier_K=fourier_K,
|
|
fourier_scale=fourier_scale,
|
|
dropout_xy=dropout_xy,
|
|
).to(dev)
|
|
|
|
# load weights
|
|
try:
|
|
state = torch.load(ckpt, map_location="cpu", weights_only=True)
|
|
except TypeError:
|
|
state = torch.load(ckpt, map_location="cpu")
|
|
model.load_state_dict(state, strict=True)
|
|
model.eval()
|
|
|
|
coords_t = torch.from_numpy(coords_np).to(dev).unsqueeze(0) # (1,M,2)
|
|
|
|
# ---- timing helpers (CUDA safe)
|
|
def _sync():
|
|
if dev.type == "cuda":
|
|
torch.cuda.synchronize(dev)
|
|
|
|
# warmup (recommended)
|
|
warmup_steps = min(2, (N + batch_size - 1) // batch_size)
|
|
for wi in range(warmup_steps):
|
|
s = wi * batch_size
|
|
e = min(N, s + batch_size)
|
|
x_img = torch.from_numpy(Rimg_np[s:e]).to(dev, dtype=torch.float32)
|
|
coords_b = coords_t.expand(e - s, -1, -1).contiguous()
|
|
_ = model(x_img, coords_b)
|
|
_sync()
|
|
|
|
preds = []
|
|
t_total0 = time.perf_counter()
|
|
forward_time_sum = 0.0
|
|
num_samples_done = 0
|
|
|
|
for s in range(0, N, batch_size):
|
|
e = min(N, s + batch_size)
|
|
x_img = torch.from_numpy(Rimg_np[s:e]).to(dev, dtype=torch.float32)
|
|
coords_b = coords_t.expand(e - s, -1, -1).contiguous()
|
|
|
|
_sync()
|
|
t0 = time.perf_counter()
|
|
pred = model(x_img, coords_b) # (B,M,2)
|
|
_sync()
|
|
t1 = time.perf_counter()
|
|
|
|
forward_time_sum += (t1 - t0)
|
|
num_samples_done += (e - s)
|
|
|
|
preds.append(pred.detach().cpu().numpy().astype(np.float32))
|
|
|
|
t_total1 = time.perf_counter()
|
|
total_time = t_total1 - t_total0
|
|
|
|
avg_time_per_sample = total_time / max(num_samples_done, 1)
|
|
avg_forward_per_sample = forward_time_sum / max(num_samples_done, 1)
|
|
|
|
fps_total = num_samples_done / max(total_time, 1e-12)
|
|
fps_forward = num_samples_done / max(forward_time_sum, 1e-12)
|
|
|
|
E_pred = np.concatenate(preds, axis=0) # (N,M,2)
|
|
|
|
print("========== Inference Timing ==========")
|
|
print(f"[Time] total elapsed : {total_time:.6f} s")
|
|
print(f"[Time] total forward (model) : {forward_time_sum:.6f} s")
|
|
print(f"[Time] avg elapsed / sample : {avg_time_per_sample*1e3:.3f} ms")
|
|
print(f"[Time] avg forward / sample : {avg_forward_per_sample*1e3:.3f} ms")
|
|
print(f"[Perf] throughput (total) : {fps_total:.3f} samples/s")
|
|
print(f"[Perf] throughput (forward) : {fps_forward:.3f} samples/s")
|
|
print("======================================")
|
|
|
|
savemat(
|
|
mat_out,
|
|
{
|
|
"E_pred": E_pred,
|
|
"coords_xy": coords_np.astype(np.float32),
|
|
"meta_ckpt": str(ckpt),
|
|
"meta_N": np.int64(N),
|
|
"meta_M": np.int64(M),
|
|
|
|
# timing meta
|
|
"meta_time_total_s": np.float64(total_time),
|
|
"meta_time_forward_s": np.float64(forward_time_sum),
|
|
"meta_ms_per_sample_total": np.float64(avg_time_per_sample * 1e3),
|
|
"meta_ms_per_sample_forward": np.float64(avg_forward_per_sample * 1e3),
|
|
"meta_throughput_total_sps": np.float64(fps_total),
|
|
"meta_throughput_forward_sps": np.float64(fps_forward),
|
|
},
|
|
)
|
|
|
|
print(f"[OK] mat_in : {mat_in}")
|
|
print(f"[OK] ckpt : {ckpt}")
|
|
print(f"[OK] mat_out : {mat_out}")
|
|
print(f"[OK] shapes : Rimg={Rimg_np.shape}, coords={coords_np.shape}, E_pred={E_pred.shape}")
|
|
|
|
|
|
def parse_args():
|
|
p = argparse.ArgumentParser("Inference only: Encoder+FNO")
|
|
p.add_argument("--mat_in", type=str, default="meta_inference.mat")
|
|
p.add_argument("--ckpt", type=str, default="fno_ddpsafe_best.pth")
|
|
p.add_argument("--mat_out", type=str, default="meta_inference_pred.mat")
|
|
p.add_argument("--device", type=str, default="cuda:0")
|
|
p.add_argument("--batch_size", type=int, default=16)
|
|
|
|
# must match training hyperparameters
|
|
p.add_argument("--modes", type=int, default=6)
|
|
p.add_argument("--width", type=int, default=24)
|
|
p.add_argument("--blocks", type=int, default=4)
|
|
p.add_argument("--padding", type=int, default=0)
|
|
p.add_argument("--dropout", type=float, default=0.10)
|
|
p.add_argument("--layerscale", type=float, default=0.10)
|
|
p.add_argument("--geom_ch", type=int, default=8)
|
|
|
|
p.add_argument("--use_fourier", action="store_true")
|
|
p.add_argument("--fourier_K", type=int, default=2)
|
|
p.add_argument("--fourier_scale", type=float, default=1.0)
|
|
p.add_argument("--dropout_xy", type=float, default=0.05)
|
|
return p.parse_args()
|
|
|
|
|
|
def main():
|
|
args = parse_args()
|
|
|
|
if not Path(args.mat_in).exists():
|
|
raise FileNotFoundError(f"Input mat not found: {args.mat_in}")
|
|
if not Path(args.ckpt).exists():
|
|
raise FileNotFoundError(f"Checkpoint not found: {args.ckpt}")
|
|
|
|
run_inference(
|
|
mat_in=args.mat_in,
|
|
ckpt=args.ckpt,
|
|
mat_out=args.mat_out,
|
|
device=args.device,
|
|
batch_size=args.batch_size,
|
|
modes=args.modes,
|
|
width=args.width,
|
|
blocks=args.blocks,
|
|
padding=args.padding,
|
|
dropout=args.dropout,
|
|
layerscale=args.layerscale,
|
|
geom_ch=args.geom_ch,
|
|
use_fourier=bool(args.use_fourier),
|
|
fourier_K=args.fourier_K,
|
|
fourier_scale=args.fourier_scale,
|
|
dropout_xy=args.dropout_xy,
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main() |