{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.6.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":3004,"databundleVersionId":861823,"sourceType":"competition"}],"dockerImageVersionId":27938,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# MNIST: CNN Keras\n","metadata":{}},{"cell_type":"markdown","source":"# 1. Introduction\n\n\nMNIST (\"Modified National Institute of Standards and Technology\") is the de facto “hello world” dataset of computer vision. Since its release in 1999, this classic dataset of handwritten images has served as the basis for benchmarking classification algorithms. A new machine learning techniques emerge, MNIST remains a reliable resource for researchers and learners alike. ","metadata":{}},{"cell_type":"markdown","source":"**Import all Necessary Libraries**","metadata":{"_uuid":"7ed04b1e7a00a7ad31ee98a7d8e55880e6274f29"}},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\n\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import confusion_matrix\n\nimport keras\nfrom keras.models import Sequential\nfrom keras.layers import Conv2D, Lambda, MaxPooling2D # convolution layers\nfrom keras.layers import Dense, Dropout, Flatten # core layers\nfrom keras.layers.normalization import BatchNormalization\n\nfrom keras.preprocessing.image import ImageDataGenerator\n\nfrom keras.utils.np_utils import to_categorical\n\n#from keras.datasets import mnist","metadata":{"_uuid":"0f935bddcc5ca02702578e712bf7f396ba7154ef","execution":{"iopub.status.busy":"2024-03-31T13:19:57.073100Z","iopub.execute_input":"2024-03-31T13:19:57.073436Z","iopub.status.idle":"2024-03-31T13:19:59.056561Z","shell.execute_reply.started":"2024-03-31T13:19:57.073374Z","shell.execute_reply":"2024-03-31T13:19:59.055638Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nprint(os.listdir('../input'))","metadata":{"execution":{"iopub.status.busy":"2024-03-31T13:19:59.058563Z","iopub.execute_input":"2024-03-31T13:19:59.058809Z","iopub.status.idle":"2024-03-31T13:19:59.063481Z","shell.execute_reply.started":"2024-03-31T13:19:59.058763Z","shell.execute_reply":"2024-03-31T13:19:59.062609Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 2. Data preparation\n## 2.1 Load data","metadata":{"_uuid":"f94870f1682c45b0e4ea378d287302656af3cf8e"}},{"cell_type":"code","source":"train = pd.read_csv('../input/train.csv')\ntest = pd.read_csv('../input/test.csv')\nsub = pd.read_csv('../input/sample_submission.csv')\nprint(\"Data are Ready!!\")","metadata":{"execution":{"iopub.status.busy":"2024-03-31T13:19:59.064618Z","iopub.execute_input":"2024-03-31T13:19:59.064874Z","iopub.status.idle":"2024-03-31T13:20:05.949157Z","shell.execute_reply.started":"2024-03-31T13:19:59.064808Z","shell.execute_reply":"2024-03-31T13:20:05.948287Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(f\"Training data size is {train.shape}\\nTesting data size is {test.shape}\")","metadata":{"execution":{"iopub.status.busy":"2024-03-31T13:20:05.950490Z","iopub.execute_input":"2024-03-31T13:20:05.950730Z","iopub.status.idle":"2024-03-31T13:20:05.954678Z","shell.execute_reply.started":"2024-03-31T13:20:05.950691Z","shell.execute_reply":"2024-03-31T13:20:05.953986Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Set data features and labels**","metadata":{}},{"cell_type":"code","source":"X = train.drop(['label'], 1).values\ny = train['label'].values","metadata":{"execution":{"iopub.status.busy":"2024-03-31T13:20:05.958325Z","iopub.execute_input":"2024-03-31T13:20:05.958556Z","iopub.status.idle":"2024-03-31T13:20:06.151286Z","shell.execute_reply.started":"2024-03-31T13:20:05.958518Z","shell.execute_reply":"2024-03-31T13:20:06.150413Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 2.2 Normalization","metadata":{}},{"cell_type":"markdown","source":"We perform a grayscale normalization to reduce the effect of illumination's differences. \n\nMoreover the CNN converg faster on [0..1] data than on [0..255].","metadata":{}},{"cell_type":"code","source":"X = X / 255.0","metadata":{"execution":{"iopub.status.busy":"2024-03-31T13:20:06.153544Z","iopub.execute_input":"2024-03-31T13:20:06.153785Z","iopub.status.idle":"2024-03-31T13:20:06.391481Z","shell.execute_reply.started":"2024-03-31T13:20:06.153747Z","shell.execute_reply":"2024-03-31T13:20:06.390818Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 2.3 Reshape","metadata":{}},{"cell_type":"code","source":"# Reshape image in 3 dimensions (height = 28px, width = 28px , canal = 1)\n# canal = 1 => For gray scale\nX = X.reshape(-1,28,28,1)","metadata":{"execution":{"iopub.status.busy":"2024-03-31T13:20:06.392955Z","iopub.execute_input":"2024-03-31T13:20:06.393257Z","iopub.status.idle":"2024-03-31T13:20:06.397373Z","shell.execute_reply.started":"2024-03-31T13:20:06.393206Z","shell.execute_reply":"2024-03-31T13:20:06.396461Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 2.4 Label encoding","metadata":{}},{"cell_type":"markdown","source":"**One-Hot Encoding**","metadata":{}},{"cell_type":"code","source":"# Encode labels to one hot vectors (ex : 2 -> [0,0,1,0,0,0,0,0,0,0])\ny = to_categorical(y)\n\nprint(f\"Label size {y.shape}\")","metadata":{"execution":{"iopub.status.busy":"2024-03-31T13:20:06.398525Z","iopub.execute_input":"2024-03-31T13:20:06.398778Z","iopub.status.idle":"2024-03-31T13:20:06.410064Z","shell.execute_reply.started":"2024-03-31T13:20:06.398732Z","shell.execute_reply":"2024-03-31T13:20:06.409303Z"},"trusted":true},"execution_count":null,"outputs":[]},{"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":{}},{"cell_type":"markdown","source":"## 2.5 Split training and valdiation set","metadata":{}},{"cell_type":"code","source":"# Split the train and the validation set for the fitting\nX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1, random_state=0)","metadata":{"execution":{"iopub.status.busy":"2024-03-31T13:20:06.411302Z","iopub.execute_input":"2024-03-31T13:20:06.411557Z","iopub.status.idle":"2024-03-31T13:20:07.077709Z","shell.execute_reply.started":"2024-03-31T13:20:06.411514Z","shell.execute_reply":"2024-03-31T13:20:07.077052Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_train.shape, X_test.shape, y_train.shape, y_test.shape","metadata":{"execution":{"iopub.status.busy":"2024-03-31T13:20:07.078966Z","iopub.execute_input":"2024-03-31T13:20:07.079245Z","iopub.status.idle":"2024-03-31T13:20:07.087525Z","shell.execute_reply.started":"2024-03-31T13:20:07.079200Z","shell.execute_reply":"2024-03-31T13:20:07.086499Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"I choosed to split the train set in two parts : a small fraction (10%) became the validation set which the model is evaluated and the rest (90%) is used to train the model.","metadata":{}},{"cell_type":"markdown","source":"**Data Visualization**","metadata":{"_uuid":"d9f73cd8890cc89d03837ef47210b27b94b156dc"}},{"cell_type":"code","source":"X_train__ = X_train.reshape(X_train.shape[0], 28, 28)\n\nfig, axis = plt.subplots(1, 4, figsize=(20, 10))\nfor i, ax in enumerate(axis.flat):\n    ax.imshow(X_train__[i], cmap='binary')\n    digit = y_train[i].argmax()\n    ax.set(title = f\"Real Number is {digit}\");","metadata":{"_uuid":"d00d9b96668d11a33c272b2b64cbb4397dcbba89","scrolled":true,"execution":{"iopub.status.busy":"2024-03-31T13:20:07.088919Z","iopub.execute_input":"2024-03-31T13:20:07.089272Z","iopub.status.idle":"2024-03-31T13:20:08.175287Z","shell.execute_reply.started":"2024-03-31T13:20:07.089215Z","shell.execute_reply":"2024-03-31T13:20:08.174212Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Normalization**","metadata":{"_uuid":"a4f73e65842423bae7cfce945cd4dc0e367c180a"}},{"cell_type":"code","source":"mean = np.mean(X_train)\nstd = np.std(X_train)\n\ndef standardize(x):\n    return (x-mean)/std","metadata":{"_uuid":"82bddf135bfad1d3f91b52cd0cadb62e55db964b","execution":{"iopub.status.busy":"2024-03-31T13:20:08.177022Z","iopub.execute_input":"2024-03-31T13:20:08.177637Z","iopub.status.idle":"2024-03-31T13:20:08.451825Z","shell.execute_reply.started":"2024-03-31T13:20:08.177571Z","shell.execute_reply":"2024-03-31T13:20:08.451187Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 3. CNN\n## 3.1 Define the model","metadata":{}},{"cell_type":"markdown","source":"I used the Keras Sequential API, where you have just to add one layer at a time, starting from the input.\n\nThe first is the convolutional (Conv2D) layer. It is like a set of learnable filters. I choosed to set 32 filters for the two firsts conv2D layers and 64 filters for the two second layers and 128 filters for two third layers and 256 for the last ones. Each filter transforms a part of the image (defined by the kernel size) using the kernel filter. The kernel filter matrix is applied on the whole image. Filters can be seen as a transformation of the image.\n\nThe CNN can isolate features that are useful everywhere from these transformed images (feature maps).\n\nThe second important layer in CNN is the pooling (MaxPool2D) layer. This layer simply acts as a downsampling filter. It looks at the 2 neighboring pixels and picks the maximal value. These are used to reduce computational cost, and to some extent also reduce overfitting. We have to choose the pooling size (i.e the area size pooled each time) more the pooling dimension is high, more the downsampling is important. \n\nCombining convolutional and pooling layers, CNN are able to combine local features and learn more global features of the image.\n\n'relu' is the rectifier (activation function max(0,x). The rectifier activation function is used to add non linearity to the network. \n\nThe Flatten layer is use to convert the final feature maps into a one single 1D vector. This flattening step is needed so that you can make use of fully connected layers after some convolutional/maxpool layers. It combines all the found local features of the previous convolutional layers.\n\nIn the end i used the features in two fully-connected (Dense) layers which is just artificial an neural networks (ANN) classifier. In the last layer(Dense(10,activation=\"softmax\")) the net outputs distribution of probability of each class.","metadata":{}},{"cell_type":"markdown","source":"**Model Definition**","metadata":{"_uuid":"57904be2d2935cece025811c128ca6738cf86800"}},{"cell_type":"code","source":"model=Sequential()\n\n#model.add(Lambda(standardize,input_shape=(28,28,1)))    \nmodel.add(Conv2D(filters=64, kernel_size = (3,3), activation=\"relu\", input_shape=(28,28,1)))\nmodel.add(Conv2D(filters=64, kernel_size = (3,3), activation=\"relu\"))\nmodel.add(MaxPooling2D(pool_size=(2,2)))\nmodel.add(BatchNormalization())\n\nmodel.add(Conv2D(filters=128, kernel_size = (3,3), activation=\"relu\"))\nmodel.add(Conv2D(filters=128, kernel_size = (3,3), activation=\"relu\"))\nmodel.add(MaxPooling2D(pool_size=(2,2)))\nmodel.add(BatchNormalization())    \n\nmodel.add(Conv2D(filters=256, kernel_size = (3,3), activation=\"relu\"))\nmodel.add(MaxPooling2D(pool_size=(2,2)))\nmodel.add(BatchNormalization())\n    \nmodel.add(Flatten())\nmodel.add(Dense(512,activation=\"relu\"))\n    \nmodel.add(Dense(10,activation=\"softmax\"))\n    \nmodel.compile(loss=\"categorical_crossentropy\", optimizer=\"adam\", metrics=[\"accuracy\"])","metadata":{"_uuid":"e935c979b0715a68bc8739e6a31f5d9a8189a750","execution":{"iopub.status.busy":"2024-03-31T13:20:08.453050Z","iopub.execute_input":"2024-03-31T13:20:08.453327Z","iopub.status.idle":"2024-03-31T13:20:10.888772Z","shell.execute_reply.started":"2024-03-31T13:20:08.453279Z","shell.execute_reply":"2024-03-31T13:20:10.888129Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.summary()","metadata":{"execution":{"iopub.status.busy":"2024-03-31T13:20:10.890017Z","iopub.execute_input":"2024-03-31T13:20:10.890295Z","iopub.status.idle":"2024-03-31T13:20:10.897532Z","shell.execute_reply.started":"2024-03-31T13:20:10.890250Z","shell.execute_reply":"2024-03-31T13:20:10.896818Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 3.2 Data augmentation","metadata":{}},{"cell_type":"markdown","source":"In order to avoid overfitting problem, we need to expand artificially our handwritten digit dataset. We can make your existing dataset even larger. The idea is to alter the training data with small transformations to reproduce the variations occuring when someone is writing a digit.\n\nFor example, the number is not centered \nThe scale is not the same (some who write with big/small numbers)\nThe image is rotated...\n\nApproaches that alter the training data in ways that change the array representation while keeping the label the same are known as data augmentation techniques. Some popular augmentations people use are grayscales, horizontal flips, vertical flips, random crops, color jitters, translations, rotations, and much more. \n\nBy applying just a couple of these transformations to our training data, we can easily double or triple the number of training examples and create a very robust model.\n\nThe improvement is important : \n   - Without data augmentation i obtained an accuracy of 98.114%\n   - With data augmentation i achieved 99.67% of accuracy","metadata":{}},{"cell_type":"code","source":"# With data augmentation to prevent overfitting\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=15,  # randomly rotate images in the range (degrees, 0 to 180)\n        zoom_range = 0.01, # 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\n#datagen.fit(X_train)\ntrain_gen = datagen.flow(X_train, y_train, batch_size=128)\ntest_gen = datagen.flow(X_test, y_test, batch_size=128)","metadata":{"execution":{"iopub.status.busy":"2024-03-31T13:20:10.898821Z","iopub.execute_input":"2024-03-31T13:20:10.899138Z","iopub.status.idle":"2024-03-31T13:20:11.009237Z","shell.execute_reply.started":"2024-03-31T13:20:10.899085Z","shell.execute_reply":"2024-03-31T13:20:11.008521Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"For the data augmentation, i choosed to :\n   - Randomly rotate some training images by 10 degrees\n   - Randomly  Zoom by 10% some training images\n   - Randomly shift images horizontally by 10% of the width\n   - Randomly shift images vertically by 10% of the height\n   \n**I did not apply a vertical_flip nor horizontal_flip since it could have lead to misclassify symetrical numbers such as 6 and 9.**\n\nOnce our model is ready, we fit the training dataset .","metadata":{}},{"cell_type":"markdown","source":"## 3.3 Model training","metadata":{"_uuid":"5a9a1f37ef33b24887f97e7992b7d24567602eb8"}},{"cell_type":"code","source":"# This make accuarcy 0.998\n#model.fit(X, y, batch_size=batch_size, validation_split=0.2, epochs=10)","metadata":{"execution":{"iopub.status.busy":"2024-03-31T13:20:11.010619Z","iopub.execute_input":"2024-03-31T13:20:11.010855Z","iopub.status.idle":"2024-03-31T13:20:11.013912Z","shell.execute_reply.started":"2024-03-31T13:20:11.010815Z","shell.execute_reply":"2024-03-31T13:20:11.013231Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Drive training phase\n**EarlyStoping**: Stop training when a monitored metric has stopped improving.\n\n**ReduceLROnPlateau**: Reduce learning rate when a metric has stopped improving.","metadata":{}},{"cell_type":"code","source":"epochs = 100\nbatch_size = 128\ntrain_steps = X_train.shape[0] // batch_size\nvalid_steps = X_test.shape[0] // batch_size\n\nes = keras.callbacks.EarlyStopping(\n        monitor=\"val_acc\", # metrics to monitor\n        patience=10, # how many epochs before stop\n        verbose=1,\n        mode=\"max\", # we need the maximum accuracy.\n        restore_best_weights=True, # \n     )\n\nrp = keras.callbacks.ReduceLROnPlateau(\n        monitor=\"val_acc\",\n        factor=0.2,\n        patience=3,\n        verbose=1,\n        mode=\"max\",\n        min_lr=0.00001,\n     )","metadata":{"execution":{"iopub.status.busy":"2024-03-31T13:20:11.015596Z","iopub.execute_input":"2024-03-31T13:20:11.015919Z","iopub.status.idle":"2024-03-31T13:20:11.025281Z","shell.execute_reply.started":"2024-03-31T13:20:11.015859Z","shell.execute_reply":"2024-03-31T13:20:11.024503Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Fit the model\nhistory = model.fit_generator(train_gen, \n                              epochs = epochs, \n                              steps_per_epoch = train_steps,\n                              validation_data = test_gen,\n                              validation_steps = valid_steps, \n                              callbacks=[es, rp])","metadata":{"execution":{"iopub.status.busy":"2024-03-31T13:20:11.026501Z","iopub.execute_input":"2024-03-31T13:20:11.026765Z","iopub.status.idle":"2024-03-31T13:25:59.733499Z","shell.execute_reply.started":"2024-03-31T13:20:11.026718Z","shell.execute_reply":"2024-03-31T13:25:59.731808Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Plot CNN model**","metadata":{}},{"cell_type":"code","source":"from keras.utils.vis_utils import plot_model\nplot_model(model, to_file='CNN_model_arch.png', show_shapes=True, show_layer_names=True)","metadata":{"execution":{"iopub.status.busy":"2024-03-31T13:25:59.735577Z","iopub.execute_input":"2024-03-31T13:25:59.735838Z","iopub.status.idle":"2024-03-31T13:26:00.996264Z","shell.execute_reply.started":"2024-03-31T13:25:59.735788Z","shell.execute_reply":"2024-03-31T13:26:00.995204Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 4. Evaluate the model\n## 4.1 Training and validation curves","metadata":{}},{"cell_type":"code","source":"# Plot the loss and accuracy curves for training and validation \nfig, ax = plt.subplots(2,1, figsize=(18, 10))\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)","metadata":{"execution":{"iopub.status.busy":"2024-03-31T13:26:00.998068Z","iopub.execute_input":"2024-03-31T13:26:00.998318Z","iopub.status.idle":"2024-03-31T13:26:01.692157Z","shell.execute_reply.started":"2024-03-31T13:26:00.998277Z","shell.execute_reply":"2024-03-31T13:26:01.691033Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 4.2 Confusion matrix","metadata":{}},{"cell_type":"markdown","source":"Confusion matrix can be very helpfull to see your model drawbacks.\n\nI plot the confusion matrix of the validation results.","metadata":{}},{"cell_type":"code","source":"fig = plt.figure(figsize=(10, 10)) # Set Figure\n\ny_pred = model.predict(X_test) # Predict class probabilities as 2 => [0.1, 0, 0.9, 0, 0, 0, 0, 0, 0, 0]\n\nY_pred = np.argmax(y_pred, 1) # Decode Predicted labels\nY_test = np.argmax(y_test, 1) # Decode labels\n\nmat = confusion_matrix(Y_test, Y_pred) # Confusion matrix\n\n# Plot Confusion matrix\nsns.heatmap(mat.T, square=True, annot=True, cbar=False, cmap=plt.cm.Blues, fmt='.0f')\nplt.xlabel('Predicted Values')\nplt.ylabel('True Values');\nplt.show();","metadata":{"execution":{"iopub.status.busy":"2024-03-31T13:26:01.694021Z","iopub.execute_input":"2024-03-31T13:26:01.694702Z","iopub.status.idle":"2024-03-31T13:26:02.729955Z","shell.execute_reply.started":"2024-03-31T13:26:01.694619Z","shell.execute_reply":"2024-03-31T13:26:02.729049Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 5. Prediction and submition","metadata":{}},{"cell_type":"markdown","source":"## 5.1 Prediction validation results","metadata":{}},{"cell_type":"code","source":"y_pred = model.predict(X_test)\nX_test__ = X_test.reshape(X_test.shape[0], 28, 28)\n\nfig, axis = plt.subplots(4, 4, figsize=(12, 14))\nfor i, ax in enumerate(axis.flat):\n    ax.imshow(X_test__[i], cmap='binary')\n    ax.set(title = f\"Real Number is {y_test[i].argmax()}\\nPredict Number is {y_pred[i].argmax()}\");","metadata":{"execution":{"iopub.status.busy":"2024-03-31T13:26:02.731402Z","iopub.execute_input":"2024-03-31T13:26:02.731675Z","iopub.status.idle":"2024-03-31T13:26:04.945105Z","shell.execute_reply.started":"2024-03-31T13:26:02.731623Z","shell.execute_reply":"2024-03-31T13:26:04.944222Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 5.2 Submition","metadata":{}},{"cell_type":"markdown","source":"**Prediciting test classes**","metadata":{"_uuid":"9949d758f73153835902ba3c87907fee7cfedaa1"}},{"cell_type":"code","source":"# Preprocess test data\ntest_x = test.values\ntest_x = test_x / 255.0\ntest_x = test_x.reshape(-1,28,28,1)\n\n# Predict test data\npred = model.predict_classes(test_x, verbose=1)","metadata":{"_uuid":"afcacfa4a023a9e01a61b5d7dcd051f0a439fa38","execution":{"iopub.status.busy":"2024-03-31T13:26:04.946661Z","iopub.execute_input":"2024-03-31T13:26:04.947244Z","iopub.status.idle":"2024-03-31T13:26:06.620121Z","shell.execute_reply.started":"2024-03-31T13:26:04.947189Z","shell.execute_reply":"2024-03-31T13:26:06.619393Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Submission\nsub['Label'] = pred\nsub.to_csv(\"CNN_keras_sub.csv\", index=False)\nsub.head()","metadata":{"execution":{"iopub.status.busy":"2024-03-31T13:26:06.621463Z","iopub.execute_input":"2024-03-31T13:26:06.621777Z","iopub.status.idle":"2024-03-31T13:26:06.934623Z","shell.execute_reply.started":"2024-03-31T13:26:06.621722Z","shell.execute_reply":"2024-03-31T13:26:06.933810Z"},"trusted":true},"execution_count":null,"outputs":[]}]}