File size: 3,568 Bytes
eca4864
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
from __future__ import annotations

import argparse
import sys
from pathlib import Path

SCRIPT_DIR = Path(__file__).resolve().parent
MODEL_DIR = SCRIPT_DIR.parent / "model"
for module_dir in (SCRIPT_DIR, MODEL_DIR):
    if str(module_dir) not in sys.path:
        sys.path.insert(0, str(module_dir))

import numpy as np
import torch

from common import DEFAULT_CONFIG, active_model_config, load_config, resolve_path
from data import build_loader, load_statistics
from fourcastnet_v2 import (
    FourCastNetV2,
    load_checkpoint,
)


def choose_device() -> torch.device:
    return torch.device("cuda", 0) if torch.cuda.is_available() else torch.device("cpu")


def main() -> None:
    parser = argparse.ArgumentParser(description="Run FourCastNet v2 inference")
    parser.add_argument("--config", default=str(DEFAULT_CONFIG))
    parser.add_argument("--checkpoint")
    args = parser.parse_args()

    config = load_config(args.config)
    inference = config["inference"]

    device = choose_device()
    model = FourCastNetV2(active_model_config(config)).to(device)
    if args.checkpoint:
        checkpoint_path = resolve_path(config, args.checkpoint)
    else:
        checkpoint_path = resolve_path(config, inference["checkpoint_path"])
    result = load_checkpoint(
        model,
        checkpoint_path,
        expected_profile=config["model"]["profile"],
        expected_variables=config["data"]["variables"],
        allowed_stages={"one_step", "finetune"},
        allowed_initializations={"random", "one_step_checkpoint"},
        strict=config["checkpoint"]["strict"],
        map_location=device,
    )
    if result["missing_keys"] or result["unexpected_keys"]:
        print(
            f"missing_keys={result['missing_keys']} "
            f"unexpected_keys={result['unexpected_keys']}"
        )

    loader, _ = build_loader(
        config,
        config["data"]["test_years"],
        train=False,
        distributed=False,
        output_steps=inference["rollout_steps"],
    )
    means, stds = load_statistics(config)
    means = means.numpy()
    stds = stds.numpy()

    output_dir = resolve_path(config, inference["output_dir"])
    output_dir.mkdir(parents=True, exist_ok=True)
    model.eval()
    with torch.no_grad():
        for sample_index, batch in enumerate(loader):
            if sample_index >= inference["max_samples"]:
                break
            inputs = batch[0].to(device)
            targets = batch[1]
            state = inputs
            predictions = []
            for _ in range(inference["rollout_steps"]):
                state = model(state)
                predictions.append(state.cpu())
            prediction = torch.stack(predictions, dim=1).numpy()
            if targets.ndim == 4:
                targets = targets.unsqueeze(1)
            target = targets.numpy()
            input_array = inputs.cpu().numpy()
            if not inference["save_normalized"]:
                prediction = prediction * stds[:, None] + means[:, None]
                target = target * stds[:, None] + means[:, None]
                input_array = input_array * stds + means
            path = output_dir / f"sample_{sample_index:04d}.npz"
            np.savez_compressed(
                path,
                input=input_array,
                prediction=prediction,
                target=target,
                variables=np.asarray(config["data"]["variables"]),
                time_index=np.asarray(batch[4], dtype=str).T,
            )
            print(path)


if __name__ == "__main__":
    main()