Download model/stablenn_phys.py from OneScience-Group/StableNN-Phys: direct link, hf CLI and curl.
- Browser
- Download file 2.16 kB
-
https://huggingface.co/OneScience-Group/StableNN-Phys/resolve/main/model/stablenn_phys.py
- Command line
-
hf download hf://OneScience-Group/StableNN-Phys/model/stablenn_phys.py
-
curl -L -o stablenn_phys.py https://huggingface.co/OneScience-Group/StableNN-Phys/resolve/main/model/stablenn_phys.py
2.16 kB
| import torch | |
| from torch import nn | |
| class StableNNPhys(nn.Module): | |
| def __init__(self, hidden_size=32, input_size=71, output_size=68): | |
| super().__init__() | |
| self.hidden_size = hidden_size | |
| self.input_size = input_size | |
| self.output_size = output_size | |
| self.hidden = nn.Linear(input_size, hidden_size) | |
| self.output = nn.Linear(hidden_size, output_size) | |
| self.bypass = nn.Linear(input_size, output_size) | |
| nn.init.zeros_(self.output.weight) | |
| nn.init.zeros_(self.output.bias) | |
| nn.init.zeros_(self.bypass.weight) | |
| nn.init.zeros_(self.bypass.bias) | |
| def forward(self, x): | |
| return self.output(torch.relu(self.hidden(x))) + self.bypass(x) | |
| def rollout(model, initial_state, surface, advection, state_mean, state_std, | |
| tendency_mean, tendency_std, dt_seconds=10800.0): | |
| """Integrate advection trapezoidally, then neural physics with Euler.""" | |
| states = [initial_state] | |
| physics = [] | |
| state = initial_state | |
| for step in range(surface.shape[1]): | |
| adv_now = advection[:, step] | |
| adv_next = advection[:, min(step + 1, advection.shape[1] - 1)] | |
| forced = state + 0.5 * dt_seconds * (adv_now + adv_next) | |
| surface_scaled = surface[:, step] / surface.new_tensor([100.0, 100.0, 1000.0]) | |
| features = torch.cat(((forced - state_mean) / state_std, surface_scaled), dim=-1) | |
| tendency = model(features) * tendency_std + tendency_mean | |
| state = forced + dt_seconds * tendency | |
| physics.append(tendency) | |
| states.append(state) | |
| return torch.stack(states, dim=1), torch.stack(physics, dim=1) | |
| def rollout_loss(prediction, target, layer_mass, mode="paper"): | |
| error = torch.abs(prediction[:, 1:] - target[:, 1:]) | |
| if mode == "paper": | |
| weights = torch.cat((layer_mass, layer_mass), dim=-1) | |
| weights = weights / weights.mean(dim=-1, keepdim=True) | |
| return (error * weights[:, None]).mean() | |
| if mode == "official_v0_3": | |
| scale = target[:, 1:].std(dim=(0, 1), unbiased=False).clamp_min(1e-6) | |
| return (error / scale).mean() | |
| raise ValueError(f"Unknown loss mode: {mode}") | |