Autoencoder for MNIST Dataset

This scripts trains an autoencoder on the MNIST dataset and plots some representation. It also tries to estimate how good the representation is using a a k-Means clustering an then computing the accurarcy of the clusters.

Reading the dataset

This reads the MNIST hand written digit dataset and creates a subset of the training data with only 10 training examples per class.


In [1]:
import gzip
import cPickle
import numpy as np
import theano
import theano.tensor as T
import random

examples_per_labels = 10


# Load the pickle file for the MNIST dataset.
dataset = 'mnist.pkl.gz'

f = gzip.open(dataset, 'rb')
train_set, dev_set, test_set = cPickle.load(f)
f.close()

#train_set contains 2 entries, first the X values, second the Y values
train_x, train_y = train_set
dev_x, dev_y = dev_set
test_x, test_y = test_set

print 'Train: ', train_x.shape
print 'Dev: ', dev_x.shape
print 'Test: ', test_x.shape

examples = []
examples_labels = []
examples_count = {}

for idx in xrange(train_x.shape[0]):
    label = train_y[idx]
    
    if label not in examples_count:
        examples_count[label] = 0
    
    if examples_count[label] < examples_per_labels:
        arr = train_x[idx]
        examples.append(arr)
        examples_labels.append(label)
        examples_count[label]+=1

train_subset_x = np.asarray(examples)
train_subset_y = np.asarray(examples_labels)

print "Train Subset: ",train_subset_x.shape


Couldn't import dot_parser, loading of dot files will not be possible.
Train:  (50000, 784)
Dev:  (10000, 784)
Test:  (10000, 784)
Train Subset:  (100, 784)

Baseline

We use a feed forward network to train on the subset and to derive a accurarcy.


In [2]:
from keras.layers import containers
import keras
from keras.models import Sequential
from keras.layers.core import Dense, Flatten, AutoEncoder, Dropout
from keras.optimizers import SGD
from keras.utils import np_utils
from keras.callbacks import EarlyStopping

random.seed(1)
np.random.seed(1)

nb_epoch = 50
batch_size = 100
nb_labels = 10

train_subset_y_cat = np_utils.to_categorical(train_subset_y, nb_labels)
dev_y_cat = np_utils.to_categorical(dev_y, nb_labels)
test_y_cat = np_utils.to_categorical(test_y, nb_labels)

model = Sequential()
model.add(Dense(1000, input_dim=train_x.shape[1], activation='tanh'))
model.add(Dropout(0.5))
model.add(Dense(nb_labels, activation='softmax'))




model.compile(loss='categorical_crossentropy', optimizer='Adam')
earlyStopping = keras.callbacks.EarlyStopping(monitor='val_loss', patience=1, verbose=0)

print('Start training')
model.fit(train_subset_x, train_subset_y_cat, batch_size=batch_size, nb_epoch=nb_epoch,
          show_accuracy=True, verbose=True, validation_data=(dev_x, dev_y_cat), callbacks=[earlyStopping])

score = model.evaluate(test_x, test_y_cat, show_accuracy=True, verbose=False)
print('Test accuracy:', score[1])


