Transfer Learning

Most of the time you won't want to train a whole convolutional network yourself. Modern ConvNets training on huge datasets like ImageNet take weeks on multiple GPUs. Instead, most people use a pretrained network either as a fixed feature extractor, or as an initial network to fine tune. In this notebook, you'll be using VGGNet trained on the ImageNet dataset as a feature extractor. Below is a diagram of the VGGNet architecture.

VGGNet is great because it's simple and has great performance, coming in second in the ImageNet competition. The idea here is that we keep all the convolutional layers, but replace the final fully connected layers with our own classifier. This way we can use VGGNet as a feature extractor for our images then easily train a simple classifier on top of that. What we'll do is take the first fully connected layer with 4096 units, including thresholding with ReLUs. We can use those values as a code for each image, then build a classifier on top of those codes.

You can read more about transfer learning from the CS231n course notes.

Pretrained VGGNet

We'll be using a pretrained network from https://github.com/machrisaa/tensorflow-vgg.


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

vgg_dir = 'tensorflow_vgg/'
# Make sure vgg exists
if not isdir(vgg_dir):
    raise Exception("VGG directory doesn't exist!")

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(vgg_dir + "vgg16.npy"):
    with DLProgress(unit='B', unit_scale=True, miniters=1, desc='VGG16 Parameters') as pbar:
        urlretrieve(
            'https://s3.amazonaws.com/content.udacity-data.com/nd101/vgg16.npy',
            vgg_dir + 'vgg16.npy',
            pbar.hook)
else:
    print("Parameter file already exists!")


Parameter file already exists!

Flower power

Here we'll be using VGGNet to classify images of flowers. To get the flower dataset, run the cell below. This dataset comes from the TensorFlow inception tutorial.


In [2]:
import tarfile

dataset_folder_path = 'flower_photos'

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('flower_photos.tar.gz'):
    with DLProgress(unit='B', unit_scale=True, miniters=1, desc='Flowers Dataset') as pbar:
        urlretrieve(
            'http://download.tensorflow.org/example_images/flower_photos.tgz',
            'flower_photos.tar.gz',
            pbar.hook)

if not isdir(dataset_folder_path):
    with tarfile.open('flower_photos.tar.gz') as tar:
        tar.extractall()
        tar.close()

ConvNet Codes

Below, we'll run through all the images in our dataset and get codes for each of them. That is, we'll run the images through the VGGNet convolutional layers and record the values of the first fully connected layer. We can then write these to a file for later when we build our own classifier.

Here we're using the vgg16 module from tensorflow_vgg. The network takes images of size $224 \times 224 \times 3$ as input. Then it has 5 sets of convolutional layers. The network implemented here has this structure (copied from the source code):

self.conv1_1 = self.conv_layer(bgr, "conv1_1")
self.conv1_2 = self.conv_layer(self.conv1_1, "conv1_2")
self.pool1 = self.max_pool(self.conv1_2, 'pool1')

self.conv2_1 = self.conv_layer(self.pool1, "conv2_1")
self.conv2_2 = self.conv_layer(self.conv2_1, "conv2_2")
self.pool2 = self.max_pool(self.conv2_2, 'pool2')

self.conv3_1 = self.conv_layer(self.pool2, "conv3_1")
self.conv3_2 = self.conv_layer(self.conv3_1, "conv3_2")
self.conv3_3 = self.conv_layer(self.conv3_2, "conv3_3")
self.pool3 = self.max_pool(self.conv3_3, 'pool3')

self.conv4_1 = self.conv_layer(self.pool3, "conv4_1")
self.conv4_2 = self.conv_layer(self.conv4_1, "conv4_2")
self.conv4_3 = self.conv_layer(self.conv4_2, "conv4_3")
self.pool4 = self.max_pool(self.conv4_3, 'pool4')

self.conv5_1 = self.conv_layer(self.pool4, "conv5_1")
self.conv5_2 = self.conv_layer(self.conv5_1, "conv5_2")
self.conv5_3 = self.conv_layer(self.conv5_2, "conv5_3")
self.pool5 = self.max_pool(self.conv5_3, 'pool5')

self.fc6 = self.fc_layer(self.pool5, "fc6")
self.relu6 = tf.nn.relu(self.fc6)

So what we want are the values of the first fully connected layer, after being ReLUd (self.relu6). To build the network, we use

with tf.Session() as sess:
    vgg = vgg16.Vgg16()
    input_ = tf.placeholder(tf.float32, [None, 224, 224, 3])
    with tf.name_scope("content_vgg"):
        vgg.build(input_)

This creates the vgg object, then builds the graph with vgg.build(input_). Then to get the values from the layer,

feed_dict = {input_: images}
codes = sess.run(vgg.relu6, feed_dict=feed_dict)

In [3]:
import os

import numpy as np
import tensorflow as tf

from tensorflow_vgg import vgg16
from tensorflow_vgg import utils

In [4]:
data_dir = 'flower_photos/'
contents = os.listdir(data_dir)
classes = [each for each in contents if os.path.isdir(data_dir + each)]

Below I'm running images through the VGG network in batches.

Exercise: Below, build the VGG network. Also get the codes from the first fully connected layer (make sure you get the ReLUd values).


In [45]:
# Set the batch size higher if you can fit in in your GPU memory
batch_size = 32
codes_list = []
labels = []
batch = []

codes = None

with tf.Session() as sess:
    
    my_vgg = vgg16.Vgg16()
    
    input_ = tf.placeholder(tf.float32, [None, 224, 224, 3])
    
    with tf.name_scope("content_vgg"):
        my_vgg.build(input_)
        
        
    for each in classes:
        
        print("Starting {} images".format(each))
        class_path = data_dir + each
        files = os.listdir(class_path)
        for ii, file in enumerate(files, 1):
            
            # Add images to the current batch
            # utils.load_image crops the input images for us, from the center
            
            img = utils.load_image(os.path.join(class_path, file))
            batch.append(img.reshape((1, 224, 224, 3)))
            labels.append(each)
            
            # Running the batch through the network to get the codes
            if ii % batch_size == 0 or ii == len(files):
                
                # Image batch to pass to VGG network
                images = np.concatenate(batch)
                
                # Get the values from the relu6 layer of the VGG network
                feed_dict = {input_ : images}
                
                # KEY!!!!
                codes_batch = sess.run(my_vgg.relu6, feed_dict = feed_dict)
                
                # Here I'm building an array of the codes
                if codes is None:
                    codes = codes_batch
                else:
                    codes = np.concatenate((codes, codes_batch))
                
                # Reset to start building the next batch
                batch = []
                print('{} images processed'.format(ii))


C:\Users\Anthony\Documents\GitHub\deep-learning-foundations\transfer-learning\tensorflow_vgg\vgg16.npy
npy file loaded
build model started
build model finished: 0s
Starting daisy images
32 images processed
64 images processed
96 images processed
128 images processed
160 images processed
192 images processed
224 images processed
256 images processed
288 images processed
320 images processed
352 images processed
384 images processed
416 images processed
448 images processed
480 images processed
512 images processed
544 images processed
576 images processed
608 images processed
633 images processed
Starting dandelion images
32 images processed
64 images processed
96 images processed
128 images processed
160 images processed
192 images processed
224 images processed
256 images processed
288 images processed
320 images processed
352 images processed
384 images processed
416 images processed
448 images processed
480 images processed
512 images processed
544 images processed
576 images processed
608 images processed
640 images processed
672 images processed
704 images processed
736 images processed
768 images processed
800 images processed
832 images processed
864 images processed
896 images processed
898 images processed
Starting roses images
32 images processed
64 images processed
96 images processed
128 images processed
160 images processed
192 images processed
224 images processed
256 images processed
288 images processed
320 images processed
352 images processed
384 images processed
416 images processed
448 images processed
480 images processed
512 images processed
544 images processed
576 images processed
608 images processed
640 images processed
641 images processed
Starting sunflowers images
32 images processed
64 images processed
96 images processed
128 images processed
160 images processed
192 images processed
224 images processed
256 images processed
288 images processed
320 images processed
352 images processed
384 images processed
416 images processed
448 images processed
480 images processed
512 images processed
544 images processed
576 images processed
608 images processed
640 images processed
672 images processed
699 images processed
Starting tulips images
32 images processed
64 images processed
96 images processed
128 images processed
160 images processed
192 images processed
224 images processed
256 images processed
288 images processed
320 images processed
352 images processed
384 images processed
416 images processed
448 images processed
480 images processed
512 images processed
544 images processed
576 images processed
608 images processed
640 images processed
672 images processed
704 images processed
736 images processed
768 images processed
799 images processed

In [6]:
# write codes to file
with open('codes', 'w') as f:
    codes.tofile(f)
    
# write labels to file
import csv
with open('labels', 'w') as f:
    writer = csv.writer(f, delimiter='\n')
    writer.writerow(labels)

Building the Classifier

Now that we have codes for all the images, we can build a simple classifier on top of them. The codes behave just like normal input into a simple neural network. Below I'm going to have you do most of the work.


In [7]:
# read codes and labels from file
import csv

with open('labels') as f:
    reader = csv.reader(f, delimiter='\n')
    labels = np.array([each for each in reader if len(each) > 0]).squeeze()
with open('codes') as f:
    codes = np.fromfile(f, dtype=np.float32)
    codes = codes.reshape((len(labels), -1))

Data prep

As usual, now we need to one-hot encode our labels and create validation/test sets. First up, creating our labels!

Exercise: From scikit-learn, use LabelBinarizer to create one-hot encoded vectors from the labels.


In [8]:
from sklearn.preprocessing import LabelBinarizer

labelBinarizer = LabelBinarizer()

labelBinarizer.fit(labels)

labels_vecs = labelBinarizer.transform(labels)

Now you'll want to create your training, validation, and test sets. An important thing to note here is that our labels and data aren't randomized yet. We'll want to shuffle our data so the validation and test sets contain data from all classes. Otherwise, you could end up with testing sets that are all one class. Typically, you'll also want to make sure that each smaller set has the same the distribution of classes as it is for the whole data set. The easiest way to accomplish both these goals is to use StratifiedShuffleSplit from scikit-learn.

You can create the splitter like so:

ss = StratifiedShuffleSplit(n_splits=1, test_size=0.2)

Then split the data with

splitter = ss.split(x, y)

ss.split returns a generator of indices. You can pass the indices into the arrays to get the split sets. The fact that it's a generator means you either need to iterate over it, or use next(splitter) to get the indices. Be sure to read the documentation and the user guide.

Exercise: Use StratifiedShuffleSplit to split the codes and labels into training, validation, and test sets.


In [9]:
from sklearn.model_selection import StratifiedShuffleSplit

sss = StratifiedShuffleSplit(n_splits=1, test_size=.2)

i, j = next( sss.split(codes, labels) )

h = len(j) // 2

j, k = j[:h], j[h: ]   # Validation 50%
# end j at half of j and start k at half of j

train_x, train_y = codes[i], labels_vecs[i]
val_x, val_y = codes[j], labels_vecs[j]
test_x, test_y =  codes[k], labels_vecs[k]

In [10]:
print("Train shapes (x, y):", train_x.shape, train_y.shape)
print("Validation shapes (x, y):", val_x.shape, val_y.shape)
print("Test shapes (x, y):", test_x.shape, test_y.shape)


Train shapes (x, y): (2936, 4096) (2936, 5)
Validation shapes (x, y): (367, 4096) (367, 5)
Test shapes (x, y): (367, 4096) (367, 5)

If you did it right, you should see these sizes for the training sets:

Train shapes (x, y): (2936, 4096) (2936, 5)
Validation shapes (x, y): (367, 4096) (367, 5)
Test shapes (x, y): (367, 4096) (367, 5)

Classifier layers


In [11]:
inputs_ = tf.placeholder(tf.float32, shape=[None, codes.shape[1]])
labels_ = tf.placeholder(tf.int64, shape=[None, labels_vecs.shape[1]])

l_1 = tf.contrib.layers.fully_connected(inputs_, 256)

logits = tf.contrib.layers.fully_connected(l_1, labels_vecs.shape[1], activation_fn=None)

cross_entropy = tf.nn.softmax_cross_entropy_with_logits(labels=labels_, logits=logits)

cost = tf.reduce_mean( cross_entropy )

optimizer = tf.train.AdamOptimizer().minimize(cost)

# Operations for validation/test accuracy
predicted = tf.nn.softmax(logits)
correct_pred = tf.equal(tf.argmax(predicted, 1), tf.argmax(labels_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))

Batches!

Here is just a simple way to do batches. I've written it so that it includes all the data. Sometimes you'll throw out some data at the end to make sure you have full batches. Here I just extend the last batch to include the remaining data.


In [12]:
def get_batches(x, y, n_batches=10):
    """ Return a generator that yields batches from arrays x and y. """
    batch_size = len(x)//n_batches
    
    for ii in range(0, n_batches*batch_size, batch_size):
        # If we're not on the last batch, grab data with size batch_size
        if ii != (n_batches-1)*batch_size:
            X, Y = x[ii: ii+batch_size], y[ii: ii+batch_size] 
        # On the last batch, grab the rest of the data
        else:
            X, Y = x[ii:], y[ii:]
        # I love generators
        yield X, Y

Training


In [13]:
saver = tf.train.Saver()

In [30]:
e = 20
iteration = 0

with tf.Session() as sess:
    
    # 1. Start session
    sess.run(tf.global_variables_initializer() )
    
    # 2. Do each epoch
    for i in range(e):
        
        #3. Do each batch
        for x, y in get_batches(train_x, train_y):
            
            #4. Input data
            feed = {inputs_: x, labels_: y}
                        
            #5. Do loss
            loss, _ = sess.run([cost, optimizer], feed_dict=feed)
            
            #6. Increment counter 
            iteration += 1
            
            #7. Print results
            print("Epoch: {} / {}".format( i, e),
                 "Iteration: {}".format( iteration ),
                 "Train loss: {:.5f}".format( loss ))
            
            #8. Do Validation
            if iteration % 5 == 0:
                feed = {inputs_: val_x, labels_: val_y}
            
                val_acc = sess.run(accuracy, feed_dict=feed)
                
                print("Epoch: {} / {}".format( i, e),
                 "Iteration: {} ".format( iteration),
                 "Validation Acc: {:.4f}".format(val_acc) )
        
    saver.save(sess, "checkpoints/flowers.ckpt")


Epoch: 0 / 20 Iteration: 1 Train loss: 5.79400
Epoch: 0 / 20 Iteration: 2 Train loss: 15.37738
Epoch: 0 / 20 Iteration: 3 Train loss: 16.86608
Epoch: 0 / 20 Iteration: 4 Train loss: 12.03363
Epoch: 0 / 20 Iteration: 5 Train loss: 7.19821
Epoch: 0 / 20 Iteration: 5  Validation Acc: 0.6594
Epoch: 0 / 20 Iteration: 6 Train loss: 2.82134
Epoch: 0 / 20 Iteration: 7 Train loss: 2.96322
Epoch: 0 / 20 Iteration: 8 Train loss: 3.67236
Epoch: 0 / 20 Iteration: 9 Train loss: 3.16198
Epoch: 0 / 20 Iteration: 10 Train loss: 2.41240
Epoch: 0 / 20 Iteration: 10  Validation Acc: 0.7302
Epoch: 1 / 20 Iteration: 11 Train loss: 1.31189
Epoch: 1 / 20 Iteration: 12 Train loss: 0.96772
Epoch: 1 / 20 Iteration: 13 Train loss: 0.85511
Epoch: 1 / 20 Iteration: 14 Train loss: 0.72209
Epoch: 1 / 20 Iteration: 15 Train loss: 0.98749
Epoch: 1 / 20 Iteration: 15  Validation Acc: 0.8038
Epoch: 1 / 20 Iteration: 16 Train loss: 0.82456
Epoch: 1 / 20 Iteration: 17 Train loss: 1.04381
Epoch: 1 / 20 Iteration: 18 Train loss: 0.55632
Epoch: 1 / 20 Iteration: 19 Train loss: 1.01295
Epoch: 1 / 20 Iteration: 20 Train loss: 0.65951
Epoch: 1 / 20 Iteration: 20  Validation Acc: 0.8420
Epoch: 2 / 20 Iteration: 21 Train loss: 0.48814
Epoch: 2 / 20 Iteration: 22 Train loss: 0.41124
Epoch: 2 / 20 Iteration: 23 Train loss: 0.49473
Epoch: 2 / 20 Iteration: 24 Train loss: 0.46525
Epoch: 2 / 20 Iteration: 25 Train loss: 0.42053
Epoch: 2 / 20 Iteration: 25  Validation Acc: 0.8665
Epoch: 2 / 20 Iteration: 26 Train loss: 0.32808
Epoch: 2 / 20 Iteration: 27 Train loss: 0.46633
Epoch: 2 / 20 Iteration: 28 Train loss: 0.29944
Epoch: 2 / 20 Iteration: 29 Train loss: 0.31682
Epoch: 2 / 20 Iteration: 30 Train loss: 0.43971
Epoch: 2 / 20 Iteration: 30  Validation Acc: 0.8583
Epoch: 3 / 20 Iteration: 31 Train loss: 0.37118
Epoch: 3 / 20 Iteration: 32 Train loss: 0.34355
Epoch: 3 / 20 Iteration: 33 Train loss: 0.26404
Epoch: 3 / 20 Iteration: 34 Train loss: 0.23805
Epoch: 3 / 20 Iteration: 35 Train loss: 0.26232
Epoch: 3 / 20 Iteration: 35  Validation Acc: 0.8856
Epoch: 3 / 20 Iteration: 36 Train loss: 0.16899
Epoch: 3 / 20 Iteration: 37 Train loss: 0.26726
Epoch: 3 / 20 Iteration: 38 Train loss: 0.13321
Epoch: 3 / 20 Iteration: 39 Train loss: 0.24080
Epoch: 3 / 20 Iteration: 40 Train loss: 0.24639
Epoch: 3 / 20 Iteration: 40  Validation Acc: 0.8774
Epoch: 4 / 20 Iteration: 41 Train loss: 0.25916
Epoch: 4 / 20 Iteration: 42 Train loss: 0.21711
Epoch: 4 / 20 Iteration: 43 Train loss: 0.16792
Epoch: 4 / 20 Iteration: 44 Train loss: 0.19045
Epoch: 4 / 20 Iteration: 45 Train loss: 0.19943
Epoch: 4 / 20 Iteration: 45  Validation Acc: 0.8828
Epoch: 4 / 20 Iteration: 46 Train loss: 0.13909
Epoch: 4 / 20 Iteration: 47 Train loss: 0.19349
Epoch: 4 / 20 Iteration: 48 Train loss: 0.08728
Epoch: 4 / 20 Iteration: 49 Train loss: 0.15784
Epoch: 4 / 20 Iteration: 50 Train loss: 0.14407
Epoch: 4 / 20 Iteration: 50  Validation Acc: 0.8747
Epoch: 5 / 20 Iteration: 51 Train loss: 0.16691
Epoch: 5 / 20 Iteration: 52 Train loss: 0.15592
Epoch: 5 / 20 Iteration: 53 Train loss: 0.10617
Epoch: 5 / 20 Iteration: 54 Train loss: 0.12340
Epoch: 5 / 20 Iteration: 55 Train loss: 0.13059
Epoch: 5 / 20 Iteration: 55  Validation Acc: 0.8828
Epoch: 5 / 20 Iteration: 56 Train loss: 0.09720
Epoch: 5 / 20 Iteration: 57 Train loss: 0.15139
Epoch: 5 / 20 Iteration: 58 Train loss: 0.07105
Epoch: 5 / 20 Iteration: 59 Train loss: 0.10495
Epoch: 5 / 20 Iteration: 60 Train loss: 0.10024
Epoch: 5 / 20 Iteration: 60  Validation Acc: 0.8883
Epoch: 6 / 20 Iteration: 61 Train loss: 0.11800
Epoch: 6 / 20 Iteration: 62 Train loss: 0.10859
Epoch: 6 / 20 Iteration: 63 Train loss: 0.07579
Epoch: 6 / 20 Iteration: 64 Train loss: 0.08784
Epoch: 6 / 20 Iteration: 65 Train loss: 0.07921
Epoch: 6 / 20 Iteration: 65  Validation Acc: 0.8965
Epoch: 6 / 20 Iteration: 66 Train loss: 0.07022
Epoch: 6 / 20 Iteration: 67 Train loss: 0.11188
Epoch: 6 / 20 Iteration: 68 Train loss: 0.05231
Epoch: 6 / 20 Iteration: 69 Train loss: 0.07455
Epoch: 6 / 20 Iteration: 70 Train loss: 0.07150
Epoch: 6 / 20 Iteration: 70  Validation Acc: 0.8910
Epoch: 7 / 20 Iteration: 71 Train loss: 0.07612
Epoch: 7 / 20 Iteration: 72 Train loss: 0.07964
Epoch: 7 / 20 Iteration: 73 Train loss: 0.05859
Epoch: 7 / 20 Iteration: 74 Train loss: 0.05713
Epoch: 7 / 20 Iteration: 75 Train loss: 0.05559
Epoch: 7 / 20 Iteration: 75  Validation Acc: 0.8910
Epoch: 7 / 20 Iteration: 76 Train loss: 0.05134
Epoch: 7 / 20 Iteration: 77 Train loss: 0.08500
Epoch: 7 / 20 Iteration: 78 Train loss: 0.04086
Epoch: 7 / 20 Iteration: 79 Train loss: 0.05215
Epoch: 7 / 20 Iteration: 80 Train loss: 0.05321
Epoch: 7 / 20 Iteration: 80  Validation Acc: 0.8965
Epoch: 8 / 20 Iteration: 81 Train loss: 0.05470
Epoch: 8 / 20 Iteration: 82 Train loss: 0.05781
Epoch: 8 / 20 Iteration: 83 Train loss: 0.04607
Epoch: 8 / 20 Iteration: 84 Train loss: 0.03999
Epoch: 8 / 20 Iteration: 85 Train loss: 0.03811
Epoch: 8 / 20 Iteration: 85  Validation Acc: 0.8965
Epoch: 8 / 20 Iteration: 86 Train loss: 0.03817
Epoch: 8 / 20 Iteration: 87 Train loss: 0.06339
Epoch: 8 / 20 Iteration: 88 Train loss: 0.03113
Epoch: 8 / 20 Iteration: 89 Train loss: 0.03848
Epoch: 8 / 20 Iteration: 90 Train loss: 0.04092
Epoch: 8 / 20 Iteration: 90  Validation Acc: 0.8992
Epoch: 9 / 20 Iteration: 91 Train loss: 0.04368
Epoch: 9 / 20 Iteration: 92 Train loss: 0.04182
Epoch: 9 / 20 Iteration: 93 Train loss: 0.03435
Epoch: 9 / 20 Iteration: 94 Train loss: 0.02918
Epoch: 9 / 20 Iteration: 95 Train loss: 0.02972
Epoch: 9 / 20 Iteration: 95  Validation Acc: 0.8992
Epoch: 9 / 20 Iteration: 96 Train loss: 0.02979
Epoch: 9 / 20 Iteration: 97 Train loss: 0.04767
Epoch: 9 / 20 Iteration: 98 Train loss: 0.02516
Epoch: 9 / 20 Iteration: 99 Train loss: 0.02889
Epoch: 9 / 20 Iteration: 100 Train loss: 0.03337
Epoch: 9 / 20 Iteration: 100  Validation Acc: 0.9046
Epoch: 10 / 20 Iteration: 101 Train loss: 0.03614
Epoch: 10 / 20 Iteration: 102 Train loss: 0.03108
Epoch: 10 / 20 Iteration: 103 Train loss: 0.02750
Epoch: 10 / 20 Iteration: 104 Train loss: 0.02213
Epoch: 10 / 20 Iteration: 105 Train loss: 0.02328
Epoch: 10 / 20 Iteration: 105  Validation Acc: 0.9019
Epoch: 10 / 20 Iteration: 106 Train loss: 0.02346
Epoch: 10 / 20 Iteration: 107 Train loss: 0.03698
Epoch: 10 / 20 Iteration: 108 Train loss: 0.02063
Epoch: 10 / 20 Iteration: 109 Train loss: 0.02353
Epoch: 10 / 20 Iteration: 110 Train loss: 0.02565
Epoch: 10 / 20 Iteration: 110  Validation Acc: 0.9046
Epoch: 11 / 20 Iteration: 111 Train loss: 0.02968
Epoch: 11 / 20 Iteration: 112 Train loss: 0.02485
Epoch: 11 / 20 Iteration: 113 Train loss: 0.02154
Epoch: 11 / 20 Iteration: 114 Train loss: 0.01755
Epoch: 11 / 20 Iteration: 115 Train loss: 0.01983
Epoch: 11 / 20 Iteration: 115  Validation Acc: 0.9074
Epoch: 11 / 20 Iteration: 116 Train loss: 0.01962
Epoch: 11 / 20 Iteration: 117 Train loss: 0.02899
Epoch: 11 / 20 Iteration: 118 Train loss: 0.01629
Epoch: 11 / 20 Iteration: 119 Train loss: 0.01901
Epoch: 11 / 20 Iteration: 120 Train loss: 0.02166
Epoch: 11 / 20 Iteration: 120  Validation Acc: 0.9074
Epoch: 12 / 20 Iteration: 121 Train loss: 0.02402
Epoch: 12 / 20 Iteration: 122 Train loss: 0.02049
Epoch: 12 / 20 Iteration: 123 Train loss: 0.01732
Epoch: 12 / 20 Iteration: 124 Train loss: 0.01425
Epoch: 12 / 20 Iteration: 125 Train loss: 0.01512
Epoch: 12 / 20 Iteration: 125  Validation Acc: 0.9074
Epoch: 12 / 20 Iteration: 126 Train loss: 0.01641
Epoch: 12 / 20 Iteration: 127 Train loss: 0.02350
Epoch: 12 / 20 Iteration: 128 Train loss: 0.01408
Epoch: 12 / 20 Iteration: 129 Train loss: 0.01638
Epoch: 12 / 20 Iteration: 130 Train loss: 0.01869
Epoch: 12 / 20 Iteration: 130  Validation Acc: 0.9074
Epoch: 13 / 20 Iteration: 131 Train loss: 0.01947
Epoch: 13 / 20 Iteration: 132 Train loss: 0.01678
Epoch: 13 / 20 Iteration: 133 Train loss: 0.01469
Epoch: 13 / 20 Iteration: 134 Train loss: 0.01174
Epoch: 13 / 20 Iteration: 135 Train loss: 0.01331
Epoch: 13 / 20 Iteration: 135  Validation Acc: 0.9101
Epoch: 13 / 20 Iteration: 136 Train loss: 0.01388
Epoch: 13 / 20 Iteration: 137 Train loss: 0.01848
Epoch: 13 / 20 Iteration: 138 Train loss: 0.01205
Epoch: 13 / 20 Iteration: 139 Train loss: 0.01387
Epoch: 13 / 20 Iteration: 140 Train loss: 0.01552
Epoch: 13 / 20 Iteration: 140  Validation Acc: 0.9101
Epoch: 14 / 20 Iteration: 141 Train loss: 0.01640
Epoch: 14 / 20 Iteration: 142 Train loss: 0.01418
Epoch: 14 / 20 Iteration: 143 Train loss: 0.01230
Epoch: 14 / 20 Iteration: 144 Train loss: 0.01022
Epoch: 14 / 20 Iteration: 145 Train loss: 0.01096
Epoch: 14 / 20 Iteration: 145  Validation Acc: 0.9128
Epoch: 14 / 20 Iteration: 146 Train loss: 0.01206
Epoch: 14 / 20 Iteration: 147 Train loss: 0.01530
Epoch: 14 / 20 Iteration: 148 Train loss: 0.01046
Epoch: 14 / 20 Iteration: 149 Train loss: 0.01206
Epoch: 14 / 20 Iteration: 150 Train loss: 0.01327
Epoch: 14 / 20 Iteration: 150  Validation Acc: 0.9101
Epoch: 15 / 20 Iteration: 151 Train loss: 0.01350
Epoch: 15 / 20 Iteration: 152 Train loss: 0.01205
Epoch: 15 / 20 Iteration: 153 Train loss: 0.01062
Epoch: 15 / 20 Iteration: 154 Train loss: 0.00867
Epoch: 15 / 20 Iteration: 155 Train loss: 0.00945
Epoch: 15 / 20 Iteration: 155  Validation Acc: 0.9101
Epoch: 15 / 20 Iteration: 156 Train loss: 0.01036
Epoch: 15 / 20 Iteration: 157 Train loss: 0.01297
Epoch: 15 / 20 Iteration: 158 Train loss: 0.00907
Epoch: 15 / 20 Iteration: 159 Train loss: 0.01052
Epoch: 15 / 20 Iteration: 160 Train loss: 0.01136
Epoch: 15 / 20 Iteration: 160  Validation Acc: 0.9128
Epoch: 16 / 20 Iteration: 161 Train loss: 0.01173
Epoch: 16 / 20 Iteration: 162 Train loss: 0.01051
Epoch: 16 / 20 Iteration: 163 Train loss: 0.00931
Epoch: 16 / 20 Iteration: 164 Train loss: 0.00768
Epoch: 16 / 20 Iteration: 165 Train loss: 0.00817
Epoch: 16 / 20 Iteration: 165  Validation Acc: 0.9128
Epoch: 16 / 20 Iteration: 166 Train loss: 0.00911
Epoch: 16 / 20 Iteration: 167 Train loss: 0.01111
Epoch: 16 / 20 Iteration: 168 Train loss: 0.00820
Epoch: 16 / 20 Iteration: 169 Train loss: 0.00932
Epoch: 16 / 20 Iteration: 170 Train loss: 0.00977
Epoch: 16 / 20 Iteration: 170  Validation Acc: 0.9101
Epoch: 17 / 20 Iteration: 171 Train loss: 0.00994
Epoch: 17 / 20 Iteration: 172 Train loss: 0.00913
Epoch: 17 / 20 Iteration: 173 Train loss: 0.00813
Epoch: 17 / 20 Iteration: 174 Train loss: 0.00689
Epoch: 17 / 20 Iteration: 175 Train loss: 0.00709
Epoch: 17 / 20 Iteration: 175  Validation Acc: 0.9101
Epoch: 17 / 20 Iteration: 176 Train loss: 0.00808
Epoch: 17 / 20 Iteration: 177 Train loss: 0.00968
Epoch: 17 / 20 Iteration: 178 Train loss: 0.00712
Epoch: 17 / 20 Iteration: 179 Train loss: 0.00822
Epoch: 17 / 20 Iteration: 180 Train loss: 0.00862
Epoch: 17 / 20 Iteration: 180  Validation Acc: 0.9101
Epoch: 18 / 20 Iteration: 181 Train loss: 0.00862
Epoch: 18 / 20 Iteration: 182 Train loss: 0.00782
Epoch: 18 / 20 Iteration: 183 Train loss: 0.00720
Epoch: 18 / 20 Iteration: 184 Train loss: 0.00612
Epoch: 18 / 20 Iteration: 185 Train loss: 0.00629
Epoch: 18 / 20 Iteration: 185  Validation Acc: 0.9128
Epoch: 18 / 20 Iteration: 186 Train loss: 0.00714
Epoch: 18 / 20 Iteration: 187 Train loss: 0.00852
Epoch: 18 / 20 Iteration: 188 Train loss: 0.00634
Epoch: 18 / 20 Iteration: 189 Train loss: 0.00740
Epoch: 18 / 20 Iteration: 190 Train loss: 0.00754
Epoch: 18 / 20 Iteration: 190  Validation Acc: 0.9101
Epoch: 19 / 20 Iteration: 191 Train loss: 0.00780
Epoch: 19 / 20 Iteration: 192 Train loss: 0.00692
Epoch: 19 / 20 Iteration: 193 Train loss: 0.00635
Epoch: 19 / 20 Iteration: 194 Train loss: 0.00556
Epoch: 19 / 20 Iteration: 195 Train loss: 0.00558
Epoch: 19 / 20 Iteration: 195  Validation Acc: 0.9155
Epoch: 19 / 20 Iteration: 196 Train loss: 0.00637
Epoch: 19 / 20 Iteration: 197 Train loss: 0.00751
Epoch: 19 / 20 Iteration: 198 Train loss: 0.00575
Epoch: 19 / 20 Iteration: 199 Train loss: 0.00666
Epoch: 19 / 20 Iteration: 200 Train loss: 0.00667
Epoch: 19 / 20 Iteration: 200  Validation Acc: 0.9155

Testing

Below you see the test accuracy. You can also see the predictions returned for images.


In [31]:
with tf.Session() as sess:
    saver.restore(sess, tf.train.latest_checkpoint('checkpoints'))
    
    feed = {inputs_: test_x,
            labels_: test_y}
    test_acc = sess.run(accuracy, feed_dict=feed)
    print("Test accuracy: {:.4f}".format(test_acc))


INFO:tensorflow:Restoring parameters from checkpoints\flowers.ckpt
Test accuracy: 0.8828

In [32]:
%matplotlib inline

import matplotlib.pyplot as plt
from scipy.ndimage import imread

Below, feel free to choose images and see how the trained classifier predicts the flowers in them.


In [33]:
# Run this cell if you don't have a vgg graph built
if 'my_vgg' in globals():
    print('"vgg" object already exists.  Will not create again.')
else:
    #create vgg
    with tf.Session() as sess:
        input_ = tf.placeholder(tf.float32, [None, 224, 224, 3])
        vgg = vgg16.Vgg16()
        vgg.build(input_)


"vgg" object already exists.  Will not create again.

In [37]:
test_img_path = 'flower_photos/daisy/5547758_eea9edfd54_n.jpg'
test_img = imread(test_img_path)
plt.imshow(test_img)


Out[37]:
<matplotlib.image.AxesImage at 0x21f3ef0d438>

In [41]:
with tf.Session() as sess:
    img = utils.load_image(test_img_path)
    img = img.reshape((1, 224, 224, 3))

    feed_dict = {input_: img}
    
    ## KEY
    code = sess.run(my_vgg.relu6, feed_dict=feed_dict)
        
saver = tf.train.Saver()
with tf.Session() as sess:
    saver.restore(sess, tf.train.latest_checkpoint('checkpoints'))
    
    feed = {inputs_: code}
    prediction = sess.run(predicted, feed_dict=feed).squeeze()


INFO:tensorflow:Restoring parameters from checkpoints\flowers.ckpt
0.199990797043

In [44]:
print(max(prediction))
plt.barh(np.arange(5), prediction)

_ = plt.yticks(np.arange(5), labelBinarizer.classes_)


0.999954

In [ ]: