{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","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":31089,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n%matplotlib inline\nfrom keras.utils import to_categorical\nfrom sklearn.model_selection import train_test_split\nimport tensorflow as tf\nfrom keras.layers import Conv2D, MaxPooling2D, Dropout, Flatten, Dense\nfrom keras.optimizers import RMSprop\nfrom keras.callbacks import ReduceLROnPlateau\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nimport numpy as np","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-08-06T00:27:59.519342Z","iopub.execute_input":"2025-08-06T00:27:59.519812Z","iopub.status.idle":"2025-08-06T00:27:59.526608Z","shell.execute_reply.started":"2025-08-06T00:27:59.519778Z","shell.execute_reply":"2025-08-06T00:27:59.525944Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Data Preparation","metadata":{}},{"cell_type":"code","source":"train = pd.read_csv(\"/kaggle/input/digit-recognizer/train.csv\")\ntest = pd.read_csv(\"/kaggle/input/digit-recognizer/test.csv\")\ntrain","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-06T00:11:02.091176Z","iopub.execute_input":"2025-08-06T00:11:02.091857Z","iopub.status.idle":"2025-08-06T00:11:05.083717Z","shell.execute_reply.started":"2025-08-06T00:11:02.091832Z","shell.execute_reply":"2025-08-06T00:11:05.082794Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_label = train[\"label\"]\ntrain_pixels = train.drop(labels=[\"label\"], axis=1)\n\n# Free some space\ndel train\n\nprint(f\"train_pixels => {train_pixels.shape}\")\nprint(f\"train_label => {train_label.shape}\")\nprint(f\"test => {test.shape}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-06T00:11:07.107784Z","iopub.execute_input":"2025-08-06T00:11:07.108042Z","iopub.status.idle":"2025-08-06T00:11:07.193243Z","shell.execute_reply.started":"2025-08-06T00:11:07.108025Z","shell.execute_reply":"2025-08-06T00:11:07.192414Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Exploration","metadata":{}},{"cell_type":"code","source":"sns.set(style='white', context='notebook', palette='deep')\ng = sns.countplot(x=train_label)\nplt.title(\"Distribution of MNIST Training Labels\")\nplt.show()\n\ntrain_label.value_counts()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-06T00:11:09.979067Z","iopub.execute_input":"2025-08-06T00:11:09.979376Z","iopub.status.idle":"2025-08-06T00:11:10.196563Z","shell.execute_reply.started":"2025-08-06T00:11:09.979355Z","shell.execute_reply":"2025-08-06T00:11:10.195576Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"We have similar counts for the 10 digits.","metadata":{}},{"cell_type":"markdown","source":"### Normalize and Reshape the Data","metadata":{}},{"cell_type":"code","source":"# Normalization\ntrain_pixels = train_pixels / 255.0\ntest = test / 255.0\n\n# Reshape\ntrain_pixels = train_pixels.values.reshape(-1, 28, 28, 1)\ntest = test.values.reshape(-1, 28, 28, 1)\nprint(f\"train_pixels => {train_pixels.shape}\")\nprint(f\"test => {test.shape}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-06T00:11:14.297788Z","iopub.execute_input":"2025-08-06T00:11:14.298463Z","iopub.status.idle":"2025-08-06T00:11:14.394384Z","shell.execute_reply.started":"2025-08-06T00:11:14.298438Z","shell.execute_reply":"2025-08-06T00:11:14.393692Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Visualization","metadata":{}},{"cell_type":"code","source":"# Some examples\nplt.figure(figsize=(6, 3))  # Create a figure with appropriate size\n\n# First digit\nplt.subplot(1, 2, 1)\nplt.imshow(train_pixels[45][:, :, 0], cmap=\"gray\")\nplt.title(f\"Label: {train_label[45]}\")\nplt.axis('off')  # Turn off axis for cleaner display\n\n# Second digit\nplt.subplot(1, 2, 2)\nplt.imshow(train_pixels[81][:, :, 0], cmap=\"gray\")\nplt.title(f\"Label: {train_label[81]}\")\nplt.axis('off')\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-06T00:11:16.438482Z","iopub.execute_input":"2025-08-06T00:11:16.438888Z","iopub.status.idle":"2025-08-06T00:11:16.688785Z","shell.execute_reply.started":"2025-08-06T00:11:16.438862Z","shell.execute_reply":"2025-08-06T00:11:16.687913Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Label Encoding","metadata":{}},{"cell_type":"code","source":"train_label_cat = to_categorical(train_label, num_classes=10)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-06T00:11:18.662543Z","iopub.execute_input":"2025-08-06T00:11:18.663188Z","iopub.status.idle":"2025-08-06T00:11:18.668071Z","shell.execute_reply.started":"2025-08-06T00:11:18.663158Z","shell.execute_reply":"2025-08-06T00:11:18.667239Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Train, Dev, Test sets Distribution","metadata":{}},{"cell_type":"code","source":"X_train, X_valid, y_train, y_valid = train_test_split(train_pixels, train_label_cat, test_size=0.1, random_state=42)\nprint(X_valid.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-06T00:11:20.914846Z","iopub.execute_input":"2025-08-06T00:11:20.915138Z","iopub.status.idle":"2025-08-06T00:11:21.299489Z","shell.execute_reply.started":"2025-08-06T00:11:20.915119Z","shell.execute_reply":"2025-08-06T00:11:21.298773Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## CNN - Define the Model","metadata":{}},{"cell_type":"code","source":"model = tf.keras.Sequential([\n    Conv2D(filters=32, kernel_size=(5, 5), padding='same', activation='relu', input_shape=(28,28,1)),\n    Conv2D(filters=32, kernel_size=(5, 5), padding=\"same\", activation=\"relu\"),\n    MaxPooling2D(pool_size=(2, 2)),\n    Conv2D(filters=64, kernel_size=(3, 3), padding=\"same\", activation=\"relu\"),\n    Conv2D(filters=64, kernel_size=(3, 3), padding=\"same\", activation=\"relu\"),\n    MaxPooling2D(pool_size=(2, 2), strides=(2, 2)),\n    Dropout(0.25),\n    Flatten(),\n    Dense(units=256, activation=\"relu\"),\n    Dropout(0.5),\n    Dense(units=10, activation=\"softmax\")\n])\nmodel.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-06T00:11:35.072375Z","iopub.execute_input":"2025-08-06T00:11:35.073288Z","iopub.status.idle":"2025-08-06T00:11:35.144273Z","shell.execute_reply.started":"2025-08-06T00:11:35.073250Z","shell.execute_reply":"2025-08-06T00:11:35.143481Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Define the optimizer\noptimizer = RMSprop(learning_rate=0.001, rho=0.9, epsilon=1e-08, decay=0.0)\n\n# Compile the model\nmodel.compile(optimizer=optimizer, loss=\"categorical_crossentropy\", metrics=[\"accuracy\"])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-06T00:11:40.288894Z","iopub.execute_input":"2025-08-06T00:11:40.289457Z","iopub.status.idle":"2025-08-06T00:11:40.298785Z","shell.execute_reply.started":"2025-08-06T00:11:40.289429Z","shell.execute_reply":"2025-08-06T00:11:40.297835Z"}},"outputs":[],"execution_count":null},{"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)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-06T00:11:41.600326Z","iopub.execute_input":"2025-08-06T00:11:41.600647Z","iopub.status.idle":"2025-08-06T00:11:41.604885Z","shell.execute_reply.started":"2025-08-06T00:11:41.600615Z","shell.execute_reply":"2025-08-06T00:11:41.604125Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"history = model.fit(X_train, y_train, batch_size=86, epochs=2, validation_data=(X_valid, y_valid))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-06T00:11:48.279681Z","iopub.execute_input":"2025-08-06T00:11:48.279979Z","iopub.status.idle":"2025-08-06T00:11:59.930617Z","shell.execute_reply.started":"2025-08-06T00:11:48.279958Z","shell.execute_reply":"2025-08-06T00:11:59.930012Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Data Augmentation\nAs, MNIST dataset is small we should use Data Augmentation as Regularization","metadata":{}},{"cell_type":"code","source":"datagen = 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)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-06T00:23:57.278333Z","iopub.execute_input":"2025-08-06T00:23:57.278681Z","iopub.status.idle":"2025-08-06T00:23:57.374987Z","shell.execute_reply.started":"2025-08-06T00:23:57.278658Z","shell.execute_reply":"2025-08-06T00:23:57.374330Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"history = model.fit(datagen.flow(X_train, y_train, batch_size=86), epochs=15, validation_data=(X_valid, y_valid), steps_per_epoch=X_train.shape[0] // 86, callbacks=[learning_rate_reduction])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-06T00:23:57.794955Z","iopub.execute_input":"2025-08-06T00:23:57.795252Z","iopub.status.idle":"2025-08-06T00:24:56.837636Z","shell.execute_reply.started":"2025-08-06T00:23:57.795233Z","shell.execute_reply":"2025-08-06T00:24:56.836789Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Training and Evaluation","metadata":{}},{"cell_type":"code","source":"fig, 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['accuracy'], color='b', label=\"Training accuracy\")\nax[1].plot(history.history['val_accuracy'], color='r',label=\"Validation accuracy\")\nlegend = ax[1].legend(loc='best', shadow=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-06T00:25:33.568977Z","iopub.execute_input":"2025-08-06T00:25:33.569263Z","iopub.status.idle":"2025-08-06T00:25:33.980011Z","shell.execute_reply.started":"2025-08-06T00:25:33.569246Z","shell.execute_reply":"2025-08-06T00:25:33.979265Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Explore the Errors","metadata":{}},{"cell_type":"code","source":"Y_pred = model.predict(X_valid)\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_valid,axis = 1)\n\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_valid[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)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-06T00:29:24.916934Z","iopub.execute_input":"2025-08-06T00:29:24.917629Z","iopub.status.idle":"2025-08-06T00:29:26.162923Z","shell.execute_reply.started":"2025-08-06T00:29:24.917601Z","shell.execute_reply":"2025-08-06T00:29:26.162053Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Final Submission","metadata":{}},{"cell_type":"code","source":"results = model.predict(test)\nresults = np.argmax(results, axis=1)\n\nresults = pd.Series(results, name=\"Label\")\n\naak_submission = pd.concat([pd.Series(range(1, (test.shape[0]+1)),name = \"ImageId\"), results],axis = 1)\n\naak_submission.to_csv(\"aak_cnn_mnist_datagen.csv\",index=False)","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}