Start training
Train on 100 samples, validate on 10000 samples
Epoch 1/50
100/100 [==============================] - 0s - loss: 2.3655 - acc: 0.0800 - val_loss: 2.1055 - val_acc: 0.3374
Epoch 2/50
100/100 [==============================] - 1s - loss: 2.0019 - acc: 0.4000 - val_loss: 1.9175 - val_acc: 0.4715
Epoch 3/50
100/100 [==============================] - 0s - loss: 1.7259 - acc: 0.6000 - val_loss: 1.7535 - val_acc: 0.5706
Epoch 4/50
100/100 [==============================] - 0s - loss: 1.4839 - acc: 0.7300 - val_loss: 1.6082 - val_acc: 0.6290
Epoch 5/50
100/100 [==============================] - 0s - loss: 1.2680 - acc: 0.8200 - val_loss: 1.4812 - val_acc: 0.6623
Epoch 6/50
100/100 [==============================] - 1s - loss: 1.1159 - acc: 0.8500 - val_loss: 1.3721 - val_acc: 0.6785
Epoch 7/50
100/100 [==============================] - 0s - loss: 0.9225 - acc: 0.9000 - val_loss: 1.2825 - val_acc: 0.6884
Epoch 8/50
100/100 [==============================] - 1s - loss: 0.7788 - acc: 0.9000 - val_loss: 1.2102 - val_acc: 0.6928
Epoch 9/50
100/100 [==============================] - 1s - loss: 0.6939 - acc: 0.9200 - val_loss: 1.1540 - val_acc: 0.6947
Epoch 10/50
100/100 [==============================] - 1s - loss: 0.6075 - acc: 0.9200 - val_loss: 1.1103 - val_acc: 0.6937
Epoch 11/50
100/100 [==============================] - 1s - loss: 0.5290 - acc: 0.9400 - val_loss: 1.0753 - val_acc: 0.6941
Epoch 12/50
100/100 [==============================] - 0s - loss: 0.4568 - acc: 0.9600 - val_loss: 1.0474 - val_acc: 0.6948
Epoch 13/50
100/100 [==============================] - 0s - loss: 0.4096 - acc: 0.9600 - val_loss: 1.0243 - val_acc: 0.6957
Epoch 14/50
100/100 [==============================] - 1s - loss: 0.3542 - acc: 0.9600 - val_loss: 1.0056 - val_acc: 0.6969
Epoch 15/50
100/100 [==============================] - 1s - loss: 0.3346 - acc: 0.9600 - val_loss: 0.9904 - val_acc: 0.6985
Epoch 16/50
100/100 [==============================] - 0s - loss: 0.2943 - acc: 0.9800 - val_loss: 0.9781 - val_acc: 0.6998
Epoch 17/50
100/100 [==============================] - 1s - loss: 0.2606 - acc: 0.9800 - val_loss: 0.9684 - val_acc: 0.7020
Epoch 18/50
100/100 [==============================] - 0s - loss: 0.2316 - acc: 0.9800 - val_loss: 0.9605 - val_acc: 0.7036
Epoch 19/50
100/100 [==============================] - 1s - loss: 0.2078 - acc: 0.9900 - val_loss: 0.9550 - val_acc: 0.7059
Epoch 20/50
100/100 [==============================] - 1s - loss: 0.1812 - acc: 0.9800 - val_loss: 0.9515 - val_acc: 0.7080
Epoch 21/50
100/100 [==============================] - 0s - loss: 0.1721 - acc: 0.9900 - val_loss: 0.9492 - val_acc: 0.7087
Epoch 22/50
100/100 [==============================] - 0s - loss: 0.1361 - acc: 0.9900 - val_loss: 0.9481 - val_acc: 0.7106
Epoch 23/50
100/100 [==============================] - 0s - loss: 0.1304 - acc: 0.9900 - val_loss: 0.9478 - val_acc: 0.7116
Epoch 24/50
100/100 [==============================] - 0s - loss: 0.1137 - acc: 1.0000 - val_loss: 0.9482 - val_acc: 0.7116
Epoch 25/50
100/100 [==============================] - 0s - loss: 0.1134 - acc: 1.0000 - val_loss: 0.9490 - val_acc: 0.7120
('Test accuracy:', 0.69140000000000001)

Autoencoder - Pretraining

This is the code how the autoencoder should work in principle. However, the pretraining does not workly too good, as is has no real impact when then trained on the labeld data. But it gives some useful representations for the data.


In [2]:
# Train the autoencoder
# Source: https://github.com/fchollet/keras/issues/358
from keras.layers import containers
import keras
from keras.models import Sequential
from keras.layers.core import Dense, Flatten, AutoEncoder, Dropout
from keras.optimizers import SGD
from keras.utils import np_utils

random.seed(3)
np.random.seed(3)



nb_epoch_pretraining = 10
batch_size_pretraining = 500


# Layer-wise pretraining
encoders = []
decoders = []
nb_hidden_layers = [train_x.shape[1], 500, 2]
X_train_tmp = np.copy(train_x)

dense_layers = []

for i, (n_in, n_out) in enumerate(zip(nb_hidden_layers[:-1], nb_hidden_layers[1:]), start=1):
    print('Training the layer {}: Input {} -> Output {}'.format(i, n_in, n_out))
    # Create AE and training
    ae = Sequential()
    if n_out >= 100:
        encoder = containers.Sequential([Dense(output_dim=n_out, input_dim=n_in, activation='tanh'), Dropout(0.5)])
    else:
        encoder = containers.Sequential([Dense(output_dim=n_out, input_dim=n_in, activation='tanh')])
    decoder = containers.Sequential([Dense(output_dim=n_in, input_dim=n_out, activation='tanh')])
    ae.add(AutoEncoder(encoder=encoder, decoder=decoder, output_reconstruction=False))
    
    sgd = SGD(lr=2, decay=1e-6, momentum=0.0, nesterov=True)
    ae.compile(loss='mse', optimizer='adam')
    ae.fit(X_train_tmp, X_train_tmp, batch_size=batch_size_pretraining, nb_epoch=nb_epoch_pretraining, verbose = True, shuffle=True)
    # Store trainined weight and update training data
    encoders.append(ae.layers[0].encoder)
    decoders.append(ae.layers[0].decoder)
    
    X_train_tmp = ae.predict(X_train_tmp)
    

    


