From 0c678051ac7b5c34ef0930a197b0cafc7db9318e Mon Sep 17 00:00:00 2001 From: Steven Potiris Date: Thu, 25 Apr 2019 11:59:20 +0000 Subject: [PATCH 1/3] Added callbacks.NeptuneLogger --- keras_contrib/callbacks/__init__.py | 1 + keras_contrib/callbacks/neptune.py | 63 +++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 keras_contrib/callbacks/neptune.py diff --git a/keras_contrib/callbacks/__init__.py b/keras_contrib/callbacks/__init__.py index 96d82c19e..8a99b9bc0 100644 --- a/keras_contrib/callbacks/__init__.py +++ b/keras_contrib/callbacks/__init__.py @@ -2,3 +2,4 @@ from .dead_relu_detector import DeadReluDetector from .cyclical_learning_rate import CyclicLR from .tensorboard import TensorBoardGrouped +from .neptune import NeptuneLogger diff --git a/keras_contrib/callbacks/neptune.py b/keras_contrib/callbacks/neptune.py new file mode 100644 index 000000000..ccdd214a9 --- /dev/null +++ b/keras_contrib/callbacks/neptune.py @@ -0,0 +1,63 @@ +"""Neptune integration for Keras via callback. +""" +from __future__ import absolute_import +from __future__ import print_function + +from keras.callbacks import Callback + +import neptune + +class NeptuneLogger(Callback): + """ + Neptune integration with keras callbacks. + """ + + def __init__( + self, + project_qualified_name, experiment_name, api_token=None, **kwargs): + """ + Construct the NeptuneLogger callback and log in to neptune. + Neptune experiment creation is delayed until the beginning of training. + + Args: + project_qualified_name (str): The username and project name with + which to log in. + experiment_name (str): The name to give to the new experiment. + api_token (str, optional): The Neptune API token to use as + credentials. By default this is read from the environment + variable NEPTUNE_API_TOKEN. + **kwargs: + For full list see neptune.projects.Project.create_experiment. + Some useful keyword names include: description (str), + params (dict), properties (dict), tags (list of str), + upload_source_files (list of str paths). + Note that the value of this can change between instatiation + and on_train_begin. + + """ + self.experiment_name = experiment_name + self.experiment_kwargs = kwargs + self.project_qualified_name = project_qualified_name + self.experiment = None + + self.session = neptune.sessions.Session(api_token=api_token) + self.project = self.session.get_project(project_qualified_name) + + def __del__(self): + if self.experiment: + self.experiment.stop() + + def on_train_begin(self, logs): + if self.experiment: + return + self.experiment = self.project.create_experiment( + self.experiment_name, **self.experiment_kwargs) + + def on_epoch_end(self, epoch, logs=None): + if not logs: + return + for key, value in logs.items(): + try: + self.experiment.send_metric(key, epoch, float(value)) + except ValueError: + pass # Ignore non numeric values From a87cc6d03355767cb63b25ec92ac5755a0fe0bae Mon Sep 17 00:00:00 2001 From: Steven Potiris Date: Thu, 25 Apr 2019 12:11:09 +0000 Subject: [PATCH 2/3] Added NeptuneLogger example in lieu of unit test. --- examples/neptunelogger.py | 54 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 examples/neptunelogger.py diff --git a/examples/neptunelogger.py b/examples/neptunelogger.py new file mode 100644 index 000000000..e6b4e6e0e --- /dev/null +++ b/examples/neptunelogger.py @@ -0,0 +1,54 @@ +"""Example application with a dummy model using callback-based Neptune integration. +""" +import numpy as np + +from keras_contrib import callbacks +from keras.models import Sequential +from keras.layers import Dense + + +# Replace with your own credentials +PROJECT_QUALIFIED_NAME = "your_username/your_project" +EXPERIMENT_NAME = "test-neptunelogger" +NEPTUNE_API_TOKEN = None # If None, read from environment variable, else provide as string + +def build_model(): + """Build a dummy binary classification model model. + + Returns: + Keras.models.Model: The dummy model. + """ + model = Sequential([ + Dense(2, activation='relu', input_shape=(2,)), + Dense(1, activation='sigmoid') + ]) + return model + + +def test_NeptuneLogger(): + """Test the NeptuneLogger callback with a dummy model and dataset. + """ + X = np.random.rand(100, 2) + y = np.random.rand(100).reshape(-1, 1) + + model = build_model() + model.compile( + optimizer='sgd', + loss='binary_crossentropy', + metrics=['accuracy'] + ) + model.fit( + X, y, + batch_size=1, + epochs=1, + verbose=0, + callbacks=[ + callbacks.NeptuneLogger( + project_qualified_name=PROJECT_QUALIFIED_NAME, + experiment_name=EXPERIMENT_NAME, + api_token=NEPTUNE_API_TOKEN + ) + ]) + +if __name__ == '__main__': + test_NeptuneLogger() From ae5dbfef0af51ec90052074da9b1e83b295d5610 Mon Sep 17 00:00:00 2001 From: Steven Potiris Date: Thu, 25 Apr 2019 13:54:26 +0000 Subject: [PATCH 3/3] PEP8 compliance on neptunelogger and example --- examples/neptunelogger.py | 17 ++++++++++------- keras_contrib/callbacks/neptune.py | 3 ++- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/examples/neptunelogger.py b/examples/neptunelogger.py index e6b4e6e0e..bbe82f725 100644 --- a/examples/neptunelogger.py +++ b/examples/neptunelogger.py @@ -7,14 +7,17 @@ from keras.layers import Dense -# Replace with your own credentials +# Replace below with your own credentials +# If NEPTUNE_API_TOKEN is None, read from environment variable +# otherwise you should provide it as a str PROJECT_QUALIFIED_NAME = "your_username/your_project" EXPERIMENT_NAME = "test-neptunelogger" -NEPTUNE_API_TOKEN = None # If None, read from environment variable, else provide as string +NEPTUNE_API_TOKEN = None + def build_model(): """Build a dummy binary classification model model. - + Returns: Keras.models.Model: The dummy model. """ @@ -44,11 +47,11 @@ def test_NeptuneLogger(): verbose=0, callbacks=[ callbacks.NeptuneLogger( - project_qualified_name=PROJECT_QUALIFIED_NAME, - experiment_name=EXPERIMENT_NAME, - api_token=NEPTUNE_API_TOKEN + project_qualified_name=PROJECT_QUALIFIED_NAME, + experiment_name=EXPERIMENT_NAME, + api_token=NEPTUNE_API_TOKEN ) ]) if __name__ == '__main__': - test_NeptuneLogger() + test_NeptuneLogger() diff --git a/keras_contrib/callbacks/neptune.py b/keras_contrib/callbacks/neptune.py index ccdd214a9..5545052a5 100644 --- a/keras_contrib/callbacks/neptune.py +++ b/keras_contrib/callbacks/neptune.py @@ -7,6 +7,7 @@ import neptune + class NeptuneLogger(Callback): """ Neptune integration with keras callbacks. @@ -60,4 +61,4 @@ def on_epoch_end(self, epoch, logs=None): try: self.experiment.send_metric(key, epoch, float(value)) except ValueError: - pass # Ignore non numeric values + pass # Ignore non numeric values