Repository: Lightning-AI/pytorch-lightning

Issue:
Early stopping: fix typo in monitor key val_early_st[o]p_on
<!--
Please note that we have freeze state on adding new features till v1.0 release.
Anyway, any new feature suggestion is welcome and you are free to draft a PR,
 but be aware that several refactoring will take place for this major release yielding in significant collision solving.
A recommendation for feature draft is draw just outline, do not implement all details and propagate the changes to codebase...
-->

## What does this PR do?

<!--
Please include a summary of the change and which issue is fixed.
 Please also include relevant motivation and context.
 List any dependencies that are required for this change.
-->

Fixes the `invalid_key` list `EarlyStopping` uses to trigger its deprecation warning. `val_early_stop_on` was typoed as `val_early_step_on`. 

Encountered locally and previously identified at https://github.com/PyTorchLightning/pytorch-lightning/pull/3073/files#r474732478. This was triggering the deprecation warning when `EvalResults` were being used correctly instead of the opposite, intended behaviour :slightly_smiling_face: 


# Before submitting

- [ ] Was this discussed/approved via a Github issue? (no need for typos and docs improvements)
- [x] Did you read the [contributor guideline](https://github.com/PyTorchLightning/pytorch-lightning/blob/master/.github/CONTRIBUTING.md), Pull Request section?
- [x] Did you make sure your PR does only one thing, instead of bundling different changes together? Otherwise, we ask you to create a separate PR for every change.
- [ ] Did you make sure to update the documentation with your changes?
- [ ] Did you write any new necessary tests? 
- [ ] Did you verify new and existing tests pass locally with your changes?
- [ ] If you made a notable change (that affects users), did you update the [CHANGELOG](https://github.com/PyTorchLightning/pytorch-lightning/blob/master/CHANGELOG.md)?

<!-- For CHANGELOG separate each item in unreleased section by a blank line to reduce collisions -->

## PR review    
Anyone in the community is free to review the PR once the tests have passed.     
If we didn't discuss your PR in Github issues there's a high chance it will not be merged.

## Did you have fun?
Make sure you had fun coding 🙃



Discussion:

Resolving patch:
diff --git a/pytorch_lightning/callbacks/early_stopping.py b/pytorch_lightning/callbacks/early_stopping.py
--- a/pytorch_lightning/callbacks/early_stopping.py
+++ b/pytorch_lightning/callbacks/early_stopping.py
@@ -178,7 +178,7 @@ def on_train_epoch_end(self, trainer, pl_module):
 
     def __warn_deprecated_monitor_key(self):
         using_result_obj = os.environ.get('PL_USING_RESULT_OBJ', None)
-        invalid_key = self.monitor not in ['val_loss', 'early_stop_on', 'val_early_step_on', 'loss']
+        invalid_key = self.monitor not in ['val_loss', 'early_stop_on', 'val_early_stop_on', 'loss']
         if using_result_obj and not self.warned_result_obj and invalid_key:
             self.warned_result_obj = True
             m = f"""
diff --git a/pytorch_lightning/trainer/trainer.py b/pytorch_lightning/trainer/trainer.py
--- a/pytorch_lightning/trainer/trainer.py
+++ b/pytorch_lightning/trainer/trainer.py
@@ -982,7 +982,7 @@ def fit(
             parsing.clean_namespace(model.hparams)
 
         # links data to the trainer
-        self.attach_data(model, train_dataloader, val_dataloaders)
+        self.attach_data(model, train_dataloader, val_dataloaders, datamodule)
 
         # check that model is configured correctly
         self.config_validator.verify_loop_configurations(model)
@@ -990,13 +990,8 @@ def fit(
         # hook
         self.call_hook('on_fit_start', model)
 
-        # on multi-gpu jobs we only want to manipulate (download, etc) on node_rank=0, local_rank=0
-        # or in the case where each node needs to do its own manipulation in which case just local_rank=0
-        if self.can_prepare_data():
-            if self.datamodule is not None:
-                self.datamodule.prepare_data()
-            model.prepare_data()
-            self._is_data_prepared = True
+        # hook
+        self.prepare_data(model)
 
         # Run auto batch size scaling
         if self.auto_scale_batch_size:
@@ -1013,18 +1008,17 @@ def fit(
         # set testing if set in environ
         self.testing = os.environ.get('PL_TESTING_MODE', self.testing)
 
-        # choose accelerator
+        # -------------------------
+        # TRAIN
+        # -------------------------
         self.accelerator_backend = self.select_accelerator()
-
-        # setup accelerator
         self.accelerator_backend.setup(model)
-
-        # train!
         results = self.accelerator_backend.train()
-
-        # teardown accelerator
         self.accelerator_backend.teardown()
 
+        # -------------------------
+        # POST-Training
+        # -------------------------
         # hook
         self.call_hook('on_fit_end')
 
@@ -1037,7 +1031,16 @@ def fit(
         # used for testing or when we need to know that training succeeded
         return results or 1
 
-    def attach_data(self, model, train_dataloader, val_dataloaders):
+    def prepare_data(self, model):
+        # on multi-gpu jobs we only want to manipulate (download, etc) on node_rank=0, local_rank=0
+        # or in the case where each node needs to do its own manipulation in which case just local_rank=0
+        if self.can_prepare_data():
+            if self.datamodule is not None:
+                self.datamodule.prepare_data()
+            model.prepare_data()
+            self._is_data_prepared = True
+
+    def attach_data(self, model, train_dataloader, val_dataloaders, datamodule):
         # if a datamodule comes in as the second arg, then fix it for the user
         if isinstance(train_dataloader, LightningDataModule):
             datamodule = train_dataloader
@@ -1059,10 +1062,7 @@ def select_accelerator(self):
 
         use_ddp_spawn = self.use_ddp and self.distributed_backend in ['ddp_cpu', 'ddp_spawn']
 
-        # -------------------
-        # route training mode
-        # -------------------
-        # DDP2 (cluster only)
+        # choose the appropriate accelerator backend
         if self.use_ddp2:
             accelerator_backend = DDP2Backend(self)
 
@@ -1072,15 +1072,12 @@ def select_accelerator(self):
         elif use_torchelastic_ddp:
             accelerator_backend = DDPBackend(self, mode='torchelastic_ddp')
 
-        # regular ddp using .spawn
         elif use_ddp_spawn:
             accelerator_backend = DDPSpawnBackend(self, nprocs=self.num_processes)
 
-        # ddp
         elif self.distributed_backend == 'ddp':
             accelerator_backend = DDPBackend(self, mode='ddp')
 
-        # dp
         elif self.use_dp:
             accelerator_backend = DataParallelBackend(self)
 
@@ -1098,7 +1095,6 @@ def select_accelerator(self):
 
         return accelerator_backend
 
-
     def can_prepare_data(self):
         should_call_dm_prepare_data = True
         if self.datamodule is not None and self.is_overridden('prepare_data', self.datamodule):


Test patch: