{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## Introduction\n\n<div style=\"text-align:center;\">\n    <img src=\"https://www.researchgate.net/profile/Steven-Young-5/publication/306056875/figure/fig1/AS:393921575309346@1470929630835/Example-images-from-the-MNIST-dataset.png\" alt=\"digit\">\n</div>\n\n\n\n\nDigit Recognizer 🤖📊 is the 'hello world' of data science. Furthermore, due to its practicality, it is excellent for elucidating basic concepts of Machine and Deep Learning. In this notebook, I will delve into what I've gleaned from the integrated courses on Coursera by DeepLearning.AI, specifically, 'TensorFlow Dev.' 🚀📚","metadata":{}},{"cell_type":"markdown","source":"## Import data and packages","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom sklearn.metrics import confusion_matrix\nfrom sklearn.metrics import ConfusionMatrixDisplay\nfrom sklearn.model_selection import train_test_split","metadata":{"execution":{"iopub.status.busy":"2023-11-01T20:03:53.656426Z","iopub.execute_input":"2023-11-01T20:03:53.657276Z","iopub.status.idle":"2023-11-01T20:03:53.663524Z","shell.execute_reply.started":"2023-11-01T20:03:53.657239Z","shell.execute_reply":"2023-11-01T20:03:53.662496Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test = pd.read_csv('/kaggle/input/digit-recognizer/test.csv')\ntrain = pd.read_csv('/kaggle/input/digit-recognizer/train.csv')","metadata":{"jupyter":{"source_hidden":true},"execution":{"iopub.status.busy":"2023-11-01T20:03:53.665622Z","iopub.execute_input":"2023-11-01T20:03:53.665912Z","iopub.status.idle":"2023-11-01T20:03:57.777333Z","shell.execute_reply.started":"2023-11-01T20:03:53.665871Z","shell.execute_reply":"2023-11-01T20:03:57.776268Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Target and features to array\ny_train = train['label'].values\nX_train = train.drop(columns='label').values\nX_test = test.values","metadata":{"execution":{"iopub.status.busy":"2023-11-01T20:03:57.778563Z","iopub.execute_input":"2023-11-01T20:03:57.778838Z","iopub.status.idle":"2023-11-01T20:03:57.861925Z","shell.execute_reply.started":"2023-11-01T20:03:57.778815Z","shell.execute_reply":"2023-11-01T20:03:57.860829Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Reshape and Normalization \n\n- Normalization is a data scaling process. It's evident that values range from 0 to 255 (justified by their grayscale scale), which can be problematic when dealing with deep learning model creation. Thus, reducing their range to [0, 1] is effective for improved performance. In various complex convolutional neural network scenarios, normalization will be necessary, so keep that in mind\n- Many activation functions, such as the \"relu\" function, work best when the input values are in the range 0 to 1. Normalizing the pixels to this range helps avoid saturation problems in the network layers and speeds up training\n- Adding the extra dimension (color channel) with size 1 lets the model know that it is working with grayscale images (one color channel). This extra dimension is important for convolution and other operations in convolutional neural networks (CNNs), which are common in image processing tasks.\n","metadata":{}},{"cell_type":"code","source":"def reshape_and_normalize(images):\n    # Normalize pixel values\n    images = images/max(images[0])\n    \n    # Reshape the images to add an extra dimension\n    images = images.reshape(-1, 28, 28, 1)\n  \n    return images","metadata":{"execution":{"iopub.status.busy":"2023-11-01T20:03:57.864428Z","iopub.execute_input":"2023-11-01T20:03:57.864748Z","iopub.status.idle":"2023-11-01T20:03:57.872889Z","shell.execute_reply.started":"2023-11-01T20:03:57.864721Z","shell.execute_reply":"2023-11-01T20:03:57.872062Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Normalize\nX_train = reshape_and_normalize(X_train)\nX_test = reshape_and_normalize(X_test)\n\nprint(f\"Maximum pixel value after normalization: {np.max(X_train)}\\n\")\nprint(f\"Shape of training set after reshaping: {X_train.shape}\\n\")\nprint(f\"Shape of one image after reshaping: {X_train[0].shape}\")","metadata":{"execution":{"iopub.status.busy":"2023-11-01T20:03:57.873939Z","iopub.execute_input":"2023-11-01T20:03:57.874201Z","iopub.status.idle":"2023-11-01T20:03:58.075193Z","shell.execute_reply.started":"2023-11-01T20:03:57.874178Z","shell.execute_reply":"2023-11-01T20:03:58.074109Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Callback\n\nA callback is a programming mechanism that allows you to specify what should happen after the completion of a certain  task, without blocking the flow of program execution.\n\n- Callbacks allow you to monitor your model's training progress in real time\n- The EarlyStopping callback is used to stop training the model as soon as a stop criterion is reached","metadata":{}},{"cell_type":"code","source":"class myCallback(tf.keras.callbacks.Callback):\n    def on_epoch_end(self, epoch, logs={}):\n            \n        if logs.get('accuracy') is not None and logs.get('accuracy') > 0.999:                 \n            print(\"\\nReached 99% accuracy so cancelling training!\")\n            self.model.stop_training = True","metadata":{"execution":{"iopub.status.busy":"2023-11-01T20:03:58.076263Z","iopub.execute_input":"2023-11-01T20:03:58.076536Z","iopub.status.idle":"2023-11-01T20:03:58.081928Z","shell.execute_reply.started":"2023-11-01T20:03:58.076513Z","shell.execute_reply":"2023-11-01T20:03:58.081015Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Split train and test set","metadata":{}},{"cell_type":"code","source":"X_train,X_val,y_train,y_val = train_test_split(X_train,y_train,test_size=0.1,\n                                                random_state = 2)","metadata":{"execution":{"iopub.status.busy":"2023-11-01T20:03:58.083098Z","iopub.execute_input":"2023-11-01T20:03:58.084415Z","iopub.status.idle":"2023-11-01T20:03:58.458340Z","shell.execute_reply.started":"2023-11-01T20:03:58.084388Z","shell.execute_reply":"2023-11-01T20:03:58.457262Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Neural Network\n\n<div style=\"text-align:center;\">\n    <img src=\"https://camo.githubusercontent.com/521578c8e820dc0f662ea03366138a6e0468bf8cb1a4b2286024a0d0b524d54b/68747470733a2f2f6d6c34612e6769746875622e696f2f696d616765732f666967757265732f6d6e6973742d696e7075742e706e67\" alt=\"digit\">\n</div>\n\n\n\n\n\nThe neural network model used for this challenge is an artificial neural network (ANN) of the sequential type, made up of three main layers: a flattening layer (`Flatten`), a hidden dense layer (`Dense` with ReLU activation), and an output dense layer (`Dense` with Softmax activation). Let's understand each part and how the network works:\n\n1. **Flattening Layer:**\n   - This layer is responsible for converting the input, which is a two-dimensional image (28x28 pixels), into a one-dimensional vector of 784 elements. It \"flattens\" the structure of the image so that it can be processed by the subsequent dense layers.\n\n2. **Hidden Dense Layer (`Dense` with ReLU activation):**\n   - This is a fully connected (dense) layer with 128 neural units. Each unit in this layer is connected to each unit in the flattening layer. The ReLU (Rectified Linear Unit) activation function is applied to each output of this layer. The ReLU function is non-linear and introduces non-linearities into the network, allowing it to learn complex representations of the data.\n   - The ReLU (Rectified Linear Unit) function is a common activation function in neural networks. It acts as a \"switch\" that keeps positive values unchanged and turns negative values into zero. Mathematically, the ReLU function is defined as $\\mathrm{ReLU}(z) = \\max(z, 0)$. This makes it a popular choice due to its non-linearity, allowing neural networks to learn complex representations of data.\n   \n$$\n\\mathbf{a} = \\mathrm{ReLU}\\big((W^{(0)})^{\\top}\\mathbf{x} + \\mathbf{b}\\big)\n$$\n\n3. **Dense Output Layer (`Dense` with Softmax activation):**\n   - This is the final layer of the neural network, and its output is used for multi-class classification. It consists of 10 neural units, each representing a possible class. Softmax activation is applied to these outputs. The Softmax function converts the outputs into a probability distribution, where each value represents the probability of belonging to a specific class. The sum of all probabilities is equal to 1.\n   - In the last layer of the neural network, softmax activation is used. In simpler terms, this means that as the network passes through the final layer, it generates a probability distribution for the output class. The probability that input xx belongs to class kk is calculated as:\n$$\nP\\big(y = k \\;| \\;\\mathbf{a}; W^{(1)}\\big) = \\sigma_k(\\mathbf{a}; W^{(1)}) := \\frac{\\exp\\big(\\boldsymbol{\\theta}^{\\top}_k \\mathbf{a} \\big)}\n{\\sum_{j=1}^K \\exp\\big(\\boldsymbol{\\theta}^{\\top}_j \\mathbf{a} \\big)}.\n$$\n\n    Here, $$\\boldsymbol{\\sigma}:= (\\sigma_1,\\dots, \\sigma_K)^{\\top}.$$ represents the probability distribution estimated by the model. Each σkσk is the probability that the input belongs to class kk. This distribution is obtained by considering the output of the hidden layer aa and using the weights $W^{(1)}$.\n\n - In short, softmax activation is used to transform the network outputs into a probability distribution over the possible classes. This allows the model to assign probabilities to each class, making it easier to interpret and make decisions based on these probabilities. \n    \n4. **Model compilation**\n   - After defining the network architecture, the model is compiled using the `compile` method. Here are the main settings:\n      - `optimizer='adam'`: The Adam optimizer is used to adjust the weights of the network during training. Adam is an adaptive optimizer that automatically adjusts the learning rate.\n      - `loss='sparse_categorical_crossentropy'`: The `sparse_categorical_crossentropy` loss function is chosen to calculate the discrepancy between the model's predictions and the actual labels during training. This function is suitable for multi-class classification problems.\n      - `metrics=['accuracy']`: During training, accuracy is monitored as a metric to evaluate the model's performance.\n\nNow, with the model compiled, we can proceed to training using appropriate data sets. During training, the weights of the network are iteratively adjusted with the aim of minimizing the loss function, making the model's predictions more accurate. Once trained, the model can be used to make predictions on new data.","metadata":{}},{"cell_type":"code","source":"def tensor_simple_model(x_train, y_train, x_test, y_test):\n    \n    callbacks = myCallback()\n    \n    model = tf.keras.models.Sequential([\n        keras.layers.Flatten(input_shape=(28, 28)),  # Camada de achatamento para converter a imagem em um vetor\n        keras.layers.Dense(128, activation='relu'),  # Camada densa com ativação 'relu'\n        keras.layers.Dense(10, activation='softmax')  # Camada de saída com ativação 'softmax' para classificação multiclasse\n    ])\n    \n    # Compile the model\n    model.compile(optimizer='adam',                   \n                  loss='sparse_categorical_crossentropy',                   \n                  metrics=['accuracy'])     \n    \n    # Fit the model for 10 epochs adding the callbacks\n    \n    history = model.fit(x_train, y_train, epochs=10, callbacks=[callbacks], batch_size=64, validation_data=(x_test, y_test))\n    \n    return history, model","metadata":{"execution":{"iopub.status.busy":"2023-11-01T20:03:58.459651Z","iopub.execute_input":"2023-11-01T20:03:58.459982Z","iopub.status.idle":"2023-11-01T20:03:58.467088Z","shell.execute_reply.started":"2023-11-01T20:03:58.459956Z","shell.execute_reply":"2023-11-01T20:03:58.466128Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history, model = tensor_simple_model(X_train, y_train, X_val, y_val)","metadata":{"execution":{"iopub.status.busy":"2023-11-01T20:03:58.468286Z","iopub.execute_input":"2023-11-01T20:03:58.468639Z","iopub.status.idle":"2023-11-01T20:04:16.479617Z","shell.execute_reply.started":"2023-11-01T20:03:58.468612Z","shell.execute_reply":"2023-11-01T20:04:16.478751Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Plot Loss and Accuracy","metadata":{}},{"cell_type":"code","source":"def plot_history(history):\n\n    accuracy = history.history['accuracy']\n    val_accuracy = history.history['val_accuracy']\n    loss = history.history['loss']\n    val_loss = history.history['val_loss']\n    epochs = range(1, len(accuracy) + 1)\n\n    plt.figure(figsize=(12, 4))\n    plt.subplot(1, 2, 1)\n    plt.plot(epochs, accuracy, 'g', label='Train Accuracy')\n    plt.plot(epochs, val_accuracy, 'purple', label='Validation Accuracy')\n    plt.title('Train and Validation Acurracy')\n    plt.xlabel('Epochs')\n    plt.ylabel('Accuracy')\n    plt.legend()\n\n    plt.subplot(1, 2, 2)\n    plt.plot(epochs, loss, 'g', label='Train Loss')\n    plt.plot(epochs, val_loss, 'purple', label='Validation Loss')\n    plt.title('Train and Validation Loss')\n    plt.xlabel('Epochs')\n    plt.ylabel('Loss')\n    plt.legend()\n\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2023-11-01T20:04:16.484215Z","iopub.execute_input":"2023-11-01T20:04:16.484574Z","iopub.status.idle":"2023-11-01T20:04:16.493031Z","shell.execute_reply.started":"2023-11-01T20:04:16.484549Z","shell.execute_reply":"2023-11-01T20:04:16.491963Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_history(history)","metadata":{"execution":{"iopub.status.busy":"2023-11-01T20:04:16.494250Z","iopub.execute_input":"2023-11-01T20:04:16.494583Z","iopub.status.idle":"2023-11-01T20:04:17.052355Z","shell.execute_reply.started":"2023-11-01T20:04:16.494552Z","shell.execute_reply":"2023-11-01T20:04:17.051405Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Predictions\ny_pred = model.predict(X_val)\ny_pred_classes = np.argmax(y_pred, axis=1)\nlabels = range(10)","metadata":{"execution":{"iopub.status.busy":"2023-11-01T20:04:17.053608Z","iopub.execute_input":"2023-11-01T20:04:17.053880Z","iopub.status.idle":"2023-11-01T20:04:17.368648Z","shell.execute_reply.started":"2023-11-01T20:04:17.053857Z","shell.execute_reply":"2023-11-01T20:04:17.367834Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def plot_confusion_matrix(y_true, y_pred, labels, title='Confusion Matrix'):\n\n    confusion = confusion_matrix(y_true, y_pred)\n\n    plt.figure(figsize=(10, 8))\n    sns.set(font_scale=1.2) \n    sns.set_style(\"white\")\n\n    disp = ConfusionMatrixDisplay(confusion, display_labels=labels)\n    disp.plot(cmap='gray', values_format='d')  \n    plt.title(title)\n    \n    plt.tight_layout()\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2023-11-01T20:04:17.369742Z","iopub.execute_input":"2023-11-01T20:04:17.370051Z","iopub.status.idle":"2023-11-01T20:04:17.376133Z","shell.execute_reply.started":"2023-11-01T20:04:17.370019Z","shell.execute_reply":"2023-11-01T20:04:17.375197Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_confusion_matrix(y_val, y_pred_classes, labels)","metadata":{"execution":{"iopub.status.busy":"2023-11-01T20:04:17.377661Z","iopub.execute_input":"2023-11-01T20:04:17.378122Z","iopub.status.idle":"2023-11-01T20:04:18.033560Z","shell.execute_reply.started":"2023-11-01T20:04:17.378090Z","shell.execute_reply":"2023-11-01T20:04:18.032606Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def display_top_errors(X_val, Y_pred, Y_true, Y_pred_classes, num_errors=6):\n    errors = (Y_pred_classes - Y_true != 0)\n    errors_index = np.where(errors)[0]\n    \n    Y_pred_classes_errors = Y_pred_classes[errors]\n    Y_pred_errors = Y_pred[errors]\n    Y_true_errors = Y_true[errors]\n    X_val_errors = X_val[errors]\n    \n    def display_errors(errors_index, img_errors, pred_errors, obs_errors):\n        nrows = 2\n        ncols = 3\n        fig, ax = plt.subplots(nrows, ncols, sharex=True, sharey=True, figsize=(12, 8))\n        n = 0\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)))  # Correção aqui\n                ax[row, col].set_title(\"Predicted label :{}\\nTrue label :{}\".format(pred_errors[error], obs_errors[error]))\n                n += 1\n        plt.show()\n\n    Y_pred_errors_prob = np.max(Y_pred_errors, axis=1)\n    true_prob_errors = np.diagonal(np.take(Y_pred_errors, Y_true_errors, axis=1))\n    delta_pred_true_errors = Y_pred_errors_prob - true_prob_errors\n    sorted_dela_errors = np.argsort(delta_pred_true_errors)\n    most_important_errors = sorted_dela_errors[-num_errors:]\n\n    display_errors(most_important_errors, X_val_errors, Y_pred_classes_errors, Y_true_errors)","metadata":{"execution":{"iopub.status.busy":"2023-11-01T20:04:18.035065Z","iopub.execute_input":"2023-11-01T20:04:18.035737Z","iopub.status.idle":"2023-11-01T20:04:18.045568Z","shell.execute_reply.started":"2023-11-01T20:04:18.035701Z","shell.execute_reply":"2023-11-01T20:04:18.044572Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"display_top_errors(X_val, y_pred, y_val, y_pred_classes)","metadata":{"execution":{"iopub.status.busy":"2023-11-01T20:04:18.046855Z","iopub.execute_input":"2023-11-01T20:04:18.047154Z","iopub.status.idle":"2023-11-01T20:04:19.207816Z","shell.execute_reply.started":"2023-11-01T20:04:18.047130Z","shell.execute_reply":"2023-11-01T20:04:19.206888Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Convolutional Neural Networks\n\n- Could we close here and submit? Yes. My place would be around 1029. However, we know that there is more to be done with Convolutional Neural Networks. Convolutional networks, or CNNs, are a type of neural network architecture designed primarily for processing images and data with spatial structure.\n\n- The convolution operation is the cornerstone of CNNs. It involves applying a filter (also called a kernel) to a local region of input data (for example, a part of the image). The convolution operation is defined as:\n$$\nS(i, j) = (I * K)(i, j) = \\sum_m \\sum_n I(i - m, j - n) K(m, n)\n$$\n\nwhere, $S(i,j)S(i,j)$ is the resulting value, $I$ is the input, $K$ is the filter and $\\sum$ represents the sum over all possible filter positions.\n\n- Pooling layers are used to reduce the dimensionality of the data while retaining the most important features. The pooling operation is often the average or maximum of a group of values in the input. For max pooling, it is defined as:\n$$\nO(i, j) = \\max_{m, n} (I(s \\cdot i + m, s \\cdot j + n)) \n$$\n\nwhere $(O(i, j)$ is the output, $I$ is the input, $max$ denotes the maximum, $m$ and $n$ are indices in the pooling dimensions, and $s$ is the step size.\n\n\n<div style=\"text-align:center;\">\n    <img src=\"https://www.researchgate.net/profile/Woongje-Sung/publication/322160320/figure/fig4/AS:631646000779331@1527607550865/LeNet-59-CNN-for-handwritten-digit-recognition-task.png\" alt=\"digit\">\n</div>\n\n","metadata":{}},{"cell_type":"code","source":"def augmented_convolutional_model():\n    model = tf.keras.models.Sequential([\n        tf.keras.layers.Conv2D(32, (5, 5), padding='same', activation='relu', input_shape=(28, 28, 1)),\n        tf.keras.layers.Conv2D(32, (5, 5), padding='same', activation='relu'),\n        tf.keras.layers.MaxPooling2D(2, 2),\n        tf.keras.layers.Dropout(0.25),\n        \n        tf.keras.layers.Conv2D(64, (5, 5), padding='same', activation='relu'),\n        tf.keras.layers.Conv2D(64, (5, 5), padding='same', activation='relu'),\n        tf.keras.layers.MaxPooling2D(2, 2),\n        tf.keras.layers.Dropout(0.25),\n        \n        tf.keras.layers.Flatten(),\n        tf.keras.layers.Dense(256, activation='relu'),\n        tf.keras.layers.Dense(10, activation='softmax')\n    ])\n\n    model.compile(optimizer='adam',\n                  loss='sparse_categorical_crossentropy',\n                  metrics=['accuracy'])\n\n    # Data augmentation\n    datagen = ImageDataGenerator(rotation_range=10, width_shift_range=0.1, height_shift_range=0.1, zoom_range=0.1)\n\n    return model, datagen","metadata":{"execution":{"iopub.status.busy":"2023-11-01T20:04:19.209335Z","iopub.execute_input":"2023-11-01T20:04:19.209610Z","iopub.status.idle":"2023-11-01T20:04:19.218535Z","shell.execute_reply.started":"2023-11-01T20:04:19.209584Z","shell.execute_reply":"2023-11-01T20:04:19.217544Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Save your untrained model\nmodel, datagen = augmented_convolutional_model()\n\n# Get number of weights\nmodel_params = model.count_params()\n\n# Unit test to limit the size of the model\nassert model_params < 1000000, (\n    f'Your model has {model_params:,} params. For successful grading, please keep it ' \n    f'under 1,000,000 by reducing the number of units in your Conv2D and/or Dense layers.'\n)\n\n# Instantiate the callback class\ncallbacks = myCallback()\n\n# Train your model (this can take up to 5 minutes)\nhistory = model.fit(datagen.flow(X_train, y_train), validation_data=(X_val, y_val), epochs=10)","metadata":{"execution":{"iopub.status.busy":"2023-11-01T20:04:19.220085Z","iopub.execute_input":"2023-11-01T20:04:19.220604Z","iopub.status.idle":"2023-11-01T20:06:36.611512Z","shell.execute_reply.started":"2023-11-01T20:04:19.220570Z","shell.execute_reply":"2023-11-01T20:06:36.610738Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_test_pred = model.predict(X_val)","metadata":{"execution":{"iopub.status.busy":"2023-11-01T20:06:36.612778Z","iopub.execute_input":"2023-11-01T20:06:36.613089Z","iopub.status.idle":"2023-11-01T20:06:37.006850Z","shell.execute_reply.started":"2023-11-01T20:06:36.613063Z","shell.execute_reply":"2023-11-01T20:06:37.005945Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_test_pred_classes = np.argmax(y_test_pred, axis=1)","metadata":{"execution":{"iopub.status.busy":"2023-11-01T20:06:37.008135Z","iopub.execute_input":"2023-11-01T20:06:37.008424Z","iopub.status.idle":"2023-11-01T20:06:37.012936Z","shell.execute_reply.started":"2023-11-01T20:06:37.008399Z","shell.execute_reply":"2023-11-01T20:06:37.011945Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_history(history)","metadata":{"execution":{"iopub.status.busy":"2023-11-01T20:06:37.013834Z","iopub.execute_input":"2023-11-01T20:06:37.014107Z","iopub.status.idle":"2023-11-01T20:06:37.619298Z","shell.execute_reply.started":"2023-11-01T20:06:37.014084Z","shell.execute_reply":"2023-11-01T20:06:37.618400Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_confusion_matrix(y_val, y_test_pred_classes, labels)","metadata":{"execution":{"iopub.status.busy":"2023-11-01T20:06:37.620536Z","iopub.execute_input":"2023-11-01T20:06:37.620926Z","iopub.status.idle":"2023-11-01T20:06:38.256698Z","shell.execute_reply.started":"2023-11-01T20:06:37.620873Z","shell.execute_reply":"2023-11-01T20:06:38.255768Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"display_top_errors(X_val, y_pred, y_val, y_pred_classes)","metadata":{"execution":{"iopub.status.busy":"2023-11-01T20:06:38.257717Z","iopub.execute_input":"2023-11-01T20:06:38.258001Z","iopub.status.idle":"2023-11-01T20:06:39.775409Z","shell.execute_reply.started":"2023-11-01T20:06:38.257976Z","shell.execute_reply":"2023-11-01T20:06:39.774412Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Submission","metadata":{}},{"cell_type":"code","source":"y_test_pred = model.predict(X_test)\ny_test_pred_classes = np.argmax(y_test_pred, axis=1)","metadata":{"execution":{"iopub.status.busy":"2023-11-01T20:06:39.776772Z","iopub.execute_input":"2023-11-01T20:06:39.777151Z","iopub.status.idle":"2023-11-01T20:06:41.948114Z","shell.execute_reply.started":"2023-11-01T20:06:39.777119Z","shell.execute_reply":"2023-11-01T20:06:41.947258Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission = pd.DataFrame({\n    \"ImageId\": np.arange(1, len(y_test_pred_classes) + 1),\n    \"Label\": y_test_pred_classes\n})\n\nsubmission.to_csv(\"submission.csv\", index=False)","metadata":{"execution":{"iopub.status.busy":"2023-11-01T20:06:41.949308Z","iopub.execute_input":"2023-11-01T20:06:41.949605Z","iopub.status.idle":"2023-11-01T20:06:42.010585Z","shell.execute_reply.started":"2023-11-01T20:06:41.949580Z","shell.execute_reply":"2023-11-01T20:06:42.009605Z"},"trusted":true},"execution_count":null,"outputs":[]}]}