Traffic Sign Classification with Keras

Keras exists to make coding deep neural networks simpler. To demonstrate just how easy it is, you’re going to use Keras to build a convolutional neural network in a few dozen lines of code.

You’ll be connecting the concepts from the previous lessons to the methods that Keras provides.

Dataset

The network you'll build with Keras is similar to the example in Keras’s GitHub repository that builds out a convolutional neural network for MNIST.

However, instead of using the MNIST dataset, you're going to use the German Traffic Sign Recognition Benchmark dataset that you've used previously.

You can download pickle files with sanitized traffic sign data here:


In [1]:
from urllib.request import urlretrieve
from os.path import isfile
from tqdm import tqdm

class DLProgress(tqdm):
    last_block = 0

    def hook(self, block_num=1, block_size=1, total_size=None):
        self.total = total_size
        self.update((block_num - self.last_block) * block_size)
        self.last_block = block_num

if not isfile('train.p'):
    with DLProgress(unit='B', unit_scale=True, miniters=1, desc='Train Dataset') as pbar:
        urlretrieve(
            'https://s3.amazonaws.com/udacity-sdc/datasets/german_traffic_sign_benchmark/train.p',
            'train.p',
            pbar.hook)

if not isfile('test.p'):
    with DLProgress(unit='B', unit_scale=True, miniters=1, desc='Test Dataset') as pbar:
        urlretrieve(
            'https://s3.amazonaws.com/udacity-sdc/datasets/german_traffic_sign_benchmark/test.p',
            'test.p',
            pbar.hook)

print('Training and Test data downloaded.')


Train Dataset: 120MB [00:15, 7.55MB/s]                              
Test Dataset: 38.8MB [00:07, 5.47MB/s]                              
Training and Test data downloaded.

Overview

Here are the steps you'll take to build the network:

  1. Load the training data.
  2. Preprocess the data.
  3. Build a feedforward neural network to classify traffic signs.
  4. Build a convolutional neural network to classify traffic signs.
  5. Evaluate the final neural network on testing data.

Keep an eye on the network’s accuracy over time. Once the accuracy reaches the 98% range, you can be confident that you’ve built and trained an effective model.


In [2]:
import pickle
import numpy as np
import math

# Fix error with TF and Keras
import tensorflow as tf
tf.python.control_flow_ops = tf

print('Modules loaded.')


Modules loaded.

Load the Data

Start by importing the data from the pickle file.


In [4]:
with open('train.p', 'rb') as f:
    data = pickle.load(f)

# TODO: Load the feature data to the variable X_train
X_train = data['features']
# TODO: Load the label data to the variable y_train
y_train = data['labels']

In [5]:
# STOP: Do not change the tests below. Your implementation should pass these tests. 
assert np.array_equal(X_train, data['features']), 'X_train not set to data[\'features\'].'
assert np.array_equal(y_train, data['labels']), 'y_train not set to data[\'labels\'].'
print('Tests passed.')


Tests passed.

Preprocess the Data

  1. Shuffle the data
  2. Normalize the features using Min-Max scaling between -0.5 and 0.5
  3. One-Hot Encode the labels

Shuffle the data

Hint: You can use the scikit-learn shuffle function to shuffle the data.


In [8]:
# TODO: Shuffle the data
from sklearn.utils import shuffle
X_train, y_train = shuffle(X_train, y_train)

In [9]:
# STOP: Do not change the tests below. Your implementation should pass these tests. 
assert X_train.shape == data['features'].shape, 'X_train has changed shape. The shape shouldn\'t change when shuffling.'
assert y_train.shape == data['labels'].shape, 'y_train has changed shape. The shape shouldn\'t change when shuffling.'
assert not np.array_equal(X_train, data['features']), 'X_train not shuffled.'
assert not np.array_equal(y_train, data['labels']), 'y_train not shuffled.'
print('Tests passed.')


Tests passed.

Normalize the features

Hint: You solved this in TensorFlow lab Problem 1.


In [13]:
# TODO: Normalize the data features to the variable X_normalized
def normalize(X, a=0, b=1):
    """
    Normalize the image data with Min-Max scaling to a range of [0.1, 0.9]
    :param image_data: The image data to be normalized
    :return: Normalized image data
    """
    # TODO: Implement Min-Max scaling for grayscale image data
    # feature range [a, b]
    X_std = (X - X.min(axis=0)) / (X.max(axis=0) - X.min(axis=0))
    X_scaled = X_std * (b - a) + a
    return X_scaled

X_normalized = normalize(X_train, a=-0.5, b=0.5)

In [14]:
# STOP: Do not change the tests below. Your implementation should pass these tests. 
assert math.isclose(np.min(X_normalized), -0.5, abs_tol=1e-5) and math.isclose(np.max(X_normalized), 0.5, abs_tol=1e-5), 'The range of the training data is: {} to {}.  It must be -0.5 to 0.5'.format(np.min(X_normalized), np.max(X_normalized))
print('Tests passed.')


Tests passed.

One-Hot Encode the labels

Hint: You can use the scikit-learn LabelBinarizer function to one-hot encode the labels.


In [21]:
# TODO: One Hot encode the labels to the variable y_one_hot
from sklearn.preprocessing import LabelBinarizer
lb = LabelBinarizer()
y_one_hot = lb.fit_transform(y_train)

In [22]:
# STOP: Do not change the tests below. Your implementation should pass these tests. 
import collections

assert y_one_hot.shape == (39209, 43), 'y_one_hot is not the correct shape.  It\'s {}, it should be (39209, 43)'.format(y_one_hot.shape)
assert next((False for y in y_one_hot if collections.Counter(y) != {0: 42, 1: 1}), True), 'y_one_hot not one-hot encoded.'
print('Tests passed.')


Tests passed.

Keras Sequential Model

from keras.models import Sequential

# Create the Sequential model
model = Sequential()

The keras.models.Sequential class is a wrapper for the neural network model. Just like many of the class models in scikit-learn, it provides common functions like fit(), evaluate(), and compile(). We'll cover these functions as we get to them. Let's start looking at the layers of the model.

Keras Layer

A Keras layer is just like a neural network layer. It can be fully connected, max pool, activation, etc. You can add a layer to the model using the model's add() function. For example, a simple model would look like this:

from keras.models import Sequential
from keras.layers.core import Dense, Activation, Flatten

# Create the Sequential model
model = Sequential()

# 1st Layer - Add a flatten layer
model.add(Flatten(input_shape=(32, 32, 3)))

# 2nd Layer - Add a fully connected layer
model.add(Dense(100))

# 3rd Layer - Add a ReLU activation layer
model.add(Activation('relu'))

# 4th Layer - Add a fully connected layer
model.add(Dense(60))

# 5th Layer - Add a ReLU activation layer
model.add(Activation('relu'))

Keras will automatically infer the shape of all layers after the first layer. This means you only have to set the input dimensions for the first layer.

The first layer from above, model.add(Flatten(input_shape=(32, 32, 3))), sets the input dimension to (32, 32, 3) and output dimension to (3072=32*32*3). The second layer takes in the output of the first layer and sets the output dimenions to (100). This chain of passing output to the next layer continues until the last layer, which is the output of the model.

Build a Multi-Layer Feedforward Network

Build a multi-layer feedforward neural network to classify the traffic sign images.

  1. Set the first layer to a Flatten layer with the input_shape set to (32, 32, 3)
  2. Set the second layer to Dense layer width to 128 output.
  3. Use a ReLU activation function after the second layer.
  4. Set the output layer width to 43, since there are 43 classes in the dataset.
  5. Use a softmax activation function after the output layer.

To get started, review the Keras documentation about models and layers.

The Keras example of a Multi-Layer Perceptron network is similar to what you need to do here. Use that as a guide, but keep in mind that there are a number of differences.


In [23]:
from keras.models import Sequential
from keras.layers.core import Dense, Activation, Flatten
model = Sequential()
# TODO: Build a Multi-layer feedforward neural network with Keras here.

# 1st Layer - Add a flatten layer
model.add(Flatten(input_shape=(32, 32, 3)))

# 2nd Layer - Add a fully connected layer
model.add(Dense(128))

# 3rd Layer - Add a ReLU activation layer
model.add(Activation('relu'))

# 4th Layer - Add a fully connected layer
model.add(Dense(43))

# 5th Layer - Add a softmax activation layer
model.add(Activation('softmax'))


Using TensorFlow backend.

In [24]:
# STOP: Do not change the tests below. Your implementation should pass these tests.
from keras.layers.core import Dense, Activation, Flatten
from keras.activations import relu, softmax

def check_layers(layers, true_layers):
    assert len(true_layers) != 0, 'No layers found'
    for layer_i in range(len(layers)):
        assert isinstance(true_layers[layer_i], layers[layer_i]), 'Layer {} is not a {} layer'.format(layer_i+1, layers[layer_i].__name__)
    assert len(true_layers) == len(layers), '{} layers found, should be {} layers'.format(len(true_layers), len(layers))

check_layers([Flatten, Dense, Activation, Dense, Activation], model.layers)

assert model.layers[0].input_shape == (None, 32, 32, 3), 'First layer input shape is wrong, it should be (32, 32, 3)'
assert model.layers[1].output_shape == (None, 128), 'Second layer output is wrong, it should be (128)'
assert model.layers[2].activation == relu, 'Third layer not a relu activation layer'
assert model.layers[3].output_shape == (None, 43), 'Fourth layer output is wrong, it should be (43)'
assert model.layers[4].activation == softmax, 'Fifth layer not a softmax activation layer'
print('Tests passed.')


Tests passed.

Training a Sequential Model

You built a multi-layer neural network in Keras, now let's look at training a neural network.

from keras.models import Sequential
from keras.layers.core import Dense, Activation

model = Sequential()
...

# Configures the learning process and metrics
model.compile('sgd', 'mean_squared_error', ['accuracy'])

# Train the model
# History is a record of training loss and metrics
history = model.fit(X_train_data, Y_train_data, batch_size=128, nb_epoch=2, validation_split=0.2, verbose=2)

# Calculate test score
test_score = model.evaluate(X_test_data, Y_test_data)

The code above configures, trains, and tests the model. The line model.compile('sgd', 'mean_squared_error', ['accuracy']) configures the model's optimizer to 'sgd'(stochastic gradient descent), the loss to 'mean_squared_error', and the metric to 'accuracy'.

You can find more optimizers here, loss functions here, and more metrics here.

To train the model, use the fit() function as shown in model.fit(X_train_data, Y_train_data, batch_size=128, nb_epoch=2, validation_split=0.2, verbose=2). The validation_split parameter will split a percentage of the training dataset to be used to validate the model. Typically you won't have to change the verbose parameter but in Jupyter notebooks the update animation can crash the notebook so we set verbose=2, this limits the animation to only update after an epoch is complete. The model can be further tested with the test dataset using the evaluation() function as shown in the last line.

Train the Network

  1. Compile the network using adam optimizer and categorical_crossentropy loss function.
  2. Train the network for ten epochs and validate with 20% of the training data.

In [27]:
# TODO: Compile and train the model here.
# Configures the learning process and metrics
# Compile the network using adam optimizer and categorical_crossentropy loss function.

model.compile('adam', 'categorical_crossentropy', ['accuracy'])

# Train the model
# History is a record of training loss and metrics
# Train the network for ten epochs and validate with 20% of the training data.
history = model.fit(X_normalized, y_one_hot, batch_size=128, nb_epoch=10, validation_split=0.2, verbose=2)


Train on 31367 samples, validate on 7842 samples
Epoch 1/10
4s - loss: 1.7946 - acc: 0.5316 - val_loss: 1.1761 - val_acc: 0.6622
Epoch 2/10
3s - loss: 0.8562 - acc: 0.7753 - val_loss: 0.9944 - val_acc: 0.7357
Epoch 3/10
3s - loss: 0.6300 - acc: 0.8385 - val_loss: 0.6998 - val_acc: 0.7914
Epoch 4/10
3s - loss: 0.5102 - acc: 0.8684 - val_loss: 0.5251 - val_acc: 0.8439
Epoch 5/10
3s - loss: 0.4250 - acc: 0.8876 - val_loss: 0.5072 - val_acc: 0.8454
Epoch 6/10
3s - loss: 0.3693 - acc: 0.9033 - val_loss: 0.3894 - val_acc: 0.8967
Epoch 7/10
3s - loss: 0.3322 - acc: 0.9134 - val_loss: 0.3404 - val_acc: 0.9149
Epoch 8/10
3s - loss: 0.3014 - acc: 0.9218 - val_loss: 0.5518 - val_acc: 0.8332
Epoch 9/10
3s - loss: 0.2767 - acc: 0.9289 - val_loss: 0.3618 - val_acc: 0.9123
Epoch 10/10
3s - loss: 0.2528 - acc: 0.9347 - val_loss: 0.2913 - val_acc: 0.9229

In [28]:
# STOP: Do not change the tests below. Your implementation should pass these tests.
from keras.optimizers import Adam

assert model.loss == 'categorical_crossentropy', 'Not using categorical_crossentropy loss function'
assert isinstance(model.optimizer, Adam), 'Not using adam optimizer'
assert len(history.history['acc']) == 10, 'You\'re using {} epochs when you need to use 10 epochs.'.format(len(history.history['acc']))

assert history.history['acc'][-1] > 0.92, 'The training accuracy was: %.3f. It shoud be greater than 0.92' % history.history['acc'][-1]
assert history.history['val_acc'][-1] > 0.85, 'The validation accuracy is: %.3f. It shoud be greater than 0.85' % history.history['val_acc'][-1]
print('Tests passed.')


Tests passed.

Convolutions

  1. Re-construct the previous network
  2. Add a convolutional layer with 32 filters, a 3x3 kernel, and valid padding before the flatten layer.
  3. Add a ReLU activation after the convolutional layer.

Hint 1: The Keras example of a convolutional neural network for MNIST would be a good example to review.


In [36]:
from keras.models import Sequential
from keras.layers.core import Dense, Activation, Flatten
from keras.layers.convolutional import Convolution2D, Conv2D

# TODO: Re-construct the network and add a convolutional layer before the flatten layer.
model = Sequential()
# TODO: Build a Multi-layer feedforward neural network with Keras here.

# 1st Layer - Add a convolution layer
model.add(Convolution2D(32, 3, 3, border_mode='valid',input_shape=(32, 32, 3)))
#model.add(Conv2D(32, 3, 3, border_mode='valid',input_shape=(32, 32, 3)))

# 2nd Layer - Add a ReLU activation layer
model.add(Activation('relu'))

# 3rd Layer - Add a flatten layer
model.add(Flatten())

# 4th Layer - Add a fully connected layer
model.add(Dense(128))

# 5th Layer - Add a ReLU activation layer
model.add(Activation('relu'))

# 6th Layer - Add a fully connected layer
model.add(Dense(43))

# 7th Layer - Add a softmax activation layer
model.add(Activation('softmax'))

In [37]:
# STOP: Do not change the tests below. Your implementation should pass these tests.
from keras.layers.core import Dense, Activation, Flatten
from keras.layers.convolutional import Convolution2D

check_layers([Convolution2D, Activation, Flatten, Dense, Activation, Dense, Activation], model.layers)

assert model.layers[0].input_shape == (None, 32, 32, 3), 'First layer input shape is wrong, it should be (32, 32, 3)'
assert model.layers[0].nb_filter == 32, 'Wrong number of filters, it should be 32'
assert model.layers[0].nb_col == model.layers[0].nb_row == 3, 'Kernel size is wrong, it should be a 3x3'
assert model.layers[0].border_mode == 'valid', 'Wrong padding, it should be valid'

model.compile('adam', 'categorical_crossentropy', ['accuracy'])
history = model.fit(X_normalized, y_one_hot, batch_size=128, nb_epoch=2, validation_split=0.2, verbose=2)
assert(history.history['val_acc'][-1] > 0.91), "The validation accuracy is: %.3f.  It should be greater than 0.91" % history.history['val_acc'][-1]
print('Tests passed.')


Train on 31367 samples, validate on 7842 samples
Epoch 1/2
36s - loss: 1.1583 - acc: 0.7028 - val_loss: 0.4355 - val_acc: 0.8834
Epoch 2/2
36s - loss: 0.2961 - acc: 0.9265 - val_loss: 0.2279 - val_acc: 0.9496
Tests passed.

Pooling

  1. Re-construct the network
  2. Add a 2x2 max pooling layer immediately following your convolutional layer.

In [42]:
from keras.models import Sequential
from keras.layers.core import Dense, Activation, Flatten
from keras.layers.convolutional import Convolution2D, Conv2D
from keras.layers.pooling import MaxPooling2D

# TODO: Re-construct the network and add a pooling layer after the convolutional layer.
model = Sequential()
# TODO: Build a Multi-layer feedforward neural network with Keras here.

# 1st Layer - Add a convolution layer
model.add(Convolution2D(32, 3, 3, border_mode='valid',input_shape=(32, 32, 3)))

# 2nd Layer - Add a 2x2 max pooling layer
model.add(MaxPooling2D(pool_size=(2, 2)))

# 3rd Layer - Add a ReLU activation layer
model.add(Activation('relu'))

# 4th Layer - Add a flatten layer
model.add(Flatten())

# 5th Layer - Add a fully connected layer
model.add(Dense(128))

# 6th Layer - Add a ReLU activation layer
model.add(Activation('relu'))

# 7th Layer - Add a fully connected layer
model.add(Dense(43))

# 8th Layer - Add a softmax activation layer
model.add(Activation('softmax'))

In [43]:
# STOP: Do not change the tests below. Your implementation should pass these tests.
from keras.layers.core import Dense, Activation, Flatten
from keras.layers.convolutional import Convolution2D
from keras.layers.pooling import MaxPooling2D

check_layers([Convolution2D, MaxPooling2D, Activation, Flatten, Dense, Activation, Dense, Activation], model.layers)
assert model.layers[1].pool_size == (2, 2), 'Second layer must be a max pool layer with pool size of 2x2'

model.compile('adam', 'categorical_crossentropy', ['accuracy'])
history = model.fit(X_normalized, y_one_hot, batch_size=128, nb_epoch=2, validation_split=0.2, verbose=2)
assert(history.history['val_acc'][-1] > 0.91), "The validation accuracy is: %.3f.  It should be greater than 0.91" % history.history['val_acc'][-1]
print('Tests passed.')


Train on 31367 samples, validate on 7842 samples
Epoch 1/2
21s - loss: 1.4584 - acc: 0.6188 - val_loss: 0.6586 - val_acc: 0.8169
Epoch 2/2
21s - loss: 0.4199 - acc: 0.8992 - val_loss: 0.3181 - val_acc: 0.9248
Tests passed.

Dropout

  1. Re-construct the network
  2. Add a dropout layer after the pooling layer. Set the dropout rate to 50%.

In [44]:
from keras.layers.core import Dense, Activation, Flatten, Dropout
from keras.layers.convolutional import Convolution2D
from keras.layers.pooling import MaxPooling2D
# TODO: Re-construct the network and add dropout after the pooling layer.
model = Sequential()
# TODO: Build a Multi-layer feedforward neural network with Keras here.

# 1st Layer - Add a convolution layer
model.add(Convolution2D(32, 3, 3, border_mode='valid',input_shape=(32, 32, 3)))

# 2nd Layer - Add a 2x2 max pooling layer
model.add(MaxPooling2D(pool_size=(2, 2)))

# 3rd Layer - Add a dropout layer. Set the dropout rate to 50%.
model.add(Dropout(0.5))

# 4th Layer - Add a ReLU activation layer
model.add(Activation('relu'))

# 5th Layer - Add a flatten layer
model.add(Flatten())

# 6th Layer - Add a fully connected layer
model.add(Dense(128))

# 7th Layer - Add a ReLU activation layer
model.add(Activation('relu'))

# 8th Layer - Add a fully connected layer
model.add(Dense(43))

# 9th Layer - Add a softmax activation layer
model.add(Activation('softmax'))

In [45]:
# STOP: Do not change the tests below. Your implementation should pass these tests.
from keras.layers.core import Dense, Activation, Flatten, Dropout
from keras.layers.convolutional import Convolution2D
from keras.layers.pooling import MaxPooling2D

check_layers([Convolution2D, MaxPooling2D, Dropout, Activation, Flatten, Dense, Activation, Dense, Activation], model.layers)
assert model.layers[2].p == 0.5, 'Third layer should be a Dropout of 50%'

model.compile('adam', 'categorical_crossentropy', ['accuracy'])
history = model.fit(X_normalized, y_one_hot, batch_size=128, nb_epoch=2, validation_split=0.2, verbose=2)
assert(history.history['val_acc'][-1] > 0.91), "The validation accuracy is: %.3f.  It should be greater than 0.91" % history.history['val_acc'][-1]
print('Tests passed.')


Train on 31367 samples, validate on 7842 samples
Epoch 1/2
25s - loss: 1.7037 - acc: 0.5525 - val_loss: 0.8175 - val_acc: 0.7768
Epoch 2/2
24s - loss: 0.5769 - acc: 0.8460 - val_loss: 0.3640 - val_acc: 0.9204
Tests passed.

Optimization

Congratulations! You've built a neural network with convolutions, pooling, dropout, and fully-connected layers, all in just a few lines of code.

Have fun with the model and see how well you can do! Add more layers, or regularization, or different padding, or batches, or more training epochs.

What is the best validation accuracy you can achieve?

batch_size=50, nb_epoch=20, border_mode='valid'


In [53]:
# TODO: Build a model
from keras.layers.core import Dense, Activation, Flatten, Dropout
from keras.layers.convolutional import Convolution2D
from keras.layers.pooling import MaxPooling2D
# TODO: Re-construct the network and add dropout after the pooling layer.
model = Sequential()
# TODO: Build a Multi-layer feedforward neural network with Keras here.

# 1st Layer - Add a convolution layer
model.add(Convolution2D(32, 3, 3, border_mode='valid',input_shape=(32, 32, 3)))

# 2nd Layer - Add a 2x2 max pooling layer
model.add(MaxPooling2D(pool_size=(2, 2)))

# 3rd Layer - Add a dropout layer. Set the dropout rate to 50%.
model.add(Dropout(0.5))

# 4th Layer - Add a ReLU activation layer
model.add(Activation('relu'))

# 5th Layer - Add a flatten layer
model.add(Flatten())

# 6th Layer - Add a fully connected layer
model.add(Dense(128))

# 7th Layer - Add a ReLU activation layer
model.add(Activation('relu'))

# 8th Layer - Add a fully connected layer
model.add(Dense(43))

# 9th Layer - Add a softmax activation layer
model.add(Activation('softmax'))

# TODO: Compile and train the model
model.compile('adam', 'categorical_crossentropy', ['accuracy'])
history = model.fit(X_normalized, y_one_hot, batch_size=50, nb_epoch=20, validation_split=0.2, verbose=2)


Train on 31367 samples, validate on 7842 samples
Epoch 1/20
28s - loss: 1.1765 - acc: 0.6885 - val_loss: 0.4629 - val_acc: 0.8717
Epoch 2/20
27s - loss: 0.3380 - acc: 0.9085 - val_loss: 0.2305 - val_acc: 0.9447
Epoch 3/20
27s - loss: 0.2257 - acc: 0.9394 - val_loss: 0.1733 - val_acc: 0.9597
Epoch 4/20
27s - loss: 0.1828 - acc: 0.9491 - val_loss: 0.1561 - val_acc: 0.9617
Epoch 5/20
27s - loss: 0.1411 - acc: 0.9614 - val_loss: 0.1356 - val_acc: 0.9722
Epoch 6/20
27s - loss: 0.1297 - acc: 0.9636 - val_loss: 0.1161 - val_acc: 0.9722
Epoch 7/20
27s - loss: 0.1057 - acc: 0.9695 - val_loss: 0.1106 - val_acc: 0.9776
Epoch 8/20
27s - loss: 0.1014 - acc: 0.9714 - val_loss: 0.1028 - val_acc: 0.9795
Epoch 9/20
28s - loss: 0.0928 - acc: 0.9735 - val_loss: 0.0979 - val_acc: 0.9786
Epoch 10/20
27s - loss: 0.0829 - acc: 0.9768 - val_loss: 0.1176 - val_acc: 0.9778
Epoch 11/20
27s - loss: 0.0822 - acc: 0.9765 - val_loss: 0.0979 - val_acc: 0.9833
Epoch 12/20
27s - loss: 0.0712 - acc: 0.9796 - val_loss: 0.0865 - val_acc: 0.9821
Epoch 13/20
1997s - loss: 0.0681 - acc: 0.9799 - val_loss: 0.0876 - val_acc: 0.9836
Epoch 14/20
28s - loss: 0.0592 - acc: 0.9830 - val_loss: 0.0884 - val_acc: 0.9819
Epoch 15/20
27s - loss: 0.0604 - acc: 0.9825 - val_loss: 0.1028 - val_acc: 0.9793
Epoch 16/20
27s - loss: 0.0553 - acc: 0.9835 - val_loss: 0.0855 - val_acc: 0.9825
Epoch 17/20
27s - loss: 0.0564 - acc: 0.9833 - val_loss: 0.0879 - val_acc: 0.9842
Epoch 18/20
27s - loss: 0.0545 - acc: 0.9850 - val_loss: 0.0864 - val_acc: 0.9842
Epoch 19/20
28s - loss: 0.0507 - acc: 0.9857 - val_loss: 0.0942 - val_acc: 0.9838
Epoch 20/20
30s - loss: 0.0482 - acc: 0.9861 - val_loss: 0.0829 - val_acc: 0.9864

batch_size=128, nb_epoch=20, border_mode='valid'


In [54]:
# TODO: Build a model
from keras.layers.core import Dense, Activation, Flatten, Dropout
from keras.layers.convolutional import Convolution2D
from keras.layers.pooling import MaxPooling2D
# TODO: Re-construct the network and add dropout after the pooling layer.
model = Sequential()
# TODO: Build a Multi-layer feedforward neural network with Keras here.

# 1st Layer - Add a convolution layer
model.add(Convolution2D(32, 3, 3, border_mode='valid',input_shape=(32, 32, 3)))

# 2nd Layer - Add a 2x2 max pooling layer
model.add(MaxPooling2D(pool_size=(2, 2)))

# 3rd Layer - Add a dropout layer. Set the dropout rate to 50%.
model.add(Dropout(0.5))

# 4th Layer - Add a ReLU activation layer
model.add(Activation('relu'))

# 5th Layer - Add a flatten layer
model.add(Flatten())

# 6th Layer - Add a fully connected layer
model.add(Dense(128))

# 7th Layer - Add a ReLU activation layer
model.add(Activation('relu'))

# 8th Layer - Add a fully connected layer
model.add(Dense(43))

# 9th Layer - Add a softmax activation layer
model.add(Activation('softmax'))

# TODO: Compile and train the model
model.compile('adam', 'categorical_crossentropy', ['accuracy'])
history = model.fit(X_normalized, y_one_hot, batch_size=128, nb_epoch=20, validation_split=0.2, verbose=2)


Train on 31367 samples, validate on 7842 samples
Epoch 1/20
26s - loss: 1.5469 - acc: 0.5925 - val_loss: 0.6827 - val_acc: 0.8159
Epoch 2/20
25s - loss: 0.4916 - acc: 0.8725 - val_loss: 0.3165 - val_acc: 0.9295
Epoch 3/20
25s - loss: 0.3060 - acc: 0.9211 - val_loss: 0.2188 - val_acc: 0.9517
Epoch 4/20
24s - loss: 0.2245 - acc: 0.9408 - val_loss: 0.1699 - val_acc: 0.9672
Epoch 5/20
25s - loss: 0.1865 - acc: 0.9519 - val_loss: 0.1437 - val_acc: 0.9694
Epoch 6/20
25s - loss: 0.1551 - acc: 0.9587 - val_loss: 0.1541 - val_acc: 0.9597
Epoch 7/20
24s - loss: 0.1384 - acc: 0.9617 - val_loss: 0.1260 - val_acc: 0.9711
Epoch 8/20
24s - loss: 0.1182 - acc: 0.9687 - val_loss: 0.1142 - val_acc: 0.9795
Epoch 9/20
24s - loss: 0.1096 - acc: 0.9706 - val_loss: 0.1078 - val_acc: 0.9767
Epoch 10/20
25s - loss: 0.1003 - acc: 0.9720 - val_loss: 0.1110 - val_acc: 0.9762
Epoch 11/20
25s - loss: 0.0960 - acc: 0.9736 - val_loss: 0.1028 - val_acc: 0.9782
Epoch 12/20
24s - loss: 0.0887 - acc: 0.9761 - val_loss: 0.0985 - val_acc: 0.9795
Epoch 13/20
25s - loss: 0.0732 - acc: 0.9796 - val_loss: 0.1024 - val_acc: 0.9784
Epoch 14/20
25s - loss: 0.0848 - acc: 0.9764 - val_loss: 0.0882 - val_acc: 0.9809
Epoch 15/20
25s - loss: 0.0674 - acc: 0.9811 - val_loss: 0.0965 - val_acc: 0.9807
Epoch 16/20
24s - loss: 0.0667 - acc: 0.9806 - val_loss: 0.0888 - val_acc: 0.9833
Epoch 17/20
24s - loss: 0.0567 - acc: 0.9838 - val_loss: 0.0850 - val_acc: 0.9841
Epoch 18/20
25s - loss: 0.0620 - acc: 0.9827 - val_loss: 0.0821 - val_acc: 0.9843
Epoch 19/20
25s - loss: 0.0592 - acc: 0.9843 - val_loss: 0.0937 - val_acc: 0.9825
Epoch 20/20
24s - loss: 0.0534 - acc: 0.9849 - val_loss: 0.0986 - val_acc: 0.9804

Add one more convolution layer with dropout 50%, batch_size=50, nb_epoch=10


In [49]:
# TODO: Build a model
from keras.layers.core import Dense, Activation, Flatten, Dropout
from keras.layers.convolutional import Convolution2D
from keras.layers.pooling import MaxPooling2D
# TODO: Re-construct the network and add dropout after the pooling layer.
model = Sequential()
# TODO: Build a Multi-layer feedforward neural network with Keras here.

# 1st Layer - Add a convolution layer
model.add(Convolution2D(32, 3, 3, border_mode='valid',input_shape=(32, 32, 3)))

# 2nd Layer - Add a 2x2 max pooling layer
model.add(MaxPooling2D(pool_size=(2, 2)))

# 3rd Layer - Add a dropout layer. Set the dropout rate to 50%.
model.add(Dropout(0.5))

# 4th Layer - Add a ReLU activation layer
model.add(Activation('relu'))

# 1st Layer - Add a convolution layer
model.add(Convolution2D(32, 3, 3, border_mode='valid'))

# 2nd Layer - Add a 2x2 max pooling layer
model.add(MaxPooling2D(pool_size=(2, 2)))

# 3rd Layer - Add a dropout layer. Set the dropout rate to 50%.
model.add(Dropout(0.5))

# 4th Layer - Add a ReLU activation layer
model.add(Activation('relu'))

# 5th Layer - Add a flatten layer
model.add(Flatten())

# 6th Layer - Add a fully connected layer
model.add(Dense(128))

# 7th Layer - Add a ReLU activation layer
model.add(Activation('relu'))

# 8th Layer - Add a fully connected layer
model.add(Dense(43))

# 9th Layer - Add a softmax activation layer
model.add(Activation('softmax'))

# TODO: Compile and train the model
model.compile('adam', 'categorical_crossentropy', ['accuracy'])
history = model.fit(X_normalized, y_one_hot, batch_size=50, nb_epoch=10, validation_split=0.2, verbose=2)


Train on 31367 samples, validate on 7842 samples
Epoch 1/10
36s - loss: 1.7506 - acc: 0.4987 - val_loss: 0.5765 - val_acc: 0.8577
Epoch 2/10
34s - loss: 0.6249 - acc: 0.8072 - val_loss: 0.2926 - val_acc: 0.9329
Epoch 3/10
33s - loss: 0.4264 - acc: 0.8696 - val_loss: 0.1966 - val_acc: 0.9626
Epoch 4/10
33s - loss: 0.3308 - acc: 0.8980 - val_loss: 0.1482 - val_acc: 0.9717
Epoch 5/10
33s - loss: 0.2786 - acc: 0.9139 - val_loss: 0.1059 - val_acc: 0.9783
Epoch 6/10
33s - loss: 0.2486 - acc: 0.9227 - val_loss: 0.1177 - val_acc: 0.9778
Epoch 7/10
33s - loss: 0.2264 - acc: 0.9301 - val_loss: 0.0949 - val_acc: 0.9795
Epoch 8/10
33s - loss: 0.2003 - acc: 0.9375 - val_loss: 0.0796 - val_acc: 0.9852
Epoch 9/10
33s - loss: 0.1862 - acc: 0.9419 - val_loss: 0.0732 - val_acc: 0.9832
Epoch 10/10
33s - loss: 0.1772 - acc: 0.9433 - val_loss: 0.0649 - val_acc: 0.9848

Add one more convolution layer with dropout 50%, batch_size=50, nb_epoch=20, border_mode='same'


In [51]:
# TODO: Build a model
from keras.layers.core import Dense, Activation, Flatten, Dropout
from keras.layers.convolutional import Convolution2D
from keras.layers.pooling import MaxPooling2D
# TODO: Re-construct the network and add dropout after the pooling layer.
model = Sequential()
# TODO: Build a Multi-layer feedforward neural network with Keras here.

# 1st Layer - Add a convolution layer
model.add(Convolution2D(32, 3, 3, border_mode='same',input_shape=(32, 32, 3)))

# 2nd Layer - Add a 2x2 max pooling layer
model.add(MaxPooling2D(pool_size=(2, 2)))

# 3rd Layer - Add a dropout layer. Set the dropout rate to 50%.
model.add(Dropout(0.5))

# 4th Layer - Add a ReLU activation layer
model.add(Activation('relu'))

# 1st Layer - Add a convolution layer
model.add(Convolution2D(32, 3, 3, border_mode='same'))

# 2nd Layer - Add a 2x2 max pooling layer
model.add(MaxPooling2D(pool_size=(2, 2)))

# 3rd Layer - Add a dropout layer. Set the dropout rate to 50%.
model.add(Dropout(0.5))

# 4th Layer - Add a ReLU activation layer
model.add(Activation('relu'))

# 5th Layer - Add a flatten layer
model.add(Flatten())

# 6th Layer - Add a fully connected layer
model.add(Dense(128))

# 7th Layer - Add a ReLU activation layer
model.add(Activation('relu'))

# 8th Layer - Add a fully connected layer
model.add(Dense(43))

# 9th Layer - Add a softmax activation layer
model.add(Activation('softmax'))

# TODO: Compile and train the model
model.compile('adam', 'categorical_crossentropy', ['accuracy'])
history = model.fit(X_normalized, y_one_hot, batch_size=50, nb_epoch=20, validation_split=0.2, verbose=2)


Train on 31367 samples, validate on 7842 samples
Epoch 1/20
325s - loss: 1.9089 - acc: 0.4478 - val_loss: 0.7274 - val_acc: 0.8247
Epoch 2/20
40s - loss: 0.6865 - acc: 0.7805 - val_loss: 0.3076 - val_acc: 0.9245
Epoch 3/20
39s - loss: 0.4379 - acc: 0.8597 - val_loss: 0.2394 - val_acc: 0.9441
Epoch 4/20
38s - loss: 0.3406 - acc: 0.8891 - val_loss: 0.1422 - val_acc: 0.9684
Epoch 5/20
39s - loss: 0.2900 - acc: 0.9066 - val_loss: 0.1272 - val_acc: 0.9697
Epoch 6/20
37s - loss: 0.2394 - acc: 0.9234 - val_loss: 0.1414 - val_acc: 0.9682
Epoch 7/20
37s - loss: 0.2140 - acc: 0.9320 - val_loss: 0.0945 - val_acc: 0.9836
Epoch 8/20
37s - loss: 0.2042 - acc: 0.9341 - val_loss: 0.0765 - val_acc: 0.9856
Epoch 9/20
37s - loss: 0.1826 - acc: 0.9410 - val_loss: 0.0678 - val_acc: 0.9842
Epoch 10/20
37s - loss: 0.1751 - acc: 0.9437 - val_loss: 0.0758 - val_acc: 0.9864
Epoch 11/20
37s - loss: 0.1581 - acc: 0.9500 - val_loss: 0.0665 - val_acc: 0.9846
Epoch 12/20
37s - loss: 0.1578 - acc: 0.9486 - val_loss: 0.0538 - val_acc: 0.9870
Epoch 13/20
37s - loss: 0.1463 - acc: 0.9520 - val_loss: 0.0590 - val_acc: 0.9861
Epoch 14/20
37s - loss: 0.1459 - acc: 0.9533 - val_loss: 0.0541 - val_acc: 0.9851
Epoch 15/20
37s - loss: 0.1400 - acc: 0.9538 - val_loss: 0.0490 - val_acc: 0.9898
Epoch 16/20
37s - loss: 0.1237 - acc: 0.9599 - val_loss: 0.0544 - val_acc: 0.9861
Epoch 17/20
36s - loss: 0.1263 - acc: 0.9591 - val_loss: 0.0577 - val_acc: 0.9866
Epoch 18/20
39s - loss: 0.1197 - acc: 0.9604 - val_loss: 0.0468 - val_acc: 0.9901
Epoch 19/20
39s - loss: 0.1196 - acc: 0.9603 - val_loss: 0.0465 - val_acc: 0.9908
Epoch 20/20
41s - loss: 0.1179 - acc: 0.9610 - val_loss: 0.0585 - val_acc: 0.9851

Add one more convolution layer with dropout 50%, batch_size=128, nb_epoch=20, border_mode='valid'


In [56]:
# TODO: Build a model
from keras.layers.core import Dense, Activation, Flatten, Dropout
from keras.layers.convolutional import Convolution2D
from keras.layers.pooling import MaxPooling2D
# TODO: Re-construct the network and add dropout after the pooling layer.
model = Sequential()
# TODO: Build a Multi-layer feedforward neural network with Keras here.

# 1st Layer - Add a convolution layer
model.add(Convolution2D(32, 3, 3, border_mode='valid',input_shape=(32, 32, 3)))

# 2nd Layer - Add a 2x2 max pooling layer
model.add(MaxPooling2D(pool_size=(2, 2)))

# 3rd Layer - Add a dropout layer. Set the dropout rate to 50%.
model.add(Dropout(0.5))

# 4th Layer - Add a ReLU activation layer
model.add(Activation('relu'))

# 1st Layer - Add a convolution layer
model.add(Convolution2D(32, 3, 3, border_mode='valid'))

# 2nd Layer - Add a 2x2 max pooling layer
model.add(MaxPooling2D(pool_size=(2, 2)))

# 3rd Layer - Add a dropout layer. Set the dropout rate to 50%.
model.add(Dropout(0.5))

# 4th Layer - Add a ReLU activation layer
model.add(Activation('relu'))

# 5th Layer - Add a flatten layer
model.add(Flatten())

# 6th Layer - Add a fully connected layer
model.add(Dense(128))

# 7th Layer - Add a ReLU activation layer
model.add(Activation('relu'))

# 8th Layer - Add a fully connected layer
model.add(Dense(43))

# 9th Layer - Add a softmax activation layer
model.add(Activation('softmax'))

# TODO: Compile and train the model
model.compile('adam', 'categorical_crossentropy', ['accuracy'])
history = model.fit(X_normalized, y_one_hot, batch_size=128, nb_epoch=20, validation_split=0.2, verbose=2)


Train on 31367 samples, validate on 7842 samples
Epoch 1/20
32s - loss: 2.3323 - acc: 0.3475 - val_loss: 1.2133 - val_acc: 0.6674
Epoch 2/20
31s - loss: 1.0042 - acc: 0.6871 - val_loss: 0.5502 - val_acc: 0.8710
Epoch 3/20
30s - loss: 0.6163 - acc: 0.8060 - val_loss: 0.3265 - val_acc: 0.9245
Epoch 4/20
29s - loss: 0.4702 - acc: 0.8556 - val_loss: 0.2473 - val_acc: 0.9484
Epoch 5/20
30s - loss: 0.3847 - acc: 0.8805 - val_loss: 0.1930 - val_acc: 0.9541
Epoch 6/20
30s - loss: 0.3300 - acc: 0.8984 - val_loss: 0.1601 - val_acc: 0.9651
Epoch 7/20
30s - loss: 0.2855 - acc: 0.9119 - val_loss: 0.1365 - val_acc: 0.9730
Epoch 8/20
30s - loss: 0.2646 - acc: 0.9173 - val_loss: 0.1249 - val_acc: 0.9748
Epoch 9/20
30s - loss: 0.2315 - acc: 0.9273 - val_loss: 0.0998 - val_acc: 0.9830
Epoch 10/20
31s - loss: 0.2122 - acc: 0.9344 - val_loss: 0.0926 - val_acc: 0.9804
Epoch 11/20
31s - loss: 0.1998 - acc: 0.9379 - val_loss: 0.0836 - val_acc: 0.9796
Epoch 12/20
33s - loss: 0.1923 - acc: 0.9407 - val_loss: 0.0779 - val_acc: 0.9834
Epoch 13/20
30s - loss: 0.1783 - acc: 0.9428 - val_loss: 0.0725 - val_acc: 0.9846
Epoch 14/20
30s - loss: 0.1673 - acc: 0.9483 - val_loss: 0.0640 - val_acc: 0.9870
Epoch 15/20
29s - loss: 0.1582 - acc: 0.9498 - val_loss: 0.0742 - val_acc: 0.9824
Epoch 16/20
30s - loss: 0.1489 - acc: 0.9526 - val_loss: 0.0618 - val_acc: 0.9866
Epoch 17/20
30s - loss: 0.1491 - acc: 0.9535 - val_loss: 0.0547 - val_acc: 0.9894
Epoch 18/20
30s - loss: 0.1433 - acc: 0.9535 - val_loss: 0.0493 - val_acc: 0.9909
Epoch 19/20
30s - loss: 0.1352 - acc: 0.9578 - val_loss: 0.0496 - val_acc: 0.9890
Epoch 20/20
31s - loss: 0.1314 - acc: 0.9591 - val_loss: 0.0568 - val_acc: 0.9897

Best Validation Accuracy: 0.9897

Testing

Once you've picked out your best model, it's time to test it.

Load up the test data and use the evaluate() method to see how well it does.

Hint 1: The evaluate() method should return an array of numbers. Use the metrics_names property to get the labels.


In [57]:
# TODO: Load test data
with open('test.p', 'rb') as f:
    test_data = pickle.load(f)

# TODO: Load the feature data to the variable X_train
X_test = test_data['features']
# TODO: Load the label data to the variable y_train
y_test = test_data['labels']
    
# TODO: Preprocess data & one-hot encode the labels
X_normalized_test = normalize(X_test, a=-0.5, b=0.5)
y_one_hot_test = lb.transform(y_test)

# TODO: Evaluate model on test data
metrics = model.evaluate(X_normalized_test, y_one_hot_test)
for metric_i in range(len(model.metrics_names)):
    metric_name = model.metrics_names[metric_i]
    metric_value = metrics[metric_i]
    print('{}: {}'.format(metric_name, metric_value))


12630/12630 [==============================] - 4s     
loss: 0.26140251071181264
acc: 0.9344418052445304

Summary

Keras is a great tool to use if you want to quickly build a neural network and evaluate performance.