{"cells":[{"metadata":{"_execution_state":"idle","_uuid":"72334cb006d02a4bcfc2a2fe622524eba824c6f8","_cell_guid":"f67b9393-8ea1-4e23-b856-2ce149cfe421","trusted":true},"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport matplotlib.image as mpimg\nimport seaborn as sns\n%matplotlib inline\n\nnp.random.seed(2)\n\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import confusion_matrix\nimport itertools\n\nfrom keras.utils.np_utils import to_categorical # convert to one-hot-encoding\nfrom keras.models import Sequential\nfrom keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPool2D\nfrom keras.optimizers import RMSprop\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom keras.callbacks import ReduceLROnPlateau\n\n\nsns.set(style='white', context='notebook', palette='deep')","execution_count":null,"outputs":[]},{"metadata":{"_execution_state":"idle","_uuid":"84bbd5ab8d7895bd430d5ecfe2f7ddf77baa7b74","_cell_guid":"5e51d00e-62fd-4141-bf73-50ac4f2da7d0","trusted":true},"cell_type":"code","source":"# Load the data\ntrain = pd.read_csv(\"../input/train.csv\")\ntest = pd.read_csv(\"../input/test.csv\")","execution_count":null,"outputs":[]},{"metadata":{"_execution_state":"idle","_uuid":"1213b979d5ed3e0d13824d17d694c79d2ece92fa","_cell_guid":"86570a36-5c20-460a-9dfd-2070548532a7","trusted":true},"cell_type":"code","source":"Y_train = train[\"label\"]\n\n# Drop 'label' column\nX_train = train.drop(labels = [\"label\"],axis = 1) \n\n# free some space\ndel train \n\ng = sns.countplot(Y_train)\n\nY_train.value_counts()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"b7b1b1d36243c885e57374c8b60c5a7e10abe922","_cell_guid":"5aea4062-1790-4987-b739-c4bebd79030f"},"cell_type":"markdown","source":"We have similar counts for the 10 digits."},{"metadata":{"_execution_state":"idle","_uuid":"cdf27c27e2a5b15e6d7bfc70de7a18c08f3feb7a","_cell_guid":"ececaa00-2ae3-4d13-b631-438df085b030","trusted":true},"cell_type":"code","source":"# Check the data\nX_train.isnull().any().describe()","execution_count":null,"outputs":[]},{"metadata":{"_execution_state":"idle","_uuid":"a0089bb7ec9aec76373db475399aea24699ae989","_cell_guid":"92572e80-8543-4e72-8767-5c9be8381b04","trusted":true},"cell_type":"code","source":"test.isnull().any().describe()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"2954681f25f0dcbe986e6914396cdbce61db591f","_cell_guid":"6812040d-80ad-43d2-a571-275f4f20067b"},"cell_type":"markdown","source":"## 2.3 Normalization"},{"metadata":{"_execution_state":"idle","_uuid":"b5d4f8fcf2a967e2c7d57daedf95aa8c5ab7f8cb","_cell_guid":"cdc4340b-6e24-4e12-be99-ac806098ff17","trusted":true},"cell_type":"code","source":"# Normalize the data\nX_train = X_train / 255.0\ntest = test / 255.0","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"a66741bf1ac597094f3a3166877008feef27c519","_cell_guid":"7413df94-bcb9-4f75-b174-c127d4445766"},"cell_type":"markdown","source":"## 2.3 Reshape"},{"metadata":{"_execution_state":"idle","_uuid":"f0a6ad80dab8e0f2c2e46165ccd9cd82dd162bc3","_cell_guid":"34b6a5f7-8fd2-4387-8ef4-c9dc19584fed","trusted":true},"cell_type":"code","source":"# Reshape image in 3 dimensions (height = 28px, width = 28px , canal = 1)\nX_train = X_train.values.reshape(-1,28,28,1)\ntest = test.values.reshape(-1,28,28,1)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"39b7a31e843bac6b705461bcce89da216b91799e","_cell_guid":"bdb422e2-bdec-444f-97a5-283a1e54bf2c"},"cell_type":"markdown","source":"## 2.5 Label encoding"},{"metadata":{"_execution_state":"idle","_uuid":"cabefd1478d5c1bdfe57fd6a34395340916a854c","_cell_guid":"4b7f3e78-44dc-4561-b1f0-9429ee024cf4","trusted":true},"cell_type":"code","source":"# Encode labels to one hot vectors (ex : 2 -> [0,0,1,0,0,0,0,0,0,0])\nY_train = to_categorical(Y_train, num_classes = 10)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"dcfb688587dfc6feafd27442a3505e35dc01b82d","_cell_guid":"ae068bd8-b12e-4768-8a7e-0fc865dd7562"},"cell_type":"markdown","source":"Labels are 10 digits numbers from 0 to 9. We need to encode these lables to one hot vectors (ex : 2 -> [0,0,1,0,0,0,0,0,0,0])."},{"metadata":{"_uuid":"d8abbbf31483b94e1b29d07c4c8253d1311648a7","_cell_guid":"32152fc3-a570-4d64-8a7d-6c689a4acd33"},"cell_type":"markdown","source":"## 2.6 Split training and valdiation set "},{"metadata":{"_execution_state":"idle","_uuid":"6e51c925c6e0f1b936679c9649fef345c853555f","_cell_guid":"3a698301-9759-4279-ae48-fd980f89ea53","trusted":true},"cell_type":"code","source":"# Set the random seed\nrandom_seed = 2","execution_count":null,"outputs":[]},{"metadata":{"_execution_state":"idle","_uuid":"b779ac76d8317647db92d5a88b4098d212d72884","_cell_guid":"dcd25ebb-d845-4d32-9867-082e352b1396","trusted":true},"cell_type":"code","source":"# Split the train and the validation set for the fitting\nX_train, X_val, Y_train, Y_val = train_test_split(X_train, Y_train, test_size = 0.1, random_state=random_seed)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X_train.shape","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"60eed15ec5bc0d354385301789ecb8538fc02267","_cell_guid":"adbeacf0-0dc0-4675-b2df-9c9663750f32"},"cell_type":"markdown","source":"We can get a better sense for one of these examples by visualising the image and looking at the label."},{"metadata":{"_execution_state":"idle","_uuid":"e0dae8943d3d35f075dba3d7ba31bde1d4bf2ff4","_cell_guid":"5f76131b-4ba0-45f1-a98c-bd4e7d561793","trusted":true},"cell_type":"code","source":"# Some examples\ng = plt.imshow(X_train[0][:,:,0])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"5fa18b37a9acd9e098bac1d12264b0dd4310fdd3","_cell_guid":"d5265777-aeb3-449d-b171-d88cad74c0a4"},"cell_type":"markdown","source":"# 3. CNN\n## 3.1 Define the model"},{"metadata":{"_execution_state":"idle","_uuid":"f7991ef6871a26f9fa57acdcd460a69bab53e804","_cell_guid":"1e0f3f88-2ad7-459e-8e02-aecc5f3511ae","trusted":true},"cell_type":"code","source":"# Set the CNN model \n# my CNN architechture is In -> [[Conv2D->relu]*2 -> MaxPool2D -> Dropout]*2 -> Flatten -> Dense -> Dropout -> Out\n\nmodel = Sequential()\n\nmodel.add(Conv2D(filters = 32, kernel_size = (5,5),padding = 'Same', \n                 activation ='relu', input_shape = (28,28,1)))\nmodel.add(Conv2D(filters = 32, kernel_size = (5,5),padding = 'Same', \n                 activation ='relu'))\nmodel.add(MaxPool2D(pool_size=(2,2)))\nmodel.add(Dropout(0.25))\n\n\nmodel.add(Conv2D(filters = 64, kernel_size = (3,3),padding = 'Same', \n                 activation ='relu'))\nmodel.add(Conv2D(filters = 64, kernel_size = (3,3),padding = 'Same', \n                 activation ='relu'))\nmodel.add(MaxPool2D(pool_size=(2,2), strides=(2,2)))\nmodel.add(Dropout(0.25))\n\nmodel.add(Conv2D(filters = 128, kernel_size = (3,3),padding = 'Same', \n                 activation ='relu'))\nmodel.add(Conv2D(filters = 128, kernel_size = (3,3),padding = 'Same', \n                 activation ='relu'))\nmodel.add(MaxPool2D(pool_size=(2,2), strides=(2,2)))\nmodel.add(Dropout(0.25))\n\n\nmodel.add(Flatten())\nmodel.add(Dense(256, activation = \"relu\"))\nmodel.add(Dropout(0.5))\nmodel.add(Dense(10, activation = \"softmax\"))","execution_count":null,"outputs":[]},{"metadata":{"_execution_state":"idle","_uuid":"420c704367b397b8255fefe9d882b35ac8929b95","_cell_guid":"a4c55409-6a65-400a-b5e8-a1dc535429c0","trusted":true},"cell_type":"code","source":"# Define the optimizer\noptimizer = RMSprop(lr=0.001, rho=0.9, epsilon=1e-08, decay=0.0)","execution_count":null,"outputs":[]},{"metadata":{"_execution_state":"idle","_uuid":"b4c0288622227a3cd05479aa765e324dbb852f34","_cell_guid":"0bd89b79-1a74-40da-af9a-7a76a8b96ff2","trusted":true},"cell_type":"code","source":"# Compile the model\nmodel.compile(optimizer = optimizer , loss = \"categorical_crossentropy\", metrics=[\"accuracy\"])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"f4d89b29d55b328e8c446880505c54e674eeec38","_cell_guid":"6bc49be3-11e5-48fb-b70f-601aec0f0c86"},"cell_type":"markdown","source":"<img src=\"http://img1.imagilive.com/0717/learningrates.jpg\"> </img>"},{"metadata":{"_execution_state":"idle","_uuid":"c4a5b4e462ec5362c47eef4fcc7956fd4e203307","_cell_guid":"b5987a18-6bbe-42a2-9d31-333ebc4f7af1","trusted":true},"cell_type":"code","source":"# Set a learning rate annealer\nlearning_rate_reduction = ReduceLROnPlateau(monitor='val_acc', \n                                            patience=3, \n                                            verbose=1, \n                                            factor=0.5, \n                                            min_lr=0.00001)","execution_count":null,"outputs":[]},{"metadata":{"_execution_state":"idle","_uuid":"26b0647c46efdb6b1096cf7335a7bf2a3417543a","_cell_guid":"970db455-b393-4b25-806d-92c6766c12c0","trusted":true},"cell_type":"code","source":"epochs = 60 # Turn epochs to 30 to get 0.9967 accuracy\nbatch_size = 100","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"f24df64b223e0177c94025b6767ab19b722c5386","_cell_guid":"241a0f4f-13f5-4b13-be1e-4e3e4a714c06"},"cell_type":"markdown","source":"## 3.3 Data augmentation "},{"metadata":{"_execution_state":"idle","_uuid":"d4e9e1ade3c04f9ca4d8cd44e799f9e09524d5a1","_cell_guid":"ade93d2d-90c6-4401-af95-f7d65f8c0a20","collapsed":true,"trusted":false},"cell_type":"code","source":"# Without data augmentation i obtained an accuracy of 0.98114\n#history = model.fit(X_train, Y_train, batch_size = batch_size, epochs = epochs, \n#          validation_data = (X_val, Y_val), verbose = 2)","execution_count":null,"outputs":[]},{"metadata":{"_execution_state":"idle","_uuid":"21d6192c87d92d497c797656474bccd9cefc5647","_cell_guid":"b342befe-1a6f-44bf-8dab-28033a729122","trusted":true},"cell_type":"code","source":"# With data augmentation to prevent overfitting (accuracy 0.99286)\n\ndatagen = ImageDataGenerator(\n        featurewise_center=False,  # set input mean to 0 over the dataset\n        samplewise_center=False,  # set each sample mean to 0\n        featurewise_std_normalization=False,  # divide inputs by std of the dataset\n        samplewise_std_normalization=False,  # divide each input by its std\n        zca_whitening=False,  # apply ZCA whitening\n        rotation_range=10,  # randomly rotate images in the range (degrees, 0 to 180)\n        zoom_range = 0.1, # Randomly zoom image \n        width_shift_range=0.1,  # randomly shift images horizontally (fraction of total width)\n        height_shift_range=0.1,  # randomly shift images vertically (fraction of total height)\n        horizontal_flip=False,  # randomly flip images\n        vertical_flip=False)  # randomly flip images\n\n\ndatagen.fit(X_train)","execution_count":null,"outputs":[]},{"metadata":{"_execution_state":"idle","_uuid":"cf36b3d029f95b553be02d612e097a9769ee8252","_cell_guid":"b453af8d-9736-43e3-b486-7a1cd7dd8909","trusted":true},"cell_type":"code","source":"# Fit the model\nhistory = model.fit_generator(datagen.flow(X_train,Y_train, batch_size=batch_size),\n                              epochs = epochs, validation_data = (X_val,Y_val),\n                              verbose = 2, steps_per_epoch=X_train.shape[0] // batch_size\n                              , callbacks=[learning_rate_reduction])","execution_count":null,"outputs":[]},{"metadata":{"_execution_state":"idle","_uuid":"3a831860dd5bb65c8ead1ddcf4ae18ae20dd7f3e","_cell_guid":"eb4b1b73-cbd4-40e8-9790-066fcef4c4c0","trusted":true},"cell_type":"code","source":"# Plot the loss and accuracy curves for training and validation \nfig, ax = plt.subplots(2,1)\nax[0].plot(history.history['loss'], color='b', label=\"Training loss\")\nax[0].plot(history.history['val_loss'], color='r', label=\"validation loss\",axes =ax[0])\nlegend = ax[0].legend(loc='best', shadow=True)\n\nax[1].plot(history.history['acc'], color='b', label=\"Training accuracy\")\nax[1].plot(history.history['val_acc'], color='r',label=\"Validation accuracy\")\nlegend = ax[1].legend(loc='best', shadow=True)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"63698d7d51381b33892ce164b0f21930abb3e937","_cell_guid":"de1c65bd-4a88-4351-9f4b-562e72e7e0fd"},"cell_type":"markdown","source":"## 4.2 Confusion matrix"},{"metadata":{"_execution_state":"idle","_uuid":"16e161179bf1b51ba66c39b2cead883f1db3a9c7","_cell_guid":"11361e73-8250-4bf5-a353-b0f8ea83e659","trusted":true},"cell_type":"code","source":"# Look at confusion matrix \n\ndef plot_confusion_matrix(cm, classes,\n                          normalize=False,\n                          title='Confusion matrix',\n                          cmap=plt.cm.Blues):\n    \"\"\"\n    This function prints and plots the confusion matrix.\n    Normalization can be applied by setting `normalize=True`.\n    \"\"\"\n    plt.imshow(cm, interpolation='nearest', cmap=cmap)\n    plt.title(title)\n    plt.colorbar()\n    tick_marks = np.arange(len(classes))\n    plt.xticks(tick_marks, classes, rotation=45)\n    plt.yticks(tick_marks, classes)\n\n    if normalize:\n        cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]\n\n    thresh = cm.max() / 2.\n    for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):\n        plt.text(j, i, cm[i, j],\n                 horizontalalignment=\"center\",\n                 color=\"white\" if cm[i, j] > thresh else \"black\")\n\n    plt.tight_layout()\n    plt.ylabel('True label')\n    plt.xlabel('Predicted label')\n\n# Predict the values from the validation dataset\nY_pred = model.predict(X_val)\n# Convert predictions classes to one hot vectors \nY_pred_classes = np.argmax(Y_pred,axis = 1) \n# Convert validation observations to one hot vectors\nY_true = np.argmax(Y_val,axis = 1) \n# compute the confusion matrix\nconfusion_mtx = confusion_matrix(Y_true, Y_pred_classes) \n# plot the confusion matrix\nplot_confusion_matrix(confusion_mtx, classes = range(10)) ","execution_count":null,"outputs":[]},{"metadata":{"_execution_state":"idle","_uuid":"e7a3d6449b499a29db224e42e950f21ca1ec4e36","_cell_guid":"7b0f31b8-c18b-4529-b0d8-eb4c31e30bbf","trusted":true},"cell_type":"code","source":"# Display some error results \n\n# Errors are difference between predicted labels and true labels\nerrors = (Y_pred_classes - Y_true != 0)\n\nY_pred_classes_errors = Y_pred_classes[errors]\nY_pred_errors = Y_pred[errors]\nY_true_errors = Y_true[errors]\nX_val_errors = X_val[errors]\n\ndef display_errors(errors_index,img_errors,pred_errors, obs_errors):\n    \"\"\" This function shows 6 images with their predicted and real labels\"\"\"\n    n = 0\n    nrows = 2\n    ncols = 3\n    fig, ax = plt.subplots(nrows,ncols,sharex=True,sharey=True)\n    for row in range(nrows):\n        for col in range(ncols):\n            error = errors_index[n]\n            ax[row,col].imshow((img_errors[error]).reshape((28,28)))\n            ax[row,col].set_title(\"Predicted label :{}\\nTrue label :{}\".format(pred_errors[error],obs_errors[error]))\n            n += 1\n\n# Probabilities of the wrong predicted numbers\nY_pred_errors_prob = np.max(Y_pred_errors,axis = 1)\n\n# Predicted probabilities of the true values in the error set\ntrue_prob_errors = np.diagonal(np.take(Y_pred_errors, Y_true_errors, axis=1))\n\n# Difference between the probability of the predicted label and the true label\ndelta_pred_true_errors = Y_pred_errors_prob - true_prob_errors\n\n# Sorted list of the delta prob errors\nsorted_dela_errors = np.argsort(delta_pred_true_errors)\n\n# Top 6 errors \nmost_important_errors = sorted_dela_errors[-6:]\n\n# Show the top 6 errors\ndisplay_errors(most_important_errors, X_val_errors, Y_pred_classes_errors, Y_true_errors)","execution_count":null,"outputs":[]},{"metadata":{"_execution_state":"idle","_uuid":"7f17e7bf0a54a01a52fef2d554780f6bc6580dc6","_cell_guid":"05ff3b9f-c3bb-4cec-a8c2-2c128e8f15b3","trusted":true},"cell_type":"code","source":"# predict results\nresults = model.predict(test)\n\n# select the indix with the maximum probability\nresults = np.argmax(results,axis = 1)\n\nresults = pd.Series(results,name=\"Label\")","execution_count":null,"outputs":[]},{"metadata":{"_execution_state":"idle","_uuid":"369dfaab09240f3f12bcff91953ffd315ab84985","_cell_guid":"b5f1f39f-13b8-439a-8913-0f120e3d47a9","trusted":true},"cell_type":"code","source":"submission = pd.concat([pd.Series(range(1,28001),name = \"ImageId\"),results],axis = 1)\n\nsubmission.to_csv(\"cnn_digit.csv\",index=False)","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"language":"python","name":"python3","display_name":"Python 3"},"language_info":{"pygments_lexer":"ipython3","mimetype":"text/x-python","nbconvert_exporter":"python","version":"3.6.1","codemirror_mode":{"version":3,"name":"ipython"},"file_extension":".py","name":"python"}},"nbformat":4,"nbformat_minor":1}