Add specific notebook ProgressCalback
# What does this PR do?

This PR introduces a new `NotebookProgressCallback` that is more suitable for trainings in notebook. There are two problems with the current use of tqdm:
- tqdm uses widgets, which disappear when you close and reopen your notebook, or download it from github. Instead of seeing 
  the full progress bar, a message "A Jupyter widget could not be displayed because the widget state could not be found. This 
  could happen if the kernel storing the widget is no longer available, or if the widget state was not saved in the notebook. You 
  may be able to create the widget by running the appropriate cells." appears
- tqdm creates a new widget each time you open a new progress bar, which, when closed, leaves a blank line there is absolutely 
  no way to remove (and I have tried!) This means we have one such blank line for every evaluation.

What's more, notebooks can properly render html code, so we can structure the output displayed during and at the end of training a bit better, using a table for instance.

This PR aims at tackling the issues above by:
- writing its own progress bar in pure HTML and using the `IPython.display` module to display and update it
- adding a table of results also in pure HTML to that progress bar.

It adds no dependency and just add a test (taken from tqdm.auto) to determine if the user is executing code in a notebook environment or not, and picking the best `ProgressCallback` accordingly.

It goes from the previous results:

![](https://i.ibb.co/W5zqv6n/old-progress.png)

To those new ones:

![](https://i.ibb.co/m8zpmmk/new-progress.png)

With a bit more work, it's also possible to add a graph of the losses/metrics that gets updated as the training progresses.
