PVNet 3.0.23__tar.gz → 3.0.25__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.
Files changed (52) hide show
  1. {PVNet-3.0.23 → pvnet-3.0.25}/PKG-INFO +1 -1
  2. {PVNet-3.0.23 → pvnet-3.0.25}/PVNet.egg-info/PKG-INFO +1 -1
  3. pvnet-3.0.25/pvnet/__init__.py +2 -0
  4. {PVNet-3.0.23 → pvnet-3.0.25}/pvnet/models/base_model.py +71 -61
  5. PVNet-3.0.23/pvnet/__init__.py +0 -2
  6. {PVNet-3.0.23 → pvnet-3.0.25}/LICENSE +0 -0
  7. {PVNet-3.0.23 → pvnet-3.0.25}/MANIFEST.in +0 -0
  8. {PVNet-3.0.23 → pvnet-3.0.25}/PVNet.egg-info/SOURCES.txt +0 -0
  9. {PVNet-3.0.23 → pvnet-3.0.25}/PVNet.egg-info/dependency_links.txt +0 -0
  10. {PVNet-3.0.23 → pvnet-3.0.25}/PVNet.egg-info/requires.txt +0 -0
  11. {PVNet-3.0.23 → pvnet-3.0.25}/PVNet.egg-info/top_level.txt +0 -0
  12. {PVNet-3.0.23 → pvnet-3.0.25}/README.md +0 -0
  13. {PVNet-3.0.23 → pvnet-3.0.25}/pvnet/callbacks.py +0 -0
  14. {PVNet-3.0.23 → pvnet-3.0.25}/pvnet/data/__init__.py +0 -0
  15. {PVNet-3.0.23 → pvnet-3.0.25}/pvnet/data/base.py +0 -0
  16. {PVNet-3.0.23 → pvnet-3.0.25}/pvnet/data/datamodule.py +0 -0
  17. {PVNet-3.0.23 → pvnet-3.0.25}/pvnet/data/pv_site_datamodule.py +0 -0
  18. {PVNet-3.0.23 → pvnet-3.0.25}/pvnet/data/utils.py +0 -0
  19. {PVNet-3.0.23 → pvnet-3.0.25}/pvnet/data/wind_datamodule.py +0 -0
  20. {PVNet-3.0.23 → pvnet-3.0.25}/pvnet/models/__init__.py +0 -0
  21. {PVNet-3.0.23 → pvnet-3.0.25}/pvnet/models/baseline/__init__.py +0 -0
  22. {PVNet-3.0.23 → pvnet-3.0.25}/pvnet/models/baseline/last_value.py +0 -0
  23. {PVNet-3.0.23 → pvnet-3.0.25}/pvnet/models/baseline/single_value.py +0 -0
  24. {PVNet-3.0.23 → pvnet-3.0.25}/pvnet/models/ensemble.py +0 -0
  25. {PVNet-3.0.23 → pvnet-3.0.25}/pvnet/models/multimodal/__init__.py +0 -0
  26. {PVNet-3.0.23 → pvnet-3.0.25}/pvnet/models/multimodal/basic_blocks.py +0 -0
  27. {PVNet-3.0.23 → pvnet-3.0.25}/pvnet/models/multimodal/encoders/__init__.py +0 -0
  28. {PVNet-3.0.23 → pvnet-3.0.25}/pvnet/models/multimodal/encoders/basic_blocks.py +0 -0
  29. {PVNet-3.0.23 → pvnet-3.0.25}/pvnet/models/multimodal/encoders/encoders2d.py +0 -0
  30. {PVNet-3.0.23 → pvnet-3.0.25}/pvnet/models/multimodal/encoders/encoders3d.py +0 -0
  31. {PVNet-3.0.23 → pvnet-3.0.25}/pvnet/models/multimodal/encoders/encodersRNN.py +0 -0
  32. {PVNet-3.0.23 → pvnet-3.0.25}/pvnet/models/multimodal/linear_networks/__init__.py +0 -0
  33. {PVNet-3.0.23 → pvnet-3.0.25}/pvnet/models/multimodal/linear_networks/basic_blocks.py +0 -0
  34. {PVNet-3.0.23 → pvnet-3.0.25}/pvnet/models/multimodal/linear_networks/networks.py +0 -0
  35. {PVNet-3.0.23 → pvnet-3.0.25}/pvnet/models/multimodal/multimodal.py +0 -0
  36. {PVNet-3.0.23 → pvnet-3.0.25}/pvnet/models/multimodal/multimodal_base.py +0 -0
  37. {PVNet-3.0.23 → pvnet-3.0.25}/pvnet/models/multimodal/site_encoders/__init__.py +0 -0
  38. {PVNet-3.0.23 → pvnet-3.0.25}/pvnet/models/multimodal/site_encoders/basic_blocks.py +0 -0
  39. {PVNet-3.0.23 → pvnet-3.0.25}/pvnet/models/multimodal/site_encoders/encoders.py +0 -0
  40. {PVNet-3.0.23 → pvnet-3.0.25}/pvnet/models/multimodal/unimodal_teacher.py +0 -0
  41. {PVNet-3.0.23 → pvnet-3.0.25}/pvnet/models/utils.py +0 -0
  42. {PVNet-3.0.23 → pvnet-3.0.25}/pvnet/optimizers.py +0 -0
  43. {PVNet-3.0.23 → pvnet-3.0.25}/pvnet/training.py +0 -0
  44. {PVNet-3.0.23 → pvnet-3.0.25}/pvnet/utils.py +0 -0
  45. {PVNet-3.0.23 → pvnet-3.0.25}/pyproject.toml +0 -0
  46. {PVNet-3.0.23 → pvnet-3.0.25}/requirements-dev.txt +0 -0
  47. {PVNet-3.0.23 → pvnet-3.0.25}/requirements.txt +0 -0
  48. {PVNet-3.0.23 → pvnet-3.0.25}/setup.cfg +0 -0
  49. {PVNet-3.0.23 → pvnet-3.0.25}/setup.py +0 -0
  50. {PVNet-3.0.23 → pvnet-3.0.25}/tests/__init__.py +0 -0
  51. {PVNet-3.0.23 → pvnet-3.0.25}/tests/conftest.py +0 -0
  52. {PVNet-3.0.23 → pvnet-3.0.25}/tests/test_end2end.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PVNet
