Publish NNCAM-Stable reproduction
Browse files- .gitattributes +1 -35
- conf/config.yaml +5 -0
- config.json +1 -0
- model/nncam_stable.py +11 -0
- scripts/fake_data.py +2 -0
- scripts/inference.py +3 -0
- scripts/result.py +3 -0
- scripts/train.py +11 -0
- weight/.gitkeep +0 -0
.gitattributes
CHANGED
|
@@ -1,35 +1 @@
|
|
| 1 |
-
*.
|
| 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 |
+
*.pt binary
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
conf/config.yaml
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
seed: 42
|
| 2 |
+
data: {path: data/data.npz, samples: 128, input: 122, output: 68}
|
| 3 |
+
model: {hidden: 64}
|
| 4 |
+
train: {lr: 0.001}
|
| 5 |
+
paths: {checkpoint: result/checkpoints/nncam_stable.pt, training_metrics: result/training/metrics.json, predictions: result/output/predictions.npz, evaluation: result/evaluation/metrics.json, figure: result/evaluation/comparison.png}
|
config.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{"model_name":"NNCAM-Stable","model_type":"nncam_stable","architectures":["NNCAM"],"framework":"PyTorch","domain":"climate-parameterization","task":"column-emulation","implementation":{"entry_point":"model/nncam_stable.py"},"architecture":{"input_features":122,"output_features":68,"vertical_levels":30,"networks":3},"data":{"source":"SPCAM","synthetic":true},"configuration_sources":["conf/config.yaml","model/nncam_stable.py","scripts/fake_data.py","scripts/train.py","scripts/inference.py","scripts/result.py"]}
|
model/nncam_stable.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json,torch,yaml
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
from torch import nn
|
| 4 |
+
def cfg(r):return yaml.safe_load((Path(r)/'conf/config.yaml').read_text())
|
| 5 |
+
class ResidualDNN(nn.Module):
|
| 6 |
+
def __init__(self,i,o,h):super().__init__();self.a=nn.Linear(i,h);self.b=nn.Linear(h,h);self.o=nn.Linear(h,o)
|
| 7 |
+
def forward(self,x):z=torch.relu(self.a(x));return self.o(z+torch.relu(self.b(z)))
|
| 8 |
+
class NNCAM(nn.Module):
|
| 9 |
+
def __init__(self,hidden=64):super().__init__();self.q=ResidualDNN(122,30,hidden);self.s=ResidualDNN(122,30,hidden);self.rad=ResidualDNN(122,8,hidden);self.model_config={'hidden':hidden}
|
| 10 |
+
def forward(self,x):return torch.cat((self.q(x),self.s(x),self.rad(x)),1)
|
| 11 |
+
def write(p,o):p=Path(p);p.parent.mkdir(parents=True,exist_ok=True);p.write_text(json.dumps(o,indent=2)+'\n')
|
scripts/fake_data.py
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from pathlib import Path
|
| 2 |
+
import numpy as np,yaml;R=Path(__file__).resolve().parents[1];c=yaml.safe_load((R/'conf/config.yaml').read_text());g=np.random.default_rng(2);x=g.normal(size=(128,122)).astype('f');y=x[:,:68]*.2;p=R/c['data']['path'];p.parent.mkdir(parents=True,exist_ok=True);np.savez(p,input=x,target=y);print(p)
|
scripts/inference.py
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from pathlib import Path
|
| 2 |
+
import sys,numpy as np,torch;R=Path(__file__).resolve().parents[1];sys.path.insert(0,str(R));from model.nncam_stable import *
|
| 3 |
+
c=cfg(R);d=np.load(R/c['data']['path']);z=torch.load(R/c['paths']['checkpoint'],weights_only=True);m=NNCAM(**z['model_config']);m.load_state_dict(z['model']);p=R/c['paths']['predictions'];p.parent.mkdir(parents=True,exist_ok=True);np.savez(p,prediction=m(torch.tensor(d['input'])).detach(),target=d['target']);print(p)
|
scripts/result.py
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from pathlib import Path
|
| 2 |
+
import sys,numpy as np,matplotlib;matplotlib.use('Agg');import matplotlib.pyplot as plt;R=Path(__file__).resolve().parents[1];sys.path.insert(0,str(R));from model.nncam_stable import *
|
| 3 |
+
c=cfg(R);d=np.load(R/c['paths']['predictions']);rmse=float(np.sqrt(np.mean((d['prediction']-d['target'])**2)));write(R/c['paths']['evaluation'],{'rmse':rmse});plt.plot(d['prediction'][0]);p=R/c['paths']['figure'];p.parent.mkdir(parents=True,exist_ok=True);plt.savefig(p);print(p)
|
scripts/train.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from pathlib import Path
|
| 2 |
+
import sys,os,numpy as np,torch;import torch.distributed as dist
|
| 3 |
+
from torch.nn.parallel import DistributedDataParallel as DDP
|
| 4 |
+
R=Path(__file__).resolve().parents[1];sys.path.insert(0,str(R));from model.nncam_stable import *
|
| 5 |
+
c=cfg(R);rank=int(os.getenv('RANK',0));world=int(os.getenv('WORLD_SIZE',1));ddp=world>1
|
| 6 |
+
if ddp:dist.init_process_group('gloo')
|
| 7 |
+
d=np.load(R/c['data']['path']);base=NNCAM(**c['model']);m=DDP(base) if ddp else base;opt=torch.optim.Adam(m.parameters(),lr=c['train']['lr']);ids=np.arange(rank,len(d['input']),world);loss=((m(torch.tensor(d['input'][ids]))-torch.tensor(d['target'][ids]))**2).mean();opt.zero_grad();loss.backward();opt.step();v=loss.detach().double()
|
| 8 |
+
if ddp:dist.all_reduce(v);v/=world
|
| 9 |
+
p=R/c['paths']['checkpoint']
|
| 10 |
+
if rank==0:p.parent.mkdir(parents=True,exist_ok=True);torch.save({'model':base.state_dict(),'model_config':c['model']},p);write(R/c['paths']['training_metrics'],{'mse':float(v),'world_size':world});print(p)
|
| 11 |
+
if ddp:dist.destroy_process_group()
|
weight/.gitkeep
ADDED
|
File without changes
|