In [1]:
import argparse
import pickle
import gzip
from collections import Counter, defaultdict
import keras
from keras.models import Sequential
from keras.layers import Conv2D
from keras.layers import Dense
from keras.layers import MaxPool2D
from keras.layers import Dropout
from keras.layers import Flatten
from keras.layers.core import Reshape
import numpy as np

from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import OneHotEncoder



import matplotlib.pyplot as plt

from collections import defaultdict

%matplotlib inline
import json
plt.style.use('ggplot')


Using TensorFlow backend.

In [2]:
class Numbers:
    """
    Class to store MNIST data
    """

    def __init__(self, location):
        # Load the dataset
        with gzip.open(location, 'rb') as f:
            train_set, valid_set, test_set = pickle.load(f)
        self.train_x, self.train_y = train_set
        self.test_x, self.test_y = valid_set

In [3]:
class CNN:
    '''
    CNN classifier
    '''
    def __init__(self, train_x, train_y, test_x, test_y, history, epochs = 15, batch_size=128, ):
        '''
        initialize CNN classifier
        '''
        self.batch_size = batch_size
        self.epochs = epochs

        print (len(train_x))
        print (len([elem for elem in train_x]))
        # TODO: reshape train_x and test_x
        # reshape our data from (n, length) to (n, width, height, 1) which width*height = length
        #self.train_x = np.array(np.array([train_x[i:i + 28] for i in range(0, len(train_x), 28)]))
        #self.train_x = np.array([[elem[i:i + 28] for i in range(0, len(elem), 28)] for elem in train_x])
        #self.test_x = np.array([[elem[i:i + 28] for i in range(0, len(elem), 28)] for elem in test_x])
        self.train_y = np.array(train_y)
        self.test_y = np.array(test_y)
        
        # input image dimensions
        img_x, img_y = 28, 28
        input_shape = (img_x, img_y, 1)
        
        # TODO: reshape train_x and test_x
        self.train_x = train_x.reshape(train_x.shape[0], img_x, img_y, 1)
        self.test_x = test_x.reshape(test_x.shape[0], img_x, img_y, 1)
        

        print (self.train_x.shape, self.test_x.shape, self.train_y.shape, self.test_y.shape)
        #print (self.train_x[0], self.test_x[0], self.train_y[0], self.test_y[0])


        # normalize data to range [0, 1]
        #self.train_x /= 255
        #self.test_x /= 255
        #print (self.train_x[0], self.test_x[0], self.train_y[0], self.test_y[0])


        # TODO: one hot encoding for train_y and test_y
        num_classes = len(set(train_y))
        one_hot_train_y = [ [0 if elem != idx else 1 for idx in range(num_classes) ] for elem in train_y]
        one_hot_test_y = [ [0 if elem != idx else 1 for idx in range(num_classes) ] for elem in test_y]
        self.train_y = one_hot_train_y
        self.test_y =  one_hot_test_y
        
    
    


        # TODO: build you CNN model
        model = Sequential()
        model.add(Conv2D(32, kernel_size=(5, 5), strides=(1, 1),
                         activation='relu',
                         input_shape=input_shape))
        model.add(MaxPool2D(pool_size=(2, 2), strides=(2, 2)))
        model.add(Dropout(0.5))
        model.add(Conv2D(64, (5, 5), activation='relu'))
        model.add(MaxPool2D(pool_size=(2, 2)))
        model.add(Dropout(0.5))
        model.add(Flatten())
        model.add(Dense(1000, activation='relu'))
        model.add(Dropout(0.5))
        model.add(Dense(num_classes, activation='softmax'))
        model.compile(loss=keras.losses.categorical_crossentropy,
              optimizer=keras.optimizers.SGD(lr=0.01),
              metrics=['accuracy'])
        
        self.model = model
        
    def train(self):
        '''
        train CNN classifier with training data
        :param x: training data input
        :param y: training label input
        :return:
        '''
        # TODO: fit in training data
        self.model.fit(self.train_x, self.train_y,
          batch_size=self.batch_size,
          epochs=self.epochs,
          verbose=1,
          validation_data=(self.test_x, self.test_y),
          callbacks=[history])

    def evaluate(self):
        '''
        test CNN classifier and get accuracy
        :return: accuracy
        '''
        acc = self.model.evaluate(self.test_x, self.test_y)
        return acc

In [4]:
class AccuracyHistory(keras.callbacks.Callback):
    def on_train_begin(self, logs={}):
        self.acc = []

    def on_epoch_end(self, batch, logs={}):
        self.acc.append(logs.get('acc'))

In [5]:
#parser = argparse.ArgumentParser(description='CNN classifier options')
#parser.add_argument('--limit', type=int, default=-1,help='Restrict training to this many examples')
#args = parser.parse_args()

data = Numbers("../data/mnist.pkl.gz")

print ( data.train_x.shape, data.test_x.shape, data.train_y.shape, data.test_y.shape )


limit = 50000


