In [0]:
#@title Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

Overview

This notebook demonstrates how to use Moving Average Optimizer along with the Model Average Checkpoint from tensorflow addons pagkage.

Moving Averaging

The advantage of Moving Averaging is that they are less prone to rampant loss shifts or irregular data representation in the latest batch. It gives a smooothened and a more genral idea of the model training until some point.

Stocastic Averaging

Stocastic Weight Averaging converges to wider optimas. By doing so, it resembles geometric ensembeling. SWA is a simple method to improve model performance when used as a wrapper around other optimizers and averaging results from different points of trajectory of the inner optimizer.

Model Average Checkpoint

callbacks.ModelCheckpoint doesn't give you the option to save moving average weights in the middle of traning, which is why Model Average Optimizers required a custom callback. Using the update_weights parameter, ModelAverageCheckpoint allows you to:

  1. Assign the moving average weights to the model, and save them.
  2. Keep the old non-averaged weights, but the saved model uses the average weights.

Setup


In [0]:
import tensorflow as tf
import tensorflow_addons as tfa


TensorFlow 2.x selected.

In [0]:
import numpy as np
import os

Build Model


In [0]:
def create_model(opt):
    model = tf.keras.models.Sequential([
        tf.keras.layers.Flatten(),                         
        tf.keras.layers.Dense(64, activation='relu', name='dense_1'),
        tf.keras.layers.Dense(64, activation='relu', name='dense_2'),
        tf.keras.layers.Dense(10, activation='softmax')
    ])

    model.compile(optimizer=opt,
                    loss='sparse_categorical_crossentropy',
                    metrics=['accuracy'])

    return model

Prepare Dataset


In [0]:
#Load Fashion MNIST dataset
train, test = tf.keras.datasets.fashion_mnist.load_data()

images, labels = train
images = images/255.0
labels = labels.astype(np.int32)

fmnist_train_ds = tf.data.Dataset.from_tensor_slices((images, labels))
fmnist_train_ds = fmnist_train_ds.shuffle(5000).batch(32)

test_images, test_labels = test

We will be comparing three optimizers here:

  • Unwrapped SGD
  • SGD with Moving Average
  • SGD with Stochastic Weight Averaging

And see how they perform with the same model.


In [0]:
#Optimizers 
sgd = tf.keras.optimizers.SGD(0.01)
moving_avg_sgd = tfa.optimizers.MovingAverage(sgd)
stocastic_avg_sgd = tfa.optimizers.SWA(sgd)

Both MovingAverage and StocasticAverage optimers use ModelAverageCheckpoint.


In [0]:
#Callback 
checkpoint_path = "./training/cp-{epoch:04d}.ckpt"
checkpoint_dir = os.path.dirname(checkpoint_path)

cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_dir,
                                                 save_weights_only=True,
                                                 verbose=1)
avg_callback = tfa.callbacks.AverageModelCheckpoint(filepath=checkpoint_dir, 
                                                    update_weights=True)

Train Model

Vanilla SGD Optimizer


In [0]:
#Build Model
model = create_model(sgd)

#Train the network
model.fit(fmnist_train_ds, epochs=5, callbacks=[cp_callback])


Train for 1875 steps
Epoch 1/5
1852/1875 [============================>.] - ETA: 0s - loss: 0.7862 - accuracy: 0.7415
Epoch 00001: saving model to ./training
1875/1875 [==============================] - 4s 2ms/step - loss: 0.7834 - accuracy: 0.7423
Epoch 2/5
1846/1875 [============================>.] - ETA: 0s - loss: 0.5004 - accuracy: 0.8253
Epoch 00002: saving model to ./training
1875/1875 [==============================] - 4s 2ms/step - loss: 0.4993 - accuracy: 0.8257
Epoch 3/5
1854/1875 [============================>.] - ETA: 0s - loss: 0.4543 - accuracy: 0.8409
Epoch 00003: saving model to ./training
1875/1875 [==============================] - 3s 2ms/step - loss: 0.4548 - accuracy: 0.8407
Epoch 4/5
1848/1875 [============================>.] - ETA: 0s - loss: 0.4275 - accuracy: 0.8487
Epoch 00004: saving model to ./training
1875/1875 [==============================] - 4s 2ms/step - loss: 0.4277 - accuracy: 0.8488
Epoch 5/5
1860/1875 [============================>.] - ETA: 0s - loss: 0.4100 - accuracy: 0.8558
Epoch 00005: saving model to ./training
1875/1875 [==============================] - 4s 2ms/step - loss: 0.4098 - accuracy: 0.8558
Out[0]:
<tensorflow.python.keras.callbacks.History at 0x7f41077eedd8>

In [0]:
#Evalute results
model.load_weights(checkpoint_dir)
loss, accuracy = model.evaluate(test_images, test_labels, batch_size=32, verbose=2)
print("Loss :", loss)
print("Accuracy :", accuracy)


10000/10000 - 0s - loss: 87.3869 - accuracy: 0.7872
Loss : 87.38689237976074
Accuracy : 0.7872

Moving Average SGD


In [0]:
#Build Model
model = create_model(moving_avg_sgd)

#Train the network
model.fit(fmnist_train_ds, epochs=5, callbacks=[avg_callback])


Train for 1875 steps
Epoch 1/5
WARNING:tensorflow:From /tensorflow-2.1.0/python3.6/tensorflow_core/python/ops/resource_variable_ops.py:1786: calling BaseResourceVariable.__init__ (from tensorflow.python.ops.resource_variable_ops) with constraint is deprecated and will be removed in a future version.
Instructions for updating:
If using Keras pass *_constraint arguments to layers.
1855/1875 [============================>.] - ETA: 0s - loss: 0.7940 - accuracy: 0.7307INFO:tensorflow:Assets written to: ./training/assets
1875/1875 [==============================] - 5s 3ms/step - loss: 0.7924 - accuracy: 0.7312
Epoch 2/5
1859/1875 [============================>.] - ETA: 0s - loss: 0.5076 - accuracy: 0.8237INFO:tensorflow:Assets written to: ./training/assets
1875/1875 [==============================] - 4s 2ms/step - loss: 0.5073 - accuracy: 0.8237
Epoch 3/5
1874/1875 [============================>.] - ETA: 0s - loss: 0.4585 - accuracy: 0.8390INFO:tensorflow:Assets written to: ./training/assets
1875/1875 [==============================] - 4s 2ms/step - loss: 0.4585 - accuracy: 0.8390
Epoch 4/5
1848/1875 [============================>.] - ETA: 0s - loss: 0.4292 - accuracy: 0.8484INFO:tensorflow:Assets written to: ./training/assets
1875/1875 [==============================] - 4s 2ms/step - loss: 0.4301 - accuracy: 0.8480
Epoch 5/5
1869/1875 [============================>.] - ETA: 0s - loss: 0.4108 - accuracy: 0.8555INFO:tensorflow:Assets written to: ./training/assets
1875/1875 [==============================] - 4s 2ms/step - loss: 0.4109 - accuracy: 0.8555
Out[0]:
<tensorflow.python.keras.callbacks.History at 0x7f410517ed30>

In [0]:
#Evalute results
model.load_weights(checkpoint_dir)
loss, accuracy = model.evaluate(test_images, test_labels, batch_size=32, verbose=2)
print("Loss :", loss)
print("Accuracy :", accuracy)


10000/10000 - 0s - loss: 87.3869 - accuracy: 0.7872
Loss : 87.38689237976074
Accuracy : 0.7872

Stocastic Weight Average SGD


In [0]:
#Build Model
model = create_model(stocastic_avg_sgd)

#Train the network
model.fit(fmnist_train_ds, epochs=5, callbacks=[avg_callback])


Train for 1875 steps
Epoch 1/5
1871/1875 [============================>.] - ETA: 0s - loss: 0.7849 - accuracy: 0.7398INFO:tensorflow:Assets written to: ./training/assets
1875/1875 [==============================] - 6s 3ms/step - loss: 0.7844 - accuracy: 0.7400
Epoch 2/5
1857/1875 [============================>.] - ETA: 0s - loss: 0.5601 - accuracy: 0.8083INFO:tensorflow:Assets written to: ./training/assets
1875/1875 [==============================] - 5s 3ms/step - loss: 0.5601 - accuracy: 0.8083
Epoch 3/5
1873/1875 [============================>.] - ETA: 0s - loss: 0.5321 - accuracy: 0.8178INFO:tensorflow:Assets written to: ./training/assets
1875/1875 [==============================] - 5s 3ms/step - loss: 0.5320 - accuracy: 0.8179
Epoch 4/5
1873/1875 [============================>.] - ETA: 0s - loss: 0.5168 - accuracy: 0.8209INFO:tensorflow:Assets written to: ./training/assets
1875/1875 [==============================] - 5s 3ms/step - loss: 0.5168 - accuracy: 0.8210
Epoch 5/5
1860/1875 [============================>.] - ETA: 0s - loss: 0.5083 - accuracy: 0.8228INFO:tensorflow:Assets written to: ./training/assets
1875/1875 [==============================] - 5s 3ms/step - loss: 0.5081 - accuracy: 0.8227
Out[0]:
<tensorflow.python.keras.callbacks.History at 0x7f410ec275c0>

In [0]:
#Evalute results
model.load_weights(checkpoint_dir)
loss, accuracy = model.evaluate(test_images, test_labels, batch_size=32, verbose=2)
print("Loss :", loss)
print("Accuracy :", accuracy)


10000/10000 - 0s - loss: 87.3869 - accuracy: 0.7872
Loss : 87.38689237976074
Accuracy : 0.7872