{"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":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-06-25T10:24:12.906729Z","iopub.execute_input":"2023-06-25T10:24:12.907035Z","iopub.status.idle":"2023-06-25T10:24:12.916475Z","shell.execute_reply.started":"2023-06-25T10:24:12.907009Z","shell.execute_reply":"2023-06-25T10:24:12.915222Z"},"jupyter":{"source_hidden":true,"outputs_hidden":true},"collapsed":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Image Classification **(Tutorial)**","metadata":{}},{"cell_type":"markdown","source":"![](https://www.louisbouchard.ai/content/images/size/w2000/2021/04/1_QPRC1lcfYxcWWPAC2hrQgg.gif)","metadata":{}},{"cell_type":"markdown","source":"## Setup","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport matplotlib.pyplot as plt\nfrom tensorflow import keras\nfrom tensorflow.keras import layers","metadata":{"execution":{"iopub.status.busy":"2023-06-25T10:24:18.015162Z","iopub.execute_input":"2023-06-25T10:24:18.015521Z","iopub.status.idle":"2023-06-25T10:24:25.874248Z","shell.execute_reply.started":"2023-06-25T10:24:18.015493Z","shell.execute_reply":"2023-06-25T10:24:25.873230Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Loading the data","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')","metadata":{"execution":{"iopub.status.busy":"2023-06-25T10:24:27.756542Z","iopub.execute_input":"2023-06-25T10:24:27.757835Z","iopub.status.idle":"2023-06-25T10:24:33.481120Z","shell.execute_reply.started":"2023-06-25T10:24:27.757798Z","shell.execute_reply":"2023-06-25T10:24:33.480075Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"x_train = train.drop(['label'],axis=1).astype('float32')\ny_train = train['label'].astype('float32')\nx_test = test.astype('float32')","metadata":{"execution":{"iopub.status.busy":"2023-06-25T10:24:33.484111Z","iopub.execute_input":"2023-06-25T10:24:33.484481Z","iopub.status.idle":"2023-06-25T10:24:33.704829Z","shell.execute_reply.started":"2023-06-25T10:24:33.484447Z","shell.execute_reply":"2023-06-25T10:24:33.703365Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Exploring the Data","metadata":{}},{"cell_type":"code","source":"print(f\"We have {len(x_train)} images in the training set and {len(x_test)} images in the test set.\")","metadata":{"execution":{"iopub.status.busy":"2023-06-25T10:24:35.737924Z","iopub.execute_input":"2023-06-25T10:24:35.738691Z","iopub.status.idle":"2023-06-25T10:24:35.745013Z","shell.execute_reply.started":"2023-06-25T10:24:35.738635Z","shell.execute_reply":"2023-06-25T10:24:35.743738Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"x_train.shape","metadata":{"execution":{"iopub.status.busy":"2023-06-25T10:24:38.100242Z","iopub.execute_input":"2023-06-25T10:24:38.100633Z","iopub.status.idle":"2023-06-25T10:24:38.109631Z","shell.execute_reply.started":"2023-06-25T10:24:38.100599Z","shell.execute_reply":"2023-06-25T10:24:38.108290Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Pre-processing the Data","metadata":{}},{"cell_type":"code","source":"# Scale images to the [0, 1] range\nx_train = x_train / 255\nx_test = x_test / 255","metadata":{"execution":{"iopub.status.busy":"2023-06-25T10:24:52.799770Z","iopub.execute_input":"2023-06-25T10:24:52.800177Z","iopub.status.idle":"2023-06-25T10:24:52.932692Z","shell.execute_reply.started":"2023-06-25T10:24:52.800138Z","shell.execute_reply":"2023-06-25T10:24:52.931705Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"the dataset contains grayscale images represented as pixel values ranging from 0 to 255, where 0 represents black and 255 represents white. In order to prepare the data for training a machine learning model, it is common to normalize the pixel values to a range between 0 and 1. This normalization step helps in improving the performance and convergence of the model during training.","metadata":{}},{"cell_type":"code","source":"# Reshape x_train and x_test\nx_train = x_train.values.reshape(-1,28,28,1)\nx_test = x_test.values.reshape(-1,28,28,1)\nprint(\"x_train shape:\", x_train.shape)\nprint(x_train.shape[0], \"train samples\")\nprint(x_test.shape[0], \"test samples\")","metadata":{"execution":{"iopub.status.busy":"2023-06-25T10:24:58.742780Z","iopub.execute_input":"2023-06-25T10:24:58.743171Z","iopub.status.idle":"2023-06-25T10:24:58.749934Z","shell.execute_reply.started":"2023-06-25T10:24:58.743139Z","shell.execute_reply":"2023-06-25T10:24:58.748913Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"adding an extra dimension to the input image arrays x_train and x_test. This extra dimension represents the channel of the image and is necessary when working with convolutional neural networks (CNNs). It ensures compatibility with CNN models that expect input data in a specific format (height, width, channels). For grayscale images, the channel dimension is set to 1, and for color images, it is typically set to 3 for red, green, and blue channels.","metadata":{}},{"cell_type":"code","source":"num_classes = 10\ninput_shape = (28, 28, 1)\n\n# convert class vectors to binary class matrices\ny_train = keras.utils.to_categorical(y_train, num_classes)","metadata":{"execution":{"iopub.status.busy":"2023-06-25T10:25:16.203084Z","iopub.execute_input":"2023-06-25T10:25:16.203456Z","iopub.status.idle":"2023-06-25T10:25:16.212763Z","shell.execute_reply.started":"2023-06-25T10:25:16.203425Z","shell.execute_reply":"2023-06-25T10:25:16.211594Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"I performed one-hot encoding on the target class labels. One-hot encoding converts categorical labels into binary vectors, making them suitable for training machine learning models. Each label is transformed into a binary vector with a value of 1 in the corresponding index and 0 elsewhere. This encoding allows the model to interpret and learn from the categorical labels effectively.\n\n**example:**\n\nImagine you have a dataset of animal categories with their corresponding labels: \"dog,\" \"cat,\" and \"bird.\" The labels are currently represented as strings, which are not suitable for training a machine learning model directly.\n\nTo convert these categorical labels into a format suitable for training, you can use one-hot encoding. One-hot encoding converts each categorical label into a binary vector representation.\n\nHere is an example of the transformation:\n\nOriginal categorical labels: [\"dog\", \"cat\", \"bird\", \"dog\", \"cat\"]\n\nAfter one-hot encoding:\n\n* \"dog\" becomes [1, 0, 0]\n* \"cat\" becomes [0, 1, 0]\n* \"bird\" becomes [0, 0, 1]\n* \"dog\" becomes [1, 0, 0]\n* \"cat\" becomes [0, 1, 0]\n\nEach label is transformed into a binary vector of length 3, where the index corresponding to the label is set to 1, and all other indices are set to 0.","metadata":{}},{"cell_type":"markdown","source":"## Visualizing the Images","metadata":{}},{"cell_type":"code","source":"num_images = 10\nimages = x_train[:num_images]\nlabels = y_train[:num_images]\n\n# Create a grid of subplots to display the images\nfig, axes = plt.subplots(2, 5, figsize=(10, 5))\naxes = axes.flatten()\n\n# Iterate over the images and plot them\nfor i in range(num_images):\n    axes[i].imshow(images[i], cmap='gray')\n    axes[i].axis('off')\n    axes[i].set_title('Label: {}'.format(np.argmax(labels[i])))\n\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-06-25T10:35:42.296606Z","iopub.execute_input":"2023-06-25T10:35:42.297216Z","iopub.status.idle":"2023-06-25T10:35:43.192485Z","shell.execute_reply.started":"2023-06-25T10:35:42.297182Z","shell.execute_reply":"2023-06-25T10:35:43.191496Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Build the model","metadata":{}},{"cell_type":"code","source":"model = keras.Sequential(\n    [\n        keras.Input(shape=input_shape),\n        layers.Conv2D(32, kernel_size=(3, 3), activation=\"relu\"),\n        layers.MaxPooling2D(pool_size=(2, 2)),\n        layers.Conv2D(64, kernel_size=(3, 3), activation=\"relu\"),\n        layers.MaxPooling2D(pool_size=(2, 2)),\n        layers.Flatten(),\n        layers.Dropout(0.5),\n        layers.Dense(num_classes, activation=\"softmax\"),\n    ]\n)\n\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2023-06-25T10:25:17.373088Z","iopub.execute_input":"2023-06-25T10:25:17.373426Z","iopub.status.idle":"2023-06-25T10:25:21.287801Z","shell.execute_reply.started":"2023-06-25T10:25:17.373390Z","shell.execute_reply":"2023-06-25T10:25:21.287010Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Before explaining the code let's explain what is **CNN**?","metadata":{}},{"cell_type":"markdown","source":"Convolutional Neural Networks (**CNNs**) are a type of deep learning model specifically designed for processing and analyzing structured grid-like data, such as images and videos. They are particularly effective in tasks such as image classification, object detection, and image segmentation.\n\nThe key idea behind **CNNs** is to leverage the concept of convolution, which is a mathematical operation that combines two functions to produce a third function. In the context of **CNNs**, convolution is used to extract local patterns or features from input data. By applying convolution operations on different parts of an image, **CNNs** can learn to recognize hierarchical patterns and capture spatial relationships between pixels.\n\nA typical **CNN** architecture consists of several layers:\n\n**Convolutional Layers:** These layers are responsible for extracting features from the input data. They apply a set of learnable filters (also known as kernels) to the input image, computing convolutions and producing feature maps. Each filter specializes in detecting a specific pattern or feature in the input.\n\n![](https://cdn-images-1.medium.com/max/540/1*LjekzL7APOzgRajHh2Z8VQ.gif) \n![](https://cdn-images-1.medium.com/max/540/1*ulfFYH5HbWpLTIfuebj5mQ.gif)\n\n\n\n**Activation Layers:** After each convolutional layer, an activation function is applied element-wise to introduce non-linearity into the network. Common activation functions include ReLU (Rectified Linear Unit) and sigmoid.\n\n![](https://cdn-images-1.medium.com/max/540/1*0jrJkmWrGVmeccnRo8sImg.png)\n\n\n**Pooling Layers:** These layers downsample the feature maps by summarizing the information within local neighborhoods. The most commonly used pooling operation is max pooling, which selects the maximum value within each neighborhood. Pooling helps to reduce the spatial dimensions of the feature maps while retaining important features.\n\n![](https://cdn-images-1.medium.com/max/540/1*6u3QK9M9ZJws58P4SAr2AQ.png)\n\n\n**Fully Connected Layers:** These layers are typically placed after the convolutional and pooling layers to perform classification or regression tasks. They connect all the neurons from the previous layer to the current layer, enabling the network to learn complex relationships between features. The final fully connected layer usually outputs the predicted class probabilities.\n\n![](https://cdn-images-1.medium.com/max/720/1*ouVXhawebH0Qvx2_gcW8KA.png)\n\n\n\nIn addition to these core layers, CNN architectures can also incorporate other techniques such as dropout (to prevent overfitting), batch normalization (to normalize the inputs), and various optimization algorithms (e.g., gradient descent) to train the network.","metadata":{}},{"cell_type":"markdown","source":"### Now let's explain the code:","metadata":{}},{"cell_type":"markdown","source":"**model = keras.Sequential([...]):** This line initializes a sequential model, which is a linear stack of layers in Keras.\n\n**keras.Input(shape=input_shape):** This line defines the input layer of the model with a specified input shape. The input_shape parameter represents the shape of the input data, typically in the format (height, width, channels).\n\n**layers.Conv2D(32, kernel_size=(3, 3), activation=\"relu\"):** This line adds a convolutional layer to the model with 32 filters, each having a kernel size of (3, 3). The activation function used is the rectified linear unit (ReLU), which introduces non-linearity to the model.\n\n**layers.MaxPooling2D(pool_size=(2, 2)):** This line adds a max pooling layer to the model with a pooling window size of (2, 2). Max pooling helps reduce the spatial dimensions of the previous layer's output while retaining important features.\n\n**layers.Conv2D(64, kernel_size=(3, 3), activation=\"relu\"):** This line adds another convolutional layer to the model, but this time with 64 filters.\n\n**layers.MaxPooling2D(pool_size=(2, 2)):** Another max pooling layer is added to further reduce the spatial dimensions.\n\n**layers.Flatten():** This line adds a flattening layer to the model, which reshapes the output from the previous layer into a 1D vector. This is necessary to connect the convolutional layers to the fully connected layers.\n\n**layers.Dropout(0.5):** This line adds a dropout layer to the model, which randomly sets a fraction of input units to 0 during training. It helps prevent overfitting by introducing regularization.\n\n**layers.Dense(num_classes, activation=\"softmax\"):** This line adds a dense (fully connected) layer to the model with num_classes units. The activation function used is softmax, which generates probabilities for each class and is suitable for multi-class classification problems.","metadata":{}},{"cell_type":"markdown","source":"## Train the model","metadata":{}},{"cell_type":"code","source":"batch_size = 128\nepochs = 20\n\nmodel.compile(loss=\"categorical_crossentropy\", optimizer=\"adam\", metrics=[\"accuracy\"])\n\nmodel.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, validation_split=0.1)","metadata":{"execution":{"iopub.status.busy":"2023-06-25T10:25:21.288899Z","iopub.execute_input":"2023-06-25T10:25:21.289274Z","iopub.status.idle":"2023-06-25T10:26:03.447605Z","shell.execute_reply.started":"2023-06-25T10:25:21.289236Z","shell.execute_reply":"2023-06-25T10:26:03.446679Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Let's go through each line step by step:\n\n**batch_size = 128:** This line sets the batch size, which determines the number of samples processed by the model in each training iteration. A larger batch size can lead to faster training but requires more memory.\n\n**epochs = 15:** This line specifies the number of epochs, which represents the number of times the model will iterate over the entire training dataset during training.\n\n**model.compile(loss=\"categorical_crossentropy\", optimizer=\"adam\", metrics=[\"accuracy\"]):** This line compiles the model by configuring its learning process. The loss parameter is set to \"categorical_crossentropy\", which is a common choice for multi-class classification problems. The optimizer parameter is set to \"adam\", which is an efficient optimization algorithm. The metrics parameter specifies that we want to track and report the accuracy of the model during training.\n\n**model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, validation_split=0.1):** This line starts the training process of the model. The fit() method takes the input data x_train and the corresponding target labels y_train. It trains the model for the specified number of epochs using the specified batch size. The validation_split parameter specifies the fraction of the training data to be used as validation data during training for monitoring the model's performance.\n\nDuring the training process, the model learns to minimize the loss function (categorical cross-entropy) using the provided optimizer (Adam) by adjusting its internal parameters. The training progress is printed to the console, including information about the loss and accuracy on both the training and validation data.","metadata":{}},{"cell_type":"markdown","source":"## Visualize the predicted labels and images","metadata":{}},{"cell_type":"code","source":"predictions = model.predict(x_test)","metadata":{"execution":{"iopub.status.busy":"2023-06-25T10:26:03.449879Z","iopub.execute_input":"2023-06-25T10:26:03.450313Z","iopub.status.idle":"2023-06-25T10:26:05.922654Z","shell.execute_reply.started":"2023-06-25T10:26:03.450279Z","shell.execute_reply":"2023-06-25T10:26:05.921597Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"num_images = 10\n\nfig, axes = plt.subplots(2, 5, figsize=(10, 5))\naxes = axes.flatten()\n\nfor i in range(num_images):\n    # Get the predicted label with the highest probability\n    predicted_label = np.argmax(predictions[i])\n    \n    axes[i].imshow(x_test[i].reshape(28, 28), cmap='gray')\n    axes[i].axis('off')\n    axes[i].set_title('Predicted: {}'.format(predicted_label))\n\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-06-25T10:26:05.924078Z","iopub.execute_input":"2023-06-25T10:26:05.925201Z","iopub.status.idle":"2023-06-25T10:26:06.820506Z","shell.execute_reply.started":"2023-06-25T10:26:05.925164Z","shell.execute_reply":"2023-06-25T10:26:06.819570Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Submission","metadata":{}},{"cell_type":"code","source":"result=np.argmax(predictions,axis=1)\nresult=pd.Series(result,name='Label')\n\nsubmission=pd.concat([pd.Series(range(1,28001),name='ImageId'),result],axis=1)\nsubmission.to_csv('submission.csv',index=False)","metadata":{"execution":{"iopub.status.busy":"2023-06-25T10:26:06.821944Z","iopub.execute_input":"2023-06-25T10:26:06.822962Z","iopub.status.idle":"2023-06-25T10:26:06.888885Z","shell.execute_reply.started":"2023-06-25T10:26:06.822925Z","shell.execute_reply":"2023-06-25T10:26:06.887979Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Thanks! don't forget to Upvote this notebook :)","metadata":{}}]}