| """ |
| NB: this script is for illustration purposes only and is not runnable as our |
| full dataset is not provided as part of the submission, due to size constraints. |
| Many of the relevant paths to the data have been thus replaced by dummy paths. |
| """ |
|
|
| import os |
| import sys |
| import pickle |
| import argparse |
|
|
| import torch |
| import torch.multiprocessing as mp |
| from torch.utils.data import DataLoader |
| import torch.utils.data.distributed |
| from torch.utils.data.distributed import DistributedSampler |
| from torch.distributed import init_process_group, destroy_process_group |
|
|
|
|
| from trainer import DDPTrainer |
| from loss_functions import WeightedRmseLoss, PressureWeightedRmseLoss, RmseLoss |
| from misc_downscaling_functionality import ConvCNPWeatherOnToOff, DownscalingRmseLoss |
| from loader import * |
| from models import * |
| from unet_wrap_padding import * |
|
|
|
|
| sys.path.append("../npw/data") |
| torch.set_float32_matmul_precision("medium") |
|
|
|
|
| def ddp_setup(rank, world_size, master_port): |
| """ |
| Args: |
| rank: Unique identifier of each process |
| world_size: Total number of processes |
| """ |
|
|
| os.environ["MASTER_ADDR"] = "localhost" |
| os.environ["MASTER_PORT"] = master_port |
| init_process_group(backend="nccl", rank=rank, world_size=world_size) |
| torch.cuda.set_device(rank) |
|
|
|
|
| def start_date(name): |
| if name == "train": |
| return "2007-01-02" |
| elif name == "val": |
| return "2019-01-01" |
| elif name == "test": |
| return "2018-01-01" |
| else: |
| raise Exception(f"Unrecognised split name {name}") |
|
|
|
|
| def end_date(name): |
| if name == "train": |
| return "2017-12-31" |
| elif name == "val": |
| return "2019-11-01" |
| elif name == "test": |
| return "2018-12-21" |
| else: |
| raise Exception(f"Unrecognised split name {name}") |
|
|
|
|
| def main(rank, world_size, output_dir, args): |
| """ |
| Primary training script for the encoder, processor and decoder modules. |
| """ |
|
|
| master_port = args.master_port |
| lead_time = args.lead_time |
| era5_mode = args.era5_mode |
| weights_dir = args.weights_dir |
| ddp_setup(rank, world_size, master_port) |
|
|
| |
| if args.loss == "lw_rmse": |
| lf = WeightedRmseLoss( |
| args.res, |
| start_ind=args.start_ind, |
| end_ind=args.end_ind, |
| weight_per_variable=bool(args.weight_per_variable), |
| ) |
| elif args.loss == "lw_rmse_pressure_weighted": |
| lf = PressureWeightedRmseLoss(args.res, era5_mode) |
| elif args.loss == "rmse": |
| lf = RmseLoss() |
| elif args.loss == "downscaling_rmse": |
| lf = DownscalingRmseLoss() |
|
|
| |
|
|
| |
| if args.mode == "assimilation": |
| train_dataset = WeatherDatasetAssimilation( |
| device="cuda", |
| hadisd_mode="train", |
| start_date="2007-01-02", |
| end_date="2017-12-31", |
| lead_time=0, |
| era5_mode="4u", |
| res=args.res, |
| var_start=args.start_ind, |
| var_end=args.end_ind, |
| diff=bool(args.diff), |
| two_frames=bool(args.two_frames), |
| ) |
| val_dataset = WeatherDatasetAssimilation( |
| device="cuda", |
| hadisd_mode="train", |
| start_date="2019-01-01", |
| end_date="2019-12-31", |
| lead_time=0, |
| era5_mode="4u", |
| res=args.res, |
| var_start=args.start_ind, |
| var_end=args.end_ind, |
| diff=bool(args.diff), |
| two_frames=bool(args.two_frames), |
| ) |
|
|
| |
| elif args.mode == "forecast": |
| if args.ic == "aardvark": |
| train_dataset = FineTuneForecastLoaderNew( |
| device="cuda", |
| mode="train", |
| lead_time=lead_time, |
| era5_mode=era5_mode, |
| res=args.res, |
| frequency=args.frequency, |
| diff=bool(args.diff), |
| aardvark_ic_path=args.aardvark_ic_path, |
| random_lt=True, |
| ) |
| val_dataset = FineTuneForecastLoaderNew( |
| device="cuda", |
| mode="val", |
| lead_time=lead_time, |
| era5_mode=era5_mode, |
| res=args.res, |
| frequency=args.frequency, |
| diff=bool(args.diff), |
| aardvark_ic_path=args.aardvark_ic_path, |
| ) |
| else: |
| train_dataset = ForecastLoader( |
| device="cuda", |
| mode="train", |
| lead_time=lead_time, |
| era5_mode=era5_mode, |
| res=args.res, |
| frequency=args.frequency, |
| diff=bool(args.diff), |
| u_only=False, |
| random_lt=False, |
| ) |
| val_dataset = ForecastLoader( |
| device="cuda", |
| mode="val", |
| lead_time=lead_time, |
| era5_mode=era5_mode, |
| res=args.res, |
| frequency=args.frequency, |
| diff=bool(args.diff), |
| u_only=False, |
| random_lt=False, |
| ) |
|
|
| |
| elif args.mode == "downscaling": |
|
|
| train_dataset = ForecasterDatasetDownscaling( |
| start_date="2007-01-02", |
| end_date="2017-12-31", |
| lead_time=args.lead_time, |
| hadisd_var=args.var, |
| mode="train", |
| device="cuda", |
| forecast_path=None, |
| ) |
|
|
| val_dataset = ForecasterDatasetDownscaling( |
| start_date="2019-01-01", |
| end_date="2019-12-21", |
| lead_time=args.lead_time, |
| hadisd_var=args.var, |
| mode="train", |
| device="cuda", |
| forecast_path=None, |
| ) |
|
|
| try: |
| os.mkdir(f"{output_dir}lt_{args.lead_time}") |
| except FileExistsError: |
| pass |
|
|
| output_dir = f"{output_dir}lt_{args.lead_time}/" |
|
|
| |
|
|
| if args.mode == "downscaling": |
| model = ConvCNPWeatherOnToOff( |
| in_channels=args.in_channels, |
| out_channels=args.end_ind - args.start_ind, |
| int_channels=args.int_channels, |
| device="cuda", |
| res=args.res, |
| decoder=args.decoder, |
| mode=args.mode, |
| film=bool(args.film), |
| ) |
| else: |
| model = ConvCNPWeather( |
| in_channels=args.in_channels, |
| out_channels=args.end_ind - args.start_ind, |
| int_channels=args.int_channels, |
| device="cuda", |
| res=args.res, |
| gnp=bool(0), |
| decoder=args.decoder, |
| mode=args.mode, |
| film=bool(args.film), |
| two_frames=bool(args.two_frames), |
| ) |
|
|
| |
| train_sampler = DistributedSampler(train_dataset) |
| val_sampler = DistributedSampler(val_dataset) |
|
|
| train_loader = DataLoader( |
| train_dataset, |
| batch_size=args.batch_size, |
| shuffle=False, |
| sampler=train_sampler, |
| ) |
|
|
| val_loader = DataLoader( |
| val_dataset, |
| batch_size=args.batch_size, |
| shuffle=False, |
| sampler=val_sampler, |
| ) |
|
|
| |
|
|
| trainer = DDPTrainer( |
| model, |
| rank, |
| train_loader, |
| val_loader, |
| lf, |
| output_dir, |
| args.lr, |
| train_sampler, |
| weight_decay=args.weight_decay, |
| weights_path=weights_dir, |
| tune_film=args.film, |
| ) |
|
|
| |
|
|
| trainer.train(n_epochs=args.epoch) |
| destroy_process_group() |
|
|
|
|
| if __name__ == "__main__": |
| parser = argparse.ArgumentParser() |
| parser.add_argument("--output_dir") |
| parser.add_argument("--mode") |
| parser.add_argument("--weights_dir") |
| parser.add_argument("--in_channels", type=int) |
| parser.add_argument("--out_channels", type=int) |
| parser.add_argument("--int_channels", type=int) |
| parser.add_argument("--loss") |
| parser.add_argument("--ic") |
| parser.add_argument("--decoder") |
| parser.add_argument("--film") |
| parser.add_argument("--aardvark_ic_path") |
| parser.add_argument("--two_frames", type=int, default=0) |
| parser.add_argument("--weight_per_variable", type=int, default=0) |
| parser.add_argument("--batch_size", type=int, default=128) |
| parser.add_argument("--epoch", type=int, default=50) |
| parser.add_argument("--master_port", default="12345") |
| parser.add_argument("--lr", type=float, default=5e-4) |
| parser.add_argument("--lead_time", type=int) |
| parser.add_argument("--era5_mode", default="4u") |
| parser.add_argument("--weight_decay", type=float, default=1e-6) |
| parser.add_argument("--res", type=int, default=1) |
| parser.add_argument("--frequency", type=int, default=6) |
| parser.add_argument("--diff", type=int, default=1) |
| parser.add_argument("--start_ind", type=int, default=0) |
| parser.add_argument("--end_ind", type=int, default=24) |
| parser.add_argument("--downscaling_train_start_date", default="1979-01-01") |
| parser.add_argument("--downscaling_train_end_date", default="2017-12-31") |
| parser.add_argument("--downscaling_context", default="era5") |
| parser.add_argument("--downscaling_lead_time", type=int) |
| parser.add_argument("--var", default=None) |
| args = parser.parse_args() |
|
|
| torch.device("cuda") |
|
|
| |
| output_dir = args.output_dir |
| if not os.path.exists(output_dir): |
| os.mkdir(output_dir) |
|
|
| |
| with open(output_dir + "/config.pkl", "wb") as f: |
| pickle.dump(vars(args), f) |
|
|
| world_size = torch.cuda.device_count() |
| mp.spawn(main, args=[world_size, output_dir, args], nprocs=world_size) |
|
|