Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/branch_ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,4 @@ jobs:
enable_typechecking: false
containerfile: 'None'
tests_folder: 'tests'
tests_matrix: true
test_python_versions: '["3.11", "3.12"]'
24 changes: 12 additions & 12 deletions pvnet/datamodule.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,18 +60,18 @@ def __init__(
self.seed = seed
self.dataset_pickle_dir = dataset_pickle_dir

self._common_dataloader_kwargs = dict(
batch_size=batch_size,
batch_sampler=None,
num_workers=num_workers,
collate_fn=collate_fn,
pin_memory=pin_memory,
timeout=0,
worker_init_fn=None,
prefetch_factor=prefetch_factor,
persistent_workers=persistent_workers,
multiprocessing_context="spawn" if num_workers > 0 else None,
)
self._common_dataloader_kwargs = {
"batch_size": batch_size,
"batch_sampler": None,
"num_workers": num_workers,
"collate_fn": collate_fn,
"pin_memory": pin_memory,
"timeout": 0,
"worker_init_fn": None,
"prefetch_factor": prefetch_factor,
"persistent_workers": persistent_workers,
"multiprocessing_context": "spawn" if num_workers > 0 else None,
}

def setup(self, stage: str | None = None):
"""Called once to prepare the datasets."""
Expand Down
18 changes: 8 additions & 10 deletions pvnet/models/base_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
PYTORCH_WEIGHTS_NAME,
)

logger = logging.getLogger(__name__)

