Additional callbacks

目录

<!DOCTYPE html>

Additional callbacks

Additional callbacks

In this reading we'll be looking at more of the inbuilt callbacks available in Keras.

In [1]:
import tensorflow as tf
print(tf.__version__)
2.0.0

We will again be using the sklearn diabetes dataset to demonstrate these callbacks.

In [2]:
# Load the diabetes dataset

from sklearn.datasets import load_diabetes

diabetes_dataset = load_diabetes()
In [3]:
# Save the input and target variables

from sklearn.model_selection import train_test_split

data = diabetes_dataset['data']
targets = diabetes_dataset['target']
In [4]:
# Split the data set into training and test sets

train_data, test_data, train_targets, test_targets = train_test_split(data, targets, test_size=0.1)

Let's also build a simple model to fit to the data with our callbacks.

In [5]:
# Build the model

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense

model = tf.keras.Sequential([
    Dense(128, activation='relu', input_shape=(train_data.shape[1],)),
    Dense(64,activation='relu'),
    Dense(64, activation='relu'),
    Dense(64, activation='relu'),
    Dense(1)        
])
In [6]:
# Compile the model

model.compile(loss='mse',
                optimizer="adam",metrics=["mse","mae"])

Now onto the callbacks!

Learning rate scheduler

Usage: tf.keras.callbacks.LearningRateScheduler(schedule, verbose=0)

The learning rate scheduler that we implemented in the previous reading as a custom callback is also available as a built in callback.

As in our custom callback, the LearningRateScheduler in Keras takes a function schedule as an argument.

This function schedule should take two arguments:

  • The current epoch (as an integer), and
  • The current learning rate,

and return new learning rate for that epoch.

The LearningRateScheduler also has an optional verbose argument, which prints information about the learning rate if it is set to 1.

Let's see a simple example.

In [7]:
# Define the learning rate schedule function

def lr_function(epoch, lr):
    if epoch % 2 == 0:
        return lr
    else:
        return lr + epoch/1000
In [8]:
# Train the model

history = model.fit(train_data, train_targets, epochs=10,
                    callbacks=[tf.keras.callbacks.LearningRateScheduler(lr_function, verbose=1)], verbose=False)
Epoch 00001: LearningRateScheduler reducing learning rate to 0.0010000000474974513.

Epoch 00002: LearningRateScheduler reducing learning rate to 0.0020000000474974513.

Epoch 00003: LearningRateScheduler reducing learning rate to 0.0020000000949949026.

Epoch 00004: LearningRateScheduler reducing learning rate to 0.005000000094994903.

Epoch 00005: LearningRateScheduler reducing learning rate to 0.004999999888241291.

Epoch 00006: LearningRateScheduler reducing learning rate to 0.009999999888241292.

Epoch 00007: LearningRateScheduler reducing learning rate to 0.009999999776482582.

Epoch 00008: LearningRateScheduler reducing learning rate to 0.01699999977648258.

Epoch 00009: LearningRateScheduler reducing learning rate to 0.016999999061226845.

Epoch 00010: LearningRateScheduler reducing learning rate to 0.025999999061226846.

You can also use lambda functions to define your schedule given an epoch.

In [9]:
# Train the model with a difference schedule

history = model.fit(train_data, train_targets, epochs=10,
                    callbacks=[tf.keras.callbacks.LearningRateScheduler(lambda x:1/(3+5*x), verbose=1)], 
                    verbose=False)
Epoch 00001: LearningRateScheduler reducing learning rate to 0.3333333333333333.

Epoch 00002: LearningRateScheduler reducing learning rate to 0.125.

Epoch 00003: LearningRateScheduler reducing learning rate to 0.07692307692307693.

Epoch 00004: LearningRateScheduler reducing learning rate to 0.05555555555555555.

Epoch 00005: LearningRateScheduler reducing learning rate to 0.043478260869565216.

Epoch 00006: LearningRateScheduler reducing learning rate to 0.03571428571428571.

Epoch 00007: LearningRateScheduler reducing learning rate to 0.030303030303030304.

Epoch 00008: LearningRateScheduler reducing learning rate to 0.02631578947368421.

Epoch 00009: LearningRateScheduler reducing learning rate to 0.023255813953488372.

Epoch 00010: LearningRateScheduler reducing learning rate to 0.020833333333333332.

CSV logger

Usage tf.keras.callbacks.CSVLogger(filename, separator=',', append=False)

This callback streams the results from each epoch into a CSV file. The first line of the CSV file will be the names of pieces of information recorded on each subsequent line, beginning with the epoch and loss value. The values of metrics at the end of each epoch will also be recorded.

The only compulsory argument is the filename for the log to be streamed to. This could also be a filepath.

You can also specify the separator to be used between entries on each line.

The append argument allows you the option to append your results to an existing file with the same name. This can be particularly useful if you are continuing training.

Let's see an example.

In [19]:
# Train the model with a CSV logger

history = model.fit(train_data, train_targets, epochs=10,
                    callbacks=[tf.keras.callbacks.CSVLogger("results.csv")], verbose=False)

Let's view the information in the CSV file we have created using pandas.

In [20]:
# Load the CSV

import pandas as pd

