Repository: pytorch/ignite

Issue:
Load checkpoints within a DeterministicEngine
## 🐛 Bug description

When loading a checkpoint trained with an`Engine` using a `DeterministEngine`, the following error is raised:

```
src/training/engine.py:44: in valid
    self.trainer.valid(self.my_task, checkpoint_path)
src/training/trainers/single_trainer.py:65: in valid
    valid_engine.run(valid_loader)
../../miniconda3/envs/training-py36/lib/python3.6/site-packages/ignite/engine/engine.py:701: in run
    return self._internal_run()
../../miniconda3/envs/training-py36/lib/python3.6/site-packages/ignite/engine/engine.py:774: in _internal_run
    self._handle_exception(e)
../../miniconda3/envs/training-py36/lib/python3.6/site-packages/ignite/engine/engine.py:469: in _handle_exception
    raise e
../../miniconda3/envs/training-py36/lib/python3.6/site-packages/ignite/engine/engine.py:751: in _internal_run
    self._fire_event(Events.EPOCH_COMPLETED)
../../miniconda3/envs/training-py36/lib/python3.6/site-packages/ignite/engine/engine.py:424: in _fire_event
    func(*first, *(event_args + others), **kwargs)
../../miniconda3/envs/training-py36/lib/python3.6/site-packages/ignite/handlers/checkpoint.py:373: in __call__
    checkpoint = self._setup_checkpoint()
../../miniconda3/envs/training-py36/lib/python3.6/site-packages/ignite/handlers/checkpoint.py:437: in _setup_checkpoint
    checkpoint[k] = obj.state_dict()
../../miniconda3/envs/training-py36/lib/python3.6/site-packages/ignite/engine/deterministic.py:186: in state_dict
    state_dict = super(DeterministicEngine, self).state_dict()
../../miniconda3/envs/training-py36/lib/python3.6/site-packages/ignite/engine/engine.py:504: in state_dict
    return OrderedDict([(k, getattr(self.state, k)) for k in keys])

.0 = <tuple_iterator object at 0x166c104a8>

>   return OrderedDict([(k, getattr(self.state, k)) for k in keys])
E   AttributeError: 'State' object has no attribute 'rng_states'
```

Expected behavior:
Since the checkpoint doesn't have rng_states, DeterministEngine should print a warning and ignore the previous rng_states (recreate on the fly)

How to reproduce:
1. Train a pytorch model with an Engine
2. Save a checkpoint
3. Resume the training using a DeterministicEngine

## Environment

- PyTorch Version (e.g., 1.4): 1.7.1
- Ignite Version (e.g., 0.3.0): 0.4.6
- OS (e.g., Linux): macOS
- How you installed Ignite (`conda`, `pip`, source): pip
- Python version: 3.6.10



Discussion:
@H4dr1en Thank you for reporting this issue ! It makes sense to have a better interoperability between `Engine` and `DeterministicEngine`. 

Would you like to help us on this ? Firstly, could you provide a snippet to reproduce ? Thanks in advance.
I think, the problem is not about Deterministic and Engine compatibility, rather I think . . . 

![image](https://user-images.githubusercontent.com/68384968/148433602-889f0cc9-1ea3-4e6c-bc64-071af4de56cf.png)

Conclusion is that we cannot access state_dict() of DeterministicEngine()

Correct me if I am wrong, that we cannot do e2.state_dict()

**reproduce the error:**
```
e2 = DeterministicEngine(lambda e, b: None)
print(e2.state_dict())
```


Resolving patch:
diff --git a/ignite/engine/deterministic.py b/ignite/engine/deterministic.py
--- a/ignite/engine/deterministic.py
+++ b/ignite/engine/deterministic.py
@@ -179,6 +179,8 @@ class DeterministicEngine(Engine):
     def __init__(self, process_function: Callable[[Engine, Any], Any]):
         super(DeterministicEngine, self).__init__(process_function)
         self.state_dict_user_keys.append("rng_states")
+        if not hasattr(self.state, "rng_states"):
+            setattr(self.state, "rng_states", None)
         self.add_event_handler(Events.STARTED, self._init_run)
         self.add_event_handler(Events.DATALOADER_STOP_ITERATION | Events.TERMINATE_SINGLE_EPOCH, self._setup_seed)
 
@@ -189,9 +191,6 @@ def state_dict(self) -> OrderedDict:
 
     def _init_run(self) -> None:
         self.state.seed = int(torch.randint(0, int(1e9), (1,)).item())
-        if not hasattr(self.state, "rng_states"):
-            setattr(self.state, "rng_states", None)
-
         if torch.cuda.is_available():
             torch.backends.cudnn.deterministic = True
             torch.backends.cudnn.benchmark = False


Test patch:
diff --git a/tests/ignite/engine/test_deterministic.py b/tests/ignite/engine/test_deterministic.py
--- a/tests/ignite/engine/test_deterministic.py
+++ b/tests/ignite/engine/test_deterministic.py
@@ -1,6 +1,7 @@
 import os
 import random
 import sys
+from collections.abc import Mapping
 from unittest.mock import patch
 
 import numpy as np
@@ -893,3 +894,13 @@ def test_engine_no_data_asserts():
 
     with pytest.raises(ValueError, match=r"Deterministic engine does not support the option of data=None"):
         trainer.run(max_epochs=10, epoch_length=10)
+
+
+def test_state_dict():
+    engine = DeterministicEngine(lambda e, b: 1)
+    sd = engine.state_dict()
+    assert isinstance(sd, Mapping) and len(sd) == 4
+    assert "iteration" in sd and sd["iteration"] == 0
+    assert "max_epochs" in sd and sd["max_epochs"] is None
+    assert "epoch_length" in sd and sd["epoch_length"] is None
+    assert "rng_states" in sd and sd["rng_states"] is not None