Title :

Pooling Mechanics

Description :

The aim of this exercise is to understand the difference between average and max pooling by comparing the accuracy and number of parameters for the classification of MNIST digits.

Instructions :

  • Use the helper function get_data() to get the train and test data.
  • Define a function cnn_model that returns a Convolutional Neural Network whose architecture varies based on a variable pool_type:
    • When pool_type is no_pooling the model does not have any pooling layers.
    • When pool_type is max_pooling add a max-pooling layer to the model.
    • When pool_type is avg_pooling add an average-pooling layer to the model.
  • Compile the model and fit it on the training data.
  • Call the function thrice:
    • Once for a model with no pooling layer.
    • Once for a model with average pooling.
    • Once for a model with max pooling.
  • For each of the above mentioned calls, compute the number of parameters in the model and the accuracy of the model on the test data.
  • Use the helper code given to visualise the computed accuracy, loss and number of parameters of all 3 models.

Hints:

MaxPooling2D()Max pooling operation for 2D spatial data.

AveragePooling2D()Average pooling operation for spatial data.

NOTE - In the case of pooling layers, if no stride size is mentioned the default size is the size of the pooling.

compile()Configures the model for training.

Conv2D() 2D convolution layer (e.g. spatial convolution over images).

flatten()Flattens the input.

Dense()A regular densely-connected NN layer.

Dropout() Applies Dropout to the corresponding input

In [0]:
# Import necessary libraries
import numpy as np
import tensorflow as tf
from numpy.random import seed
import matplotlib.pyplot as plt
from prettytable import PrettyTable
from helper import get_data, plot_activation
from tensorflow.keras.models import Sequential
from sklearn.model_selection import train_test_split
from tensorflow.keras.layers import Dense,Conv2D,Dropout,Flatten,MaxPooling2D,AveragePooling2D

# Set random seed
seed(1)
tf.random.set_seed(1)

%matplotlib inline
In [0]:
# Use the helper function get_data to get the train and 
# test MNIST dataset
x_train, y_train, x_test, y_test = get_data()
In [0]:
# Setting the random seed
seed(1)
tf.random.set_seed(1)

# Function to define the CNN model for MNIST classification
def cnn_model(pool_type="no_pooling"):

  # Intialize a sequential model
  model = Sequential(name=pool_type)

  # Define the input shape 
  input_shape = (28, 28, 1)

  # Add a convolutional layer with 28 filters, kernel size of 3,
  # input_shape as input_shape defined above and tanh activation
  model.add(___)

  # Define size of the pooling operation
  pool_size=(3,3)

  # Add an average pooling layer with pool size value as defined 
  # above by pool_size
  if pool_type=="avg_pooling":
    model.add(___)

  # Add a max pooling layer based with pool size value as defined 
  # above by pool_size
  if pool_type=="max_pooling":
    model.add(___)

  # Add a flatten layer
  model.add(___)

  # Add a dense layer with ReLU activation with 16 nodes
  model.add(___)

  # Add a dropout layer with 0.3 as the dropout percentage
  model.add(___)

  # Add an output layer with 10 nodes and softmax activation
  model.add(___)

  # Compile the model with adam optimizer, 
  # sparse_categorical_crossentropy as the loss 
  # and accuracy as the metric
  model.compile(___)
  
  # Fit the model on the train data with 8 epochs
  model.fit(x_train , y_train , epochs= 8, verbose=0,
            shuffle=False, workers=0, use_multiprocessing=False)

  return model
In [0]:
### edTest(test_no_pool) ###
# Call the cnn_model function with pool_type as no_pooling 
# to get the trained model without pooling
model = cnn_model(pool_type="no_pooling")

# Evaluate on the test data
no_pool_acc = model.evaluate(x_test, y_test)
print("The accuracy of the model with no pooling is", no_pool_acc[1])

# Get the number of parameters of the network
no_pool_params = model.count_params()
In [0]:
### edTest(test_avg_pool) ###
# Call the cnn_model function with pool_type as avg_pooling 
# to get the trained model with avg pooling
model = cnn_model(pool_type="avg_pooling")

# Evaluate on the test data
avg_pool_acc = model.evaluate(x_test, y_test)
print("The accuracy of the model with average pooling is", avg_pool_acc[1])

# Get the number of parameters of the network
avg_pool_params = model.count_params()
In [0]:
### edTest(test_max_pool) ###
# Call the cnn_model function with pool_type as max_pooling 
# to get the trained model with max pooling
model = cnn_model(pool_type="max_pooling")

# Evaluate on the test data
max_pool_acc = model.evaluate(x_test, y_test)
print("The accuracy of the model with max pooling is", max_pool_acc[1])

# Get the number of parameters of the network
max_pool_params = model.count_params()

⏸ Based on the results seen here, which of the following is the most true?

A. The average pooling provides no advantage over no pooling models.

B. The no pooling model is more robust and reliable for all datasets.

C. The max pooling and average pooling though have lower number of parameters takes longer time to train than the no pooling model.

D. The max pooling model performs better as MNIST is made up of mostly edges and high contrasts which provide for max pooling to easily identify the sharp edges.

In [0]:
### edTest(test_chow1) ###
# Submit an answer choice as a string below (eg. if you choose option C, put 'C')
answer1 = '___'
In [0]:
### edTest(test_accuracy) ###
# Display the models with their accuracy score and parameters 
table = PrettyTable()

table.field_names = ["Model Type", "Test Accuracy", "Test Loss", "Number of Parameters"]
table.add_row(["Without pooling", round(no_pool_acc[1],4), round(no_pool_acc[0],4), no_pool_params])
table.add_row(["With avg pooling", round(avg_pool_acc[1],4), round(avg_pool_acc[0],4), avg_pool_params])
table.add_row(["With max pooling", round(max_pool_acc[1],4), round(max_pool_acc[0],4), max_pool_params])
print(table)

⏸ How does the accuracy and loss of the model vary by increasing the pool_size to (5x5)? Why does this happen?

In [0]:
### edTest(test_chow2) ###

# Type your answer within in the quotes given
answer2 = '___'