3
- Version: 3.0.23
3
+ Version: 3.0.25
4
4
  Summary: PVNet
5
5
  Author: Peter Dudfield
6
6
  Author-email: info@openclimatefix.org
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PVNet
3
- Version: 3.0.23
3
+ Version: 3.0.25
4
4
  Summary: PVNet
5
5
  Author: Peter Dudfield
6
6
  Author-email: info@openclimatefix.org
@@ -0,0 +1,2 @@
1
+ """PVNet"""
2
+ __version__ = "3.0.25"
@@ -302,6 +302,7 @@ class BaseModel(pl.LightningModule, PVNetModelHubMixin):
302
302
  self._accumulated_metrics = MetricAccumulator()
303
303
  self._accumulated_batches = BatchAccumulator(key_to_keep=self._target_key_name)
304
304
  self._accumulated_y_hat = PredAccumulator()
305
+ self._horizon_maes = MetricAccumulator()
305
306
 
306
307
  # Store whether the model should use quantile regression or simply predict the mean
307
308
  self.use_quantile_regression = self.output_quantiles is not None
@@ -390,6 +391,18 @@ class BaseModel(pl.LightningModule, PVNetModelHubMixin):
390
391
 
391
392
  return losses
392
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
+
393
406
  def _calculate_val_losses(self, y, y_hat):
394
407
  """Calculate additional validation losses"""
395
408
 
@@ -405,12 +418,17 @@ class BaseModel(pl.LightningModule, PVNetModelHubMixin):
405
418
 
406
419
  # Take median value for remaining metric calculations
407
420
  y_hat = self._quantiles_to_prediction(y_hat)
408
- mse_each_step = torch.mean((y_hat - y) ** 2, dim=0)
409
- mae_each_step = torch.mean(torch.abs(y_hat - y), dim=0)
410
421
 
411
- losses.update({f"MSE_horizon/step_{i:03}": m for i, m in enumerate(mse_each_step)})
412
- losses.update({f"MAE_horizon/step_{i:03}": m for i, m in enumerate(mae_each_step)})
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)
413
429
 
430
+ # Log persistance loss at each time horizon
431
+ losses.update(self._step_mae_and_mse(y, y_persist, dict_key_root="persistence"))
414
432
  return losses
415
433
 
416
434
  def _calculate_test_losses(self, y, y_hat):
@@ -477,51 +495,36 @@ class BaseModel(pl.LightningModule, PVNetModelHubMixin):
477
495
  opt_target = losses["MAE/train"]
478
496
  return opt_target
479
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
+
480
512
  def validation_step(self, batch: dict, batch_idx):
481
513
  """Run validation step"""
482
514
  y_hat = self(batch)
483
515
  # Sensor seems to be in batch, station, time order
484
516
  y = batch[self._target_key][:, -self.forecast_len :, 0]
485
- persistence = batch[self._target_key][:, -self.forecast_len - 1, 0]
517
+
486
518
  # Expand persistence to be the same shape as y
487
- persistence = persistence.unsqueeze(1).expand(-1, self.forecast_len)
488
519
  losses = self._calculate_common_losses(y, y_hat)
489
520
  losses.update(self._calculate_val_losses(y, y_hat))
490
521
 