##############
    
    
    
    

#End to End Autoencoder training    
if len(nb_hidden_layers) > 2:
    full_encoder = containers.Sequential()
    for encoder in encoders:
        full_encoder.add(encoder)

    full_decoder = containers.Sequential()
    for decoder in reversed(decoders):
        full_decoder.add(decoder)

    full_ae = Sequential()
    full_ae.add(AutoEncoder(encoder=full_encoder, decoder=full_decoder, output_reconstruction=False))    
    full_ae.compile(loss='mse', optimizer='adam')

    print "Pretraining of full AE"
    full_ae.fit(train_x, train_x, batch_size=batch_size_pretraining, nb_epoch=nb_epoch_pretraining, verbose = True, shuffle=True)


Training the layer 1: Input 784 -> Output 500
Epoch 1/10
50000/50000 [==============================] - 10s - loss: 0.0450    
Epoch 2/10
50000/50000 [==============================] - 11s - loss: 0.0212    
Epoch 3/10
50000/50000 [==============================] - 10s - loss: 0.0179    
Epoch 4/10
50000/50000 [==============================] - 9s - loss: 0.0168     
Epoch 5/10
50000/50000 [==============================] - 10s - loss: 0.0163    
Epoch 6/10
50000/50000 [==============================] - 9s - loss: 0.0160     
Epoch 7/10
50000/50000 [==============================] - 9s - loss: 0.0158     
Epoch 8/10
50000/50000 [==============================] - 9s - loss: 0.0157     
Epoch 9/10
50000/50000 [==============================] - 9s - loss: 0.0156     
Epoch 10/10
50000/50000 [==============================] - 9s - loss: 0.0154     
Training the layer 2: Input 500 -> Output 2
Epoch 1/10
50000/50000 [==============================] - 1s - loss: 0.0187     
Epoch 2/10
50000/50000 [==============================] - 1s - loss: 0.0176     
Epoch 3/10
50000/50000 [==============================] - 1s - loss: 0.0174     
Epoch 4/10
50000/50000 [==============================] - 1s - loss: 0.0173     
Epoch 5/10
50000/50000 [==============================] - 1s - loss: 0.0173     
Epoch 6/10
50000/50000 [==============================] - 1s - loss: 0.0173     
Epoch 7/10
50000/50000 [==============================] - 1s - loss: 0.0173     
Epoch 8/10
50000/50000 [==============================] - 1s - loss: 0.0172     
Epoch 9/10
50000/50000 [==============================] - 1s - loss: 0.0172     
Epoch 10/10
50000/50000 [==============================] - 1s - loss: 0.0172     
Pretraining of full AE
Epoch 1/10
50000/50000 [==============================] - 10s - loss: 0.0569    
Epoch 2/10
50000/50000 [==============================] - 11s - loss: 0.0562    
Epoch 3/10
50000/50000 [==============================] - 11s - loss: 0.0561    
Epoch 4/10
50000/50000 [==============================] - 11s - loss: 0.0560    
Epoch 5/10
50000/50000 [==============================] - 11s - loss: 0.0560    
Epoch 6/10
50000/50000 [==============================] - 11s - loss: 0.0560    
Epoch 7/10
50000/50000 [==============================] - 11s - loss: 0.0560    
Epoch 8/10
50000/50000 [==============================] - 12s - loss: 0.0560    
Epoch 9/10
50000/50000 [==============================] - 11s - loss: 0.0560    
Epoch 10/10
50000/50000 [==============================] - 11s - loss: 0.0560    

Plot Autoencoder

Here we are going to plot the output of the autoencoder (dimension of the last hidden layer should be 2).


In [4]:
############
# Plot it
############
%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches

model = Sequential()
for encoder in encoders:
    model.add(encoder)
model.compile(loss='categorical_crossentropy', optimizer='Adam')

ae_test = model.predict(test_x)

colors = {0: 'b', 1: 'g', 2: 'r', 3:'c', 4:'m',
          5:'y', 6:'k', 7:'orange', 8:'darkgreen', 9:'maroon'}

markers = {0: 'o', 1: '+', 2: 'v', 3:'<', 4:'>',
          5:'^', 6:'s', 7:'p', 8:'*', 9:'x'}

plt.figure(figsize=(10, 10)) 
patches = []
for idx in xrange(0,300):    
    point = ae_test[idx]
    label = test_y[idx]
    
    if label in [2,5,8,9]: #We skip these labels to make the plot clearer
        continue
    
    color = colors[label]
    marker = markers[label]
    line = plt.plot(point[0], point[1], color=color, marker=marker, markersize=8)
        
#plt.axis([-1.1, 1.1, -1.1, +1.1])


PCA

In comparison we are going to plot also an PCA image.


In [7]:
from sklearn.decomposition import PCA
pca = PCA(n_components=2)
pca.fit(train_x)

pca_test = pca.transform(test_x)

colors = {0: 'b', 1: 'g', 2: 'r', 3:'c', 4:'m',
          5:'y', 6:'k', 7:'orange', 8:'darkgreen', 9:'maroon'}

markers = {0: 'o', 1: '+', 2: 'v', 3:'<', 4:'>',
          5:'^', 6:'s', 7:'p', 8:'*', 9:'x'}

plt.figure(figsize=(10, 10)) 
patches = []
for idx in xrange(0,300):    
    point = pca_test[idx]
    label = test_y[idx]
    if label in [2,5,8,9]:
        continue
    color = colors[label]
    marker = markers[label]
    line = plt.plot(point[0], point[1], color=color, marker=marker, markersize=8)
        
#plt.axis([-1.1, 1.1, -1.1, +1.1])
plt.show()


k-Means clustering

We run a k-means clustering on the AutoEncoder representations and the PCA representations and then do a majority voting to get the label per cluster. We then compute the accurarcy of the clustering. This gives us some impression how good the 2-dim representations are. This is not perfect, as AutoEncoder and PCA might create non-linear cluster boundaries.


In [8]:
from sklearn.cluster import KMeans
import operator

def clusterAccurarcy(predictions, n_clusters=10):
    km = KMeans(n_clusters=n_clusters)

    clusters = km.fit_predict(predictions)

    #Count labels per cluster
    labelCount = {}

    for idx in xrange(len(test_y)):
        cluster = clusters[idx]
        label = test_y[idx]

        if cluster not in labelCount:
            labelCount[cluster] = {}

        if label not in labelCount[cluster]:
            labelCount[cluster][label] = 0

        labelCount[cluster][label] += 1

    #Majority Voting
    clusterLabels = {}
    for num in xrange(n_clusters):    
        maxLabel = max(labelCount[num].iteritems(), key=operator.itemgetter(1))[0]
        clusterLabels[num] = maxLabel
    #print clusterLabels
    #Number of errors
    errCount = 0
    for idx in xrange(len(test_y)):
        cluster = clusters[idx] 
        clusterLabel = clusterLabels[cluster]
        label = test_y[idx]

        if label != clusterLabel:
            errCount += 1
    
    return errCount/float(len(test_y))
        
print "PCA Accurarcy: %f%%" % (clusterAccurarcy(pca_test)*100)
print "AE Accurarcy: %f%%" % (clusterAccurarcy(ae_test)*100)


PCA Accurarcy: 57.900000%
AE Accurarcy: 61.130000%

Using pretrained AutoEncoder for Classification

In principle the pretrained AutoEncoder could be used for classification as in the following code. But it does not yet result to better results than the Neural Network without pretraining.


In [9]:
nb_epoch = 50
batch_size = 100

model = Sequential()
for encoder in encoders:
    model.add(encoder)
    

model.add(Dense(output_dim=nb_labels, activation='softmax'))

train_subset_y_cat = np_utils.to_categorical(train_subset_y, nb_labels)
test_y_cat = np_utils.to_categorical(test_y, nb_labels)




model.compile(loss='categorical_crossentropy', optimizer='Adam')
score = model.evaluate(test_x, test_y_cat, show_accuracy=True, verbose=0)
print('Test score before fine turning:', score[0])
print('Test accuracy before fine turning:', score[1])
model.fit(train_subset_x, train_subset_y_cat, batch_size=batch_size, nb_epoch=nb_epoch,
          show_accuracy=True, validation_data=(dev_x, dev_y_cat), shuffle=True)
