PVNet 3.0.22__tar.gz → 3.0.24__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {PVNet-3.0.22 → PVNet-3.0.24}/PKG-INFO +1 -1
- {PVNet-3.0.22 → PVNet-3.0.24}/PVNet.egg-info/PKG-INFO +1 -1
- PVNet-3.0.24/pvnet/__init__.py +2 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/pvnet/models/base_model.py +74 -63
- {PVNet-3.0.22 → PVNet-3.0.24}/pvnet/models/multimodal/unimodal_teacher.py +10 -1
- {PVNet-3.0.22 → PVNet-3.0.24}/pvnet/optimizers.py +0 -1
- PVNet-3.0.22/pvnet/__init__.py +0 -2
- {PVNet-3.0.22 → PVNet-3.0.24}/LICENSE +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/MANIFEST.in +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/PVNet.egg-info/SOURCES.txt +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/PVNet.egg-info/dependency_links.txt +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/PVNet.egg-info/requires.txt +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/PVNet.egg-info/top_level.txt +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/README.md +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/pvnet/callbacks.py +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/pvnet/data/__init__.py +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/pvnet/data/base.py +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/pvnet/data/datamodule.py +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/pvnet/data/pv_site_datamodule.py +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/pvnet/data/utils.py +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/pvnet/data/wind_datamodule.py +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/pvnet/models/__init__.py +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/pvnet/models/baseline/__init__.py +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/pvnet/models/baseline/last_value.py +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/pvnet/models/baseline/single_value.py +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/pvnet/models/ensemble.py +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/pvnet/models/multimodal/__init__.py +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/pvnet/models/multimodal/basic_blocks.py +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/pvnet/models/multimodal/encoders/__init__.py +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/pvnet/models/multimodal/encoders/basic_blocks.py +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/pvnet/models/multimodal/encoders/encoders2d.py +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/pvnet/models/multimodal/encoders/encoders3d.py +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/pvnet/models/multimodal/encoders/encodersRNN.py +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/pvnet/models/multimodal/linear_networks/__init__.py +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/pvnet/models/multimodal/linear_networks/basic_blocks.py +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/pvnet/models/multimodal/linear_networks/networks.py +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/pvnet/models/multimodal/multimodal.py +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/pvnet/models/multimodal/multimodal_base.py +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/pvnet/models/multimodal/site_encoders/__init__.py +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/pvnet/models/multimodal/site_encoders/basic_blocks.py +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/pvnet/models/multimodal/site_encoders/encoders.py +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/pvnet/models/utils.py +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/pvnet/training.py +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/pvnet/utils.py +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/pyproject.toml +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/requirements-dev.txt +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/requirements.txt +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/setup.cfg +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/setup.py +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/tests/__init__.py +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/tests/conftest.py +0 -0
- {PVNet-3.0.22 → PVNet-3.0.24}/tests/test_end2end.py +0 -0
|
@@ -165,7 +165,7 @@ class PVNetModelHubMixin(PyTorchModelHubMixin):
|
|
|
165
165
|
self,
|
|
166
166
|
save_directory: Union[str, Path],
|
|
167
167
|
config: dict,
|
|
168
|
-
data_config: Union[str, Path],
|
|
168
|
+
data_config: Optional[Union[str, Path]],
|
|
169
169
|
repo_id: Optional[str] = None,
|
|
170
170
|
push_to_hub: bool = False,
|
|
171
171
|
wandb_ids: Optional[Union[list[str], str]] = None,
|
|
@@ -206,7 +206,8 @@ class PVNetModelHubMixin(PyTorchModelHubMixin):
|
|
|
206
206
|
(save_directory / CONFIG_NAME).write_text(json.dumps(config, indent=4))
|
|
207
207
|
|
|
208
208
|
# Save cleaned datapipes configuration file
|
|
209
|
-
|
|
209
|
+
if data_config is not None:
|
|
210
|
+
make_clean_data_config(data_config, save_directory / DATA_CONFIG_NAME)
|
|
210
211
|
|
|
211
212
|
# Creating and saving model card.
|
|
212
213
|
card_data = ModelCardData(language="en", license="mit", library_name="pytorch")
|
|
@@ -301,6 +302,7 @@ class BaseModel(pl.LightningModule, PVNetModelHubMixin):
|
|
|
301
302
|
self._accumulated_metrics = MetricAccumulator()
|
|
302
303
|
self._accumulated_batches = BatchAccumulator(key_to_keep=self._target_key_name)
|
|
303
304
|
self._accumulated_y_hat = PredAccumulator()
|
|
305
|
+
self._horizon_maes = MetricAccumulator()
|
|
304
306
|
|
|
305
307
|
# Store whether the model should use quantile regression or simply predict the mean
|
|
306
308
|
self.use_quantile_regression = self.output_quantiles is not None
|
|
@@ -389,6 +391,18 @@ class BaseModel(pl.LightningModule, PVNetModelHubMixin):
|
|
|
389
391
|
|
|
390
392
|
return losses
|
|
391
393
|
|
|
394
|
+
def _step_mae_and_mse(self, y, y_hat, dict_key_root):
|
|
395
|
+
"""Calculate the MSE and MAE at each forecast step"""
|
|
396
|
+
losses = {}
|
|
397
|
+
|
|
398
|
+
mse_each_step = torch.mean((y_hat - y) ** 2, dim=0)
|
|
399
|
+
mae_each_step = torch.mean(torch.abs(y_hat - y), dim=0)
|
|
400
|
+
|
|
401
|
+
losses.update({f"MSE_{dict_key_root}/step_{i:03}": m for i, m in enumerate(mse_each_step)})
|
|
402
|
+
losses.update({f"MAE_{dict_key_root}/step_{i:03}": m for i, m in enumerate(mae_each_step)})
|
|
403
|
+
|
|
404
|
+
return losses
|
|
405
|
+
|
|
392
406
|
def _calculate_val_losses(self, y, y_hat):
|
|
393
407
|
"""Calculate additional validation losses"""
|
|
394
408
|
|
|
@@ -404,12 +418,17 @@ class BaseModel(pl.LightningModule, PVNetModelHubMixin):
|
|
|
404
418
|
|
|
405
419
|
# Take median value for remaining metric calculations
|
|
406
420
|
y_hat = self._quantiles_to_prediction(y_hat)
|
|
407
|
-
mse_each_step = torch.mean((y_hat - y) ** 2, dim=0)
|
|
408
|
-
mae_each_step = torch.mean(torch.abs(y_hat - y), dim=0)
|
|
409
421
|
|
|
410
|
-
|
|
411
|
-
losses.update(
|
|
422
|
+
# Log the loss at each time horizon
|
|
423
|
+
losses.update(self._step_mae_and_mse(y, y_hat, dict_key_root="horizon"))
|
|
424
|
+
|
|
425
|
+
# Log the persistance losses
|
|
426
|
+
y_persist = y[:, -1].unsqueeze(1).expand(-1, self.forecast_len)
|
|
427
|
+
losses["MAE_persistence/val"] = F.l1_loss(y_persist, y)
|
|
428
|
+
losses["MSE_persistence/val"] = F.mse_loss(y_persist, y)
|
|
412
429
|
|
|
430
|
+
# Log persistance loss at each time horizon
|
|
431
|
+
losses.update(self._step_mae_and_mse(y, y_persist, dict_key_root="persistence"))
|
|
413
432
|
return losses
|
|
414
433
|
|
|
415
434
|
def _calculate_test_losses(self, y, y_hat):
|
|
@@ -476,51 +495,36 @@ class BaseModel(pl.LightningModule, PVNetModelHubMixin):
|
|
|
476
495
|
opt_target = losses["MAE/train"]
|
|
477
496
|
return opt_target
|
|
478
497
|
|
|
498
|
+
def _log_forecast_plot(self, batch, y_hat, accum_batch_num, timesteps_to_plot, plot_suffix):
|
|
499
|
+
"""Log forecast plot to wandb"""
|
|
500
|
+
fig = plot_batch_forecasts(
|
|
501
|
+
batch,
|
|
502
|
+
y_hat,
|
|
503
|
+
quantiles=self.output_quantiles,
|
|
504
|
+
key_to_plot=self._target_key_name,
|
|
505
|
+
)
|
|
506
|
+
|
|
507
|
+
plot_name = f"val_forecast_samples/batch_idx_{accum_batch_num}_{plot_suffix}"
|
|
508
|
+
|
|
509
|
+
self.logger.experiment.log({plot_name: wandb.Image(fig)})
|
|
510
|
+
plt.close(fig)
|
|
511
|
+
|
|
479
512
|
def validation_step(self, batch: dict, batch_idx):
|
|
480
513
|
"""Run validation step"""
|
|
481
514
|
y_hat = self(batch)
|
|
482
515
|
# Sensor seems to be in batch, station, time order
|
|
483
516
|
y = batch[self._target_key][:, -self.forecast_len :, 0]
|
|
484
|
-
|
|
517
|
+
|
|
485
518
|
# Expand persistence to be the same shape as y
|
|
486
|
-
persistence = persistence.unsqueeze(1).expand(-1, self.forecast_len)
|
|
487
519
|
losses = self._calculate_common_losses(y, y_hat)
|
|
488
520
|
losses.update(self._calculate_val_losses(y, y_hat))
|
|
489
521
|
|
|
522
|
+
# Store these to make horizon accuracy plot
|
|
523
|
+
self._horizon_maes.append(
|
|
524
|
+
{i: losses[f"MAE_horizon/step_{i:03}"] for i in range(self.forecast_len)}
|
|
525
|
+
)
|
|
526
|
+
|
|
490
527
|
logged_losses = {f"{k}/val": v for k, v in losses.items()}
|
|
491
|
-
logged_losses["MAE_persistence/val"] = F.l1_loss(persistence, y)
|
|
492
|
-
logged_losses["MSE_persistence/val"] = F.mse_loss(persistence, y)
|
|
493
|
-
# Log for each timestep the persistence loss
|
|
494
|
-
for i in range(self.forecast_len):
|
|
495
|
-
logged_losses[f"MAE_persistence/step_{i:03}/val"] = F.l1_loss(
|
|
496
|
-
persistence[:, i], y[:, i]
|
|
497
|
-
)
|
|
498
|
-
logged_losses[f"MSE_persistence/step_{i:03}/val"] = F.mse_loss(
|
|
499
|
-
persistence[:, i], y[:, i]
|
|
500
|
-
)
|
|
501
|
-
# Get the losses in the format of {VAL>_horizon/step_000: 0.1, VAL>_horizon/step_001: 0.2}
|
|
502
|
-
# for each step in the forecast horizon
|
|
503
|
-
# This is needed for the custom plot
|
|
504
|
-
# And needs to be in order of step
|
|
505
|
-
x_values = [
|
|
506
|
-
int(k.split("_")[-1].split("/")[0])
|
|
507
|
-
for k in logged_losses.keys()
|
|
508
|
-
if "MAE_horizon/step" in k
|
|
509
|
-
]
|
|
510
|
-
y_values = []
|
|
511
|
-
for x in x_values:
|
|
512
|
-
y_values.append(logged_losses[f"MAE_horizon/step_{x:03}/val"])
|
|
513
|
-
per_step_losses = [[x, y] for (x, y) in zip(x_values, y_values)]
|
|
514
|
-
# Check if WandBLogger is being used
|
|
515
|
-
if isinstance(self.logger, pl.loggers.WandbLogger):
|
|
516
|
-
table = wandb.Table(data=per_step_losses, columns=["timestep", "MAE"])
|
|
517
|
-
wandb.log(
|
|
518
|
-
{
|
|
519
|
-
"mae_vs_timestep": wandb.plot.line(
|
|
520
|
-
table, "timestep", "MAE", title="MAE vs Timestep"
|
|
521
|
-
)
|
|
522
|
-
}
|
|
523
|
-
)
|
|
524
528
|
|
|
525
529
|
self.log_dict(
|
|
526
530
|
logged_losses,
|
|
@@ -530,7 +534,8 @@ class BaseModel(pl.LightningModule, PVNetModelHubMixin):
|
|
|
530
534
|
|
|
531
535
|
accum_batch_num = batch_idx // self.trainer.accumulate_grad_batches
|
|
532
536
|
|
|
533
|
-
if
|
|
537
|
+
# Make plots only if using wandb logger
|
|
538
|
+
if isinstance(self.logger, pl.loggers.WandbLogger) and accum_batch_num in [0, 1]:
|
|
534
539
|
# Store these temporarily under self
|
|
535
540
|
if not hasattr(self, "_val_y_hats"):
|
|
536
541
|
self._val_y_hats = PredAccumulator()
|
|
@@ -538,47 +543,53 @@ class BaseModel(pl.LightningModule, PVNetModelHubMixin):
|
|
|
538
543
|
|
|
539
544
|
self._val_y_hats.append(y_hat)
|
|
540
545
|
self._val_batches.append(batch)
|
|
541
|
-
|
|
546
|
+
|
|
547
|
+
# if batch has accumulated
|
|
542
548
|
if (batch_idx + 1) % self.trainer.accumulate_grad_batches == 0:
|
|
543
549
|
y_hat = self._val_y_hats.flush()
|
|
544
550
|
batch = self._val_batches.flush()
|
|
545
551
|
|
|
546
|
-
|
|
552
|
+
self._log_forecast_plot(
|
|
547
553
|
batch,
|
|
548
554
|
y_hat,
|
|
549
|
-
|
|
550
|
-
|
|
555
|
+
accum_batch_num,
|
|
556
|
+
timesteps_to_plot=None,
|
|
557
|
+
plot_suffix="all",
|
|
551
558
|
)
|
|
552
559
|
|
|
553
|
-
self.logger.experiment.log(
|
|
554
|
-
{
|
|
555
|
-
f"val_forecast_samples/batch_idx_{accum_batch_num}_all": wandb.Image(fig),
|
|
556
|
-
}
|
|
557
|
-
)
|
|
558
|
-
plt.close(fig)
|
|
559
|
-
|
|
560
560
|
if self.time_step_intervals_to_plot is not None:
|
|
561
561
|
for interval in self.time_step_intervals_to_plot:
|
|
562
|
-
|
|
562
|
+
self._log_forecast_plot(
|
|
563
563
|
batch,
|
|
564
564
|
y_hat,
|
|
565
|
-
|
|
566
|
-
key_to_plot=self._target_key_name,
|
|
565
|
+
accum_batch_num,
|
|
567
566
|
timesteps_to_plot=interval,
|
|
567
|
+
plot_suffix=f"timestep_{interval}",
|
|
568
568
|
)
|
|
569
|
-
self.logger.experiment.log(
|
|
570
|
-
{
|
|
571
|
-
f"val_forecast_samples/batch_idx_{accum_batch_num}_"
|
|
572
|
-
f"timestep_{interval}": wandb.Image(fig),
|
|
573
|
-
}
|
|
574
|
-
)
|
|
575
|
-
plt.close(fig)
|
|
576
569
|
|
|
577
570
|
del self._val_y_hats
|
|
578
571
|
del self._val_batches
|
|
579
572
|
|
|
580
573
|
return logged_losses
|
|
581
574
|
|
|
575
|
+
def on_validation_epoch_end(self):
|
|
576
|
+
"""Run on epoch end"""
|
|
577
|
+
|
|
578
|
+
horizon_maes_dict = self._horizon_maes.flush()
|
|
579
|
+
|
|
580
|
+
# Create the horizon accuracy curve
|
|
581
|
+
if isinstance(self.logger, pl.loggers.WandbLogger):
|
|
582
|
+
per_step_losses = [[i, horizon_maes_dict[i]] for i in range(self.forecast_len)]
|
|
583
|
+
|
|
584
|
+
table = wandb.Table(data=per_step_losses, columns=["horizon_step", "MAE"])
|
|
585
|
+
wandb.log(
|
|
586
|
+
{
|
|
587
|
+
"horizon_loss_curve": wandb.plot.line(
|
|
588
|
+
table, "horizon_step", "MAE", title="Horizon loss curve"
|
|
589
|
+
)
|
|
590
|
+
},
|
|
591
|
+
)
|
|
592
|
+
|
|
582
593
|
def test_step(self, batch, batch_idx):
|
|
583
594
|
"""Run test step"""
|
|
584
595
|
y_hat = self(batch)
|
|
@@ -369,7 +369,10 @@ class Model(MultimodalBaseModel):
|
|
|
369
369
|
def convert_to_multimodal_model(self, config):
|
|
370
370
|
"""Convert the model into a multimodal model class whilst preserving weights"""
|
|
371
371
|
config = config.copy()
|
|
372
|
-
|
|
372
|
+
|
|
373
|
+
if "cold_start" in config:
|
|
374
|
+
del config["cold_start"]
|
|
375
|
+
|
|
373
376
|
config["_target_"] = "pvnet.models.multimodal.multimodal.Model"
|
|
374
377
|
|
|
375
378
|
sources = []
|
|
@@ -416,4 +419,10 @@ class Model(MultimodalBaseModel):
|
|
|
416
419
|
|
|
417
420
|
multimodal_model.output_network.load_state_dict(self.output_network.state_dict())
|
|
418
421
|
|
|
422
|
+
if self.embedding_dim:
|
|
423
|
+
multimodal_model.embed.load_state_dict(self.embed.state_dict())
|
|
424
|
+
|
|
425
|
+
if self.include_sun:
|
|
426
|
+
multimodal_model.sun_fc1.load_state_dict(self.sun_fc1.state_dict())
|
|
427
|
+
|
|
419
428
|
return multimodal_model, config
|
|
@@ -185,7 +185,6 @@ class AdamWReduceLROnPlateau(AbstractOptimizer):
|
|
|
185
185
|
if not isinstance(self._lr, float):
|
|
186
186
|
return self._call_multi(model)
|
|
187
187
|
else:
|
|
188
|
-
assert False
|
|
189
188
|
default_lr = self._lr if model.lr is None else model.lr
|
|
190
189
|
opt = torch.optim.AdamW(model.parameters(), lr=default_lr, **self.opt_kwargs)
|
|
191
190
|
sch = torch.optim.lr_scheduler.ReduceLROnPlateau(
|
PVNet-3.0.22/pvnet/__init__.py
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|