zhangrenchao commited on
Commit
b72f6a3
·
verified ·
1 Parent(s): 281c4f7

Publish AI-GAMFS reproduction

Browse files
.gitattributes CHANGED
@@ -1,35 +1,2 @@
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
+ *.pt binary
2
+ *.npz binary
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
conf/config.yaml ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ seed: 42
2
+ data: {path: data/aerosol.npz, samples: 8, channels: 54, tile: 16, logical_grid: [361, 576]}
3
+ model: {channels: 54, hidden: 24, heads: 4}
4
+ train: {epochs: 1, learning_rate: 0.001, leads: [3, 6, 9, 12]}
5
+ inference: {hours: 120}
6
+ paths: {checkpoint: result/checkpoints/ai_gamfs.pt, training_metrics: result/training/metrics.json, predictions: result/output/predictions.npz, evaluation: result/evaluation/metrics.json, figure: result/evaluation/comparison.png}
7
+ paper_model: {grid: [361, 576], channels: 54, aerosol_variables: 12, upper_levels: 9, leads: [3, 6, 9, 12], epochs: 80, forecast_hours: 120, paper_license: CC-BY-NC-ND-4.0}
config.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {"model_name":"AI-GAMFS","model_type":"ai_gamfs","architectures":["AIGAMFS"],"framework":"PyTorch","domain":"aerosol-weather","task":"global-aerosol-forecasting","implementation":{"entry_point":"model/ai_gamfs.py","scope":"L2 relay-forecast reproduction"},"architecture":{"logical_grid":[361,576],"aerosol_variables":12,"surface_variables":6,"upper_variables":4,"upper_levels":9,"total_channels":54,"lead_models":[3,6,9,12]},"data":{"source":"MERRA-2","years":[1980,2023],"test_year":2022,"operational_initialization":"GEOS-FP","synthetic_tiles":true},"configuration_sources":["conf/config.yaml","model/ai_gamfs.py","scripts/fake_data.py","scripts/train.py","scripts/inference.py","scripts/result.py"]}
model/ai_gamfs.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json,torch
2
+ from pathlib import Path
3
+ from torch import nn
4
+ import yaml
5
+ AEROSOL=('AOD','TSAOD','SUAOD','DUAOD','BCAOD','OCAOD','SSAOD','SUSMC','DUSMC','BCSMC','OCSMC','SSSMC')
6
+ def cfg(r):return yaml.safe_load((Path(r)/'conf/config.yaml').read_text())
7
+ def state(i,h=0):
8
+ y,x=torch.meshgrid(torch.linspace(-1,1,16),torch.linspace(-1,1,16),indexing='ij');c=torch.arange(54)[:,None,None];return (torch.sin((c%8+1)*x+.02*(i+h))*torch.cos((c%6+1)*y)).float()
9
+ class Relay(nn.Module):
10
+ def __init__(self,c,h,heads):super().__init__();self.e=nn.Conv2d(c,h,2,2);self.a=nn.MultiheadAttention(h,heads,batch_first=True);self.d=nn.ConvTranspose2d(h,c,2,2)
11
+ def forward(self,x):z=self.e(x);b,c,y,w=z.shape;t=z.permute(0,2,3,1).reshape(b,y*w,c);t=self.a(t,t,t,need_weights=False)[0];return x+self.d(t.reshape(b,y,w,c).permute(0,3,1,2))
12
+ class AIGAMFS(nn.Module):
13
+ def __init__(self,channels=54,hidden=24,heads=4):super().__init__();self.models=nn.ModuleDict({str(h):Relay(channels,hidden,heads) for h in (3,6,9,12)});self.model_config={'channels':channels,'hidden':hidden,'heads':heads}
14
+ def forward(self,x,lead):return self.models[str(lead)](x)
15
+ 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,4 @@
 
 
 
 
 
1
+ from pathlib import Path
2
+ import sys,numpy as np
3
+ R=Path(__file__).resolve().parents[1];sys.path.insert(0,str(R));from model.ai_gamfs import *
4
+ c=cfg(R);x=np.stack([state(i).numpy() for i in range(8)]);t=np.stack([[state(i,h).numpy() for h in (3,6,9,12)] for i in range(8)]);p=R/c['data']['path'];p.parent.mkdir(parents=True,exist_ok=True);np.savez_compressed(p,input=x,targets=t,leads=[3,6,9,12],aerosol_variables=AEROSOL,logical_shape=[54,361,576],is_complete_global=False);print(p)
scripts/inference.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ from pathlib import Path
2
+ import sys,numpy as np,torch
3
+ R=Path(__file__).resolve().parents[1];sys.path.insert(0,str(R));from model.ai_gamfs import *
4
+ c=cfg(R);z=torch.load(R/c['paths']['checkpoint'],map_location='cpu',weights_only=True);m=AIGAMFS(**z['model_config']);m.load_state_dict(z['model']);x=state(20)[None];seq=[]
5
+ with torch.no_grad():
6
+ for h in range(3,121,3):lead=max(v for v in (12,9,6,3) if v<=120-(h-3));x=m(x,lead);seq.append(x[0].numpy())
7
+ p=R/c['paths']['predictions'];p.parent.mkdir(parents=True,exist_ok=True);np.savez_compressed(p,prediction=seq,target=[state(20,h).numpy() for h in range(3,121,3)],lead_hours=np.arange(3,121,3),logical_shape=[54,361,576],is_complete_global=False);print(p)
scripts/result.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ from pathlib import Path
2
+ import sys,numpy as np;import matplotlib;matplotlib.use('Agg');import matplotlib.pyplot as plt
3
+ R=Path(__file__).resolve().parents[1];sys.path.insert(0,str(R));from model.ai_gamfs import cfg,write
4
+ c=cfg(R);d=np.load(R/c['paths']['predictions']);p=d['prediction'];t=d['target'];rmse=np.sqrt(np.mean((p-t)**2,axis=(1,2,3)));corr=[float(np.corrcoef(p[i,0].ravel(),t[i,0].ravel())[0,1]) for i in range(40)];write(R/c['paths']['evaluation'],{'aod_rmse':rmse.tolist(),'aod_correlation':corr,'is_complete_global':False,'synthetic':True});plt.plot(d['lead_hours'],rmse);plt.xlabel('Lead (h)');plt.ylabel('RMSE');q=R/c['paths']['figure'];q.parent.mkdir(parents=True,exist_ok=True);plt.savefig(q,dpi=150);print(q)
scripts/train.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.ai_gamfs 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=AIGAMFS(**c['model']);m=DDP(base,find_unused_parameters=True) if ddp else base;opt=torch.optim.AdamW(m.parameters(),lr=c['train']['learning_rate']);ls=[]
8
+ for i in range(rank,8,world):
9
+ for j,h in enumerate(c['train']['leads']):loss=((m(torch.tensor(d['input'][i:i+1]),h)-torch.tensor(d['targets'][i:i+1,j]))**2).mean();opt.zero_grad();loss.backward();opt.step();ls.append(float(loss))
10
+ v=torch.tensor([sum(ls),len(ls)],dtype=torch.float64)
11
+ if ddp:dist.all_reduce(v)
12
+ p=R/c['paths']['checkpoint']
13
+ 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[0]/v[1]),'world_size':world});print(p)
14
+ if ddp:dist.destroy_process_group()
weight/.gitkeep ADDED
File without changes