score = model.evaluate(test_x, test_y_cat, show_accuracy=True, verbose=0)
print('Test score after fine turning:', score[0])
print('Test accuracy after fine turning:', score[1])


('Test score before fine turning:', 4.8862177627563472)
('Test accuracy before fine turning:', 0.067799999999999999)
Train on 100 samples, validate on 10000 samples
Epoch 1/50
100/100 [==============================] - 0s - loss: 5.1481 - acc: 0.0500 - val_loss: 4.7258 - val_acc: 0.0712
Epoch 2/50
100/100 [==============================] - 0s - loss: 4.6525 - acc: 0.0500 - val_loss: 4.4477 - val_acc: 0.0731
Epoch 3/50
100/100 [==============================] - 0s - loss: 4.3487 - acc: 0.0500 - val_loss: 4.1904 - val_acc: 0.0743
Epoch 4/50
100/100 [==============================] - 0s - loss: 4.0998 - acc: 0.0500 - val_loss: 3.9535 - val_acc: 0.0767
Epoch 5/50
100/100 [==============================] - 0s - loss: 3.7961 - acc: 0.0600 - val_loss: 3.7355 - val_acc: 0.0786
Epoch 6/50
100/100 [==============================] - 0s - loss: 3.4519 - acc: 0.0500 - val_loss: 3.5363 - val_acc: 0.0812
Epoch 7/50
100/100 [==============================] - 0s - loss: 3.1851 - acc: 0.0500 - val_loss: 3.3565 - val_acc: 0.0835
Epoch 8/50
100/100 [==============================] - 0s - loss: 2.9941 - acc: 0.0500 - val_loss: 3.1962 - val_acc: 0.0855
Epoch 9/50
100/100 [==============================] - 0s - loss: 2.8861 - acc: 0.0500 - val_loss: 3.0535 - val_acc: 0.0874
Epoch 10/50
100/100 [==============================] - 0s - loss: 2.7091 - acc: 0.0800 - val_loss: 2.9279 - val_acc: 0.0887
Epoch 11/50
100/100 [==============================] - 0s - loss: 2.6117 - acc: 0.0800 - val_loss: 2.8184 - val_acc: 0.0907
Epoch 12/50
100/100 [==============================] - 0s - loss: 2.5456 - acc: 0.0900 - val_loss: 2.7234 - val_acc: 0.0939
Epoch 13/50
100/100 [==============================] - 0s - loss: 2.4163 - acc: 0.0900 - val_loss: 2.6419 - val_acc: 0.0977
Epoch 14/50
100/100 [==============================] - 0s - loss: 2.3665 - acc: 0.0600 - val_loss: 2.5727 - val_acc: 0.1014
Epoch 15/50
100/100 [==============================] - 0s - loss: 2.3453 - acc: 0.0900 - val_loss: 2.5145 - val_acc: 0.1052
Epoch 16/50
100/100 [==============================] - 0s - loss: 2.2934 - acc: 0.1100 - val_loss: 2.4658 - val_acc: 0.1092
Epoch 17/50
100/100 [==============================] - 0s - loss: 2.2766 - acc: 0.1100 - val_loss: 2.4252 - val_acc: 0.1124
Epoch 18/50
100/100 [==============================] - 0s - loss: 2.2576 - acc: 0.1200 - val_loss: 2.3909 - val_acc: 0.1165
Epoch 19/50
100/100 [==============================] - 0s - loss: 2.2273 - acc: 0.1300 - val_loss: 2.3620 - val_acc: 0.1574
Epoch 20/50
100/100 [==============================] - 0s - loss: 2.2184 - acc: 0.1700 - val_loss: 2.3374 - val_acc: 0.1638
Epoch 21/50
100/100 [==============================] - 0s - loss: 2.2222 - acc: 0.1900 - val_loss: 2.3159 - val_acc: 0.1667
Epoch 22/50
100/100 [==============================] - 0s - loss: 2.1982 - acc: 0.1500 - val_loss: 2.2970 - val_acc: 0.1700
Epoch 23/50
100/100 [==============================] - 0s - loss: 2.2035 - acc: 0.1600 - val_loss: 2.2802 - val_acc: 0.1732
Epoch 24/50
100/100 [==============================] - 0s - loss: 2.1855 - acc: 0.1700 - val_loss: 2.2651 - val_acc: 0.1749
Epoch 25/50
100/100 [==============================] - 0s - loss: 2.1896 - acc: 0.1900 - val_loss: 2.2514 - val_acc: 0.1781
Epoch 26/50
100/100 [==============================] - 0s - loss: 2.1768 - acc: 0.1800 - val_loss: 2.2389 - val_acc: 0.1790
Epoch 27/50
100/100 [==============================] - 0s - loss: 2.1643 - acc: 0.2000 - val_loss: 2.2277 - val_acc: 0.1795
Epoch 28/50
100/100 [==============================] - 0s - loss: 2.1540 - acc: 0.1800 - val_loss: 2.2176 - val_acc: 0.1809
Epoch 29/50
100/100 [==============================] - 0s - loss: 2.1498 - acc: 0.1700 - val_loss: 2.2085 - val_acc: 0.1816
Epoch 30/50
100/100 [==============================] - 0s - loss: 2.1425 - acc: 0.1500 - val_loss: 2.2005 - val_acc: 0.1820
Epoch 31/50
100/100 [==============================] - 0s - loss: 2.1319 - acc: 0.1800 - val_loss: 2.1935 - val_acc: 0.1827
Epoch 32/50
100/100 [==============================] - 0s - loss: 2.1189 - acc: 0.1800 - val_loss: 2.1874 - val_acc: 0.1839
Epoch 33/50
100/100 [==============================] - 0s - loss: 2.1191 - acc: 0.1900 - val_loss: 2.1823 - val_acc: 0.1850
Epoch 34/50
100/100 [==============================] - 0s - loss: 2.1118 - acc: 0.1800 - val_loss: 2.1777 - val_acc: 0.1845
Epoch 35/50
100/100 [==============================] - 0s - loss: 2.1122 - acc: 0.1900 - val_loss: 2.1735 - val_acc: 0.1861
Epoch 36/50
100/100 [==============================] - 0s - loss: 2.1053 - acc: 0.1800 - val_loss: 2.1698 - val_acc: 0.1860
Epoch 37/50
100/100 [==============================] - 0s - loss: 2.0987 - acc: 0.1400 - val_loss: 2.1661 - val_acc: 0.1864
Epoch 38/50
100/100 [==============================] - 0s - loss: 2.1001 - acc: 0.1600 - val_loss: 2.1625 - val_acc: 0.1857
Epoch 39/50
100/100 [==============================] - 0s - loss: 2.0948 - acc: 0.1500 - val_loss: 2.1587 - val_acc: 0.1852
Epoch 40/50
100/100 [==============================] - 0s - loss: 2.0880 - acc: 0.1700 - val_loss: 2.1548 - val_acc: 0.1848
Epoch 41/50
100/100 [==============================] - 0s - loss: 2.0864 - acc: 0.1600 - val_loss: 2.1511 - val_acc: 0.1842
Epoch 42/50
100/100 [==============================] - 0s - loss: 2.0751 - acc: 0.1600 - val_loss: 2.1475 - val_acc: 0.1839
Epoch 43/50
100/100 [==============================] - 0s - loss: 2.0735 - acc: 0.1500 - val_loss: 2.1439 - val_acc: 0.1838
Epoch 44/50
100/100 [==============================] - 0s - loss: 2.0711 - acc: 0.1600 - val_loss: 2.1404 - val_acc: 0.1842
Epoch 45/50
100/100 [==============================] - 0s - loss: 2.0570 - acc: 0.1700 - val_loss: 2.1372 - val_acc: 0.1843
Epoch 46/50
100/100 [==============================] - 0s - loss: 2.0555 - acc: 0.1500 - val_loss: 2.1339 - val_acc: 0.1842
Epoch 47/50
100/100 [==============================] - 0s - loss: 2.0578 - acc: 0.1700 - val_loss: 2.1306 - val_acc: 0.1841
Epoch 48/50
100/100 [==============================] - 0s - loss: 2.0542 - acc: 0.1500 - val_loss: 2.1278 - val_acc: 0.1837
Epoch 49/50
100/100 [==============================] - 0s - loss: 2.0605 - acc: 0.1700 - val_loss: 2.1251 - val_acc: 0.1830
Epoch 50/50
100/100 [==============================] - 0s - loss: 2.0521 - acc: 0.1500 - val_loss: 2.1226 - val_acc: 0.1830
('Test score after fine turning:', 2.1195155143737794)
('Test accuracy after fine turning:', 0.1799)

In [ ]: