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:

Patch:
diff --git a/ignite/engine/engine.py b/ignite/engine/engine.py
index 31c7b134..c50bcfe3 100644
--- a/ignite/engine/engine.py
+++ b/ignite/engine/engine.py
@@ -639,6 +639,18 @@ class Engine(Serializable):
                 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 @@ class Engine(Serializable):
                 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
index 95cfea5e..478583c1 100644
--- a/ignite/engine/events.py
+++ b/ignite/engine/events.py
@@ -341,6 +341,9 @@ class State:
             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
index a9413853..7bc55220 100644
--- a/tests/ignite/engine/test_engine_state_dict.py
+++ b/tests/ignite/engine/test_engine_state_dict.py
@@ -267,3 +267,18 @@ def test_state_custom_attrs_init():
 
     _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)