diff --git a/examples/neptunelogger.py b/examples/neptunelogger.py new file mode 100644 index 000000000..bbe82f725 --- /dev/null +++ b/examples/neptunelogger.py @@ -0,0 +1,57 @@ +"""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 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 + + +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() 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..5545052a5 --- /dev/null +++ b/keras_contrib/callbacks/neptune.py @@ -0,0 +1,64 @@ +"""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