This post will demonstrate how to implement stacked multilayer perceptron for digit recognition.
Here, we consider a multilayer perceptron with four layers and employ the technology of sparse autoencoder to determine the initial values of weighting parameters for the first three layers.
Main workflow
- Preparing training/validation/testing datasets.
- Set the hyperparameters and numerical parameters.
- Determining the initial values for each layer.
- Fine-tuning the model.
- Estimate the accuracy of predictions.
Ipython notebook
In [1]:
%load_ext autoreload
%autoreload 2
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
from dnn_play.classifiers.sparse_autoencoder import SparseAutoencoder
from dnn_play.classifiers.softmax import Softmax
from dnn_play.classifiers.mlp import MLP
from dnn_play.utils.data_utils import load_mnist
from dnn_play.utils.visualize_utils import display_network
# Plot settings
plt.rcParams['figure.figsize'] = (10.0, 10.0) # set default size of plots
plt.rcParams['image.interpolation'] = 'nearest'
In [2]:
# Load MNIST data
(X_train, y_train), (X_val, y_val), (X_test, y_test) = load_mnist()
#(X_train, y_train), (X_val, y_val), (X_test, y_test) = load_mnist(n_train=5500, n_val=500, n_test=1000)
print("X_train shape = {} y_train shape = {}".format(X_train.shape, y_train.shape))
print("X_val shape = {} y_val shape = {}".format(X_val.shape, y_val.shape))
print("X_test shape = {} y_test shape = {}".format(X_test.shape, y_test.shape))
In [3]:
# Network configuration
input_size = X_train.shape[1] # Dimension of features
hidden_size_L1 = 200
hidden_size_L2 = 200
output_size = np.max(y_train) + 1 # Number of classes
layer_units = (input_size, hidden_size_L1, hidden_size_L2, output_size)
n_layers = len(layer_units)
# Hyperparameters
reg = 2e-4 # 1e-4 # Regulation, weight decay
beta = 3 # weight of sparsity penalty term
sparsity_param = 1e-1 # desired average activation of the hidden units
# Numerical parameters
max_iters = 400
In [4]:
# Train the first sparse autoencoder
sae1_layer_units = (input_size, hidden_size_L1, input_size)
sae1 = SparseAutoencoder(sae1_layer_units)
sae1_weights, sae1_loss_history = sae1.fit(X_train, reg=reg, beta=beta, sparsity_param=sparsity_param,
max_iters=max_iters, verbose=True)
# Train / Validation features of layer 1
train_features_L1 = sae1.forward_pass(X_train)
val_features_L1 = sae1.forward_pass(X_val)
In [5]:
# Plot the loss function and train / validation accuracies
plt.subplot(2, 1, 1)
plt.plot(sae1_loss_history)
plt.title('SAE1 Loss history')
plt.xlabel('Epoch')
plt.ylabel('Loss')
Out[5]:
In [6]:
# Visualize the weights
sae1_W0 = sae1_weights[0]['W']
image = display_network(sae1_W0)
plt.imshow(image, cmap = plt.cm.gray)
Out[6]:
In [7]:
# Train the second sparse autoencoder
sae2_layer_units = (hidden_size_L1, hidden_size_L2, hidden_size_L1)
sae2 = SparseAutoencoder(sae2_layer_units)
sae2_weights, sae2_loss_history = sae2.fit(train_features_L1, reg=reg, beta=beta, sparsity_param=sparsity_param,
max_iters=max_iters, verbose=True)
# Train / Validation features of layer 2
train_features_L2 = sae2.forward_pass(train_features_L1)
val_features_L2 = sae2.forward_pass(val_features_L1)
In [8]:
# Plot the loss function and train / validation accuracies
plt.subplot(2, 1, 1)
plt.plot(sae2_loss_history)
plt.title('SAE2 Loss history')
plt.xlabel('Epoch')
plt.ylabel('Loss')
Out[8]:
In [9]:
# Train softmax classifier
sm_layer_units = (hidden_size_L2, output_size)
sm_clf = Softmax(sm_layer_units)
sm_weights, sm_loss_history, sm_train_acc_history, sm_val_acc_history = sm_clf.fit(train_features_L2, y_train,
val_features_L2, y_val, reg=reg, max_iters=max_iters, verbose=True)
In [10]:
# Plot the loss function and train / validation accuracies
plt.subplot(2, 1, 1)
plt.plot(sm_loss_history)
plt.title('Softmax Loss history')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.subplot(2, 1, 2)
plt.plot(sm_train_acc_history)
plt.plot(sm_val_acc_history)
plt.legend(['Softmax Training accuracy', 'Softmax Validation accuracy'], loc='lower right')
plt.xlabel('Epoch')
plt.ylabel('Clasification accuracy')
Out[10]:
In [11]:
# Initial weights
init_weights = [{} for i in range(n_layers - 1)] # Initial weights
init_weights[0] = sae1_weights[0]
init_weights[1] = sae2_weights[0]
init_weights[2] = sm_weights[0]
# Define the Multilayer perceptron classifier
clf = MLP(layer_units, weights=init_weights)
# Train
opt_weights, loss_history, train_acc_history, val_acc_history = clf.fit(X_train, y_train, X_val, y_val,
reg=reg, max_iters=max_iters, verbose=True)
In [12]:
# Plot the loss function and train / validation accuracies
plt.subplot(2, 1, 1)
plt.plot(loss_history)
plt.title('Loss history')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.subplot(2, 1, 2)
plt.plot(train_acc_history)
plt.plot(val_acc_history)
plt.legend(['Training accuracy', 'Validation accuracy'], loc='lower right')
plt.xlabel('Epoch')
plt.ylabel('Clasification accuracy')
Out[12]:
In [13]:
# Make predictions with fine-tune
pred = clf.predict(X_test)
acc = np.mean(y_test == pred)
print("Accuracy with fine-tune: {:5.2f}% \n".format(acc*100))
In [14]:
# Make predictions without fine-tune
clf_without_finetune = MLP(layer_units, weights=init_weights)
pred = clf_without_finetune.predict(X_test)
acc = np.mean(y_test == pred)
print("Accuracy without fine-tune: {:5.2f}% \n".format(acc*100))
In [15]:
# View some images and predictions
n_images = 4
images = X_test[:n_images].reshape((n_images, 28, 28))
pred = clf.predict(X_test[:n_images])
for i in range(n_images):
plt.subplot(1, n_images, i+1)
plt.imshow(images[i], cmap = plt.cm.gray)
plt.title('Predicted digit: {}'.format(pred[i]))
plt.axis('off')
In [16]:
# Visulize the optimal W0
image = display_network(opt_weights[0]['W'])
plt.imshow(image, cmap = plt.cm.gray)
Out[16]:
Sparse autoencoder
Multilayer perceptron
In case you are interested in all codes related in this demonstration, please check the repository.
comments powered by Disqus