Repository: ourownstory/neural_prophet

Issue:
[lightning] GPU support
> Depends on the Lightning migration pr #837 

Adds functionality to train the TimeNet model using an accelerator.
Supports GPU, MPS (M1) automatically and all other available Pytorch Lightning accelerators via manual declaration (eg. TPU etc.). Closes #420 


Discussion:
48a0e3d

## Model Benchmark

| Benchmark     | Metric      |      main |   current | diff    |                    |
|---------------|-------------|-----------|-----------|---------|--------------------|
| AirPassengers | MAE_val     |  85.1099  |  15.2698  | -82.06% | :white_check_mark: |
| AirPassengers | RMSE_val    | 108.276   |  19.4209  | -82.06% | :white_check_mark: |
| AirPassengers | Loss_val    | nan       |   0.00195 | 0.0%    | :white_check_mark: |
| AirPassengers | RegLoss_val | nan       |   0       | 0.0%    | :white_check_mark: |
| AirPassengers | epoch       | nan       |  89       | 0.0%    | :white_check_mark: |
| AirPassengers | MAE         |   6.35364 |   9.82902 | 54.7%   | :warning:          |
| AirPassengers | RMSE        |   7.68085 |  11.7005  | 52.33%  | :warning:          |
| AirPassengers | Loss        |   0.00023 |   0.00056 | 140.91% | :warning:          |
| AirPassengers | RegLoss     |   0       |   0       | 0.0%    | :white_check_mark: |
| PeytonManning | MAE_val     |   0.92518 |   0.64636 | -30.14% | :white_check_mark: |
| PeytonManning | RMSE_val    |   1.13074 |   0.79276 | -29.89% | :white_check_mark: |
| PeytonManning | Loss_val    | nan       |   0.01494 | 0.0%    | :white_check_mark: |
| PeytonManning | RegLoss_val | nan       |   0       | 0.0%    | :white_check_mark: |
| PeytonManning | epoch       | nan       |  37       | 0.0%    | :white_check_mark: |
| PeytonManning | MAE         |   0.34839 |   0.42701 | 22.57%  | :warning:          |
| PeytonManning | RMSE        |   0.48617 |   0.57032 | 17.31%  | :warning:          |
| PeytonManning | Loss        |   0.00464 |   0.00635 | 36.95%  | :warning:          |
| PeytonManning | RegLoss     |   0       |   0       | 0.0%    | :white_check_mark: |
| YosemiteTemps | MAE_val     |   1.71173 |   1.72949 | 1.04%   | :white_check_mark: |
| YosemiteTemps | RMSE_val    |   2.2758  |   2.27386 | -0.08%  | :white_check_mark: |
| YosemiteTemps | Loss_val    | nan       |   0.00096 | 0.0%    | :white_check_mark: |
| YosemiteTemps | RegLoss_val | nan       |   0       | 0.0%    | :white_check_mark: |
| YosemiteTemps | epoch       | nan       |  84       | 0.0%    | :white_check_mark: |
| YosemiteTemps | MAE         |   1.43672 |   1.45189 | 1.06%   | :white_check_mark: |
| YosemiteTemps | RMSE        |   2.14749 |   2.16631 | 0.88%   | :white_check_mark: |
| YosemiteTemps | Loss        |   0.00064 |   0.00066 | 1.81%   | :white_check_mark: |
| YosemiteTemps | RegLoss     |   0       |   0       | 0.0%    | :white_check_mark: |

## Model Training

### PeytonManning

![](https://asset.cml.dev/1bcb0a2b86f9ab304053923a9e75153f71fc2c71?cml=svg%2Bxml&cache-bypass=66953d6f-abfc-47be-b9fd-266bc66e66cf)

### YosemiteTemps

![](https://asset.cml.dev/6f26923583523211d42f07709e43d90ac5e26bfe?cml=svg%2Bxml&cache-bypass=4430b11a-4456-4eb1-8d9c-6da1b42d08cb)

### AirPassengers

![](https://asset.cml.dev/6d445875bdcfb2cfde02f76d89cdf6fcbf0eafb7?cml=svg%2Bxml&cache-bypass=459303af-fcc9-446a-9ea3-d31b5012a4d3)

![](https://cml.dev/watermark.png "CML watermark")

# [Codecov](https://codecov.io/gh/ourownstory/neural_prophet/pull/938?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Oskar+Triebe) Report
> :exclamation: No coverage uploaded for pull request base (`lightning@a1db9aa`). [Click here to learn what that means](https://docs.codecov.io/docs/error-reference?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Oskar+Triebe#section-missing-base-commit).
> The diff coverage is `n/a`.

```diff
@@             Coverage Diff              @@
##             lightning     #938   +/-   ##
============================================
  Coverage             ?   87.12%           
============================================
  Files                ?       17           
  Lines                ?     4442           
  Branches             ?        0           
============================================
  Hits                 ?     3870           
  Misses               ?      572           
  Partials             ?        0           
```



Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Oskar+Triebe). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Oskar+Triebe)

@karl-richter One more question: Why did the performance metrics change so heavily? Anything wrong there?

Resolving patch:
diff --git a/neuralprophet/forecaster.py b/neuralprophet/forecaster.py
--- a/neuralprophet/forecaster.py
+++ b/neuralprophet/forecaster.py
@@ -295,6 +295,9 @@ class NeuralProphet:
             Options
                 * ``True``: test data is normalized with global data params even if trained with local data params (global modeling with local normalization)
                 * (default) ``False``: no global modeling with local normalization
+        accelerator: str
+            Name of accelerator from pytorch_lightning.accelerators to use for training. Use "auto" to automatically select an available accelerator.
+            Provide `None` to deactivate the use of accelerators.
         trainer_config: dict
             Dictionary of additional trainer configuration parameters.
     """
@@ -337,6 +340,7 @@ def __init__(
         global_normalization=False,
         global_time_normalization=True,
         unknown_data_normalization=False,
+        accelerator=None,
         trainer_config={},
     ):
         kwargs = locals()
@@ -401,6 +405,7 @@ def __init__(
 
         # Pytorch Lightning Trainer
         self.metrics_logger = MetricsLogger(save_dir=os.getcwd())
+        self.accelerator = accelerator
         self.trainer_config = trainer_config
         self.trainer = None
 
@@ -2377,6 +2382,7 @@ def _train(self, df, df_val=None, minimal=False, continue_training=False):
             config=self.trainer_config,
             metrics_logger=self.metrics_logger,
             early_stopping_target="Loss_val" if df_val is not None else "Loss",
+            accelerator=self.accelerator,
             minimal=minimal,
             num_batches_per_epoch=len(train_loader),
         )
@@ -2439,6 +2445,7 @@ def restore_trainer(self):
             config_train=self.config_train,
             config=self.trainer_config,
             metrics_logger=self.metrics_logger,
+            accelerator=self.accelerator,
         )
         self.metrics = metrics.get_metrics(self.collect_metrics)
 
diff --git a/neuralprophet/utils.py b/neuralprophet/utils.py
--- a/neuralprophet/utils.py
+++ b/neuralprophet/utils.py
@@ -748,6 +748,7 @@ def configure_trainer(
     config: dict,
     metrics_logger,
     early_stopping_target: str = "Loss",
+    accelerator: str = None,
     minimal=False,
     num_batches_per_epoch=100,
 ):
@@ -764,6 +765,8 @@ def configure_trainer(
             MetricsLogger object to log metrics to.
         early_stopping_target : str
             Target metric to use for early stopping.
+        accelerator : str
+            Accelerator to use for training.
         minimal : bool
             If True, no metrics are logged and no progress bar is displayed.
         num_batches_per_epoch : int
@@ -789,6 +792,24 @@ def configure_trainer(
     if "default_root_dir" not in config.keys():
         config["default_root_dir"] = os.getcwd()
 
+    # Accelerator
+    if isinstance(accelerator, str):
+        if (accelerator == "auto" and torch.cuda.is_available()) or accelerator == "gpu":
+            config["accelerator"] = "gpu"
+            config["devices"] = -1
+        elif (accelerator == "auto" and hasattr(torch.backends, "mps")) or accelerator == "mps":
+            if torch.backends.mps.is_available():
+                config["accelerator"] = "mps"
+                config["devices"] = 1
+        elif accelerator != "auto":
+            config["accelerator"] = accelerator
+            config["devices"] = 1
+
+        if hasattr(config, "accelerator"):
+            log.info(f"Using accelerator {config['accelerator']} with {config['devices']} device(s).")
+        else:
+            log.info("No accelerator available. Using CPU for training.")
+
     # Configure callbacks
     callbacks = []
 


Test patch: