Repository: pytorch/ignite

Issue:
Improve State and Engine docs
## 🚀 Feature

Currently, if we execute twice `trainer.run` we can fall into the following situation:
```python
# ...
trainer.run(train_loader, max_epochs=5)

# reset model weights etc and rerun
trainer.run(train_loader, max_epochs=2)
> ValueError: Argument max_epochs should be larger than the start epoch defined in the state: 2 vs 5
```

But if we would like to restart the training from the begining, we have to reset `trainer.state` as 
```python
trainer.run(train_loader, max_epochs=5)

# reset model weights etc and rerun
trainer.state.max_epochs = None
trainer.run(train_loader, max_epochs=2)
```

Let's improve two things:
1) let's provide `State.restart()` method that just sets `state.max_epochs = None`
2) Add a note into `Engine.run` docstring saying if we would like to restart the training from zero, we have to either call `trainer.state.restart()` or `trainer.state.max_epochs = None`.
3) Improve the message "ValueError: Argument max_epochs should be larger than the start epoch defined in the state: 2 vs 5" by adding something like "Please, call state.restart() before calling engine.run() if would like to restart from zero."


For Hacktoberfest contributors, feel free to ask questions for details if any and say that you would like to tackle the issue.
Please, take a look at [CONTRIBUTING guide](https://github.com/pytorch/ignite/blob/master/CONTRIBUTING.md).


Discussion:
@vfdev-5 I could give some help on this one!
@fco-dv thanks, go ahead !

Resolving patch:
diff --git a/ignite/engine/engine.py b/ignite/engine/engine.py
--- a/ignite/engine/engine.py
+++ b/ignite/engine/engine.py
@@ -639,6 +639,18 @@ def run(
                 def switch_batch(engine):
                     engine.state.batch = preprocess_batch(engine.state.batch)
 
+            Restart the training from the beginning. User can reset `max_epochs = None` or either call
+            `trainer.state.restart()`:
+
+            .. code-block:: python
+
+                # ...
+                trainer.run(train_loader, max_epochs=5)
+
+                # Reset model weights etc. and restart the training
+                trainer.state.restart() # equivalent to trainer.state.max_epochs = None
+                trainer.run(train_loader, max_epochs=2)
+
         """
         if seed is not None:
             warnings.warn(
@@ -655,7 +667,10 @@ def switch_batch(engine):
                 if max_epochs < self.state.epoch:
                     raise ValueError(
                         "Argument max_epochs should be larger than the start epoch "
-                        "defined in the state: {} vs {}".format(max_epochs, self.state.epoch)
+                        "defined in the state: {} vs {}. Please, call state.restart() "
+                        "before calling engine.run() in order to restart the training from the beginning.".format(
+                            max_epochs, self.state.epoch
+                        )
                     )
                 self.state.max_epochs = max_epochs
             if epoch_length is not None:
diff --git a/ignite/engine/events.py b/ignite/engine/events.py
--- a/ignite/engine/events.py
+++ b/ignite/engine/events.py
@@ -341,6 +341,9 @@ def get_event_attrib_value(self, event_name: Union[CallableEventWithFilter, Enum
             raise RuntimeError("Unknown event name '{}'".format(event_name))
         return getattr(self, State.event_to_attr[event_name])
 
+    def restart(self) -> None:
+        self.max_epochs = None
+
     def __repr__(self) -> str:
         s = "State:\n"
         for attr, value in self.__dict__.items():


Test patch:
diff --git a/tests/ignite/engine/test_engine_state_dict.py b/tests/ignite/engine/test_engine_state_dict.py
--- a/tests/ignite/engine/test_engine_state_dict.py
+++ b/tests/ignite/engine/test_engine_state_dict.py
@@ -267,3 +267,18 @@ def check_custom_attr():
 
     _test()
     _test(with_load_state_dict=True)
+
+
+def test_restart_training():
+    data = range(10)
+    engine = Engine(lambda e, b: 1)
+    state = engine.run(data, max_epochs=5)
+    with pytest.raises(
+        ValueError,
+        match=r"Argument max_epochs should be larger than the start epoch defined in the state: 2 vs 5. "
+        r"Please, call state.restart\(\) "
+        r"before calling engine.run\(\) in order to restart the training from the beginning.",
+    ):
+        state = engine.run(data, max_epochs=2)
+    state.restart()
+    engine.run(data, max_epochs=2)