{"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":"# Importing the utils packages","metadata":{}},{"cell_type":"code","source":"import torch\nfrom torch.utils.data import DataLoader, TensorDataset\nimport torch.nn as nn, torch.nn.functional as F, torch.optim as optim\nfrom torch.autograd import Variable\nimport pandas as pd,numpy as np,matplotlib.pyplot as plt, os\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import confusion_matrix, accuracy_score\n%matplotlib inline","metadata":{"execution":{"iopub.status.busy":"2023-07-22T07:44:06.528246Z","iopub.execute_input":"2023-07-22T07:44:06.529261Z","iopub.status.idle":"2023-07-22T07:44:06.537750Z","shell.execute_reply.started":"2023-07-22T07:44:06.529220Z","shell.execute_reply":"2023-07-22T07:44:06.536601Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Set device to GPU or CPU based on availability","metadata":{}},{"cell_type":"code","source":"if torch.cuda.is_available():\n    device = torch.device('cuda')\nelse:\n    device = torch.device('cpu')\nprint(device)","metadata":{"execution":{"iopub.status.busy":"2023-07-22T07:44:40.587291Z","iopub.execute_input":"2023-07-22T07:44:40.587743Z","iopub.status.idle":"2023-07-22T07:44:40.608279Z","shell.execute_reply.started":"2023-07-22T07:44:40.587708Z","shell.execute_reply":"2023-07-22T07:44:40.598653Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# The CSV contains a flat file of images\n* i.e. each 28*28 image is flattened into a row of 784 colums\n* (1 column represents a pixel value)\n* For CNN, we would need to reshape this to our desired shape","metadata":{}},{"cell_type":"code","source":"train_df = pd.read_csv(\"/kaggle/input/digit-recognizer/train.csv\")","metadata":{"execution":{"iopub.status.busy":"2023-07-22T07:52:07.169725Z","iopub.execute_input":"2023-07-22T07:52:07.170173Z","iopub.status.idle":"2023-07-22T07:52:10.858262Z","shell.execute_reply.started":"2023-07-22T07:52:07.170113Z","shell.execute_reply":"2023-07-22T07:52:10.857199Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* First column is the target/label","metadata":{}},{"cell_type":"code","source":"train_labels = train_df['label'].values","metadata":{"execution":{"iopub.status.busy":"2023-07-22T07:52:22.165688Z","iopub.execute_input":"2023-07-22T07:52:22.166056Z","iopub.status.idle":"2023-07-22T07:52:22.173714Z","shell.execute_reply.started":"2023-07-22T07:52:22.166025Z","shell.execute_reply":"2023-07-22T07:52:22.172669Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* Pixels values start from the 2nd column\n","metadata":{}},{"cell_type":"code","source":"train_images = (train_df.iloc[:,1:].values).astype('float32')","metadata":{"execution":{"iopub.status.busy":"2023-07-22T07:52:39.781337Z","iopub.execute_input":"2023-07-22T07:52:39.781730Z","iopub.status.idle":"2023-07-22T07:52:39.852390Z","shell.execute_reply.started":"2023-07-22T07:52:39.781699Z","shell.execute_reply":"2023-07-22T07:52:39.851360Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_images, val_images, train_labels, val_labels = train_test_split(\n    train_images,\n    train_labels,\n    random_state=2020,\n    test_size=0.2\n)","metadata":{"execution":{"iopub.status.busy":"2023-07-22T07:52:52.159319Z","iopub.execute_input":"2023-07-22T07:52:52.159885Z","iopub.status.idle":"2023-07-22T07:52:52.495526Z","shell.execute_reply.started":"2023-07-22T07:52:52.159844Z","shell.execute_reply":"2023-07-22T07:52:52.494490Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Here we reshape the flat row into [images, Channels, Width, Height]\n* Given this a simple grayscale image, we will have just 1 channel\n","metadata":{}},{"cell_type":"code","source":"train_images = train_images.reshape(train_images.shape[0], 1, 28, 28)\nval_images = val_images.reshape(val_images.shape[0], 1, 28, 28)","metadata":{"execution":{"iopub.status.busy":"2023-07-22T07:53:27.047021Z","iopub.execute_input":"2023-07-22T07:53:27.047646Z","iopub.status.idle":"2023-07-22T07:53:27.052737Z","shell.execute_reply.started":"2023-07-22T07:53:27.047612Z","shell.execute_reply":"2023-07-22T07:53:27.051652Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* Also, let's plot few samples\n","metadata":{}},{"cell_type":"code","source":"for i in range(0, 6):\n    plt.subplot(160 + (i+1))\n    plt.imshow(train_images[i].reshape(28,28), cmap=plt.get_cmap('gray'))\n    plt.title(train_labels[i])","metadata":{"execution":{"iopub.status.busy":"2023-07-22T07:53:43.408882Z","iopub.execute_input":"2023-07-22T07:53:43.409274Z","iopub.status.idle":"2023-07-22T07:53:44.285225Z","shell.execute_reply.started":"2023-07-22T07:53:43.409243Z","shell.execute_reply":"2023-07-22T07:53:44.284290Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Normalize the dataset :","metadata":{}},{"cell_type":"markdown","source":"* Convert Train Images from pandas/numpy to tensor and normalize the values\n","metadata":{}},{"cell_type":"code","source":"train_images_tensor = torch.tensor(train_images)/255.0\ntrain_images_tensor = train_images_tensor.view(-1,1,28,28)\ntrain_labels_tensor = torch.tensor(train_labels)","metadata":{"execution":{"iopub.status.busy":"2023-07-22T07:54:25.819737Z","iopub.execute_input":"2023-07-22T07:54:25.820114Z","iopub.status.idle":"2023-07-22T07:54:26.011436Z","shell.execute_reply.started":"2023-07-22T07:54:25.820078Z","shell.execute_reply":"2023-07-22T07:54:26.010175Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* Create a tensor dataset\n","metadata":{}},{"cell_type":"code","source":"train_tensor = TensorDataset(train_images_tensor, train_labels_tensor)","metadata":{"execution":{"iopub.status.busy":"2023-07-22T07:54:52.380771Z","iopub.execute_input":"2023-07-22T07:54:52.381190Z","iopub.status.idle":"2023-07-22T07:54:52.386251Z","shell.execute_reply.started":"2023-07-22T07:54:52.381132Z","shell.execute_reply":"2023-07-22T07:54:52.384914Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* Covert Validation Images from pandas/numpy to tensor and normalize the values\n","metadata":{}},{"cell_type":"code","source":"val_images_tensor = torch.tensor(val_images)/255.0\nval_images_tensor = val_images_tensor.view(-1,1,28,28)\nval_labels_tensor = torch.tensor(val_labels)","metadata":{"execution":{"iopub.status.busy":"2023-07-22T07:55:09.382918Z","iopub.execute_input":"2023-07-22T07:55:09.383329Z","iopub.status.idle":"2023-07-22T07:55:09.412151Z","shell.execute_reply.started":"2023-07-22T07:55:09.383293Z","shell.execute_reply":"2023-07-22T07:55:09.411202Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* Create a Validation TensorDataset\n","metadata":{}},{"cell_type":"code","source":"val_tensor = TensorDataset(val_images_tensor, val_labels_tensor)","metadata":{"execution":{"iopub.status.busy":"2023-07-22T07:55:29.420732Z","iopub.execute_input":"2023-07-22T07:55:29.421788Z","iopub.status.idle":"2023-07-22T07:55:29.426667Z","shell.execute_reply.started":"2023-07-22T07:55:29.421753Z","shell.execute_reply":"2023-07-22T07:55:29.425226Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(\"Train Labels Shape:\",train_labels_tensor.shape)\nprint(\"Train Images Shape:\",train_images_tensor.shape)\nprint(\"Validation Labels Shape:\",val_labels_tensor.shape)\nprint(\"Validation Images Shape:\",val_images_tensor.shape)","metadata":{"execution":{"iopub.status.busy":"2023-07-22T07:55:35.764560Z","iopub.execute_input":"2023-07-22T07:55:35.764942Z","iopub.status.idle":"2023-07-22T07:55:35.770819Z","shell.execute_reply.started":"2023-07-22T07:55:35.764911Z","shell.execute_reply":"2023-07-22T07:55:35.769847Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* Load Train and Validation TensorDatasets into the data generator for Training\n","metadata":{}},{"cell_type":"code","source":"train_loader = DataLoader(train_tensor, batch_size = 64, num_workers = 2, shuffle = True)\nval_loader = DataLoader(val_tensor, batch_size = 64, num_workers = 2, shuffle = True)","metadata":{"execution":{"iopub.status.busy":"2023-07-22T07:55:55.106373Z","iopub.execute_input":"2023-07-22T07:55:55.106755Z","iopub.status.idle":"2023-07-22T07:55:55.113293Z","shell.execute_reply.started":"2023-07-22T07:55:55.106724Z","shell.execute_reply":"2023-07-22T07:55:55.112346Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* Defining the convolutional neural network\n","metadata":{}},{"cell_type":"code","source":"class ConvNet(nn.Module):\n    def __init__(self, num_classes = 10):\n        super(ConvNet, self).__init__()\n        # First unit of convolution\n        self.conv_unit_1 = nn.Sequential(\n            nn.Conv2d(1, 16, kernel_size=3, stride=1, padding=1),\n            nn.BatchNorm2d(16),\n            nn.ReLU(),\n            nn.MaxPool2d(kernel_size=2, stride=2))\n        # Second unit of convolution\n        self.conv_unit_2 = nn.Sequential(\n            nn.Conv2d(16, 32, kernel_size=3, stride=1, padding=1),\n            nn.BatchNorm2d(32),\n            nn.ReLU(),\n            nn.MaxPool2d(kernel_size=2, stride=2))\n        # Fully connected layers\n        self.fc1 = nn.Linear(7*7*32, 128)\n        self.fc2 = nn.Linear(128, 10)\n\n    # Connect the units\n    def forward(self, x):\n        out = self.conv_unit_1(x)\n        out = self.conv_unit_2(out)\n        out = out.view(out.size(0), -1)\n        out = self.fc1(out)\n        out = self.fc2(out)\n        out = F.log_softmax(out,dim=1)\n        return out","metadata":{"execution":{"iopub.status.busy":"2023-07-22T07:56:28.327492Z","iopub.execute_input":"2023-07-22T07:56:28.327878Z","iopub.status.idle":"2023-07-22T07:56:28.338558Z","shell.execute_reply.started":"2023-07-22T07:56:28.327847Z","shell.execute_reply":"2023-07-22T07:56:28.337365Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Define Functions for Model Evaluation and generating Predictions","metadata":{}},{"cell_type":"code","source":"def make_predictions(data_loader):\n    # Explcitly set the model to eval mode\n    model.eval()\n    test_preds = torch.LongTensor()\n    actual = torch.LongTensor()\n\n    for data, target in data_loader:\n        if torch.cuda.is_available():\n            data = data.cuda()\n        output = model(data)\n        # Predict output/Take the index of the output with max value\n        preds = output.cpu().data.max(1, keepdim=True)[1]\n        #Combine tensors from each batch\n        test_preds = torch.cat((test_preds, preds), dim=0)\n        actual = torch.cat((actual,target),dim=0)\n    return actual,test_preds","metadata":{"execution":{"iopub.status.busy":"2023-07-22T07:56:56.521673Z","iopub.execute_input":"2023-07-22T07:56:56.522045Z","iopub.status.idle":"2023-07-22T07:56:56.530801Z","shell.execute_reply.started":"2023-07-22T07:56:56.522013Z","shell.execute_reply":"2023-07-22T07:56:56.529541Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Evaluate the model : \ndef evaluate(data_loader):\n    model.eval()\n    loss = 0\n    correct = 0\n    for data, target in data_loader:\n        if torch.cuda.is_available():\n            data = data.cuda()\n            target = target.cuda()\n        output = model(data)\n        loss += F.cross_entropy(output, target, size_average=False).data.item()\n        predicted = output.data.max(1, keepdim=True)[1]\n        correct += (target.reshape(-1,1) == predicted.\n        reshape(-1,1)).float().sum()\n    loss /= len(data_loader.dataset)\n    print('\\nAverage Val Loss: {:.4f}, Val Accuracy: {}/{} ({:.3f}%)\\n'.format(loss, correct, len(data_loader.dataset),100.* correct / len(data_loader.dataset)))","metadata":{"execution":{"iopub.status.busy":"2023-07-22T07:58:03.666134Z","iopub.execute_input":"2023-07-22T07:58:03.666539Z","iopub.status.idle":"2023-07-22T07:58:03.675487Z","shell.execute_reply.started":"2023-07-22T07:58:03.666510Z","shell.execute_reply":"2023-07-22T07:58:03.674211Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Create a model instance","metadata":{}},{"cell_type":"code","source":"model = ConvNet(10).to(device)","metadata":{"execution":{"iopub.status.busy":"2023-07-22T07:59:04.362415Z","iopub.execute_input":"2023-07-22T07:59:04.363435Z","iopub.status.idle":"2023-07-22T07:59:07.184637Z","shell.execute_reply.started":"2023-07-22T07:59:04.363400Z","shell.execute_reply":"2023-07-22T07:59:07.183562Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Define the loss function \ncriterion = nn.CrossEntropyLoss()\noptimizer = torch.optim.Adam(model.parameters(), lr=0.001)\nprint(model)","metadata":{"execution":{"iopub.status.busy":"2023-07-22T07:59:18.556026Z","iopub.execute_input":"2023-07-22T07:59:18.557036Z","iopub.status.idle":"2023-07-22T07:59:18.563454Z","shell.execute_reply.started":"2023-07-22T07:59:18.556997Z","shell.execute_reply":"2023-07-22T07:59:18.562422Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Training the model","metadata":{}},{"cell_type":"code","source":"num_epochs = 5\ntotal_step = len(train_loader)","metadata":{"execution":{"iopub.status.busy":"2023-07-22T07:59:59.250576Z","iopub.execute_input":"2023-07-22T07:59:59.250942Z","iopub.status.idle":"2023-07-22T07:59:59.256763Z","shell.execute_reply.started":"2023-07-22T07:59:59.250911Z","shell.execute_reply":"2023-07-22T07:59:59.255452Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for epoch in range(num_epochs):\n    for i, (images, labels) in enumerate(train_loader):\n        images = images.to(device)\n        labels = labels.to(device)\n        # Forward pass\n        outputs = model(images)\n        loss = criterion(outputs, labels)\n        # Backward and optimize\n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n    # After each epoch print Train loss and validation loss + accuracy\n    print ('Epoch [{}/{}], Loss: {:.4f}' .format(epoch+1, num_epochs, loss.item()))\n    evaluate(val_loader)","metadata":{"execution":{"iopub.status.busy":"2023-07-22T08:01:09.977709Z","iopub.execute_input":"2023-07-22T08:01:09.978188Z","iopub.status.idle":"2023-07-22T08:01:25.373849Z","shell.execute_reply.started":"2023-07-22T08:01:09.978121Z","shell.execute_reply":"2023-07-22T08:01:25.372540Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Making prediction","metadata":{}},{"cell_type":"code","source":"actual, predicted = make_predictions(val_loader)\nactual,predicted = np.array(actual).reshape(-1,1) ,np.array(predicted).reshape(-1,1)\nprint(\"Validation Accuracy-\",round(accuracy_score(actual, predicted),4)*100)\nprint(\"\\n Confusion Matrix\\n\",confusion_matrix(actual,predicted))","metadata":{"execution":{"iopub.status.busy":"2023-07-22T08:02:03.128897Z","iopub.execute_input":"2023-07-22T08:02:03.129322Z","iopub.status.idle":"2023-07-22T08:02:03.719025Z","shell.execute_reply.started":"2023-07-22T08:02:03.129282Z","shell.execute_reply":"2023-07-22T08:02:03.717818Z"},"trusted":true},"execution_count":null,"outputs":[]}]}