{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","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":30822,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nfrom matplotlib import pyplot as plt\n\ntrainData = pd.read_csv('/kaggle/input/digit-recognizer/train.csv')\ntestData = pd.read_csv('/kaggle/input/digit-recognizer/test.csv')","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-01-10T20:45:03.351256Z","iopub.execute_input":"2025-01-10T20:45:03.351561Z","iopub.status.idle":"2025-01-10T20:45:06.635235Z","shell.execute_reply.started":"2025-01-10T20:45:03.351539Z","shell.execute_reply":"2025-01-10T20:45:06.634171Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nfrom torch import nn , save , load\nfrom torch.optim import Adam\nfrom torch.utils.data import DataLoader , TensorDataset\nfrom torchvision import datasets\nfrom torchvision.transforms import ToTensor","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-10T20:45:06.636259Z","iopub.execute_input":"2025-01-10T20:45:06.636572Z","iopub.status.idle":"2025-01-10T20:45:06.640829Z","shell.execute_reply.started":"2025-01-10T20:45:06.636544Z","shell.execute_reply":"2025-01-10T20:45:06.639934Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(trainData.shape)\ntrainData.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-10T20:45:06.642367Z","iopub.execute_input":"2025-01-10T20:45:06.642639Z","iopub.status.idle":"2025-01-10T20:45:06.667342Z","shell.execute_reply.started":"2025-01-10T20:45:06.642607Z","shell.execute_reply":"2025-01-10T20:45:06.666414Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#AS A REMINDER OF HOW SLICING WORKS:\narray = [[1,2,3],[4,5,6],[7,8,9]]\narray = np.array(array)\nprint(array[1:2,:2])\narraydf = pd.DataFrame(array)\nprint(arraydf.iloc[1:2,:2].values)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-10T20:45:06.668789Z","iopub.execute_input":"2025-01-10T20:45:06.669096Z","iopub.status.idle":"2025-01-10T20:45:06.685249Z","shell.execute_reply.started":"2025-01-10T20:45:06.669074Z","shell.execute_reply":"2025-01-10T20:45:06.684158Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"features = trainData.iloc[:30000, 1:].values #returns an numpy array\nlabels = trainData.iloc[:30000, 0].values #returns an numpy array\ntestF = trainData.iloc[30000:,1:].values\ntestL = trainData.iloc[30000:,0].values\nfeatures = features / 255.0\ntestF = testF / 225.0\nfeatures_tensor = torch.tensor(features, dtype=torch.float32)  \nfeatures_tensor = features_tensor.view(-1, 1, 28, 28)  # Reshape to match [batch_size, channels, height, width]\ntestF_tensor = torch.tensor(testF, dtype=torch.float32)\ntestF_tensor = testF_tensor.view(-1,1,28,28)\nlabels_tensor = torch.tensor(labels, dtype=torch.long)\ntestL_tensor = torch.tensor(testL, dtype=torch.long)\n\nprint(testF_tensor.shape)\nprint(testL_tensor.shape)\ntData = TensorDataset(testF_tensor, testL_tensor)\ntdataset = DataLoader(tData, batch_size=12000)\n\n# Create a TensorDataset\ndata = TensorDataset(features_tensor, labels_tensor)\n# Create Dataloader\ndataset = DataLoader(data, batch_size=32, shuffle=True)\n\n#torch.Size([64, 1, 28, 28])\n#torch.Size([64])\n# Check shape and image\nfor batch_features, batch_labels in dataset:\n    print(\"Batch Features Shape:\", batch_features.shape)\n    print(\"Batch Labels Shape:\", batch_labels.shape)\n\n    print(batch_labels[7])\n\n    # Select the first image in the batch\n    image = batch_features[7].squeeze(0)  # Remove the channel dimension (from shape [1, 28, 28] to [28, 28])\n    \n    # Display the image\n    plt.imshow(image, cmap='gray')  # Grayscale image\n    plt.axis('off')  # Hide axes for cleaner display\n    plt.show()\n    \n    break\n\nfor X, Y in tdataset:\n    print(X.shape)\n    print(Y.shape) ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-10T20:45:06.686480Z","iopub.execute_input":"2025-01-10T20:45:06.686842Z","iopub.status.idle":"2025-01-10T20:45:07.290724Z","shell.execute_reply.started":"2025-01-10T20:45:06.686810Z","shell.execute_reply":"2025-01-10T20:45:07.289974Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class ImageClassifier(nn.Module):\n    def __init__(self):\n        super().__init__()\n        self.model = nn.Sequential(\n            nn.Conv2d(1, 6, (3,3)), \n            nn.ReLU(),\n            nn.Conv2d(6, 6, (3,3)), \n            nn.ReLU(),\n            nn.Flatten(), \n            nn.Linear(6*(28-4)*(28-4), 10)  \n        )\n    def forward(self,x):\n        return self.model(x)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-10T20:45:07.291590Z","iopub.execute_input":"2025-01-10T20:45:07.291925Z","iopub.status.idle":"2025-01-10T20:45:07.297078Z","shell.execute_reply.started":"2025-01-10T20:45:07.291899Z","shell.execute_reply":"2025-01-10T20:45:07.296074Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"clf = ImageClassifier().to('cuda')\nopt = Adam(clf.parameters(), lr=1e-3 )\nlossfn = nn.CrossEntropyLoss()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-10T20:45:07.297976Z","iopub.execute_input":"2025-01-10T20:45:07.298239Z","iopub.status.idle":"2025-01-10T20:45:07.314707Z","shell.execute_reply.started":"2025-01-10T20:45:07.298192Z","shell.execute_reply":"2025-01-10T20:45:07.313959Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"losses = []\naccuracies = []\n    \nfor epoch in range(15): # train for 10 epochs\n    correct = 0\n    total = 0\n\n    \n    for batch in dataset:\n        X,y = batch \n        X, y = X.to('cuda'), y.to('cuda') \n        yhat = clf(X) \n        loss = lossfn(yhat, y) \n\n        # Calculate accuracy\n        _, predicted = torch.max(yhat, 1)  # Get the predicted class (argmax over output)\n        total += y.size(0)  # Update the total number of samples processed\n        correct += (predicted == y).sum().item()  # Update the number of correct predictions\n\n        # Apply backprop \n        opt.zero_grad()\n        loss.backward() \n        opt.step() \n\n    accuracy = (correct / total) * 100  # Compute the accuracy as a percentage\n    print(f\"Epoch: {epoch} - Loss: {loss.item()} - Accuracy: {accuracy:.2f}%\")\n    losses.append(loss.item())\n    accuracies.append(accuracy)\n\n\nwith open('model_state.pt', 'wb') as f: \n    save(clf.state_dict(), f) \n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-10T20:45:07.316795Z","iopub.execute_input":"2025-01-10T20:45:07.317103Z","iopub.status.idle":"2025-01-10T20:45:45.387242Z","shell.execute_reply.started":"2025-01-10T20:45:07.317081Z","shell.execute_reply":"2025-01-10T20:45:45.386314Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(losses)\nplt.plot(np.array(losses))\nplt.show()\n\nplt.plot(accuracies)\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-10T20:45:45.388476Z","iopub.execute_input":"2025-01-10T20:45:45.388811Z","iopub.status.idle":"2025-01-10T20:45:45.675055Z","shell.execute_reply.started":"2025-01-10T20:45:45.388778Z","shell.execute_reply":"2025-01-10T20:45:45.673978Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"with open('model_state.pt', 'rb') as f: \n    state_dict = torch.load(f, weights_only=True)  # Explicitly set weights_only=True\n    clf.load_state_dict(state_dict)\n\nfor X,Y in tdataset:\n    X,Y = X.to('cuda') , Y.to('cuda')\n    Yhat = clf(X)\n    _, predicted = torch.max(Yhat, 1)\n    correct = (predicted == Y).sum().item()\n    accuracy = (correct / Y.size(0)) * 100\n    print(f'new data accuracy: {accuracy}')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-10T20:45:45.676176Z","iopub.execute_input":"2025-01-10T20:45:45.676570Z","iopub.status.idle":"2025-01-10T20:45:45.840680Z","shell.execute_reply.started":"2025-01-10T20:45:45.676529Z","shell.execute_reply":"2025-01-10T20:45:45.839857Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nfrom scipy.signal import convolve2d\n\ndef printAndSave(layerNum, filterNum, channelNum, npfilter, original, convolution):\n\n    folder_name = str(layerNum)\n    if not os.path.exists(folder_name):\n        os.makedirs(folder_name)\n    \n    plt.imshow(npfilter, cmap='gray')\n    plt.axis('off')\n    plt.savefig(os.path.join(folder_name, f'filter:{layerNum},{filterNum},{channelNum}.png'), bbox_inches='tight', pad_inches=0)\n    plt.show()\n    plt.imshow(original, cmap='gray')\n    plt.axis('off')\n    plt.show()\n    plt.imshow(convolution, cmap='gray')\n    plt.axis('off')\n    plt.savefig(os.path.join(folder_name, f'convolution:{layerNum},{filterNum},{channelNum}.png'), bbox_inches='tight', pad_inches=0)\n    plt.show()\n\n# Instantiate the model\nmodel = ImageClassifier()\n\nnpfilter = np.empty((3, 3))\nimage = trainData.iloc[100, 1:].values\noriginal = image.reshape(28, 28)\n\n# Iterate through layers and print filters for Conv2d layers\nfor name, layer in model.model.named_children():  # Access layers inside nn.Sequential\n    if isinstance(layer, nn.Conv2d):\n        print(f\"Layer: {name}\")\n        print(f\"Filters (weights): {layer.weight.data.shape}\")\n        # indexed as [number of filters, number of channels, filter size, filter size]\n        # print(layer.weight.data[2,0,:,:])\n        nOfFilters , nOfChannels, _, _ = layer.weight.data.shape\n        for F in range(nOfFilters):\n            for C in range(nOfChannels):\n                npfilter = layer.weight.data[F,C,:,:].detach().cpu().numpy()\n                convolution = convolve2d(original, npfilter)\n                printAndSave(name,F,C,npfilter,original,convolution)\n        print(f\"Biases: {layer.bias.data if layer.bias is not None else 'No Bias'}\")\n        print(\"-\" * 50)\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-10T20:45:45.841486Z","iopub.execute_input":"2025-01-10T20:45:45.841696Z","iopub.status.idle":"2025-01-10T20:45:54.498580Z","shell.execute_reply.started":"2025-01-10T20:45:45.841677Z","shell.execute_reply":"2025-01-10T20:45:54.497332Z"}},"outputs":[],"execution_count":null}]}