pd.read_csv("results.csv", index_col='epoch')
Out[20]:
loss mae mse
epoch
0 23896.504123 134.48586 23896.504
1 23826.282485 134.22104 23826.281
2 23755.256533 133.95755 23755.254
3 23684.821267 133.69608 23684.820
4 23614.457902 133.43208 23614.453
5 23545.134470 133.16771 23545.137
6 23475.444909 132.90617 23475.445
7 23405.455093 132.64537 23405.455
8 23335.961223 132.38477 23335.959
9 23267.293874 132.12321 23267.293
In [20]:
# Load the CSV

import pandas as pd

pd.read_csv("results.csv", index_col='epoch')
Out[20]:
loss mae mse
epoch
0 23896.504123 134.48586 23896.504
1 23826.282485 134.22104 23826.281
2 23755.256533 133.95755 23755.254
3 23684.821267 133.69608 23684.820
4 23614.457902 133.43208 23614.453
5 23545.134470 133.16771 23545.137
6 23475.444909 132.90617 23475.445
7 23405.455093 132.64537 23405.455
8 23335.961223 132.38477 23335.959
9 23267.293874 132.12321 23267.293

Lambda callbacks

Usage tf.keras.callbacks.LambdaCallback( on_epoch_begin=None, on_epoch_end=None, on_batch_begin=None, on_batch_end=None, on_train_begin=None, on_train_end=None)

Lambda callbacks are used to quickly define simple custom callbacks with the use of lambda functions.

Each of the functions require some positional arguments.

  • on_epoch_begin and on_epoch_end expect two arguments: epoch and logs,
  • on_batch_begin and on_batch_end expect two arguments: batch and logs and
  • on_train_begin and on_train_end expect one argument: logs.

Let's see an example of this in practice.

In [21]:
# Print the epoch number at the beginning of each epoch

epoch_callback = tf.keras.callbacks.LambdaCallback(
    on_epoch_begin=lambda epoch,logs: print('Starting Epoch {}!'.format(epoch+1)))
In [22]:
# Print the loss at the end of each batch

batch_loss_callback = tf.keras.callbacks.LambdaCallback(
    on_batch_end=lambda batch,logs: print('\n After batch {}, the loss is {:7.2f}.'.format(batch, logs['loss'])))
In [23]:
# Inform that training is finished

train_finish_callback = tf.keras.callbacks.LambdaCallback(
    on_train_end=lambda logs: print('Training finished!'))
In [25]:
# Train the model with the lambda callbacks

history = model.fit(train_data, train_targets, epochs=5, batch_size=100,
                    callbacks=[epoch_callback, batch_loss_callback,train_finish_callback,tf.keras.callbacks.CSVLogger("results.csv")], verbose=False)
Starting Epoch 1!

 After batch 0, the loss is 23779.13.

 After batch 1, the loss is 24449.60.

 After batch 2, the loss is 23613.42.

 After batch 3, the loss is 20543.16.
Starting Epoch 2!

 After batch 0, the loss is 21188.72.

 After batch 1, the loss is 21663.91.

 After batch 2, the loss is 24936.44.

 After batch 3, the loss is 24634.62.
Starting Epoch 3!

 After batch 0, the loss is 22631.88.

 After batch 1, the loss is 23554.28.

 After batch 2, the loss is 25745.78.

 After batch 3, the loss is 20279.41.
Starting Epoch 4!

 After batch 0, the loss is 22748.96.

 After batch 1, the loss is 21562.11.

 After batch 2, the loss is 21779.12.

 After batch 3, the loss is 26215.65.
Starting Epoch 5!

 After batch 0, the loss is 24382.75.

 After batch 1, the loss is 19106.40.

 After batch 2, the loss is 22746.14.

 After batch 3, the loss is 25980.83.
Training finished!
In [26]:
# Load the CSV

import pandas as pd

pd.read_csv("results.csv", index_col='epoch')
Out[26]:
loss mae mse
epoch
0 23115.618663 131.54805 23115.620
1 23094.371974 131.46873 23094.373
2 23073.793844 131.38940 23073.793
3 23052.738089 131.30988 23052.738
4 23031.913413 131.23051 23031.912

Reduce learning rate on plateau

Usage tf.keras.callbacks.ReduceLROnPlateau( monitor='val_loss', factor=0.1, patience=10, verbose=0, mode='auto', min_delta=0.0001, cooldown=0, min_lr=0)

The ReduceLROnPlateau callback allows reduction of the learning rate when a metric has stopped improving. The arguments are similar to those used in the EarlyStopping callback.

  • The argument monitor is used to specify which metric to base the callback on.
  • The factor is the factor by which the learning rate decreases i.e., new_lr=factor*old_lr.
  • The patience is the number of epochs where there is no improvement on the monitored metric before the learning rate is reduced.
  • The verbose argument will produce progress messages when set to 1.
  • The mode determines whether the learning rate will decrease when the monitored quantity stops increasing (max) or decreasing (min). The auto setting causes the callback to infer the mode from the monitored quantity.
  • The min_delta is the smallest change in the monitored quantity to be deemed an improvement.
  • The cooldown is the number of epochs to wait after the learning rate is changed before the callback resumes normal operation.
  • The min_lr is a lower bound on the learning rate that the callback will produce.

Let's examine a final example.

In [16]:
# Train the model with the ReduceLROnPlateau callback

history = model.fit(train_data, train_targets, epochs=100, batch_size=100,
                    callbacks=[tf.keras.callbacks.ReduceLROnPlateau(
                        monitor="loss",factor=0.2, verbose=1)], verbose=False)