zhangrenchao commited on
Commit
986404c
·
verified ·
1 Parent(s): 247ef44

Upload folder using huggingface_hub

Browse files
.gitattributes CHANGED
@@ -1,35 +1,47 @@
1
  *.7z filter=lfs diff=lfs merge=lfs -text
2
  *.arrow filter=lfs diff=lfs merge=lfs -text
3
  *.bin filter=lfs diff=lfs merge=lfs -text
 
4
  *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
  *.ftz filter=lfs diff=lfs merge=lfs -text
7
  *.gz filter=lfs diff=lfs merge=lfs -text
8
  *.h5 filter=lfs diff=lfs merge=lfs -text
9
  *.joblib filter=lfs diff=lfs merge=lfs -text
10
  *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
  *.model filter=lfs diff=lfs merge=lfs -text
13
  *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
  *.onnx filter=lfs diff=lfs merge=lfs -text
17
  *.ot filter=lfs diff=lfs merge=lfs -text
18
  *.parquet filter=lfs diff=lfs merge=lfs -text
19
  *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
  *.pt filter=lfs diff=lfs merge=lfs -text
23
  *.pth filter=lfs diff=lfs merge=lfs -text
24
  *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
  saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
  *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
  *.tflite filter=lfs diff=lfs merge=lfs -text
30
  *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
  *.xz filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
1
  *.7z filter=lfs diff=lfs merge=lfs -text
2
  *.arrow filter=lfs diff=lfs merge=lfs -text
3
  *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bin.* filter=lfs diff=lfs merge=lfs -text
5
  *.bz2 filter=lfs diff=lfs merge=lfs -text
 
6
  *.ftz filter=lfs diff=lfs merge=lfs -text
7
  *.gz filter=lfs diff=lfs merge=lfs -text
8
  *.h5 filter=lfs diff=lfs merge=lfs -text
9
  *.joblib filter=lfs diff=lfs merge=lfs -text
10
  *.lfs.* filter=lfs diff=lfs merge=lfs -text
 
11
  *.model filter=lfs diff=lfs merge=lfs -text
12
  *.msgpack filter=lfs diff=lfs merge=lfs -text
 
 
13
  *.onnx filter=lfs diff=lfs merge=lfs -text
14
  *.ot filter=lfs diff=lfs merge=lfs -text
15
  *.parquet filter=lfs diff=lfs merge=lfs -text
16
  *.pb filter=lfs diff=lfs merge=lfs -text
 
 
17
  *.pt filter=lfs diff=lfs merge=lfs -text
18
  *.pth filter=lfs diff=lfs merge=lfs -text
19
  *.rar filter=lfs diff=lfs merge=lfs -text
 
20
  saved_model/**/* filter=lfs diff=lfs merge=lfs -text
21
  *.tar.* filter=lfs diff=lfs merge=lfs -text
 
22
  *.tflite filter=lfs diff=lfs merge=lfs -text
23
  *.tgz filter=lfs diff=lfs merge=lfs -text
 
24
  *.xz filter=lfs diff=lfs merge=lfs -text
25
  *.zip filter=lfs diff=lfs merge=lfs -text