history = AccuracyHistory()
epochs = 50
cnn = CNN(data.train_x[:limit], data.train_y[:limit], data.test_x, data.test_y, history, epochs = epochs, batch_size=128)
cnn.train()
acc = cnn.evaluate()
print(acc)


(50000, 784) (10000, 784) (50000,) (10000,)
50000
50000
(50000, 28, 28, 1) (10000, 28, 28, 1) (50000,) (10000,)
Train on 50000 samples, validate on 10000 samples
Epoch 1/50
50000/50000 [==============================] - 157s - loss: 1.8356 - acc: 0.3592 - val_loss: 0.7027 - val_acc: 0.8382
Epoch 2/50
50000/50000 [==============================] - 165s - loss: 0.7702 - acc: 0.7477 - val_loss: 0.3593 - val_acc: 0.9046
Epoch 3/50
50000/50000 [==============================] - 174s - loss: 0.5291 - acc: 0.8311 - val_loss: 0.2568 - val_acc: 0.9280
Epoch 4/50
50000/50000 [==============================] - 172s - loss: 0.4216 - acc: 0.8669 - val_loss: 0.2065 - val_acc: 0.9442
Epoch 5/50
50000/50000 [==============================] - 171s - loss: 0.3545 - acc: 0.8894 - val_loss: 0.1756 - val_acc: 0.9493
Epoch 6/50
50000/50000 [==============================] - 171s - loss: 0.3124 - acc: 0.9028 - val_loss: 0.1571 - val_acc: 0.9558
Epoch 7/50
50000/50000 [==============================] - 177s - loss: 0.2867 - acc: 0.9107 - val_loss: 0.1420 - val_acc: 0.9591
Epoch 8/50
50000/50000 [==============================] - 175s - loss: 0.2599 - acc: 0.9193 - val_loss: 0.1302 - val_acc: 0.9628
Epoch 9/50
50000/50000 [==============================] - 153s - loss: 0.2449 - acc: 0.9233 - val_loss: 0.1218 - val_acc: 0.9659
Epoch 10/50
50000/50000 [==============================] - 140s - loss: 0.2305 - acc: 0.9281 - val_loss: 0.1133 - val_acc: 0.9686
Epoch 11/50
50000/50000 [==============================] - 140s - loss: 0.2169 - acc: 0.9326 - val_loss: 0.1070 - val_acc: 0.9696
Epoch 12/50
50000/50000 [==============================] - 141s - loss: 0.2092 - acc: 0.9347 - val_loss: 0.1037 - val_acc: 0.9704
Epoch 13/50
50000/50000 [==============================] - 140s - loss: 0.1994 - acc: 0.9377 - val_loss: 0.0969 - val_acc: 0.9719
Epoch 14/50
50000/50000 [==============================] - 141s - loss: 0.1871 - acc: 0.9416 - val_loss: 0.0919 - val_acc: 0.9742
Epoch 15/50
50000/50000 [==============================] - 142s - loss: 0.1844 - acc: 0.9420 - val_loss: 0.0902 - val_acc: 0.9742
Epoch 16/50
50000/50000 [==============================] - 141s - loss: 0.1749 - acc: 0.9457 - val_loss: 0.0858 - val_acc: 0.9758
Epoch 17/50
50000/50000 [==============================] - 140s - loss: 0.1689 - acc: 0.9477 - val_loss: 0.0840 - val_acc: 0.9768
Epoch 18/50
50000/50000 [==============================] - 142s - loss: 0.1633 - acc: 0.9489 - val_loss: 0.0801 - val_acc: 0.9772
Epoch 19/50
50000/50000 [==============================] - 141s - loss: 0.1571 - acc: 0.9515 - val_loss: 0.0781 - val_acc: 0.9779
Epoch 20/50
50000/50000 [==============================] - 138s - loss: 0.1538 - acc: 0.9519 - val_loss: 0.0757 - val_acc: 0.9793
Epoch 21/50
50000/50000 [==============================] - 141s - loss: 0.1489 - acc: 0.9530 - val_loss: 0.0738 - val_acc: 0.9797
Epoch 22/50
50000/50000 [==============================] - 141s - loss: 0.1448 - acc: 0.9547 - val_loss: 0.0712 - val_acc: 0.9806
Epoch 23/50
50000/50000 [==============================] - 140s - loss: 0.1418 - acc: 0.9562 - val_loss: 0.0686 - val_acc: 0.9814
Epoch 24/50
50000/50000 [==============================] - 141s - loss: 0.1390 - acc: 0.9566 - val_loss: 0.0680 - val_acc: 0.9812
Epoch 25/50
50000/50000 [==============================] - 139s - loss: 0.1337 - acc: 0.9583 - val_loss: 0.0670 - val_acc: 0.9818
Epoch 26/50
50000/50000 [==============================] - 140s - loss: 0.1321 - acc: 0.9585 - val_loss: 0.0649 - val_acc: 0.9831
Epoch 27/50
50000/50000 [==============================] - 141s - loss: 0.1290 - acc: 0.9600 - val_loss: 0.0642 - val_acc: 0.9827
Epoch 28/50
50000/50000 [==============================] - 143s - loss: 0.1265 - acc: 0.9608 - val_loss: 0.0632 - val_acc: 0.9832
Epoch 29/50
50000/50000 [==============================] - 142s - loss: 0.1238 - acc: 0.9609 - val_loss: 0.0612 - val_acc: 0.9833
Epoch 30/50
50000/50000 [==============================] - 140s - loss: 0.1227 - acc: 0.9605 - val_loss: 0.0600 - val_acc: 0.9837
Epoch 31/50
50000/50000 [==============================] - 141s - loss: 0.1206 - acc: 0.9620 - val_loss: 0.0588 - val_acc: 0.9844
Epoch 32/50
50000/50000 [==============================] - 142s - loss: 0.1186 - acc: 0.9633 - val_loss: 0.0571 - val_acc: 0.9845
Epoch 33/50
50000/50000 [==============================] - 142s - loss: 0.1133 - acc: 0.9642 - val_loss: 0.0561 - val_acc: 0.9851
Epoch 34/50
50000/50000 [==============================] - 143s - loss: 0.1119 - acc: 0.9651 - val_loss: 0.0562 - val_acc: 0.9845
Epoch 35/50
50000/50000 [==============================] - 140s - loss: 0.1130 - acc: 0.9647 - val_loss: 0.0547 - val_acc: 0.9852
Epoch 36/50
50000/50000 [==============================] - 141s - loss: 0.1091 - acc: 0.9665 - val_loss: 0.0540 - val_acc: 0.9855
Epoch 37/50
50000/50000 [==============================] - 142s - loss: 0.1079 - acc: 0.9667 - val_loss: 0.0536 - val_acc: 0.9850
Epoch 38/50
50000/50000 [==============================] - 140s - loss: 0.1034 - acc: 0.9675 - val_loss: 0.0523 - val_acc: 0.9858
Epoch 39/50
50000/50000 [==============================] - 140s - loss: 0.1027 - acc: 0.9678 - val_loss: 0.0515 - val_acc: 0.9856
Epoch 40/50
50000/50000 [==============================] - 140s - loss: 0.1002 - acc: 0.9685 - val_loss: 0.0510 - val_acc: 0.9857
Epoch 41/50
50000/50000 [==============================] - 142s - loss: 0.1000 - acc: 0.9685 - val_loss: 0.0509 - val_acc: 0.9862
Epoch 42/50
50000/50000 [==============================] - 141s - loss: 0.1023 - acc: 0.9679 - val_loss: 0.0502 - val_acc: 0.9862
Epoch 43/50
50000/50000 [==============================] - 140s - loss: 0.0987 - acc: 0.9694 - val_loss: 0.0494 - val_acc: 0.9864
Epoch 44/50
50000/50000 [==============================] - 139s - loss: 0.0992 - acc: 0.9696 - val_loss: 0.0496 - val_acc: 0.9866
Epoch 45/50
50000/50000 [==============================] - 141s - loss: 0.0964 - acc: 0.9692 - val_loss: 0.0479 - val_acc: 0.9863
Epoch 46/50
50000/50000 [==============================] - 141s - loss: 0.0943 - acc: 0.9709 - val_loss: 0.0472 - val_acc: 0.9865
Epoch 47/50
50000/50000 [==============================] - 141s - loss: 0.0945 - acc: 0.9700 - val_loss: 0.0466 - val_acc: 0.9866
Epoch 48/50
50000/50000 [==============================] - 141s - loss: 0.0909 - acc: 0.9710 - val_loss: 0.0466 - val_acc: 0.9871
Epoch 49/50
50000/50000 [==============================] - 141s - loss: 0.0910 - acc: 0.9719 - val_loss: 0.0466 - val_acc: 0.9869
Epoch 50/50
50000/50000 [==============================] - 143s - loss: 0.0892 - acc: 0.9716 - val_loss: 0.0449 - val_acc: 0.9874
10000/10000 [==============================] - 8s     
[0.044877817283477638, 0.98740000000000006]

In [6]:
plt.plot(range(1,epochs+1), history.acc)
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.title('CNN with 2 convolutional layers, one of 32 nodes and one of 64 nodes')

plt.show()



In [7]:
print (cnn.model.summary())


_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 24, 24, 32)        832       
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 12, 12, 32)        0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 12, 12, 32)        0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 8, 8, 64)          51264     
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 4, 4, 64)          0         
_________________________________________________________________
dropout_2 (Dropout)          (None, 4, 4, 64)          0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 1024)              0         
_________________________________________________________________
dense_1 (Dense)              (None, 1000)              1025000   
_________________________________________________________________
dropout_3 (Dropout)          (None, 1000)              0         
_________________________________________________________________
dense_2 (Dense)              (None, 10)                10010     
=================================================================
Total params: 1,087,106
Trainable params: 1,087,106
Non-trainable params: 0
_________________________________________________________________
None

In [ ]:


In [ ]: