Image Classification Demo using TensorFlow on Windows

I’ve been looking at the TensorFlow library of machine learning code running on a Windows machine. In particular, I’ve been experimenting with the famous MNIST image classification problem.

The MNIST image data set has a total of 70,000 images. Each image is a picture of one of the ten digits, ‘0’ through ‘9’, that were handwritten. There are 60,000 test images used to create a prediction model, and 10,000 test images used to evaluate the accuracy of a prediction model.

03_mnist_convolutional_tf_on_windows

There are many techniques that can be used to do MNIST image recognition, but the technique that works best is called a convolutional neural network. In the directory of TensorFlow examples, I found several bad examples, plus an excellent one by Aymeric Damien. I’m a very experienced software engineer, but just like a beginner, I learn best by taking an existing example and then experimenting with it.

After a few days, my conclusions are that TensorFlow has a steep learning curve, is still volatile because the code base is under constant revision, but is very powerful once you learn it.

# mnist_convo.py
# classify the MNIST data set using a TensorFlow convolutional neural network
# based on the excellent example by Aymeric Damien

# from __future__ import print_function  # print(x) vs print x if using Python 2

import tensorflow as tf
tf.set_random_seed(1)  # to get reproducible results

# get MNIST data ("Mixed National Institute of Standards and Technology" digit images)
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("/tmp/data/", one_hot=True)  # one-hot -> '2' = (0,0,1,0,0,0,0,0,0)

# training parameters
learn_rate = 0.001
# max_iter = 2000  # for demo purposes
max_iter = 200000  # yields 0.996094 classification accuracy on the 256-item test set (255 / 256)
batch_size = 128  # aka "mini-batch"
display_step = 200

# neural network parameters
num_input = 784 # MNIST data input (28*28 pixels)
num_classes = 10 # MNIST total classes (0-9 digits)
dropout = 0.75 # dropout -- probability to keep units

# tf Graph input
x = tf.placeholder(tf.float32, [None, num_input])  # a tf.placeholder is used mostly for input and output values
y = tf.placeholder(tf.float32, [None, num_classes])
keep_prob = tf.placeholder(tf.float32) # dropout keep prob -- here essentially a function parameter


# define some helper functions
def my_conv2d(x, W, b, strides=1):
    # tf.nn.conv2D wrapper, with bias and relu activation
    x = tf.nn.conv2d(x, W, strides=[1, strides, strides, 1], padding='SAME')
    x = tf.nn.bias_add(x, b)
    return tf.nn.relu(x)

def my_maxpool(x, k=2):
    # tf.nn.max_pool wrapper
    return tf.nn.max_pool(x, ksize=[1, k, k, 1], strides=[1, k, k, 1], padding='SAME')
	
# cdefine the model
def conv_net(x, weights, biases, dropout):
    # reshape input picture
    x = tf.reshape(x, shape=[-1, 28, 28, 1])

    # first convolution Layer
    conv1 = my_conv2d(x, weights['wc1'], biases['bc1'])
    # max pooling (down-sampling)
    conv1 = my_maxpool(conv1, k=2)

    # second convolution Layer
    conv2 = my_conv2d(conv1, weights['wc2'], biases['bc2'])
    # max pooling (down-sampling)
    conv2 = my_maxpool(conv2, k=2)

    # fully connected layer
    # reshape conv2 output to fit fully connected layer input
    fc1 = tf.reshape(conv2, [-1, weights['wd1'].get_shape().as_list()[0]])
    fc1 = tf.add(tf.matmul(fc1, weights['wd1']), biases['bd1'])
    fc1 = tf.nn.relu(fc1)
    # apply dropout to fully connected layer
    fc1 = tf.nn.dropout(fc1, dropout)

    # output, class prediction
    result = tf.add(tf.matmul(fc1, weights['out']), biases['out'])
    return result

# save weights & biases
weights = {
    # 5x5 conv, 1 input, 32 outputs. A tf.Variable is used for weights & biases
    'wc1': tf.Variable(tf.random_normal([5, 5, 1, 32])),
    # 5x5 conv, 32 inputs, 64 outputs
    'wc2': tf.Variable(tf.random_normal([5, 5, 32, 64])),
    # fully connected, 7*7*64 inputs, 1024 outputs
    'wd1': tf.Variable(tf.random_normal([7*7*64, 1024])),
    # 1024 inputs, 10 outputs (class prediction)
    'out': tf.Variable(tf.random_normal([1024, num_classes]))
}

biases = {
    'bc1': tf.Variable(tf.random_normal([32])),
    'bc2': tf.Variable(tf.random_normal([64])),
    'bd1': tf.Variable(tf.random_normal([1024])),
    'out': tf.Variable(tf.random_normal([num_classes]))
}

# create the model
pred = conv_net(x, weights, biases, keep_prob)  # almost too easy when prep done

# define CE loss function and optimizer
ce_error = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=pred, labels=y))
optimizer = tf.train.AdamOptimizer(learning_rate=learn_rate).minimize(ce_error)  # sophisticated alternative
# optimizer = tf.train.GradientDescentOptimizer(learning_rate=learn_rate).minimize(cost)  # standard SGD is ineffective

# evaluate model classification accuracy
correct_pred = tf.equal(tf.argmax(pred, 1), tf.argmax(y, 1))
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))

# magic TF incantation 
init = tf.global_variables_initializer()

# run the graph
print("\nTraining started")
with tf.Session() as sess:
    sess.run(init)
    step = 1
    # train
    while step * batch_size < max_iter:
        batch_x, batch_y = mnist.train.next_batch(batch_size)
        # run optimization op (backprop)
        sess.run(optimizer, feed_dict={x: batch_x, y: batch_y, keep_prob: dropout})
        if step % display_step == 0:
            # calculate batch error/loss and classification accuracy
            loss, acc = sess.run([ce_error, accuracy], feed_dict={x: batch_x, y: batch_y, keep_prob: 1.})
            print("iteration = " + str(step*batch_size) + ", minibatch error = " + \
                  "{:.6f}".format(loss) + ", minibatch classification accuracy = " + \
                  "{:.5f}".format(acc))
        step += 1
    print("\nTraining complete")

    # calculate classification accuracy for 256 mnist test images
    print("\nTesting Accuracy:", sess.run(accuracy, feed_dict={x: mnist.test.images[:256], y: mnist.test.labels[:256], keep_prob: 1.}))

# end script

01_mnist_convolutional_tf_on_windows

Advertisements
This entry was posted in Machine Learning. Bookmark the permalink.