def fill_config_paths_with_placeholder(config: dict, placeholder: str = "PLACEHOLDER") -> dict:
"""Modify the config in place to fill data paths with placeholder strings.
Expand All @@ -34,10 +35,9 @@ def fill_config_paths_with_placeholder(config: dict, placeholder: str = "PLACEHO
input_config = config["input_data"]

for source in ["generation", "satellite"]:
if source in input_config:
# If not empty - i.e. if used
if input_config[source]["zarr_path"] != "":
input_config[source]["zarr_path"] = f"{placeholder}.zarr"
# If source present but path not empty
if (source in input_config) and (input_config[source]["zarr_path"] != ""):
input_config[source]["zarr_path"] = f"{placeholder}.zarr"

if "nwp" in input_config:
for source in input_config["nwp"]:
Expand Down Expand Up @@ -101,8 +101,7 @@ def minimize_config_for_model(config: dict, model: "BaseModel") -> dict:
+ (model.sat_encoder.sequence_length - 1) * sat_config["time_resolution_minutes"]
)

if "pv" in input_config:
if not model.include_pv:
if ("pv" in input_config) and (not model.include_pv):
del input_config["pv"]

if "generation" in input_config:
Expand Down Expand Up @@ -166,11 +165,11 @@ def download_from_hf(
raise Exception(
f"Failed to download {filename} from {repo_id} after {max_retries} attempts."
) from e
logging.warning(
(
logger.warning(

f"Attempt {attempt}/{max_retries} failed to download {filename} "
f"from {repo_id}. Retrying in {wait_time} seconds..."
)

)
time.sleep(wait_time)

Expand Down Expand Up @@ -343,7 +342,6 @@ def save_pretrained(

print(message)

return

@staticmethod
def create_hugging_face_model_card(
Expand Down
2 changes: 1 addition & 1 deletion pvnet/models/ensemble.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def __init__(
forecast_minutes,
interval_minutes,
]:
assert all([p == param_list[0] for p in param_list]), param_list
assert all(p == param_list[0] for p in param_list), param_list

super().__init__(
history_minutes=history_minutes[0],
Expand Down
1 change: 0 additions & 1 deletion pvnet/models/late_fusion/encoders/basic_blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ def __init__(
@abstractmethod
def forward(self):
"""Run model forward"""
pass


class ResidualConv3dBlock(nn.Module):
Expand Down
2 changes: 1 addition & 1 deletion pvnet/models/late_fusion/encoders/encoders3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def __init__(
),
nn.ELU(),
]
for _ in range(0, number_of_conv3d_layers - 1):
for _ in range(number_of_conv3d_layers - 1):
conv_layers += [
nn.Conv3d(
in_channels=conv3d_channels,
Expand Down
2 changes: 1 addition & 1 deletion pvnet/models/late_fusion/late_fusion.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ def __init__(
if add_image_embedding_channel:
self.nwp_embed_dict = torch.nn.ModuleDict()

for nwp_source in nwp_encoders_dict.keys():
for nwp_source in nwp_encoders_dict:
nwp_sequence_len = (
nwp_history_minutes[nwp_source] // nwp_interval_minutes[nwp_source]
+ nwp_forecast_minutes[nwp_source] // nwp_interval_minutes[nwp_source]
Expand Down
3 changes: 1 addition & 2 deletions pvnet/models/late_fusion/linear_networks/basic_blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,11 @@ def cat_modes(self, x: OrderedDict[str, torch.Tensor] | torch.Tensor) -> torch.T
elif isinstance(x, torch.Tensor):
return x
else:
raise ValueError(f"Input of unexpected type {type(x)}")
raise TypeError(f"Input of unexpected type {type(x)}")

@abstractmethod
def forward(self, x: OrderedDict[str, torch.Tensor] | torch.Tensor) -> torch.Tensor:
"""Run model forward"""
pass


class ResidualLinearBlock(nn.Module):
Expand Down
1 change: 0 additions & 1 deletion pvnet/models/late_fusion/site_encoders/basic_blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,3 @@ def __init__(
@abstractmethod
def forward(self) -> torch.Tensor:
"""Run model forward"""
pass
3 changes: 1 addition & 2 deletions pvnet/optimizers.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ class AbstractOptimizer(ABC):
@abstractmethod
def __call__(self, model: Module):
"""Abstract call"""
pass


class Adam(AbstractOptimizer):
Expand Down Expand Up @@ -166,7 +165,7 @@ def _call_multi(self, model):

group_args = []

for key in self.lr.keys():
for key in self.lr:
if key == "default":
continue

Expand Down
18 changes: 9 additions & 9 deletions pvnet/training/lightning_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,15 +168,15 @@ def _store_val_predictions(self, batch: TensorBatch, y_hat: torch.Tensor) -> Non
y_hat = y_hat[..., None]

ds_preds_batch = xr.Dataset(
data_vars=dict(
y_hat=(["sample_num", "forecast_step", "p_level"], y_hat),
y=(["sample_num", "forecast_step"], y),
),
coords=dict(
ids=("sample_num", ids),
init_times_utc=("sample_num", init_times_utc),
p_level=p_levels,
),
data_vars={
"y_hat": (["sample_num", "forecast_step", "p_level"], y_hat),
"y": (["sample_num", "forecast_step"], y),
},
coords={
"ids": ("sample_num", ids),
"init_times_utc": ("sample_num", init_times_utc),
"p_level": p_levels,
},
)
self.all_val_results.append(ds_preds_batch)

Expand Down
4 changes: 2 additions & 2 deletions pvnet/training/train.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,13 @@ def train(config: DictConfig) -> None:
# Init lightning loggers
loggers: list[Logger] = []
if "logger" in config:
for _, lg_conf in config.logger.items():
for lg_conf in config.logger.values():
loggers.append(hydra.utils.instantiate(lg_conf))

# Init lightning callbacks
callbacks: list[Callback] = []
if "callbacks" in config:
for _, cb_conf in config.callbacks.items():
for cb_conf in config.callbacks.values():
callbacks.append(hydra.utils.instantiate(cb_conf))

# Align the wandb id with the checkpoint path
Expand Down
5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,10 @@ target-version = "py310"

[tool.ruff.lint]
extend-select = ["E", "D", "I"]
ignore = ["D200","D202","D210","D212","D415","D105"]
ignore = ["D200","D202","D210","D212","D415","D105",

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoids the following errors which I was unsure how to deal with:

TRY002 Create your own exception
   --> pvnet/models/base_model.py:166:23
    |
164 |           except Exception as e:
165 |               if attempt == max_retries:
166 |                   raise Exception(
    |  _______________________^
167 | |                     f"Failed to download {filename} from {repo_id} after {max_retries} attempts."
168 | |                 ) from e


LOG015 `warning()` call on root logger
   --> pvnet/models/base_model.py:169:13
    |
167 |                       f"Failed to download {filename} from {repo_id} after {max_retries} attempts."
168 |                   ) from e
169 | /             logging.warning(
170 | |                 (
171 | |                     f"Attempt {attempt}/{max_retries} failed to download {filename} "
172 | |                     f"from {repo_id}. Retrying in {wait_time} seconds..."
173 | |                 )
174 | |             )

B008 Do not perform function call `typer.Argument` in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable
  --> scripts/checkpoint_to_huggingface.py:33:39
   |
31 | @app.command()
32 | def push_to_huggingface(
33 |     checkpoint_dir_paths: list[str] = typer.Argument(...,),
   |                                       ^^^^^^^^^^^^^^^^^^^^
34 |     huggingface_repo: str = typer.Option(..., "--huggingface-repo"),
35 |     wandb_repo: str = typer.Option(..., "--wandb-repo"),

"TRY002", # Create your own exception
"B008", # Do not perform function call typer.Argument
]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

happy to ignore TRY002 and B008


[tool.ruff.lint.mccabe]
# Unlike Flake8, default to a complexity level of 10.
Expand Down
12 changes: 6 additions & 6 deletions scripts/backtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def populate_config_with_data_filepaths(config: dict, data_paths: dict) -> dict:
# NWP is nested so must be treated separately
if "nwp" in config["input_data"]:
nwp_config = config["input_data"]["nwp"]
for nwp_source in nwp_config.keys():
for nwp_source in nwp_config:
provider = nwp_config[nwp_source]["provider"]
assert provider in data_paths["nwp"], f"Missing NWP path: {provider}"
nwp_config[nwp_source]["zarr_path"] = data_paths["nwp"][provider]
Expand Down Expand Up @@ -325,11 +325,11 @@ def to_dataarray(
"""Put numpy array of predictions into a dataarray"""

dims = ["init_time_utc", "location_id", "step"]
coords = dict(
init_time_utc=[t0],
location_id=location_ids,
step=self.steps,
)
coords = {
"init_time_utc": [t0],
"location_id": location_ids,
"step": self.steps,
}

if output_quantiles is not None:
dims.append("quantile")
Expand Down
15 changes: 9 additions & 6 deletions scripts/migrate_old_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,17 @@

# This parameter has been removed
if "target_key" in model_config:
if model_config["target_key"] == "site":
if "include_site_yield_history" in model_config:
if (
(model_config["target_key"] == "site")
and ("include_site_yield_history" in model_config)
):
model_config["include_generation_history"] = model_config.pop(
"include_site_yield_history"
)

if model_config["target_key"] == "gsp" or not model_config["target_key"]:
if "include_site_yield_history" in model_config:
if (
(model_config["target_key"] == "gsp" or not model_config["target_key"])
and ("include_site_yield_history" in model_config)):
del model_config["include_site_yield_history"]

del model_config["target_key"]
Expand All @@ -100,7 +103,7 @@

# Re-find the model components in the new package structure
if model_config.get("nwp_encoders_dict", None) is not None:
for k, v in model_config["nwp_encoders_dict"].items():
for v in model_config["nwp_encoders_dict"].values():
v["_target_"] = (
v["_target_"]
.replace("multimodal", "late_fusion")
Expand Down Expand Up @@ -154,7 +157,7 @@

# Add a note to the model card to say the model has been migrated
with open(f"{save_dir}/{MODEL_CARD_NAME}", "a") as f:
current_date = datetime.date.today().strftime("%Y-%m-%d")
current_date = datetime.datetime.now(datetime.timezone.utc).date().strftime("%Y-%m-%d")
pvnet_version = version("pvnet")
f.write(
f"\n\n---\n**Migration Note**: This model was migrated on {current_date} "
Expand Down
10 changes: 5 additions & 5 deletions scripts/scorecard/generate_scorecard.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,14 +136,14 @@ def prep_ds(ds, y_true):
backtest_ds_list = []

# Add model name dimension to each backtest
for model in backtest_dict.keys():
if type(backtest_dict[model]) is list:
ds = xr.open_mfdataset(backtest_dict[model], engine="zarr")
for model, backtest_filepath in backtest_dict.items():
if type(backtest_filepath) is list:
ds = xr.open_mfdataset(backtest_filepath, engine="zarr")
ds = ds.drop_duplicates(dim='init_time_utc')
else:
ds = xr.open_zarr(backtest_dict[model])
ds = xr.open_zarr(backtest_filepath)

ds = ds.expand_dims(dict(model=[model]))
ds = ds.expand_dims({"model": [model]})
backtest_ds_list.append(ds)

# Intersect backtests by all dimensions except model name
Expand Down
Loading
Loading