| import sys |
| from pathlib import Path |
|
|
| |
| root_path = Path(__file__).parent.parent |
| sys.path.append(str(root_path)) |
| import torch |
| import os |
| import glob |
| import numpy as np |
| import h5py |
| from tqdm import tqdm |
| from model.prithvi_wxc import PrithviWxC |
| from onescience.utils.YParams import YParams |
| from onescience.datapipes.climate import ERA5Datapipe |
|
|
|
|
| def get_stats(data_dir, channels): |
| """从新版 h5 中读取变量列表与归一化参数(均值/标准差)""" |
| h5_files = sorted(glob.glob(os.path.join(data_dir, "data", "*.h5"))) |
| with h5py.File(h5_files[0], "r") as f: |
| ds = f["fields"] |
| all_variables = [v.decode() if isinstance(v, bytes) else v for v in ds.attrs["variables"]] |
| mu = f["global_means"][:] |
| std = f["global_stds"][:] |
|
|
| channel_indices = [all_variables.index(v) for v in channels] |
| means = mu[:, channel_indices, :, :] |
| stds = std[:, channel_indices, :, :] |
| return means, stds |
|
|
|
|
| if __name__ == "__main__": |
| current_path = os.getcwd() |
| sys.path.append(current_path) |
|
|
| |
| config_file_path = os.path.join(current_path, "conf/config.yaml") |
| cfg = YParams(config_file_path, "model") |
|
|
| |
| cfg_data = YParams(config_file_path, "datapipe") |
| means, stds = get_stats(cfg_data.dataset.data_dir, cfg_data.dataset.channels) |
|
|
| cfg['N_in_channels'] = len(cfg_data.dataset.channels) |
| cfg['N_out_channels'] = len(cfg_data.dataset.channels) |
|
|
| datapipe = ERA5Datapipe( |
| dataset_dir=cfg_data.dataset.data_dir, |
| used_variables=cfg_data.dataset.channels, |
| used_years=cfg_data.dataset.test_time, |
| distributed=False, |
| input_steps=2, |
| batch_size=1, |
| num_workers=4, |
| ) |
| test_dataloader, _ = datapipe.get_dataloader("test") |
|
|
| device = "cuda:0" if torch.cuda.is_available() else "cpu" |
| ckpt = torch.load(f"{cfg.checkpoint_dir}/model_bak.pth", map_location=device, weights_only=False) |
| model = PrithviWxC( |
| in_channels=cfg['N_in_channels'], |
| input_size_time=cfg.input_size_time, |
| in_channels_static=cfg.in_channels_static, |
| n_lats_px=cfg.n_lats_px, |
| n_lons_px=cfg.n_lons_px, |
| patch_size_px=cfg.patch_size_px, |
| mask_unit_size_px=cfg.mask_unit_size_px, |
| mask_ratio_inputs=0.0, |
| embed_dim=cfg.embed_dim, |
| n_blocks_encoder=cfg.n_blocks_encoder, |
| n_blocks_decoder=cfg.n_blocks_decoder, |
| mlp_multiplier=cfg.mlp_multiplier, |
| n_heads=cfg.n_heads, |
| dropout=cfg.dropout, |
| drop_path=cfg.drop_path, |
| parameter_dropout=cfg.parameter_dropout, |
| residual=cfg.residual, |
| masking_mode=cfg.masking_mode, |
| positional_encoding=cfg.positional_encoding, |
| encoder_shifting=cfg.encoder_shifting, |
| decoder_shifting=cfg.decoder_shifting, |
| ).to(device) |
| model.load_state_dict(ckpt["model_state_dict"]) |
|
|
| model.eval() |
| os.makedirs('result/output/', exist_ok=True) |
| print(f"📂 infer results will be generated to './result/output/'") |
| H, W = int(cfg.n_lats_px), int(cfg.n_lons_px) |
| static_path = os.path.join(cfg_data.dataset.data_dir, "static", "static.npy") |
| static_base = torch.from_numpy(np.load(static_path)).to(device=device, dtype=torch.float32).unsqueeze(0) |
| expected_static = (1, int(cfg.in_channels_static), H, W) |
| if tuple(static_base.shape) != expected_static: |
| raise ValueError(f"static data shape {tuple(static_base.shape)} != expected {expected_static}") |
| with torch.no_grad(): |
| for data in tqdm(test_dataloader, desc="Inferring testset", unit="batch"): |
| invar = data[0].to(device, dtype=torch.float32) |
| filename = data[4][-1][0] |
| B = invar.shape[0] |
| static = static_base.expand(B, -1, -1, -1) |
| lead_time = torch.full((B,), 6.0, device=device) |
| pred_var = model(invar, static, lead_time=lead_time).cpu().numpy() |
| pred_var = pred_var * stds + means |
| np.save(f"result/output/{filename}.npy", pred_var) |
|
|