liveBook · Manning

Learning rate schedule

As explained in Machine Learning Algorithms in Depth

A learning rate schedule is a rule that specifies how an optimization learning rate changes across iterations.

A learning rate schedule specifies how the optimization step size changes across iterations. It balances progress toward an optimum against unstable updates or unnecessarily long training. section 10.4 section 5.4

A commonly used schedule is

  • ηk = (τ0 + k)^−κ, with τ0 ≥ 0 and κ ∈ (0.5, 1]. section 5.4 section 5.7
  • τ0 slows early iterations, while κ controls how quickly older step sizes are forgotten. section 5.4
  • Robbins–Monro conditions require learning rates to support convergence while controlling oscillations. section 10.4
  • For neural networks, a practical starting point is 1e−3, followed by reduction as iterations increase. section 10.4

SGD logistic regression

An SGD implementation stores τ0, κ, and an η array, then computes η[i] = (τ0 + i)^−κ before updating parameters opposite to the gradient. A synthetic Gaussian-mixture dataset supplies the training example. section 5.4

Listing 10.6 Neural network optimizers
import numpy as np
import pandas as pd
import tensorflow as tf
from tensorflow import keras

from keras import backend as K
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D, Activation

from keras.callbacks import ModelCheckpoint
from keras.callbacks import TensorBoard
from keras.callbacks import LearningRateScheduler 
from keras.callbacks import EarlyStopping

import math
import matplotlib.pyplot as plt

tf.keras.utils.set_random_seed(42)

SAVE_PATH = "/content/drive/MyDrive/Colab Notebooks/data/"

def scheduler(epoch, lr):
    if epoch < 4:
        return lr
    else:
        return lr * tf.math.exp(-0.1)

if __name__ == "__main__":

    img_rows, img_cols = 32, 32
    (x_train, y_train), (x_test, y_test) = 
     keras.datasets.cifar100.load_data()    #1
    x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 
     3).astype("float32") / 255
    x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 
     3).astype("float32") / 255

    y_train_label = keras.utils.to_categorical(y_train)
    y_test_label = keras.utils.to_categorical(y_test)
    num_classes = y_train_label.shape[1]

    batch_size = 256     
    num_epochs = 32    #2

    num_filters_l1 = 64     
    num_filters_l2 = 128     #3

    #CNN architecture
    cnn = Sequential()
    cnn.add(Conv2D(num_filters_l1, kernel_size = (5, 5), 
     input_shape=(img_rows, img_cols, 3), padding='same'))
    cnn.add(Activation('relu'))
    cnn.add(MaxPooling2D(pool_size=(2,2), strides=(2,2)))

    cnn.add(Conv2D(num_filters_l2, kernel_size = (5, 5), padding='same'))
    cnn.add(Activation('relu'))
    cnn.add(MaxPooling2D(pool_size=(2,2), strides=(2,2)))

    cnn.add(Flatten())
    cnn.add(Dense(128))
    cnn.add(Activation('relu'))

    cnn.add(Dense(num_classes))
    cnn.add(Activation('softmax'))

    opt1 = tf.keras.optimizers.SGD()                   #4
    opt2 = tf.keras.optimizers.SGD(momentum=0.9,  #4
     nesterov=True)                                #4
    opt3 = tf.keras.optimizers.RMSprop()                #4
    opt4 = tf.keras.optimizers.Adam()                #4

    optimizer_list = [opt1, opt2, opt3, opt4]

    history_list = []

    for idx in range(len(optimizer_list)):

        K.clear_session()

        opt = optimizer_list[idx]

        cnn.compile(
            loss=keras.losses.CategoricalCrossentropy(),
            optimizer=opt,
            metrics=["accuracy"]
        )

        #define callbacks
        reduce_lr = LearningRateScheduler(scheduler, verbose=1)
        callbacks_list = [reduce_lr]

        #training loop
        hist = cnn.fit(x_train, y_train_label, batch_size=batch_size, 
         epochs=num_epochs, callbacks=callbacks_list, validation_split=0.2)
        history_list.append(hist)

    #end for

    plt.figure()
    plt.plot(history_list[0].history['loss'], 'b', lw=2.0, label='SGD')
    plt.plot(history_list[1].history['loss'], '--r', lw=2.0, label='SGD 
     Nesterov')
    plt.plot(history_list[2].history['loss'], ':g', lw=2.0, label='RMSProp')
    plt.plot(history_list[3].history['loss'], '-.k', lw=2.0, label='ADAM')
    plt.title('LeNet, CIFAR-100, Optimizers')
    plt.xlabel('Epochs')
    plt.ylabel('Cross-Entropy Training Loss')
    plt.legend(loc='upper right')
    plt.show()
    #plt.savefig('./figures/lenet_loss.png')

    plt.figure()
    plt.plot(history_list[0].history['val_accuracy'], 'b', lw=2.0, 
     label='SGD')
    plt.plot(history_list[1].history['val_accuracy'], '--r', lw=2.0, 
     label='SGD Nesterov')
    plt.plot(history_list[2].history['val_accuracy'], ':g', lw=2.0, 
     label='RMSProp')
    plt.plot(history_list[3].history['val_accuracy'], '-.k', lw=2.0, 
     label='ADAM')
    plt.title('LeNet, CIFAR-100, Optimizers')
    plt.xlabel('Epochs')
    plt.ylabel('Validation Accuracy')
    plt.legend(loc='upper right')
    plt.show()
    #plt.savefig('./figures/lenet_loss.png')

    plt.figure()
    plt.plot(history_list[0].history['lr'], 'b', lw=2.0, label='SGD')
    plt.plot(history_list[1].history['lr'], '--r', lw=2.0, label='SGD 
     Nesterov')
    plt.plot(history_list[2].history['lr'], ':g', lw=2.0, label='RMSProp')
    plt.plot(history_list[3].history['lr'], '-.k', lw=2.0, label='ADAM')
    plt.title('LeNet, CIFAR-100, Optimizers')
    plt.xlabel('Epochs')
    plt.ylabel('Learning Rate Schedule')
    plt.legend(loc='upper right')
    plt.show()
    #plt.savefig('./figures/lenet_loss.png')

The TensorFlow/Keras implementation defines a LearningRateScheduler callback that keeps the rate unchanged for four epochs and then multiplies it by exp(−0.1). section 10.4

How Machine Learning Algorithms in Depth covers it

How deep it goes
Derives a Robbins–Monro schedule, interprets its parameters, and implements iteration- and epoch-based decay.
Examples
Uses SGD logistic regression on a synthetic Gaussian mixture and neural-network training on CIFAR-100.
What it assumes
Assumes gradients, parameter updates, and stochastic gradient descent while defining schedule parameters and convergence conditions.
What you can do after
Apply it via SGD code or a TensorFlow/Keras LearningRateScheduler callback.
How it connects
Connects stochastic gradient descent with Robbins–Monro conditions, logistic regression, and neural-network optimizers.

Also explained in

Compare how 2 books explain learning rate schedule →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Machine Learning Algorithms in Depth. The section links point to the parts of the book it draws on.