In [1]:
import pandas as pd
import numpy as np
import tensorflow as tf

In [2]:
# read in some of the data
df = pd.read_csv('../data/facial keypoints training.csv', nrows=5000)

In [3]:
# check that the image is really 96*96
print(len(np.fromstring(df.Image.iloc[0], dtype=int, sep=' ')))
print('{}, {}'.format(96**2, df.columns.tolist()))


9216
9216, ['left_eye_center_x', 'left_eye_center_y', 'right_eye_center_x', 'right_eye_center_y', 'left_eye_inner_corner_x', 'left_eye_inner_corner_y', 'left_eye_outer_corner_x', 'left_eye_outer_corner_y', 'right_eye_inner_corner_x', 'right_eye_inner_corner_y', 'right_eye_outer_corner_x', 'right_eye_outer_corner_y', 'left_eyebrow_inner_end_x', 'left_eyebrow_inner_end_y', 'left_eyebrow_outer_end_x', 'left_eyebrow_outer_end_y', 'right_eyebrow_inner_end_x', 'right_eyebrow_inner_end_y', 'right_eyebrow_outer_end_x', 'right_eyebrow_outer_end_y', 'nose_tip_x', 'nose_tip_y', 'mouth_left_corner_x', 'mouth_left_corner_y', 'mouth_right_corner_x', 'mouth_right_corner_y', 'mouth_center_top_lip_x', 'mouth_center_top_lip_y', 'mouth_center_bottom_lip_x', 'mouth_center_bottom_lip_y', 'Image']

In [4]:
df = df[['left_eye_center_x', 'left_eye_center_y','Image']]
# for now only train on the left eye center
df = df[df['left_eye_center_x'].notnull() & df['left_eye_center_y'].notnull()]

In [5]:
# check how much data is left of the initial blob
print(df.shape)


(4990, 3)

In [6]:
# round the left eye x, y coordinates to integers (could multiply by powers of ten to get higher position resolution)
df[['left_eye_center_x', 'left_eye_center_y']] = df[['left_eye_center_x', 'left_eye_center_y']].round(0)
print(df[['left_eye_center_x', 'left_eye_center_y']].head())


   left_eye_center_x  left_eye_center_y
0               66.0               39.0
1               64.0               35.0
2               65.0               35.0
3               65.0               37.0
4               67.0               40.0

In [7]:
# encode. must give column names if numeric
left_eye_x = pd.get_dummies(df['left_eye_center_x'], columns=['left_eye_center_x'])
left_eye_y = pd.get_dummies(df['left_eye_center_y'], columns=['left_eye_center_y'])

In [8]:
# convert faces to dataframe
faces = df.Image.apply(lambda x: pd.Series(np.fromstring(x, dtype=np.float32, sep=' ')))

In [9]:
# see the results
print(faces.head())
print(faces.shape)


    0      1      2      3      4      5      6      7      8      9     \
0  238.0  236.0  237.0  238.0  240.0  240.0  239.0  241.0  241.0  243.0   
1  219.0  215.0  204.0  196.0  204.0  211.0  212.0  200.0  180.0  168.0   
2  144.0  142.0  159.0  180.0  188.0  188.0  184.0  180.0  167.0  132.0   
3  193.0  192.0  193.0  194.0  194.0  194.0  193.0  192.0  168.0  111.0   
4  147.0  148.0  160.0  196.0  215.0  214.0  216.0  217.0  219.0  220.0   

   ...    9206  9207  9208  9209  9210  9211  9212   9213   9214   9215  
0  ...    33.0  29.0  30.0  34.0  39.0  49.0  62.0   70.0   75.0   90.0  
1  ...     1.0   1.0   1.0   1.0   1.0   1.0   1.0    1.0    1.0    1.0  
2  ...    64.0  60.0  56.0  61.0  70.0  69.0  71.0   78.0   78.0   77.0  
3  ...     1.0   1.0   1.0   1.0   1.0   1.0   1.0    1.0    1.0    1.0  
4  ...    33.0  34.0  37.0  37.0  43.0  46.0  83.0  140.0  170.0  176.0  

[5 rows x 9216 columns]
(4990, 9216)

In [10]:
# free space
del df['Image']
faces = faces.as_matrix()
left_eye_x = left_eye_x.as_matrix()
print(faces.shape)
print(left_eye_x.shape)


(4990, 9216)
(4990, 48)

In [11]:
# tf doesn't appear to like cross-type operations. keep everything float32
print(type(faces[0,0]))


<class 'numpy.float32'>

In [13]:
num_labels = left_eye_x.shape[1]
image_size = 96

graph = tf.Graph()
with graph.as_default():
    
    # graph
    face = tf.placeholder(tf.float32, [None, image_size**2])
    label = tf.placeholder(tf.float32, [None, 48])
    
    weights = tf.Variable(tf.truncated_normal([image_size*image_size, num_labels]))
    biases = tf.Variable(tf.zeros([num_labels]))
    
    #print('{},{}'.format(type(train_dataset), type(weights)))
    
    # loss
    logits = tf.matmul(face, weights) + biases
    loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=label, logits=logits))
    
    # add to export graph collection
    tf.add_to_collection('logits', logits)
    
    # optimizer
    optimizer = tf.train.GradientDescentOptimizer(0.5).minimize(loss)
    
    # predictions
    train_prediction = tf.nn.softmax(logits)

In [17]:
num_steps = 1000

with tf.Session(graph=graph) as session:
    
    # initialise graph
    tf.global_variables_initializer().run()
    
    # saver
    saver = tf.train.Saver()
    
    # define what you mean by accuracy (to-do: add another measure)
    def accuracy(predictions, labels):
        return (100.0 * np.sum(np.argmax(predictions, 1) == np.argmax(labels, 1)) / predictions.shape[0])
    
    
    # optimise the coefficients of the graph using the loss function and optimiser
    for step in range(num_steps):
        _, l, predictions = session.run([optimizer, loss, train_prediction], feed_dict={face:faces, label:left_eye_x})
        
        if (step % 50 == 0):
            print('Loss at step {}: {}'.format(step, l))
            print('Training accuracy: %.1f%%' % accuracy(predictions, left_eye_x))
            try:
                saver.save(session,'../models/left-eye-test-model')
                saver.export_meta_graph('../models/left-eye-test-model' + '.meta')
                print('saved model to left-eye-test-model.meta')
            except Exception as e:
                print(repr(e))


Loss at step 0: 30303.38671875
Training accuracy: 0.1%
saved model to left-eye-test-model.meta
Loss at step 50: 21171542.0
Training accuracy: 8.3%
saved model to left-eye-test-model.meta
Loss at step 100: 28318582.0
Training accuracy: 1.9%
saved model to left-eye-test-model.meta
Loss at step 150: 24202570.0
Training accuracy: 19.5%
saved model to left-eye-test-model.meta
Loss at step 200: 28739388.0
Training accuracy: 13.6%
saved model to left-eye-test-model.meta
Loss at step 250: 19681742.0
Training accuracy: 21.2%
saved model to left-eye-test-model.meta
Loss at step 300: 19938856.0
Training accuracy: 19.5%
saved model to left-eye-test-model.meta
Loss at step 350: 29377148.0
Training accuracy: 8.5%
saved model to left-eye-test-model.meta
Loss at step 400: 20592718.0
Training accuracy: 10.3%
saved model to left-eye-test-model.meta
Loss at step 450: 25504884.0
Training accuracy: 18.2%
saved model to left-eye-test-model.meta
Loss at step 500: 21748848.0
Training accuracy: 20.1%
saved model to left-eye-test-model.meta
Loss at step 550: 19902308.0
Training accuracy: 20.3%
saved model to left-eye-test-model.meta
Loss at step 600: 21075372.0
Training accuracy: 19.6%
saved model to left-eye-test-model.meta
Loss at step 650: 30525182.0
Training accuracy: 14.8%
saved model to left-eye-test-model.meta
Loss at step 700: 18866710.0
Training accuracy: 17.7%
saved model to left-eye-test-model.meta
Loss at step 750: 16688698.0
Training accuracy: 16.7%
saved model to left-eye-test-model.meta
Loss at step 800: 17648538.0
Training accuracy: 18.2%
saved model to left-eye-test-model.meta
Loss at step 850: 23152060.0
Training accuracy: 18.0%
saved model to left-eye-test-model.meta
Loss at step 900: 13744905.0
Training accuracy: 20.2%
saved model to left-eye-test-model.meta
Loss at step 950: 15377029.0
Training accuracy: 21.0%
saved model to left-eye-test-model.meta

In [ ]: