In [1]:
%matplotlib inline  
import struct
from struct import unpack
from numpy import zeros, uint8, float32
from pylab import imshow, show, cm
import matplotlib
import numpy as np
import matplotlib.pyplot as plt
import subprocess


#Initialize for keras
import keras
from keras.datasets import mnist
from keras.models import Sequential, Input,Model
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D, AveragePooling2D
from keras import backend as K


Using TensorFlow backend.

In [2]:
# Define functions for reading data.
# Based on https://gist.github.com/tylerneylon/
def read_idx(filename):
    """
        Read from file and create numpy array
    """
    with open(filename, 'rb') as f:
        zero, data_type, dims = struct.unpack('>HBB', f.read(4))
        shape = tuple(struct.unpack('>I', f.read(4))[0] for d in range(dims))
        return np.fromstring(f.read(), dtype=np.uint8).reshape(shape)

def get_data(image_file, label_file, num_classes = 10, starts_at=0 ):
    """
        Read the image and label data
    """
    # Read the files
    pre_images = read_idx(image_file)
    pre_labels = read_idx(label_file)
    
    images = np.zeros((len(pre_images), 28,28, 1), dtype=np.float32)
    labels = np.zeros((len(pre_labels),num_classes), dtype=np.int8)
    for i in range(len(pre_images)):
        pre_img=pre_images[i]
        pre_label=pre_labels[i]-starts_at
        img = (pre_img.transpose() / 255.0)
        images[i] = img.reshape(28,28,1) 
        labels[i] = keras.utils.to_categorical(pre_label, num_classes)
    
    return images, labels

def file_len(fname):
    p = subprocess.Popen(['wc', '-l', fname], stdout=subprocess.PIPE, 
                                              stderr=subprocess.PIPE)
    result, err = p.communicate()
    if p.returncode != 0:
        raise IOError(err)
    return int(result.strip().split()[0])

In [3]:
train_mapping_file = '/home/carnd/data/emnist/emnist-bymerge-mapping.txt'
num_classes = file_len(train_mapping_file)
train_image_file = '/home/carnd/data/emnist/emnist-bymerge-train-images-idx3-ubyte'
train_label_file = '/home/carnd/data/emnist/emnist-bymerge-train-labels-idx1-ubyte'
train_images, train_labels = get_data(train_image_file, train_label_file,num_classes)
print ('Training Data')
print ('Images Shape: {}'.format(train_images.shape))
print ('Labels Shape: {}'.format(train_labels.shape))

test_image_file = '/home/carnd/data/emnist/emnist-bymerge-test-images-idx3-ubyte'
test_label_file = '/home/carnd/data/emnist/emnist-bymerge-test-labels-idx1-ubyte'
test_images, test_labels = get_data(test_image_file, test_label_file,num_classes)
print ('Training Data')
print ('Images Shape: {}'.format(test_images.shape))
print ('Labels Shape: {}'.format(test_labels.shape))


Training Data
Images Shape: (697932, 28, 28, 1)
Labels Shape: (697932, 47)
Training Data
Images Shape: (116323, 28, 28, 1)
Labels Shape: (116323, 47)

In [4]:
def view_image(image, label=""):
    """View a single image."""
    print("Label - {} : {} ".format(np.argmax(label), label))
    plt.imshow((image.reshape(28,28)), cmap="gray")
    plt.show()

for i in range(2):
    view_image(train_images[i], train_labels[i])


Label - 24 : [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0] 
Label - 36 : [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
 0 0 0 0 0 0 0 0 0 0] 

In [5]:
# Train, Test split
from sklearn.model_selection import train_test_split
X_val, X_test, y_val, y_test = train_test_split(test_images, test_labels, test_size=0.5, random_state=42)

In [6]:
# Initialize the hyperparameters
input_shape = (28,28, 1)

In [14]:
# Build model
inputs = Input(shape=input_shape)
conv = Conv2D(32, (7, 7), strides=(1, 1), padding='same', name = "conv1", activation='relu')(inputs)
conv = Dropout(0.4)(conv)
conv = MaxPooling2D((2, 2))(conv)
conv = Conv2D(64, (7, 7), strides=(1, 1), padding='same', name = "conv3", activation='relu')(conv)
conv = Dropout(0.4)(conv)
conv = MaxPooling2D((2, 2))(conv)
conv = Conv2D(128, (7, 7), strides=(1, 1), padding='same', name = "conv4", activation='relu')(conv)
flat = Flatten()(conv)
dense = Dense(128, activation='relu', name = "dense2")(flat)
dropout = Dropout(0.4)(dense)
outputs = Dense(num_classes, activation='softmax', name = "output")(dropout)

model = Model(inputs=inputs, outputs=outputs)

model.summary()
model.compile(loss=keras.losses.categorical_crossentropy,
              optimizer=keras.optimizers.Nadam(),
              metrics=['accuracy'])


_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_4 (InputLayer)         (None, 28, 28, 1)         0         
_________________________________________________________________
conv1 (Conv2D)               (None, 28, 28, 32)        1600      
_________________________________________________________________
dropout_11 (Dropout)         (None, 28, 28, 32)        0         
_________________________________________________________________
max_pooling2d_8 (MaxPooling2 (None, 14, 14, 32)        0         
_________________________________________________________________
conv3 (Conv2D)               (None, 14, 14, 64)        100416    
_________________________________________________________________
dropout_12 (Dropout)         (None, 14, 14, 64)        0         
_________________________________________________________________
max_pooling2d_9 (MaxPooling2 (None, 7, 7, 64)          0         
_________________________________________________________________
conv4 (Conv2D)               (None, 7, 7, 128)         401536    
_________________________________________________________________
flatten_4 (Flatten)          (None, 6272)              0         
_________________________________________________________________
dense2 (Dense)               (None, 128)               802944    
_________________________________________________________________
dropout_13 (Dropout)         (None, 128)               0         
_________________________________________________________________
output (Dense)               (None, 47)                6063      
=================================================================
Total params: 1,312,559
Trainable params: 1,312,559
Non-trainable params: 0
_________________________________________________________________

In [15]:
batch_size = 1000
epochs = 50
history = model.fit(train_images, train_labels,
          batch_size=batch_size,
          epochs=epochs,
          verbose=2,
          validation_data=(X_val, y_val))


Train on 697932 samples, validate on 58161 samples
Epoch 1/50
199s - loss: 0.5827 - acc: 0.8214 - val_loss: 0.3965 - val_acc: 0.8950
Epoch 2/50
197s - loss: 0.3130 - acc: 0.8896 - val_loss: 0.3507 - val_acc: 0.9006
Epoch 3/50
198s - loss: 0.2920 - acc: 0.8954 - val_loss: 0.3095 - val_acc: 0.8998
Epoch 4/50
197s - loss: 0.2800 - acc: 0.8979 - val_loss: 0.3061 - val_acc: 0.9018
Epoch 5/50
197s - loss: 0.2725 - acc: 0.9005 - val_loss: 0.3003 - val_acc: 0.9021
Epoch 6/50
197s - loss: 0.2668 - acc: 0.9017 - val_loss: 0.2803 - val_acc: 0.9044
Epoch 7/50
197s - loss: 0.2619 - acc: 0.9031 - val_loss: 0.2712 - val_acc: 0.9031
Epoch 8/50
197s - loss: 0.2580 - acc: 0.9040 - val_loss: 0.2689 - val_acc: 0.9044
Epoch 9/50
197s - loss: 0.2547 - acc: 0.9052 - val_loss: 0.2610 - val_acc: 0.9056
Epoch 10/50
197s - loss: 0.2519 - acc: 0.9054 - val_loss: 0.2653 - val_acc: 0.9064
Epoch 11/50
197s - loss: 0.2498 - acc: 0.9060 - val_loss: 0.2590 - val_acc: 0.9055
Epoch 12/50
197s - loss: 0.2480 - acc: 0.9066 - val_loss: 0.2608 - val_acc: 0.9041
Epoch 13/50
197s - loss: 0.2454 - acc: 0.9071 - val_loss: 0.2593 - val_acc: 0.9044
Epoch 14/50
197s - loss: 0.2445 - acc: 0.9073 - val_loss: 0.2646 - val_acc: 0.9027
Epoch 15/50
197s - loss: 0.2427 - acc: 0.9079 - val_loss: 0.2584 - val_acc: 0.9043
Epoch 16/50
197s - loss: 0.2400 - acc: 0.9085 - val_loss: 0.2589 - val_acc: 0.9046
Epoch 17/50
198s - loss: 0.2392 - acc: 0.9087 - val_loss: 0.2552 - val_acc: 0.9046
Epoch 18/50
197s - loss: 0.2382 - acc: 0.9091 - val_loss: 0.2580 - val_acc: 0.9046
Epoch 19/50
197s - loss: 0.2379 - acc: 0.9091 - val_loss: 0.2532 - val_acc: 0.9063
Epoch 20/50
197s - loss: 0.2368 - acc: 0.9096 - val_loss: 0.2573 - val_acc: 0.9052
Epoch 21/50
197s - loss: 0.2360 - acc: 0.9096 - val_loss: 0.2529 - val_acc: 0.9067
Epoch 22/50
197s - loss: 0.2359 - acc: 0.9094 - val_loss: 0.2587 - val_acc: 0.9022
Epoch 23/50
197s - loss: 0.2348 - acc: 0.9099 - val_loss: 0.2559 - val_acc: 0.9051
Epoch 24/50
197s - loss: 0.2333 - acc: 0.9099 - val_loss: 0.2547 - val_acc: 0.9053
Epoch 25/50
197s - loss: 0.2328 - acc: 0.9104 - val_loss: 0.2554 - val_acc: 0.9052
Epoch 26/50
197s - loss: 0.2324 - acc: 0.9105 - val_loss: 0.2560 - val_acc: 0.9055
Epoch 27/50
197s - loss: 0.2315 - acc: 0.9108 - val_loss: 0.2565 - val_acc: 0.9060
Epoch 28/50
197s - loss: 0.2308 - acc: 0.9111 - val_loss: 0.2522 - val_acc: 0.9084
Epoch 29/50
197s - loss: 0.2309 - acc: 0.9108 - val_loss: 0.2559 - val_acc: 0.9069
Epoch 30/50
197s - loss: 0.2292 - acc: 0.9114 - val_loss: 0.2578 - val_acc: 0.9052
Epoch 31/50
197s - loss: 0.2305 - acc: 0.9109 - val_loss: 0.2571 - val_acc: 0.9061
Epoch 32/50
197s - loss: 0.2288 - acc: 0.9119 - val_loss: 0.2589 - val_acc: 0.9064
Epoch 33/50
197s - loss: 0.2285 - acc: 0.9116 - val_loss: 0.2585 - val_acc: 0.9056
Epoch 34/50
197s - loss: 0.2283 - acc: 0.9115 - val_loss: 0.2582 - val_acc: 0.9054
Epoch 35/50
197s - loss: 0.2286 - acc: 0.9116 - val_loss: 0.2553 - val_acc: 0.9057
Epoch 36/50
197s - loss: 0.2279 - acc: 0.9118 - val_loss: 0.2577 - val_acc: 0.9064
Epoch 37/50
197s - loss: 0.2263 - acc: 0.9122 - val_loss: 0.2588 - val_acc: 0.9047
Epoch 38/50
197s - loss: 0.2261 - acc: 0.9120 - val_loss: 0.2581 - val_acc: 0.9060
Epoch 39/50
197s - loss: 0.2256 - acc: 0.9125 - val_loss: 0.2598 - val_acc: 0.9048
Epoch 40/50
197s - loss: 0.2265 - acc: 0.9123 - val_loss: 0.2594 - val_acc: 0.9063
Epoch 41/50
197s - loss: 0.2261 - acc: 0.9123 - val_loss: 0.2566 - val_acc: 0.9072
Epoch 42/50
197s - loss: 0.2265 - acc: 0.9120 - val_loss: 0.2568 - val_acc: 0.9056
Epoch 43/50
197s - loss: 0.2247 - acc: 0.9125 - val_loss: 0.2621 - val_acc: 0.9044
Epoch 44/50
197s - loss: 0.2257 - acc: 0.9126 - val_loss: 0.2591 - val_acc: 0.9061
Epoch 45/50
197s - loss: 0.2246 - acc: 0.9128 - val_loss: 0.2661 - val_acc: 0.9024
Epoch 46/50
197s - loss: 0.2251 - acc: 0.9125 - val_loss: 0.2601 - val_acc: 0.9049
Epoch 47/50
197s - loss: 0.2244 - acc: 0.9127 - val_loss: 0.2574 - val_acc: 0.9062
Epoch 48/50
196s - loss: 0.2232 - acc: 0.9136 - val_loss: 0.2597 - val_acc: 0.9050
Epoch 49/50
197s - loss: 0.2246 - acc: 0.9129 - val_loss: 0.2581 - val_acc: 0.9060
Epoch 50/50
197s - loss: 0.2229 - acc: 0.9133 - val_loss: 0.2606 - val_acc: 0.9051

In [16]:
# summarize history for accuracy
plt.plot(history.history['acc'])
plt.plot(history.history['val_acc'])
plt.title('model accuracy')
plt.ylabel('accuracy')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()
# summarize history for loss
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('model loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()



In [17]:
score = model.evaluate(X_test, y_test, verbose=1, batch_size=batch_size)
print('Test loss:', score[0])
print('Test accuracy:', score[1])


58162/58162 [==============================] - 4s     
Test loss: 0.259860303524
Test accuracy: 0.905092708084

In [ ]: