From 049e211a0becfbd6a7bfbeddd490ed7195027386 Mon Sep 17 00:00:00 2001 From: rodrigoarenas <31422766+rodrigo-arenas@users.noreply.github.com> Date: Sat, 26 Jun 2021 16:32:40 -0500 Subject: [PATCH] TensorBoard callback --- README.rst | 14 ++--- dev-requirements.txt | 1 + docs/api/callbacks.rst | 7 ++- docs/images/tensorboard_log.png | Bin 0 -> 92432 bytes docs/release_notes.rst | 8 ++- docs/tutorials/callbacks.rst | 30 ++++++++++ sklearn_genetic/callbacks/__init__.py | 3 +- sklearn_genetic/callbacks/loggers.py | 55 +++++++++++++++++- .../callbacks/tests/test_callbacks.py | 35 +++++++++++ sklearn_genetic/tests/test_genetic_search.py | 1 + 10 files changed, 139 insertions(+), 15 deletions(-) create mode 100644 docs/images/tensorboard_log.png diff --git a/README.rst b/README.rst index 68aa22f..b507fcb 100644 --- a/README.rst +++ b/README.rst @@ -48,7 +48,8 @@ Main Features: * **GASearchCV**: Principal class of the package, holds the evolutionary cross validation optimization routine. * **Algorithms**: Set of different evolutionary algorithms to use as optimization procedure. -* **Callbacks**: Custom evaluation strategies to generate early stopping rules, logging or custom logic. +* **Callbacks**: Custom evaluation strategies to generate early stopping rules, + logging (into TensorBoard, .pkl files, etc) or your custom logic. * **Plots**: Generate pre-defined plots to understand the optimization process. * **MLflow**: Build-in integration with mlflow to log all the hyperparameters, cv-scores and the fitted models. @@ -153,16 +154,13 @@ Contributions are more than welcome! There are lots of opportunities on the on going project, so please get in touch if you would like to help out. Also check the `Contribution guide `_ +Big thanks to the people who are helping this project! + +|Contributors|_ + Testing ####### After installation, you can launch the test suite from outside the source directory:: pytest sklearn_genetic - - -Current Contributors -#################### -Big thanks to the people who are helping this project! - -|Contributors|_ diff --git a/dev-requirements.txt b/dev-requirements.txt index 527febf..68f03f3 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -14,3 +14,4 @@ sphinx_rtd_theme sphinx-copybutton numpydoc nbsphinx +tensorflow>=2.0.0 diff --git a/docs/api/callbacks.rst b/docs/api/callbacks.rst index 13708b9..3326e5e 100644 --- a/docs/api/callbacks.rst +++ b/docs/api/callbacks.rst @@ -9,9 +9,10 @@ Callbacks DeltaThreshold TimerStopping ThresholdStopping - ThresholdStopping + TensorBoard LogbookSaver + .. autoclass:: sklearn_genetic.callbacks.base.BaseCallback :members: :undoc-members: False @@ -32,6 +33,10 @@ Callbacks :members: :undoc-members: False +.. autoclass:: TensorBoard + :members: + :undoc-members: False + .. autoclass:: LogbookSaver :members: :undoc-members: False diff --git a/docs/images/tensorboard_log.png b/docs/images/tensorboard_log.png new file mode 100644 index 0000000000000000000000000000000000000000..7049af656d36c594f90cbbf3fe3a2d9916fdb730 GIT binary patch literal 92432 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%0De_cV)LiN0dWovJ+PkBTD0k3 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 literal 0 HcmV?d00001 diff --git a/docs/release_notes.rst b/docs/release_notes.rst index 5363a07..9dcd2d1 100644 --- a/docs/release_notes.rst +++ b/docs/release_notes.rst @@ -12,6 +12,9 @@ This is the current development version, these features are not yet available th Features: ^^^^^^^^^ +* Added the :class:`~sklearn_genetic.callbacks.TensorBoard` callback to log the + generation metrics, watch in real time while the models are trained + and compare different runs in your TensorBoard instance. * Added the :class:`~sklearn_genetic.callbacks.TimerStopping` callback to stop the iterations after a total (threshold) fitting time has been elapsed. * Added new parallel coordinates plot in :func:`~sklearn_genetic.plots.plot_parallel_coordinates`. @@ -33,8 +36,9 @@ Docs: ^^^^^ * Edited all demos to be in the jupyter notebook format. -* Added embedded jupyter notebooks examples -* The modules of the package now have a summary of their classes/functions in the docs +* Added embedded jupyter notebooks examples. +* The modules of the package now have a summary of their classes/functions in the docs. +* Updated the callbacks tutorials to add new TensorBoard callback. What's new in 0.5.0 ------------------- diff --git a/docs/tutorials/callbacks.rst b/docs/tutorials/callbacks.rst index 05ba874..05b22e5 100644 --- a/docs/tutorials/callbacks.rst +++ b/docs/tutorials/callbacks.rst @@ -31,6 +31,8 @@ the data set and model used in :ref:`basic-usage`. The available callbacks are: * ThresholdStopping +* TensorBoard + * LogbookSaver ConsecutiveStopping @@ -108,6 +110,34 @@ if the 'fitness_max' is above 0.98: evolved_estimator.fit(X, y, callbacks=callback) + +TensorBoard +------------ +It saves at each iteration the fitness metrics into a log folder that can be +read by Tensorboard. + +To use this callback you must install tensorflow first:: + + pip install tensorflow + +It only requires to define the folder where you want to log your run, and optionally, a run_id, so +your consecutive runs doesn't mix up. +If the run_id is not provided, it will create a subfolder with the current datetime of your run. + +.. code:: python3 + + from sklearn_genetic.callbacks import TensorBoard + callback = TensorBoard(log_dir="./logs") + + evolved_estimator.fit(X, y, callbacks=callback) + +While the model is being trained you can see in real time the metrics in Tensorboard. +If you have run more that 1 GASearchCV model and use the TensordBoard callback using +the same log_dir but different run_id, you can compare the metrics of each run, it looks +like this for the fitness in three different runs: + +.. image:: ../images/tensorboard_log.png + LogbookSaver ------------ It saves at each iteration the Logbook object with all the parameters and diff --git a/sklearn_genetic/callbacks/__init__.py b/sklearn_genetic/callbacks/__init__.py index 49a5ade..c11b37e 100644 --- a/sklearn_genetic/callbacks/__init__.py +++ b/sklearn_genetic/callbacks/__init__.py @@ -4,7 +4,7 @@ ConsecutiveStopping, TimerStopping, ) -from .loggers import LogbookSaver +from .loggers import LogbookSaver, TensorBoard __all__ = [ "DeltaThreshold", @@ -12,4 +12,5 @@ "ConsecutiveStopping", "TimerStopping", "LogbookSaver", + "TensorBoard", ] diff --git a/sklearn_genetic/callbacks/loggers.py b/sklearn_genetic/callbacks/loggers.py index 4cd7caf..2808a85 100644 --- a/sklearn_genetic/callbacks/loggers.py +++ b/sklearn_genetic/callbacks/loggers.py @@ -1,8 +1,20 @@ import logging +import os +import time from copy import deepcopy from joblib import dump from .base import BaseCallback +from ..parameters import Metrics + +logger = logging.getLogger(__name__) # noqa + +try: + import tensorflow as tf +except ModuleNotFoundError: # noqa + logger.error( + "Tensorflow not found, pip install tensorflow to use TensorBoard callback" + ) # noqa class LogbookSaver(BaseCallback): @@ -28,9 +40,46 @@ def on_step(self, record=None, logbook=None, estimator=None): dump_logbook = deepcopy(estimator.logbook.chapters["parameters"]) dump(dump_logbook, self.checkpoint_path, **self.dump_options) except Exception as e: - logging.error("Could not save the Logbook in the checkpoint") + logger.error("Could not save the Logbook in the checkpoint") return False - def __call__(self, record=None, logbook=None, estimator=None): - return self.on_step(record, logbook, estimator) + +class TensorBoard(BaseCallback): + """Log all the fitness metrics to Tensorboard into log_dir/run_id folder""" + + def __init__(self, log_dir="./logs", run_id=None): + """ + Parameters + ---------- + log_dir: str, default="./logs" + Path to the main folder where the data will be log + run_id: str, default=None + Subfolder where the data will be log, if None it will create a folder + with the current datetime with format time.strftime("%Y_%m_%d-%H_%M_%S") + """ + + self.log_dir = log_dir + + if run_id is None: + self.run_id = time.strftime("%Y_%m_%d-%H_%M_%S") + else: + self.run_id = run_id + + self.path = os.path.join(log_dir, self.run_id) + + def on_step(self, record=None, logbook=None, estimator=None): + + # Get the last metric value + stats = logbook[-1] + + # Create logs files placeholder + writer = tf.summary.create_file_writer(self.path) + + # Log the metrics + with writer.as_default(): + for metric in Metrics.list(): + tf.summary.scalar(name=metric, data=stats[metric], step=stats["gen"]) + writer.flush() + + return False diff --git a/sklearn_genetic/callbacks/tests/test_callbacks.py b/sklearn_genetic/callbacks/tests/test_callbacks.py index 9096e05..575c40e 100644 --- a/sklearn_genetic/callbacks/tests/test_callbacks.py +++ b/sklearn_genetic/callbacks/tests/test_callbacks.py @@ -1,5 +1,6 @@ import pytest import os +import shutil import logging from deap.tools import Logbook @@ -14,6 +15,7 @@ ConsecutiveStopping, DeltaThreshold, LogbookSaver, + TensorBoard, ) from ..validations import check_stats, check_callback from ..base import BaseCallback @@ -189,3 +191,36 @@ def test_logbook_saver_callback(caplog): callback = LogbookSaver(checkpoint_path="./no_folder/logbook.pkl", estimator=4) callback() assert "Could not save the Logbook in the checkpoint" in caplog.text + + +@pytest.mark.parametrize( + "callback, path", + [ + (TensorBoard(), "./logs"), + (TensorBoard(log_dir="./sklearn_logs"), "./sklearn_logs"), + (TensorBoard(log_dir="./logs", run_id="0"), "./logs/0"), + (TensorBoard(log_dir="./logs", run_id="1"), "./logs/1"), + ], +) +def test_tensorboard_callback(callback, path): + assert check_callback(callback) == [callback] + + clf = DecisionTreeClassifier() + evolved_estimator = GASearchCV( + clf, + cv=3, + scoring="accuracy", + generations=2, + param_grid={ + "min_weight_fraction_leaf": Continuous(0, 0.5), + "max_depth": Integer(2, 20), + "max_leaf_nodes": Integer(2, 30), + }, + verbose=False, + ) + + evolved_estimator.fit(X_train, y_train, callbacks=callback) + + assert os.path.exists(path) + + shutil.rmtree(path) diff --git a/sklearn_genetic/tests/test_genetic_search.py b/sklearn_genetic/tests/test_genetic_search.py index b0b7412..1fd7fdc 100644 --- a/sklearn_genetic/tests/test_genetic_search.py +++ b/sklearn_genetic/tests/test_genetic_search.py @@ -15,6 +15,7 @@ DeltaThreshold, ConsecutiveStopping, TimerStopping, + TensorBoard, ) data = load_digits()