522
+ # Store these to make horizon accuracy plot
523
+ self._horizon_maes.append(
524
+ {i: losses[f"MAE_horizon/step_{i:03}"].cpu().numpy() for i in range(self.forecast_len)}
525
+ )
526
+
491
527
  logged_losses = {f"{k}/val": v for k, v in losses.items()}
492
- logged_losses["MAE_persistence/val"] = F.l1_loss(persistence, y)
493
- logged_losses["MSE_persistence/val"] = F.mse_loss(persistence, y)
494
- # Log for each timestep the persistence loss
495
- for i in range(self.forecast_len):
496
- logged_losses[f"MAE_persistence/step_{i:03}/val"] = F.l1_loss(
497
- persistence[:, i], y[:, i]
498
- )
499
- logged_losses[f"MSE_persistence/step_{i:03}/val"] = F.mse_loss(
500
- persistence[:, i], y[:, i]
501
- )
502
- # Get the losses in the format of {VAL>_horizon/step_000: 0.1, VAL>_horizon/step_001: 0.2}
503
- # for each step in the forecast horizon
504
- # This is needed for the custom plot
505
- # And needs to be in order of step
506
- x_values = [
507
- int(k.split("_")[-1].split("/")[0])
508
- for k in logged_losses.keys()
509
- if "MAE_horizon/step" in k
510
- ]
511
- y_values = []
512
- for x in x_values:
513
- y_values.append(logged_losses[f"MAE_horizon/step_{x:03}/val"])
514
- per_step_losses = [[x, y] for (x, y) in zip(x_values, y_values)]
515
- # Check if WandBLogger is being used
516
- if isinstance(self.logger, pl.loggers.WandbLogger):
517
- table = wandb.Table(data=per_step_losses, columns=["timestep", "MAE"])
518
- wandb.log(
519
- {
520
- "mae_vs_timestep": wandb.plot.line(
521
- table, "timestep", "MAE", title="MAE vs Timestep"
522
- )
523
- }
524
- )
525
528
 
526
529
  self.log_dict(
527
530
  logged_losses,
@@ -531,7 +534,8 @@ class BaseModel(pl.LightningModule, PVNetModelHubMixin):
531
534
 
532
535
  accum_batch_num = batch_idx // self.trainer.accumulate_grad_batches
533
536
 
534
- if accum_batch_num in [0, 1]:
537
+ # Make plots only if using wandb logger
538
+ if isinstance(self.logger, pl.loggers.WandbLogger) and accum_batch_num in [0, 1]:
535
539
  # Store these temporarily under self
536
540
  if not hasattr(self, "_val_y_hats"):
537
541
  self._val_y_hats = PredAccumulator()
@@ -539,47 +543,53 @@ class BaseModel(pl.LightningModule, PVNetModelHubMixin):
539
543
 
540
544
  self._val_y_hats.append(y_hat)
541
545
  self._val_batches.append(batch)
542
- # if batch had accumulated
546
+
547
+ # if batch has accumulated
543
548
  if (batch_idx + 1) % self.trainer.accumulate_grad_batches == 0:
544
549
  y_hat = self._val_y_hats.flush()
545
550
  batch = self._val_batches.flush()
546
551
 
547
- fig = plot_batch_forecasts(
552
+ self._log_forecast_plot(
548
553
  batch,
549
554
  y_hat,
550
- quantiles=self.output_quantiles,
551
- key_to_plot=self._target_key_name,
555
+ accum_batch_num,
556
+ timesteps_to_plot=None,
557
+ plot_suffix="all",
552
558
  )
553
559
 
554
- self.logger.experiment.log(
555
- {
556
- f"val_forecast_samples/batch_idx_{accum_batch_num}_all": wandb.Image(fig),
557
- }
558
- )
559
- plt.close(fig)
560
-
561
560
  if self.time_step_intervals_to_plot is not None:
562
561
  for interval in self.time_step_intervals_to_plot:
563
- fig = plot_batch_forecasts(
562
+ self._log_forecast_plot(
564
563
  batch,
565
564
  y_hat,
566
- quantiles=self.output_quantiles,
567
- key_to_plot=self._target_key_name,
565
+ accum_batch_num,
568
566
  timesteps_to_plot=interval,
567
+ plot_suffix=f"timestep_{interval}",
569
568
  )
570
- self.logger.experiment.log(
571
- {
572
- f"val_forecast_samples/batch_idx_{accum_batch_num}_"
573
- f"timestep_{interval}": wandb.Image(fig),
574
- }
575
- )
576
- plt.close(fig)
577
569
 
578
570
  del self._val_y_hats
579
571
  del self._val_batches
580
572
 
581
573
  return logged_losses
582
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
+
583
593
  def test_step(self, batch, batch_idx):
584
594
  """Run test step"""
585
595
  y_hat = self(batch)
@@ -1,2 +0,0 @@
1
- """PVNet"""
2
- __version__ = "3.0.23"
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