Image Classification

In this project, you'll classify images from the CIFAR-10 dataset. The dataset consists of airplanes, dogs, cats, and other objects. You'll preprocess the images, then train a convolutional neural network on all the samples. The images need to be normalized and the labels need to be one-hot encoded. You'll get to apply what you learned and build a convolutional, max pooling, dropout, and fully connected layers. At the end, you'll get to see your neural network's predictions on the sample images.

Get the Data

Run the following cell to download the CIFAR-10 dataset for python.


In [1]:
"""
DON'T MODIFY ANYTHING IN THIS CELL THAT IS BELOW THIS LINE
"""
from urllib.request import urlretrieve
from os.path import isfile, isdir
from tqdm import tqdm
import problem_unittests as tests
import tarfile

cifar10_dataset_folder_path = 'cifar-10-batches-py'

# Use Floyd's cifar-10 dataset if present
floyd_cifar10_location = '/input/cifar-10/python.tar.gz'
if isfile(floyd_cifar10_location):
    tar_gz_path = floyd_cifar10_location
else:
    tar_gz_path = 'cifar-10-python.tar.gz'

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(tar_gz_path):
    with DLProgress(unit='B', unit_scale=True, miniters=1, desc='CIFAR-10 Dataset') as pbar:
        urlretrieve(
            'https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz',
            tar_gz_path,
            pbar.hook)

if not isdir(cifar10_dataset_folder_path):
    with tarfile.open(tar_gz_path) as tar:
        tar.extractall()
        tar.close()


tests.test_folder_path(cifar10_dataset_folder_path)


CIFAR-10 Dataset: 171MB [01:38, 1.73MB/s]                              
All files found!

Explore the Data

The dataset is broken into batches to prevent your machine from running out of memory. The CIFAR-10 dataset consists of 5 batches, named data_batch_1, data_batch_2, etc.. Each batch contains the labels and images that are one of the following:

  • airplane
  • automobile
  • bird
  • cat
  • deer
  • dog
  • frog
  • horse
  • ship
  • truck

Understanding a dataset is part of making predictions on the data. Play around with the code cell below by changing the batch_id and sample_id. The batch_id is the id for a batch (1-5). The sample_id is the id for a image and label pair in the batch.

Ask yourself "What are all possible labels?", "What is the range of values for the image data?", "Are the labels in order or random?". Answers to questions like these will help you preprocess the data and end up with better predictions.


In [2]:
%matplotlib inline
%config InlineBackend.figure_format = 'retina'

import helper
import numpy as np

# Explore the dataset
batch_id = 3
sample_id = 5
helper.display_stats(cifar10_dataset_folder_path, batch_id, sample_id)


Stats of batch 3:
Samples: 10000
Label Counts: {0: 994, 1: 1042, 2: 965, 3: 997, 4: 990, 5: 1029, 6: 978, 7: 1015, 8: 961, 9: 1029}
First 20 Labels: [8, 5, 0, 6, 9, 2, 8, 3, 6, 2, 7, 4, 6, 9, 0, 0, 7, 3, 7, 2]

Example of Image 5:
Image - Min Value: 9 Max Value: 255
Image - Shape: (32, 32, 3)
Label - Label Id: 2 Name: bird

Implement Preprocess Functions

Normalize

In the cell below, implement the normalize function to take in image data, x, and return it as a normalized Numpy array. The values should be in the range of 0 to 1, inclusive. The return object should be the same shape as x.


In [3]:
def normalize(x):
    """
    Normalize a list of sample image data in the range of 0 to 1
    : x: List of image data.  The image shape is (32, 32, 3)
    : return: Numpy array of normalize data
    """
    return np.array(x)/255


"""
DON'T MODIFY ANYTHING IN THIS CELL THAT IS BELOW THIS LINE
"""
tests.test_normalize(normalize)


Tests Passed

One-hot encode

Just like the previous code cell, you'll be implementing a function for preprocessing. This time, you'll implement the one_hot_encode function. The input, x, are a list of labels. Implement the function to return the list of labels as One-Hot encoded Numpy array. The possible values for labels are 0 to 9. The one-hot encoding function should return the same encoding for each value between each call to one_hot_encode. Make sure to save the map of encodings outside the function.

Hint: Don't reinvent the wheel.


In [4]:
import tensorflow as tf

def one_hot_encode(x):
    """
    One hot encode a list of sample labels. Return a one-hot encoded vector for each label.
    : x: List of sample Labels
    : return: Numpy array of one-hot encoded labels
    """
    one_hot = np.array(tf.one_hot(x, 10).eval(session=tf.Session()))
    return one_hot


"""
DON'T MODIFY ANYTHING IN THIS CELL THAT IS BELOW THIS LINE
"""
tests.test_one_hot_encode(one_hot_encode)


Tests Passed

Randomize Data

As you saw from exploring the data above, the order of the samples are randomized. It doesn't hurt to randomize it again, but you don't need to for this dataset.

Preprocess all the data and save it

Running the code cell below will preprocess all the CIFAR-10 data and save it to file. The code below also uses 10% of the training data for validation.


In [5]:
"""
DON'T MODIFY ANYTHING IN THIS CELL
"""
# Preprocess Training, Validation, and Testing Data
helper.preprocess_and_save_data(cifar10_dataset_folder_path, normalize, one_hot_encode)

Check Point

This is your first checkpoint. If you ever decide to come back to this notebook or have to restart the notebook, you can start from here. The preprocessed data has been saved to disk.


In [1]:
"""
DON'T MODIFY ANYTHING IN THIS CELL
"""
import pickle
import problem_unittests as tests
import helper

# Load the Preprocessed Validation data
valid_features, valid_labels = pickle.load(open('preprocess_validation.p', mode='rb'))

Build the network

For the neural network, you'll build each layer into a function. Most of the code you've seen has been outside of functions. To test your code more thoroughly, we require that you put each layer in a function. This allows us to give you better feedback and test for simple mistakes using our unittests before you submit your project.

Note: If you're finding it hard to dedicate enough time for this course each week, we've provided a small shortcut to this part of the project. In the next couple of problems, you'll have the option to use classes from the TensorFlow Layers or TensorFlow Layers (contrib) packages to build each layer, except the layers you build in the "Convolutional and Max Pooling Layer" section. TF Layers is similar to Keras's and TFLearn's abstraction to layers, so it's easy to pickup.

However, if you would like to get the most out of this course, try to solve all the problems without using anything from the TF Layers packages. You can still use classes from other packages that happen to have the same name as ones you find in TF Layers! For example, instead of using the TF Layers version of the conv2d class, tf.layers.conv2d, you would want to use the TF Neural Network version of conv2d, tf.nn.conv2d.

Let's begin!

Input

The neural network needs to read the image data, one-hot encoded labels, and dropout keep probability. Implement the following functions

  • Implement neural_net_image_input
    • Return a TF Placeholder
    • Set the shape using image_shape with batch size set to None.
    • Name the TensorFlow placeholder "x" using the TensorFlow name parameter in the TF Placeholder.
  • Implement neural_net_label_input
    • Return a TF Placeholder
    • Set the shape using n_classes with batch size set to None.
    • Name the TensorFlow placeholder "y" using the TensorFlow name parameter in the TF Placeholder.
  • Implement neural_net_keep_prob_input
    • Return a TF Placeholder for dropout keep probability.
    • Name the TensorFlow placeholder "keep_prob" using the TensorFlow name parameter in the TF Placeholder.

These names will be used at the end of the project to load your saved model.

Note: None for shapes in TensorFlow allow for a dynamic size.


In [2]:
import tensorflow as tf

def neural_net_image_input(image_shape):
    """
    Return a Tensor for a batch of image input
    : image_shape: Shape of the images
    : return: Tensor for image input.
    """
    # TODO: Implement Function
    return tf.placeholder(tf.float32, [None] + list(image_shape), name='x')


def neural_net_label_input(n_classes):
    """
    Return a Tensor for a batch of label input
    : n_classes: Number of classes
    : return: Tensor for label input.
    """
    # TODO: Implement Function
    return tf.placeholder(tf.float32, [None, n_classes], name='y')


def neural_net_keep_prob_input():
    """
    Return a Tensor for keep probability
    : return: Tensor for keep probability.
    """
    # TODO: Implement Function
    return tf.placeholder(tf.float32, name='keep_prob')


"""
DON'T MODIFY ANYTHING IN THIS CELL THAT IS BELOW THIS LINE
"""
tf.reset_default_graph()
tests.test_nn_image_inputs(neural_net_image_input)
tests.test_nn_label_inputs(neural_net_label_input)
tests.test_nn_keep_prob_inputs(neural_net_keep_prob_input)


Image Input Tests Passed.
Label Input Tests Passed.
Keep Prob Tests Passed.

Convolution and Max Pooling Layer

Convolution layers have a lot of success with images. For this code cell, you should implement the function conv2d_maxpool to apply convolution then max pooling:

  • Create the weight and bias using conv_ksize, conv_num_outputs and the shape of x_tensor.
  • Apply a convolution to x_tensor using weight and conv_strides.
    • We recommend you use same padding, but you're welcome to use any padding.
  • Add bias
  • Add a nonlinear activation to the convolution.
  • Apply Max Pooling using pool_ksize and pool_strides.
    • We recommend you use same padding, but you're welcome to use any padding.

Note: You can't use TensorFlow Layers or TensorFlow Layers (contrib) for this layer, but you can still use TensorFlow's Neural Network package. You may still use the shortcut option for all the other layers.


In [35]:
def conv2d_maxpool(x_tensor, conv_num_outputs, conv_ksize, conv_strides, pool_ksize, pool_strides):
    """
    Apply convolution then max pooling to x_tensor
    :param x_tensor: TensorFlow Tensor
    :param conv_num_outputs: Number of outputs for the convolutional layer
    :param conv_ksize: kernal size 2-D Tuple for the convolutional layer
    :param conv_strides: Stride 2-D Tuple for convolution
    :param pool_ksize: kernal size 2-D Tuple for pool
    :param pool_strides: Stride 2-D Tuple for pool
    : return: A tensor that represents convolution and max pooling of x_tensor
    """
    # Weight and bias
    weight = tf.Variable(tf.truncated_normal([conv_ksize[0], conv_ksize[1], x_tensor.shape[-1].value, conv_num_outputs]
                                             , mean=0.0, stddev=0.1))
    bias = tf.Variable(tf.zeros(conv_num_outputs))

    # Apply Convolution
    conv_layer = tf.nn.conv2d(x_tensor, weight, strides=[1, conv_strides[0], conv_strides[1], 1], padding='VALID')
    # Add bias
    conv_layer = tf.nn.bias_add(conv_layer, bias)
    # Apply activation function
    conv_layer = tf.nn.relu(conv_layer)

    pool_layer = tf.nn.max_pool(conv_layer, [1, pool_ksize[0], pool_ksize[1], 1], 
                                strides=[1, pool_strides[1], pool_strides[1], 1], padding='VALID')
    return pool_layer


"""
DON'T MODIFY ANYTHING IN THIS CELL THAT IS BELOW THIS LINE
"""
tests.test_con_pool(conv2d_maxpool)


Tests Passed

Flatten Layer

Implement the flatten function to change the dimension of x_tensor from a 4-D tensor to a 2-D tensor. The output should be the shape (Batch Size, Flattened Image Size). Shortcut option: you can use classes from the TensorFlow Layers or TensorFlow Layers (contrib) packages for this layer. For more of a challenge, only use other TensorFlow packages.


In [36]:
def flatten(x_tensor):
    """
    Flatten x_tensor to (Batch Size, Flattened Image Size)
    : x_tensor: A tensor of size (Batch Size, ...), where ... are the image dimensions.
    : return: A tensor of size (Batch Size, Flattened Image Size).
    """
    # TODO: Implement Function
    t = 1
    for d in map(lambda d: d.value, x_tensor.shape[1:]):
        t *= d
    dim = [-1, t]
    return tf.reshape(x_tensor, dim)


"""
DON'T MODIFY ANYTHING IN THIS CELL THAT IS BELOW THIS LINE
"""
tests.test_flatten(flatten)


Tests Passed

Fully-Connected Layer

Implement the fully_conn function to apply a fully connected layer to x_tensor with the shape (Batch Size, num_outputs). Shortcut option: you can use classes from the TensorFlow Layers or TensorFlow Layers (contrib) packages for this layer. For more of a challenge, only use other TensorFlow packages.


In [37]:
def fully_conn(x_tensor, num_outputs):
    """
    Apply a fully connected layer to x_tensor using weight and bias
    : x_tensor: A 2-D tensor where the first dimension is batch size.
    : num_outputs: The number of output that the new tensor should be.
    : return: A 2-D tensor where the second dimension is num_outputs.
    """
    # Weight and bias
    weight = tf.Variable(tf.truncated_normal([x_tensor.shape[-1].value, num_outputs], mean=0.0, stddev=0.1))
    bias = tf.Variable(tf.zeros(num_outputs))

    # Apply Convolution
    # Apply activation function
    layer = tf.nn.relu_layer(x_tensor, weight, bias)
    return layer


"""
DON'T MODIFY ANYTHING IN THIS CELL THAT IS BELOW THIS LINE
"""
tests.test_fully_conn(fully_conn)


Tests Passed

Output Layer

Implement the output function to apply a fully connected layer to x_tensor with the shape (Batch Size, num_outputs). Shortcut option: you can use classes from the TensorFlow Layers or TensorFlow Layers (contrib) packages for this layer. For more of a challenge, only use other TensorFlow packages.

Note: Activation, softmax, or cross entropy should not be applied to this.


In [38]:
def output(x_tensor, num_outputs):
    """
    Apply a output layer to x_tensor using weight and bias
    : x_tensor: A 2-D tensor where the first dimension is batch size.
    : num_outputs: The number of output that the new tensor should be.
    : return: A 2-D tensor where the second dimension is num_outputs.
    """
    # Weight and bias
    weight = tf.Variable(tf.truncated_normal([x_tensor.shape[-1].value, num_outputs], mean=0.0, stddev=0.1))
    bias = tf.Variable(tf.zeros(num_outputs))

    layer = tf.nn.bias_add(tf.matmul(x_tensor, weight), bias)
    return layer


"""
DON'T MODIFY ANYTHING IN THIS CELL THAT IS BELOW THIS LINE
"""
tests.test_output(output)


Tests Passed

Create Convolutional Model

Implement the function conv_net to create a convolutional neural network model. The function takes in a batch of images, x, and outputs logits. Use the layers you created above to create this model:

  • Apply 1, 2, or 3 Convolution and Max Pool layers
  • Apply a Flatten Layer
  • Apply 1, 2, or 3 Fully Connected Layers
  • Apply an Output Layer
  • Return the output
  • Apply TensorFlow's Dropout to one or more layers in the model using keep_prob.

In [51]:
def conv_net(x, keep_prob):
    """
    Create a convolutional neural network model
    : x: Placeholder tensor that holds image data.
    : keep_prob: Placeholder tensor that hold dropout keep probability.
    : return: Tensor that represents logits
    """
    net = x
    # TODO: Apply 1, 2, or 3 Convolution and Max Pool layers
    #    Play around with different number of outputs, kernel size and stride
    # Function Definition from Above:
    net = conv2d_maxpool(net, 10, (3,3), (1,1), (2,2), (1,1))
    net = conv2d_maxpool(net, 20, (3,3), (1,1), (2,2), (1,1))
    # net = conv2d_maxpool(net, 30, (3,3), (1,1), (2,2), (1,1))
    

    # TODO: Apply a Flatten Layer
    # Function Definition from Above:
    flattened = flatten(net)
    # flattened = tf.nn.dropout(flattened, keep_prob)

    # TODO: Apply 1, 2, or 3 Fully Connected Layers
    #    Play around with different number of outputs
    # Function Definition from Above:
    fc1 = fully_conn(flattened, 512)
    fc1 = tf.nn.dropout(fc1, keep_prob)
    
    fc2 = fully_conn(fc1, 256)
    # fc2 = tf.nn.dropout(fc2, keep_prob)
    
    fc3 = fully_conn(fc2, 128)
    # fc3 = tf.nn.dropout(fc3, keep_prob)
    
    # TODO: Apply an Output Layer
    #    Set this to the number of classes
    # Function Definition from Above:
    out = output(fc3, 10)
    
    # TODO: return output
    return out


"""
DON'T MODIFY ANYTHING IN THIS CELL THAT IS BELOW THIS LINE
"""

##############################
## Build the Neural Network ##
##############################

# Remove previous weights, bias, inputs, etc..
tf.reset_default_graph()

# Inputs
x = neural_net_image_input((32, 32, 3))
y = neural_net_label_input(10)
keep_prob = neural_net_keep_prob_input()

# Model
logits = conv_net(x, keep_prob)

# Name logits Tensor, so that is can be loaded from disk after training
logits = tf.identity(logits, name='logits')

# Loss and Optimizer
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=y))
optimizer = tf.train.AdamOptimizer().minimize(cost)

# Accuracy
correct_pred = tf.equal(tf.argmax(logits, 1), tf.argmax(y, 1))
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32), name='accuracy')

tests.test_conv_net(conv_net)


Neural Network Built!

Train the Neural Network

Single Optimization

Implement the function train_neural_network to do a single optimization. The optimization should use optimizer to optimize in session with a feed_dict of the following:

  • x for image input
  • y for labels
  • keep_prob for keep probability for dropout

This function will be called for each batch, so tf.global_variables_initializer() has already been called.

Note: Nothing needs to be returned. This function is only optimizing the neural network.


In [8]:
def train_neural_network(session, optimizer, keep_probability, feature_batch, label_batch):
    """
    Optimize the session on a batch of images and labels
    : session: Current TensorFlow session
    : optimizer: TensorFlow optimizer function
    : keep_probability: keep probability
    : feature_batch: Batch of Numpy image data
    : label_batch: Batch of Numpy label data
    """
    session.run(optimizer, feed_dict={
                x: feature_batch,
                y: label_batch,
                keep_prob: keep_probability})

"""
DON'T MODIFY ANYTHING IN THIS CELL THAT IS BELOW THIS LINE
"""
tests.test_train_nn(train_neural_network)


Tests Passed

Show Stats

Implement the function print_stats to print loss and validation accuracy. Use the global variables valid_features and valid_labels to calculate validation accuracy. Use a keep probability of 1.0 to calculate the loss and validation accuracy.


In [9]:
def print_stats(session, feature_batch, label_batch, cost, accuracy, end='\n'):
    """
    Print information about loss and validation accuracy
    : session: Current TensorFlow session
    : feature_batch: Batch of Numpy image data
    : label_batch: Batch of Numpy label data
    : cost: TensorFlow cost function
    : accuracy: TensorFlow accuracy function
    """
    stats_cost= sess.run(cost, feed_dict={
        x: valid_features,
        y: valid_labels,
        keep_prob: 1.0})
    stats_acc = sess.run(accuracy, feed_dict={
        x: valid_features,
        y: valid_labels,
        keep_prob: 1.0})
    print("Cost:", stats_cost, "Acc:", stats_acc, end=end)

Hyperparameters

Tune the following parameters:

  • Set epochs to the number of iterations until the network stops learning or start overfitting
  • Set batch_size to the highest number that your machine has memory for. Most people set them to common sizes of memory:
    • 64
    • 128
    • 256
    • ...
  • Set keep_probability to the probability of keeping a node using dropout

In [52]:
# TODO: Tune Parameters
epochs = 30
batch_size = 1024
keep_probability = 0.4

Train on a Single CIFAR-10 Batch

Instead of training the neural network on all the CIFAR-10 batches of data, let's use a single batch. This should save time while you iterate on the model to get a better accuracy. Once the final validation accuracy is 50% or greater, run the model on all the data in the next section.


In [53]:
import timeit
"""
DON'T MODIFY ANYTHING IN THIS CELL
"""
print('Checking the Training on a Single Batch...')
with tf.Session() as sess:
    # Initializing the variables
    sess.run(tf.global_variables_initializer())
    
    # Training cycle
    for epoch in range(epochs):
        batch_i = 1
        start = timeit.default_timer()
        for batch_features, batch_labels in helper.load_preprocess_training_batch(batch_i, batch_size):
            train_neural_network(sess, optimizer, keep_probability, batch_features, batch_labels)
        print('Epoch {:>2}, CIFAR-10 Batch {}:  '.format(epoch + 1, batch_i), end='')
        print_stats(sess, batch_features, batch_labels, cost, accuracy, end='')
        end = timeit.default_timer()
        print(" time:", end-start)


Checking the Training on a Single Batch...
Epoch  1, CIFAR-10 Batch 1:  Cost: 2.23033 Acc: 0.2248 time: 2.535980448999908
Epoch  2, CIFAR-10 Batch 1:  Cost: 1.96235 Acc: 0.3074 time: 2.509991369999625
Epoch  3, CIFAR-10 Batch 1:  Cost: 1.77453 Acc: 0.3668 time: 2.507089407999956
Epoch  4, CIFAR-10 Batch 1:  Cost: 1.64415 Acc: 0.3998 time: 2.516965466000329
Epoch  5, CIFAR-10 Batch 1:  Cost: 1.55915 Acc: 0.4412 time: 2.5114109269998153
Epoch  6, CIFAR-10 Batch 1:  Cost: 1.55568 Acc: 0.4416 time: 2.51453621499968
Epoch  7, CIFAR-10 Batch 1:  Cost: 1.46625 Acc: 0.475 time: 2.5213728550006635
Epoch  8, CIFAR-10 Batch 1:  Cost: 1.43265 Acc: 0.4894 time: 2.5109619089998887
Epoch  9, CIFAR-10 Batch 1:  Cost: 1.39032 Acc: 0.501 time: 2.518789129000652
Epoch 10, CIFAR-10 Batch 1:  Cost: 1.36651 Acc: 0.5144 time: 2.510863438999877
Epoch 11, CIFAR-10 Batch 1:  Cost: 1.3473 Acc: 0.5238 time: 2.5179944680003246
Epoch 12, CIFAR-10 Batch 1:  Cost: 1.34084 Acc: 0.5252 time: 2.5162024420005764
Epoch 13, CIFAR-10 Batch 1:  Cost: 1.3308 Acc: 0.5318 time: 2.510778391999338
Epoch 14, CIFAR-10 Batch 1:  Cost: 1.32827 Acc: 0.5292 time: 2.513070066999717
Epoch 15, CIFAR-10 Batch 1:  Cost: 1.33967 Acc: 0.5316 time: 2.5151056030008476
Epoch 16, CIFAR-10 Batch 1:  Cost: 1.42293 Acc: 0.5078 time: 2.5142000039995764
Epoch 17, CIFAR-10 Batch 1:  Cost: 1.32006 Acc: 0.5444 time: 2.514484191999145
Epoch 18, CIFAR-10 Batch 1:  Cost: 1.33795 Acc: 0.5402 time: 2.5168399730009696
Epoch 19, CIFAR-10 Batch 1:  Cost: 1.34592 Acc: 0.5428 time: 2.5109817899992777
Epoch 20, CIFAR-10 Batch 1:  Cost: 1.33453 Acc: 0.5566 time: 2.518230824998682
Epoch 21, CIFAR-10 Batch 1:  Cost: 1.35792 Acc: 0.5498 time: 2.521674254001482
Epoch 22, CIFAR-10 Batch 1:  Cost: 1.39888 Acc: 0.5504 time: 2.5212041419999878
Epoch 23, CIFAR-10 Batch 1:  Cost: 1.419 Acc: 0.5522 time: 2.5168877109990717
Epoch 24, CIFAR-10 Batch 1:  Cost: 1.46871 Acc: 0.5402 time: 2.5122304080014146
Epoch 25, CIFAR-10 Batch 1:  Cost: 1.49943 Acc: 0.5364 time: 2.5132876280003984
Epoch 26, CIFAR-10 Batch 1:  Cost: 1.6332 Acc: 0.521 time: 2.5141451220006275
Epoch 27, CIFAR-10 Batch 1:  Cost: 1.50732 Acc: 0.547 time: 2.517731776999426
Epoch 28, CIFAR-10 Batch 1:  Cost: 1.53471 Acc: 0.5518 time: 2.5142946729993128
Epoch 29, CIFAR-10 Batch 1:  Cost: 1.5314 Acc: 0.5604 time: 2.5146876359995076
Epoch 30, CIFAR-10 Batch 1:  Cost: 1.55129 Acc: 0.5608 time: 2.511491373001263

Fully Train the Model

Now that you got a good accuracy with a single CIFAR-10 batch, try it with all five batches.


In [54]:
"""
DON'T MODIFY ANYTHING IN THIS CELL
"""
save_model_path = './image_classification'

print('Training...')
with tf.Session() as sess:
    # Initializing the variables
    sess.run(tf.global_variables_initializer())
    
    # Training cycle
    for epoch in range(epochs):
        # Loop over all batches
        n_batches = 5
        for batch_i in range(1, n_batches + 1):
            for batch_features, batch_labels in helper.load_preprocess_training_batch(batch_i, batch_size):
                train_neural_network(sess, optimizer, keep_probability, batch_features, batch_labels)
            print('Epoch {:>2}, CIFAR-10 Batch {}:  '.format(epoch + 1, batch_i), end='')
            print_stats(sess, batch_features, batch_labels, cost, accuracy)
            
    # Save Model
    saver = tf.train.Saver()
    save_path = saver.save(sess, save_model_path)


Training...
Epoch  1, CIFAR-10 Batch 1:  Cost: 2.27921 Acc: 0.1312
Epoch  1, CIFAR-10 Batch 2:  Cost: 2.18264 Acc: 0.1774
Epoch  1, CIFAR-10 Batch 3:  Cost: 2.04958 Acc: 0.2268
Epoch  1, CIFAR-10 Batch 4:  Cost: 1.96178 Acc: 0.2654
Epoch  1, CIFAR-10 Batch 5:  Cost: 1.84151 Acc: 0.3384
Epoch  2, CIFAR-10 Batch 1:  Cost: 1.73969 Acc: 0.3644
Epoch  2, CIFAR-10 Batch 2:  Cost: 1.69532 Acc: 0.3874
Epoch  2, CIFAR-10 Batch 3:  Cost: 1.61566 Acc: 0.409
Epoch  2, CIFAR-10 Batch 4:  Cost: 1.58294 Acc: 0.436
Epoch  2, CIFAR-10 Batch 5:  Cost: 1.52568 Acc: 0.4388
Epoch  3, CIFAR-10 Batch 1:  Cost: 1.50442 Acc: 0.4512
Epoch  3, CIFAR-10 Batch 2:  Cost: 1.51339 Acc: 0.4488
Epoch  3, CIFAR-10 Batch 3:  Cost: 1.43237 Acc: 0.476
Epoch  3, CIFAR-10 Batch 4:  Cost: 1.41488 Acc: 0.4844
Epoch  3, CIFAR-10 Batch 5:  Cost: 1.40601 Acc: 0.4876
Epoch  4, CIFAR-10 Batch 1:  Cost: 1.36598 Acc: 0.5028
Epoch  4, CIFAR-10 Batch 2:  Cost: 1.39946 Acc: 0.4976
Epoch  4, CIFAR-10 Batch 3:  Cost: 1.3553 Acc: 0.5088
Epoch  4, CIFAR-10 Batch 4:  Cost: 1.33481 Acc: 0.5198
Epoch  4, CIFAR-10 Batch 5:  Cost: 1.32758 Acc: 0.5178
Epoch  5, CIFAR-10 Batch 1:  Cost: 1.30496 Acc: 0.5346
Epoch  5, CIFAR-10 Batch 2:  Cost: 1.29267 Acc: 0.5374
Epoch  5, CIFAR-10 Batch 3:  Cost: 1.27636 Acc: 0.5372
Epoch  5, CIFAR-10 Batch 4:  Cost: 1.2694 Acc: 0.5428
Epoch  5, CIFAR-10 Batch 5:  Cost: 1.26666 Acc: 0.5414
Epoch  6, CIFAR-10 Batch 1:  Cost: 1.23377 Acc: 0.5616
Epoch  6, CIFAR-10 Batch 2:  Cost: 1.23825 Acc: 0.558
Epoch  6, CIFAR-10 Batch 3:  Cost: 1.22728 Acc: 0.5616
Epoch  6, CIFAR-10 Batch 4:  Cost: 1.23116 Acc: 0.5584
Epoch  6, CIFAR-10 Batch 5:  Cost: 1.21127 Acc: 0.5634
Epoch  7, CIFAR-10 Batch 1:  Cost: 1.19674 Acc: 0.5724
Epoch  7, CIFAR-10 Batch 2:  Cost: 1.1927 Acc: 0.5722
Epoch  7, CIFAR-10 Batch 3:  Cost: 1.18699 Acc: 0.5762
Epoch  7, CIFAR-10 Batch 4:  Cost: 1.19104 Acc: 0.5722
Epoch  7, CIFAR-10 Batch 5:  Cost: 1.16356 Acc: 0.5798
Epoch  8, CIFAR-10 Batch 1:  Cost: 1.16232 Acc: 0.587
Epoch  8, CIFAR-10 Batch 2:  Cost: 1.18011 Acc: 0.5814
Epoch  8, CIFAR-10 Batch 3:  Cost: 1.15503 Acc: 0.5842
Epoch  8, CIFAR-10 Batch 4:  Cost: 1.15345 Acc: 0.5878
Epoch  8, CIFAR-10 Batch 5:  Cost: 1.14067 Acc: 0.5876
Epoch  9, CIFAR-10 Batch 1:  Cost: 1.12542 Acc: 0.5988
Epoch  9, CIFAR-10 Batch 2:  Cost: 1.13429 Acc: 0.5934
Epoch  9, CIFAR-10 Batch 3:  Cost: 1.1176 Acc: 0.601
Epoch  9, CIFAR-10 Batch 4:  Cost: 1.10984 Acc: 0.6096
Epoch  9, CIFAR-10 Batch 5:  Cost: 1.10907 Acc: 0.6104
Epoch 10, CIFAR-10 Batch 1:  Cost: 1.10319 Acc: 0.6084
Epoch 10, CIFAR-10 Batch 2:  Cost: 1.1133 Acc: 0.6056
Epoch 10, CIFAR-10 Batch 3:  Cost: 1.13462 Acc: 0.5994
Epoch 10, CIFAR-10 Batch 4:  Cost: 1.12159 Acc: 0.6076
Epoch 10, CIFAR-10 Batch 5:  Cost: 1.10132 Acc: 0.6072
Epoch 11, CIFAR-10 Batch 1:  Cost: 1.08779 Acc: 0.6182
Epoch 11, CIFAR-10 Batch 2:  Cost: 1.07093 Acc: 0.6188
Epoch 11, CIFAR-10 Batch 3:  Cost: 1.11955 Acc: 0.6106
Epoch 11, CIFAR-10 Batch 4:  Cost: 1.12693 Acc: 0.6072
Epoch 11, CIFAR-10 Batch 5:  Cost: 1.07712 Acc: 0.6122
Epoch 12, CIFAR-10 Batch 1:  Cost: 1.07404 Acc: 0.6254
Epoch 12, CIFAR-10 Batch 2:  Cost: 1.05537 Acc: 0.6288
Epoch 12, CIFAR-10 Batch 3:  Cost: 1.07908 Acc: 0.6182
Epoch 12, CIFAR-10 Batch 4:  Cost: 1.0726 Acc: 0.6224
Epoch 12, CIFAR-10 Batch 5:  Cost: 1.0609 Acc: 0.621
Epoch 13, CIFAR-10 Batch 1:  Cost: 1.05651 Acc: 0.6316
Epoch 13, CIFAR-10 Batch 2:  Cost: 1.05294 Acc: 0.6278
Epoch 13, CIFAR-10 Batch 3:  Cost: 1.09413 Acc: 0.6198
Epoch 13, CIFAR-10 Batch 4:  Cost: 1.05624 Acc: 0.6304
Epoch 13, CIFAR-10 Batch 5:  Cost: 1.03161 Acc: 0.6338
Epoch 14, CIFAR-10 Batch 1:  Cost: 1.03173 Acc: 0.6362
Epoch 14, CIFAR-10 Batch 2:  Cost: 1.0285 Acc: 0.6408
Epoch 14, CIFAR-10 Batch 3:  Cost: 1.05158 Acc: 0.6352
Epoch 14, CIFAR-10 Batch 4:  Cost: 1.04155 Acc: 0.6408
Epoch 14, CIFAR-10 Batch 5:  Cost: 1.04242 Acc: 0.6392
Epoch 15, CIFAR-10 Batch 1:  Cost: 1.04762 Acc: 0.638
Epoch 15, CIFAR-10 Batch 2:  Cost: 1.01237 Acc: 0.6442
Epoch 15, CIFAR-10 Batch 3:  Cost: 1.03366 Acc: 0.6412
Epoch 15, CIFAR-10 Batch 4:  Cost: 1.04756 Acc: 0.6364
Epoch 15, CIFAR-10 Batch 5:  Cost: 1.02097 Acc: 0.6444
Epoch 16, CIFAR-10 Batch 1:  Cost: 1.02882 Acc: 0.6436
Epoch 16, CIFAR-10 Batch 2:  Cost: 1.0178 Acc: 0.6486
Epoch 16, CIFAR-10 Batch 3:  Cost: 1.03485 Acc: 0.646
Epoch 16, CIFAR-10 Batch 4:  Cost: 1.0234 Acc: 0.6458
Epoch 16, CIFAR-10 Batch 5:  Cost: 1.01137 Acc: 0.6452
Epoch 17, CIFAR-10 Batch 1:  Cost: 1.00972 Acc: 0.6514
Epoch 17, CIFAR-10 Batch 2:  Cost: 1.01436 Acc: 0.6476
Epoch 17, CIFAR-10 Batch 3:  Cost: 1.06427 Acc: 0.639
Epoch 17, CIFAR-10 Batch 4:  Cost: 1.04233 Acc: 0.6356
Epoch 17, CIFAR-10 Batch 5:  Cost: 1.02694 Acc: 0.6464
Epoch 18, CIFAR-10 Batch 1:  Cost: 1.00892 Acc: 0.6526
Epoch 18, CIFAR-10 Batch 2:  Cost: 1.02067 Acc: 0.6462
Epoch 18, CIFAR-10 Batch 3:  Cost: 1.05904 Acc: 0.6442
Epoch 18, CIFAR-10 Batch 4:  Cost: 1.01302 Acc: 0.6502
Epoch 18, CIFAR-10 Batch 5:  Cost: 1.02396 Acc: 0.6502
Epoch 19, CIFAR-10 Batch 1:  Cost: 1.00227 Acc: 0.6552
Epoch 19, CIFAR-10 Batch 2:  Cost: 1.02092 Acc: 0.652
Epoch 19, CIFAR-10 Batch 3:  Cost: 1.05893 Acc: 0.6414
Epoch 19, CIFAR-10 Batch 4:  Cost: 1.00674 Acc: 0.6528
Epoch 19, CIFAR-10 Batch 5:  Cost: 1.02698 Acc: 0.6522
Epoch 20, CIFAR-10 Batch 1:  Cost: 1.03263 Acc: 0.651
Epoch 20, CIFAR-10 Batch 2:  Cost: 1.03441 Acc: 0.643
Epoch 20, CIFAR-10 Batch 3:  Cost: 1.08015 Acc: 0.6406
Epoch 20, CIFAR-10 Batch 4:  Cost: 1.02448 Acc: 0.6486
Epoch 20, CIFAR-10 Batch 5:  Cost: 1.09049 Acc: 0.6296
Epoch 21, CIFAR-10 Batch 1:  Cost: 1.01664 Acc: 0.649
Epoch 21, CIFAR-10 Batch 2:  Cost: 1.05581 Acc: 0.6386
Epoch 21, CIFAR-10 Batch 3:  Cost: 1.09459 Acc: 0.6348
Epoch 21, CIFAR-10 Batch 4:  Cost: 1.03846 Acc: 0.6508
Epoch 21, CIFAR-10 Batch 5:  Cost: 1.0413 Acc: 0.6524
Epoch 22, CIFAR-10 Batch 1:  Cost: 1.03496 Acc: 0.6436
Epoch 22, CIFAR-10 Batch 2:  Cost: 1.04312 Acc: 0.6406
Epoch 22, CIFAR-10 Batch 3:  Cost: 1.06326 Acc: 0.6396
Epoch 22, CIFAR-10 Batch 4:  Cost: 1.01442 Acc: 0.6598
Epoch 22, CIFAR-10 Batch 5:  Cost: 1.04885 Acc: 0.6488
Epoch 23, CIFAR-10 Batch 1:  Cost: 0.999467 Acc: 0.6624
Epoch 23, CIFAR-10 Batch 2:  Cost: 1.02874 Acc: 0.6592
Epoch 23, CIFAR-10 Batch 3:  Cost: 1.02443 Acc: 0.6582
Epoch 23, CIFAR-10 Batch 4:  Cost: 1.03932 Acc: 0.6576
Epoch 23, CIFAR-10 Batch 5:  Cost: 1.04947 Acc: 0.6564
Epoch 24, CIFAR-10 Batch 1:  Cost: 1.01877 Acc: 0.6678
Epoch 24, CIFAR-10 Batch 2:  Cost: 1.03529 Acc: 0.658
Epoch 24, CIFAR-10 Batch 3:  Cost: 1.04442 Acc: 0.6554
Epoch 24, CIFAR-10 Batch 4:  Cost: 1.0249 Acc: 0.6584
Epoch 24, CIFAR-10 Batch 5:  Cost: 1.03117 Acc: 0.6594
Epoch 25, CIFAR-10 Batch 1:  Cost: 1.03513 Acc: 0.662
Epoch 25, CIFAR-10 Batch 2:  Cost: 1.02535 Acc: 0.6596
Epoch 25, CIFAR-10 Batch 3:  Cost: 1.05435 Acc: 0.6558
Epoch 25, CIFAR-10 Batch 4:  Cost: 1.00808 Acc: 0.6606
Epoch 25, CIFAR-10 Batch 5:  Cost: 1.03519 Acc: 0.6616
Epoch 26, CIFAR-10 Batch 1:  Cost: 1.01605 Acc: 0.6702
Epoch 26, CIFAR-10 Batch 2:  Cost: 1.04516 Acc: 0.6574
Epoch 26, CIFAR-10 Batch 3:  Cost: 1.03903 Acc: 0.6584
Epoch 26, CIFAR-10 Batch 4:  Cost: 1.02932 Acc: 0.6574
Epoch 26, CIFAR-10 Batch 5:  Cost: 1.06601 Acc: 0.6606
Epoch 27, CIFAR-10 Batch 1:  Cost: 1.03486 Acc: 0.6686
Epoch 27, CIFAR-10 Batch 2:  Cost: 1.05434 Acc: 0.6558
Epoch 27, CIFAR-10 Batch 3:  Cost: 1.07359 Acc: 0.65
Epoch 27, CIFAR-10 Batch 4:  Cost: 1.01697 Acc: 0.6666
Epoch 27, CIFAR-10 Batch 5:  Cost: 1.05586 Acc: 0.6634
Epoch 28, CIFAR-10 Batch 1:  Cost: 1.05456 Acc: 0.6606
Epoch 28, CIFAR-10 Batch 2:  Cost: 1.08377 Acc: 0.6558
Epoch 28, CIFAR-10 Batch 3:  Cost: 1.09045 Acc: 0.6506
Epoch 28, CIFAR-10 Batch 4:  Cost: 1.04092 Acc: 0.6632
Epoch 28, CIFAR-10 Batch 5:  Cost: 1.05459 Acc: 0.6644
Epoch 29, CIFAR-10 Batch 1:  Cost: 1.05086 Acc: 0.6624
Epoch 29, CIFAR-10 Batch 2:  Cost: 1.0676 Acc: 0.6552
Epoch 29, CIFAR-10 Batch 3:  Cost: 1.07764 Acc: 0.6566
Epoch 29, CIFAR-10 Batch 4:  Cost: 1.03127 Acc: 0.6672
Epoch 29, CIFAR-10 Batch 5:  Cost: 1.05262 Acc: 0.6642
Epoch 30, CIFAR-10 Batch 1:  Cost: 1.08191 Acc: 0.662
Epoch 30, CIFAR-10 Batch 2:  Cost: 1.07141 Acc: 0.6552
Epoch 30, CIFAR-10 Batch 3:  Cost: 1.08628 Acc: 0.6544
Epoch 30, CIFAR-10 Batch 4:  Cost: 1.02888 Acc: 0.6708
Epoch 30, CIFAR-10 Batch 5:  Cost: 1.04384 Acc: 0.6692

Checkpoint

The model has been saved to disk.

Test Model

Test your model against the test dataset. This will be your final accuracy. You should have an accuracy greater than 50%. If you don't, keep tweaking the model architecture and parameters.


In [55]:
"""
DON'T MODIFY ANYTHING IN THIS CELL
"""
%matplotlib inline
%config InlineBackend.figure_format = 'retina'

import tensorflow as tf
import pickle
import helper
import random

# Set batch size if not already set
try:
    if batch_size:
        pass
except NameError:
    batch_size = 64

save_model_path = './image_classification'
n_samples = 4
top_n_predictions = 3

def test_model():
    """
    Test the saved model against the test dataset
    """

    test_features, test_labels = pickle.load(open('preprocess_test.p', mode='rb'))
    loaded_graph = tf.Graph()

    with tf.Session(graph=loaded_graph) as sess:
        # Load model
        loader = tf.train.import_meta_graph(save_model_path + '.meta')
        loader.restore(sess, save_model_path)

        # Get Tensors from loaded model
        loaded_x = loaded_graph.get_tensor_by_name('x:0')
        loaded_y = loaded_graph.get_tensor_by_name('y:0')
        loaded_keep_prob = loaded_graph.get_tensor_by_name('keep_prob:0')
        loaded_logits = loaded_graph.get_tensor_by_name('logits:0')
        loaded_acc = loaded_graph.get_tensor_by_name('accuracy:0')
        
        # Get accuracy in batches for memory limitations
        test_batch_acc_total = 0
        test_batch_count = 0
        
        for test_feature_batch, test_label_batch in helper.batch_features_labels(test_features, test_labels, batch_size):
            test_batch_acc_total += sess.run(
                loaded_acc,
                feed_dict={loaded_x: test_feature_batch, loaded_y: test_label_batch, loaded_keep_prob: 1.0})
            test_batch_count += 1

        print('Testing Accuracy: {}\n'.format(test_batch_acc_total/test_batch_count))

        # Print Random Samples
        random_test_features, random_test_labels = tuple(zip(*random.sample(list(zip(test_features, test_labels)), n_samples)))
        random_test_predictions = sess.run(
            tf.nn.top_k(tf.nn.softmax(loaded_logits), top_n_predictions),
            feed_dict={loaded_x: random_test_features, loaded_y: random_test_labels, loaded_keep_prob: 1.0})
        helper.display_image_predictions(random_test_features, random_test_labels, random_test_predictions)


test_model()


Testing Accuracy: 0.6664779961109162

Why 50-80% Accuracy?

You might be wondering why you can't get an accuracy any higher. First things first, 50% isn't bad for a simple CNN. Pure guessing would get you 10% accuracy. However, you might notice people are getting scores well above 80%. That's because we haven't taught you all there is to know about neural networks. We still need to cover a few more techniques.

Submitting This Project

When submitting this project, make sure to run all the cells before saving the notebook. Save the notebook file as "dlnd_image_classification.ipynb" and save it as a HTML file under "File" -> "Download as". Include the "helper.py" and "problem_unittests.py" files in your submission.