26
+ *.zstandard filter=lfs diff=lfs merge=lfs -text
27
+ *.tfevents* filter=lfs diff=lfs merge=lfs -text
28
+ *.db* filter=lfs diff=lfs merge=lfs -text
29
+ *.ark* filter=lfs diff=lfs merge=lfs -text
30
+ **/*ckpt*data* filter=lfs diff=lfs merge=lfs -text
31
+ **/*ckpt*.meta filter=lfs diff=lfs merge=lfs -text
32
+ **/*ckpt*.index filter=lfs diff=lfs merge=lfs -text
33
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
34
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
35
+ *.gguf* filter=lfs diff=lfs merge=lfs -text
36
+ *.ggml filter=lfs diff=lfs merge=lfs -text
37
+ *.llamafile* filter=lfs diff=lfs merge=lfs -text
38
+ *.pt2 filter=lfs diff=lfs merge=lfs -text
39
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
40
+ *.npy filter=lfs diff=lfs merge=lfs -text
41
+ *.npz filter=lfs diff=lfs merge=lfs -text
42
+ *.pickle filter=lfs diff=lfs merge=lfs -text
43
+ *.pkl filter=lfs diff=lfs merge=lfs -text
44
+ *.tar filter=lfs diff=lfs merge=lfs -text
45
+ *.wasm filter=lfs diff=lfs merge=lfs -text
46
  *.zst filter=lfs diff=lfs merge=lfs -text
47
  *tfevents* filter=lfs diff=lfs merge=lfs -text
README.md ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ frameworks: PyTorch
3
+ language:
4
+ - en
5
+ license: apache-2.0
6
+ tags:
7
+ - OneScience
8
+ - Earth Science
9
+ - Weather Downscaling
10
+ - Diffusion Model
11
+ - ERA5
12
+ - CorrDiff
13
+ - arxiv:2309.15214
14
+ tasks: []
15
+ datasets:
16
+ - OneScience/ERA5
17
+ ---
18
+
19
+ <p align="center">
20
+ <strong>
21
+ <span style="font-size: 30px;">CorrDiff</span>
22
+ </strong>
23
+ </p>
24
+
25
+ # Model Introduction
26
+
27
+ CorrDiff (Residual Corrective Diffusion Model) is a two-stage generative model for kilometer-scale regional weather downscaling. It downscales approximately 25 km ERA5 fields to approximately 2 km regional weather fields over Taiwan and synthesizes radar reflectivity that is not present in the input.
28
+
29
+ Paper: Residual Corrective Diffusion Modeling for Km-scale Atmospheric Downscaling
30
+
31
+ https://arxiv.org/abs/2309.15214
32
+
33
+ # Model Description
34
+
35
+ CorrDiff was proposed by NVIDIA and its collaborators for kilometer-scale regional weather downscaling and was trained with coarse-resolution ERA5 reanalysis and high-resolution WRF regional model data from Taiwan's Central Weather Administration.
36
+ The model is suitable for converting coarse-resolution global weather fields into high-resolution regional weather fields and producing probabilistic weather predictions.
37
+
38
+ # Use Cases
39
+
40
+ | Scenario | Description |
41
+ | :---: | :--- |
42
+ | Weather forecast training | Train CorrDiff with ERA5 HDF5 data. |
43
+ | Local quick validation | Use synthetic data to check data loading, model training, inference, and result visualization. |
44
+ | ModelScope / OneCode execution | Download the standalone model package, install dependencies, and run the scripts directly. |
45
+ | Multi-GPU training | Launch multi-process training with `torchrun`. |
46
+
47
+ # Usage Guide
48
+
49
+ ## 1. OneCode Usage
50
+
51
+ Experience intelligent one-click AI4S programming through the OneCode online environment:
52
+
53
+ [Click to Experience Intelligent One-Click AI4S Programming](https://web-2069360198568017922-iaaj.ksai.scnet.cn:58043/home)
54
+
55
+ ## 2. Manual Installation and Usage
56
+
57
+ **Hardware Requirements**
58
+
59
+ - A GPU or DCU is recommended.
60
+ - CPU can be used for import and small-scale connectivity verification; full training and inference will be slow.
61
+ - DCU users must install DTK in advance. DTK 25.04.2 or above, or the OneScience recommended version matching your cluster, is recommended.
62
+
63
+ ### Download the Model Package
64
+
65
+ ```bash
66
+ hf download OneScience-Group/CorrDiff --local-dir ./CorrDiff
67
+ cd CorrDiff
68
+ ```
69
+
70
+ ### Install the Runtime Environment
71
+
72
+ **DCU Environment**
73
+
74
+ ```bash
75
+ # Please activate DTK and CONDA first
76
+ conda create -n onescience311 python=3.11 -y
77
+ conda activate onescience311
78
+ # uv installation is supported
79
+ pip install onescience[earth-dcu] -i http://mirrors.onescience.ai:3141/pypi/simple/ --trusted-host mirrors.onescience.ai
80
+ ```
81
+
82
+ **GPU Environment**
83
+
84
+ ```bash
85
+ # Please activate CONDA first
86
+ conda create -n onescience311 python=3.11 -y libstdcxx-ng=12 libgcc-ng=12 gcc_linux-64=12 gxx_linux-64=12
87
+ conda activate onescience311
88
+ # uv installation is supported
89
+ pip install onescience[earth-gpu] -i http://mirrors.onescience.ai:3141/pypi/simple/ --trusted-host mirrors.onescience.ai
90
+ ```
91
+
92
+ ### Training Data Introduction
93
+
94
+ The OneScience community provides an ERA5 data slice that can be downloaded as follows:
95
+
96
+ ```bash
97
+ hf download --repo-type dataset OneScience-Group/ERA5 --local-dir ./data
98
+ ```
99
+
100
+ When real data is unavailable, generate synthetic data for pipeline validation:
101
+
102
+ ```bash
103
+ python scripts/fake_data.py --output data/era5_corrdiff.npz
104
+ ```
105
+
106
+ ### Training
107
+
108
+ Single GPU:
109
+
110
+ ```bash
111
+ python scripts/train.py
112
+ ```
113
+
114
+ Multi-GPU:
115
+
116
+ ```bash
117
+ torchrun --nproc_per_node=8 --nnodes=1 --rdzv_id=1000 --rdzv_backend=c10d --max_restarts=0 --master_addr="localhost" --master_port=29500 scripts/train.py
118
+ ```
119
+
120
+ Training outputs:
121
+
122
+ ```text
123
+ data/checkpoints/model_bak.pth
124
+ data/checkpoints/trloss.npy
125
+ data/checkpoints/valoss.npy
126
+ ```
127
+
128
+ ### Training Weights
129
+
130
+ This repository provides weights trained on 39 years of ERA5 reanalysis data in the `weight/` folder. The weight files will be uploaded soon and are expected to be available in the near future.
131
+
132
+ ### Inference
133
+
134
+ ```bash
135
+ python scripts/inference.py
136
+ ```
137
+
138
+ Prediction results are written to `result/output/` by default.
139
+
140
+ ### Evaluation and Visualization
141
+
142
+ ```bash
143
+ python scripts/result.py
144
+ ```
145
+
146
+ # Official OneScience Resources
147
+
148
+ | Platform | OneScience Main Repository | Skills Repository |
149
+ | --- | --- | --- |
150
+ | Gitee | https://gitee.com/onescience-ai/onescience | https://gitee.com/onescience-ai/oneskills |
151
+ | GitHub | https://github.com/onescience-ai/OneScience | https://github.com/onescience-ai/oneskills |
152
+
153
+ # Citation and License
154
+
155
+ - This repository is a reproduction of the original CorrDiff paper.
conf/config.yaml ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Lightweight OneScience configuration for the official CorrDiff example.
2
+ model:
3
+ regression_config: conf/config_training_taiwan_regression.yaml
4
+ diffusion_config: conf/config_training_taiwan_diffusion.yaml
5
+ generation_config: conf/config_generate_taiwan.yaml
6
+ input_channels: 12
7
+ output_channels: 4
8
+ input_shape: [36, 36]
9
+ output_shape: [448, 448]
10
+ ensemble_size: 32
11
+
12
+ data:
13
+ type: cwb_zarr
14
+ path: ./data/era5_corrdiff.npz
15
+ input_variables: [tcwv, t2m, u10m, v10m, t500, z500, u500, v500, t850, z850, u850, v850]
16
+ output_variables: [t2m, u10m, v10m, maximum_radar_reflectivity]
17
+
18
+ runtime:
19
+ device: auto
20
+ output_dir: ./result/output
21
+ seed: 42
config.json ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model_name": "CorrDiff",
3
+ "model_type": "corrdiff",
4
+ "architectures": [
5
+ "CorrDiff"
6
+ ],
7
+ "framework": "PyTorch",
8
+ "domain": "atmosphere",
9
+ "task": "regional-weather-downscaling",
10
+ "implementation": {
11
+ "entry_point": "model/corrdiff.py",
12
+ "scope": "compact two-stage reproduction of the CorrDiff regression and residual diffusion architecture"
13
+ },
14
+ "architecture": {
15
+ "family": "residual corrective diffusion model",
16
+ "input_grid_shape": [
17
+ 36,
18
+ 36
19
+ ],
20
+ "output_grid_shape": [
21
+ 448,
22
+ 448
23
+ ],
24
+ "input_channels": 12,
25
+ "output_channels": 4,
26
+ "base_channels": 32,
27
+ "mean_model": "RegressionUNet",
28
+ "residual_model": "ResidualDiffusionUNet",
29
+ "conditioning": [
30
+ "bilinearly upsampled coarse input",
31
+ "high-resolution regression mean",
32
+ "noise level sigma"
33
+ ],
34
+ "normalization": "group_norm",
35
+ "activation": "silu",
36
+ "sampling_steps": 4,
37
+ "sigma_max": 1.0,
38
+ "sigma_min": 0.01
39
+ },
40
+ "data": {
41
+ "dataset": "ERA5 and CWA-WRF",
42
+ "input_spatial_resolution_km": 25,
43
+ "output_spatial_resolution_km": 2,
44
+ "time_step_hours": 1,
45
+ "input_steps": 1,
46
+ "output_steps": 1,
47
+ "protocol": "synthetic_era5_corrdiff"
48
+ },
49
+ "configuration_sources": [
50
+ "conf/config.yaml",
51
+ "model/corrdiff.py"
52
+ ]
53
+ }
configuration.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {"framework":"Pytorch","task":"weather_downscaling"}
model/corrdiff.py ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Compact CorrDiff implementation for the OneScience model package."""
2
+
3
+ import math
4
+ import torch
5
+ from torch import nn
6
+ from torch.nn import functional as F
7
+
8
+
9
+ class ConvBlock(nn.Module):
10
+ def __init__(self, in_channels, out_channels):
11
+ super().__init__()
12
+ self.block = nn.Sequential(
13
+ nn.Conv2d(in_channels, out_channels, 3, padding=1),
14
+ nn.GroupNorm(8, out_channels),
15
+ nn.SiLU(),
16
+ nn.Conv2d(out_channels, out_channels, 3, padding=1),
17
+ nn.GroupNorm(8, out_channels),
18
+ nn.SiLU(),
19
+ )
20
+ self.skip = nn.Conv2d(in_channels, out_channels, 1)
21
+
22
+ def forward(self, x):
23
+ return self.block(x) + self.skip(x)
24
+
25
+
26
+ class RegressionUNet(nn.Module):
27
+ """Mean predictor: 12x36x36 coarse fields to 4x448x448 fields."""
28
+
29
+ def __init__(self, in_channels=12, out_channels=4, base_channels=32):
30
+ super().__init__()
31
+ self.encoder = nn.Sequential(
32
+ ConvBlock(in_channels, base_channels),
33
+ ConvBlock(base_channels, base_channels * 2),
34
+ ConvBlock(base_channels * 2, base_channels * 4),
35
+ )
36
+ self.head = nn.Sequential(
37
+ ConvBlock(base_channels * 4, base_channels * 2),
38
+ nn.Conv2d(base_channels * 2, out_channels, 1),
39
+ )
40
+
41
+ def forward(self, x):
42
+ x = self.encoder[0](x)
43
+ x = F.avg_pool2d(x, 2)
44
+ x = self.encoder[1](x)
45
+ x = F.avg_pool2d(x, 2)
46
+ x = self.encoder[2](x)
47
+ x = self.head[0](x)
48
+ x = F.interpolate(x, size=(448, 448), mode="bilinear", align_corners=False)
49
+ return self.head[1](x)
50
+
51
+
52
+ class ResidualDiffusionUNet(nn.Module):
53
+ """Conditional residual denoiser used by the compact EDM-style sampler."""
54
+
55
+ def __init__(self, condition_channels=16, out_channels=4, base_channels=32):
56
+ super().__init__()
57
+ self.time = nn.Sequential(
58
+ nn.Linear(1, base_channels), nn.SiLU(), nn.Linear(base_channels, base_channels)
59
+ )
60
+ self.net = nn.Sequential(
61
+ ConvBlock(condition_channels, base_channels),
62
+ ConvBlock(base_channels, base_channels * 2),
63
+ ConvBlock(base_channels * 2, base_channels),
64
+ nn.Conv2d(base_channels, out_channels, 1),
65
+ )
66
+
67
+ def forward(self, noisy_residual, condition, sigma):
68
+ x = torch.cat((noisy_residual, condition), dim=1)
69
+ embedding = self.time(torch.log(sigma).reshape(-1, 1).float())
70
+ x = self.net[0](x)
71
+ x = x + embedding[:, :, None, None]
72
+ for layer in self.net[1:]:
73
+ x = layer(x)
74
+ return x
75
+
76
+
77
+ class CorrDiff(nn.Module):
78
+ """Two-stage mean plus stochastic residual atmospheric downscaler."""
79
+
80
+ def __init__(self, in_channels=12, out_channels=4, base_channels=32):
81
+ super().__init__()
82
+ self.regression = RegressionUNet(in_channels, out_channels, base_channels)
83
+ self.diffusion = ResidualDiffusionUNet(in_channels + 2 * out_channels, out_channels, base_channels)
84
+
85
+ def mean(self, coarse):
86
+ return self.regression(coarse)
87
+
88
+ def denoise(self, noisy_residual, coarse, mean, sigma):
89
+ coarse = F.interpolate(coarse, size=mean.shape[-2:], mode="bilinear", align_corners=False)
90
+ return self.diffusion(noisy_residual, torch.cat((coarse, mean), dim=1), sigma)
91
+
92
+ def forward(self, coarse, steps=4):
93
+ mean = self.mean(coarse)
94
+ residual = torch.randn_like(mean)
95
+ schedule = torch.linspace(1.0, 0.01, steps, device=coarse.device)
96
+ for sigma in schedule:
97
+ sigma_batch = sigma.expand(coarse.shape[0])
98
+ residual = residual - 0.2 * self.denoise(residual, coarse, mean, sigma_batch)
99
+ return mean + residual
100
+
101
+
102
+ __all__ = ["CorrDiff", "RegressionUNet", "ResidualDiffusionUNet"]
scripts/fake_data.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pathlib import Path
2
+ import argparse
3
+ import numpy as np
4
+
5
+
6
+ def main():
7
+ parser = argparse.ArgumentParser()
8
+ parser.add_argument("--output", default="data/fake_corrdiff.npz")
9
+ parser.add_argument("--samples", type=int, default=1)
10
+ args = parser.parse_args()
11
+ path = Path(args.output)
12
+ path.parent.mkdir(parents=True, exist_ok=True)
13
+ rng = np.random.default_rng(42)
14
+ inputs = rng.standard_normal((args.samples, 12, 36, 36)).astype("float32")
15
+ targets = rng.standard_normal((args.samples, 4, 448, 448)).astype("float32")
16
+ np.savez_compressed(path, input=inputs, target=targets)
17
+ print(f"input: {inputs.shape}")
18
+ print(f"target: {targets.shape}")
19
+ print(f"saved: {path}")
20
+
21
+
22
+ if __name__ == "__main__":
23
+ main()
scripts/inference.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+ from pathlib import Path
3
+ import numpy as np
4
+ import torch
5
+
6
+ import sys
7
+ sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
8
+ from model.corrdiff import CorrDiff
9
+
10
+
11
+ def main():
12
+ parser = argparse.ArgumentParser(description="Run CorrDiff inference")
13
+ parser.add_argument("--data", default="data/era5_corrdiff.npz")
14
+ parser.add_argument("--checkpoint", default="data/checkpoints/model_bak.pth")
15
+ parser.add_argument("--ensemble-size", type=int, default=1)
16
+ parser.add_argument("--output", default="result/output/predictions.npz")
17
+ args = parser.parse_args()
18
+ data = np.load(args.data)
19
+ coarse = torch.from_numpy(data["input"])
20
+ model = CorrDiff()
21
+ checkpoint = Path(args.checkpoint)
22
+ if checkpoint.exists():
23
+ model.load_state_dict(torch.load(checkpoint, map_location="cpu")["model"])
24
+ model.eval()
25
+ samples = []
26
+ with torch.no_grad():
27
+ for _ in range(args.ensemble_size):
28
+ samples.append(model(coarse).numpy().astype("float32"))
29
+ output = Path(args.output)
30
+ output.parent.mkdir(parents=True, exist_ok=True)
31
+ np.savez_compressed(output, prediction=np.stack(samples), input=data["input"])
32
+ print(f"prediction: {np.stack(samples).shape}")
33
+ print(f"saved: {output}")
34
+
35
+
36
+ if __name__ == "__main__":
37
+ main()
scripts/result.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+ from pathlib import Path
3
+ import numpy as np
4
+
5
+
6
+ def main():
7
+ parser = argparse.ArgumentParser(description="Evaluate CorrDiff NPZ predictions")
8
+ parser.add_argument("--prediction", default="result/output/predictions.npz")
9
+ parser.add_argument("--target", default="data/era5_corrdiff.npz")
10
+ args = parser.parse_args()
11
+ prediction = np.load(args.prediction)["prediction"]
12
+ target = np.load(args.target)["target"]
13
+ mae = np.abs(prediction.mean(axis=0) - target).mean()
14
+ output = Path(args.prediction).with_name("metrics.npz")
15
+ np.savez(output, mae=np.array(mae, dtype="float32"))
16
+ print(f"ensemble={prediction.shape[0]} mae={mae:.6f}")
17
+ print(f"saved: {output}")
18
+
19
+
20
+ if __name__ == "__main__":
21
+ main()
scripts/train.py ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+ from pathlib import Path
3
+ import numpy as np
4
+ import torch
5
+ from torch.nn import functional as F
6
+
7
+ import sys
8
+ sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
9
+ from model.corrdiff import CorrDiff
10
+
11
+
12
+ def main():
13
+ parser = argparse.ArgumentParser(description="Train compact CorrDiff on NPZ data")
14
+ parser.add_argument("--data", default="data/era5_corrdiff.npz")
15
+ parser.add_argument("--steps", type=int, default=2)
16
+ parser.add_argument("--output", default="data/checkpoints/model_bak.pth")
17
+ args = parser.parse_args()
18
+ data = np.load(args.data)
19
+ coarse = torch.from_numpy(data["input"])
20
+ target = torch.from_numpy(data["target"])
21
+ model = CorrDiff()
22
+ optimizer = torch.optim.Adam(model.parameters(), lr=2e-4)
23
+ model.train()
24
+ for step in range(args.steps):
25
+ mean = model.mean(coarse)
26
+ residual = target - mean
27
+ sigma = torch.rand(coarse.shape[0]).clamp_min(0.01)
28
+ noisy = residual + sigma[:, None, None, None] * torch.randn_like(residual)
29
+ predicted = model.denoise(noisy, coarse, mean.detach(), sigma)
30
+ loss = F.mse_loss(mean, target) + F.mse_loss(predicted, residual)
31
+ optimizer.zero_grad()
32
+ loss.backward()
33
+ optimizer.step()
34
+ print(f"step={step + 1} loss={loss.item():.6f}")
35
+ output = Path(args.output)
36
+ output.parent.mkdir(parents=True, exist_ok=True)
37
+ torch.save({"model": model.state_dict(), "format": "corrdiff-compact-v1"}, output)
38
+ np.save(output.parent / "trloss.npy", np.asarray([loss.item()], dtype="float32"))
39
+ np.save(output.parent / "valoss.npy", np.asarray([loss.item()], dtype="float32"))
40
+ print(f"saved: {output}")
41
+
42
+
43
+ if __name__ == "__main__":
44
+ main()
weight/.gitkeep ADDED
File without changes