{"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":"import torch\nimport pandas as pd\nfrom torch import nn, optim\nimport torch.nn.functional as F","metadata":{"execution":{"iopub.status.busy":"2023-01-30T14:57:24.523610Z","iopub.execute_input":"2023-01-30T14:57:24.524005Z","iopub.status.idle":"2023-01-30T14:57:24.529392Z","shell.execute_reply.started":"2023-01-30T14:57:24.523948Z","shell.execute_reply":"2023-01-30T14:57:24.528225Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Digit Recognizer\n\nThis is a work in progress, I will soon add prose explaining my approach. The code and model is complete, although can be improved.","metadata":{}},{"cell_type":"code","source":"import torchvision.transforms as transforms\n\ntransform = transforms.Compose(\n            [transforms.ToTensor(),\n            transforms.Normalize((0.5),(0.5))])","metadata":{"execution":{"iopub.status.busy":"2023-01-30T14:57:24.531642Z","iopub.execute_input":"2023-01-30T14:57:24.532247Z","iopub.status.idle":"2023-01-30T14:57:24.542370Z","shell.execute_reply.started":"2023-01-30T14:57:24.532209Z","shell.execute_reply":"2023-01-30T14:57:24.540772Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"device = torch.device(\"cuda\")","metadata":{"execution":{"iopub.status.busy":"2023-01-30T14:57:24.543793Z","iopub.execute_input":"2023-01-30T14:57:24.544115Z","iopub.status.idle":"2023-01-30T14:57:24.550310Z","shell.execute_reply.started":"2023-01-30T14:57:24.544080Z","shell.execute_reply":"2023-01-30T14:57:24.549248Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train = pd.read_csv(\"/kaggle/input/digit-recognizer/train.csv\")\n\nX = train.iloc[:,1:].values.astype('float32').reshape(-1,28,28)\ny = train.iloc[:,0]","metadata":{"execution":{"iopub.status.busy":"2023-01-30T14:57:24.552851Z","iopub.execute_input":"2023-01-30T14:57:24.553662Z","iopub.status.idle":"2023-01-30T14:57:26.901111Z","shell.execute_reply.started":"2023-01-30T14:57:24.553623Z","shell.execute_reply":"2023-01-30T14:57:26.899982Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torch.utils.data import Dataset\n\nclass ImgDataset(Dataset):\n    def __init__(self, imgs, labels, transform=None):\n        self.labels = labels # pd Series\n        self.imgs = imgs \n        self.transform = transform\n        \n    def __len__(self):\n        return len(self.labels)\n    \n    def __getitem__(self, idx):\n        label = self.labels[idx]\n        if self.transform:\n            image = transform(self.imgs[idx])\n        return image, label","metadata":{"execution":{"iopub.status.busy":"2023-01-30T14:57:26.902607Z","iopub.execute_input":"2023-01-30T14:57:26.903592Z","iopub.status.idle":"2023-01-30T14:57:26.916185Z","shell.execute_reply.started":"2023-01-30T14:57:26.903554Z","shell.execute_reply":"2023-01-30T14:57:26.915020Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torch.utils.data import random_split\n\ntrain_data = ImgDataset(X,y, transform=True)\n\nsize = 0.1\nv_size = round(len(train_data)*size)\nt_size = len(train_data) - v_size\n\ntrain_set, valid_set = random_split(train_data, [t_size, v_size])","metadata":{"execution":{"iopub.status.busy":"2023-01-30T14:57:26.917575Z","iopub.execute_input":"2023-01-30T14:57:26.918417Z","iopub.status.idle":"2023-01-30T14:57:26.934894Z","shell.execute_reply.started":"2023-01-30T14:57:26.918380Z","shell.execute_reply":"2023-01-30T14:57:26.934058Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torch.utils.data import DataLoader\n\nbatch_size=128 \n\ndl = DataLoader(train_data, batch_size=batch_size, shuffle=True)\nvalid_dl = DataLoader(valid_set, batch_size=batch_size, shuffle=True)","metadata":{"execution":{"iopub.status.busy":"2023-01-30T14:57:26.937909Z","iopub.execute_input":"2023-01-30T14:57:26.940703Z","iopub.status.idle":"2023-01-30T14:57:26.951259Z","shell.execute_reply.started":"2023-01-30T14:57:26.940668Z","shell.execute_reply":"2023-01-30T14:57:26.950344Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class CNN(nn.Module):\n\n    def __init__(self, out_1 = 32, out_2 = 64, n_classes = 10):\n        super(CNN, self).__init__()\n        self.bn1 = nn.BatchNorm2d(32, eps=1e-07, momentum=0.9, affine=True)\n        self.bn2 = nn.BatchNorm2d(64, eps=1e-07, momentum=0.9, affine=True)\n\n        self.cnn1 = nn.Conv2d(1, 32, kernel_size = 3, padding = 1)\n        self.maxpool1 = nn.MaxPool2d(kernel_size = 2)\n        \n        self.cnn2 = nn.Conv2d(32, 64, kernel_size = 3, padding = 1)\n        self.maxpool2 = nn.MaxPool2d(kernel_size = 2)\n        self.fc1 = nn.Linear(out_2 * 7 * 7, n_classes)\n        \n    def forward(self, x):\n        x = self.cnn1(x)\n        x = self.bn1(x)\n        x = torch.relu(x)\n        x = self.maxpool1(x)\n        x = self.cnn2(x)\n        x = self.bn2(x)\n        x = torch.relu(x)\n        x = self.maxpool2(x)\n        x = x.view(x.size(0), -1)\n        x = self.fc1(x)\n        return(x)","metadata":{"execution":{"iopub.status.busy":"2023-01-30T14:57:26.954843Z","iopub.execute_input":"2023-01-30T14:57:26.956773Z","iopub.status.idle":"2023-01-30T14:57:26.972664Z","shell.execute_reply.started":"2023-01-30T14:57:26.956709Z","shell.execute_reply":"2023-01-30T14:57:26.971498Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def train_epoch(model):\n    size = len(dl.dataset)\n    for batch, (X,y) in enumerate(dl):\n        X = X.to(device)\n        y = y.to(device)\n\n        optimizer.zero_grad()\n        \n        pred = model(X)\n        loss = loss_fn(pred, y)\n        \n        loss.backward()\n        optimizer.step()\n        \n        if batch % 100 == 0:\n            loss, current = loss.item(), batch * len(X)\n            print(f\"loss: {loss:>7f}  [{current:>5d}/{size:>5d}]\")","metadata":{"execution":{"iopub.status.busy":"2023-01-30T14:57:26.979113Z","iopub.execute_input":"2023-01-30T14:57:26.982050Z","iopub.status.idle":"2023-01-30T14:57:26.991129Z","shell.execute_reply.started":"2023-01-30T14:57:26.981951Z","shell.execute_reply":"2023-01-30T14:57:26.990013Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def validate_epoch(model):\n    size = len(valid_dl.dataset)\n    num_batches = len(valid_dl)\n    test_loss, correct = 0, 0\n    \n    with torch.no_grad():\n        for (X, y) in valid_dl:\n            X = X.to(device)\n            y = y.to(device)\n            \n            pred = model(X)\n            test_loss += loss_fn(pred, y).item()\n            correct += (pred.argmax(1) == y).type(torch.float).sum().item()\n            \n    test_loss /= num_batches\n    correct /= size\n    print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\") ","metadata":{"execution":{"iopub.status.busy":"2023-01-30T14:57:26.995681Z","iopub.execute_input":"2023-01-30T14:57:26.996577Z","iopub.status.idle":"2023-01-30T14:57:27.008906Z","shell.execute_reply.started":"2023-01-30T14:57:26.996538Z","shell.execute_reply":"2023-01-30T14:57:27.008003Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def train_model(model,n_epochs):\n    model = model.to(device)\n    for i in range(n_epochs):\n        print(f\"Epoch {i+1}\\n-------------------------------\")\n        train_epoch(model)\n        validate_epoch(model)\n    print(\"Done.\")","metadata":{"execution":{"iopub.status.busy":"2023-01-30T14:57:27.013659Z","iopub.execute_input":"2023-01-30T14:57:27.016420Z","iopub.status.idle":"2023-01-30T14:57:27.023536Z","shell.execute_reply.started":"2023-01-30T14:57:27.016386Z","shell.execute_reply":"2023-01-30T14:57:27.022378Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"lr = 0.002\nn_epochs = 10\nmomentum = 0.9\n\nmodel = CNN()\n\nloss_fn = nn.CrossEntropyLoss()\noptimizer = optim.SGD(model.parameters(), lr=lr, momentum=momentum)\n\ntrain_model(model,n_epochs)","metadata":{"execution":{"iopub.status.busy":"2023-01-30T14:57:27.028329Z","iopub.execute_input":"2023-01-30T14:57:27.031180Z","iopub.status.idle":"2023-01-30T14:58:12.605391Z","shell.execute_reply.started":"2023-01-30T14:57:27.031119Z","shell.execute_reply":"2023-01-30T14:58:12.604210Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Testing","metadata":{}},{"cell_type":"code","source":"testdata = pd.read_csv(\"/kaggle/input/digit-recognizer/test.csv\")\n\ntestdata = testdata.values.reshape(-1,1,28,28)\ntestdata = torch.Tensor(testdata)\n\nsubmission = pd.read_csv(\"/kaggle/input/digit-recognizer/sample_submission.csv\")\n\nmodel.to(device)\n\nfor i, test in enumerate(DataLoader(testdata, batch_size=1)):\n    test = test.to(device)\n    model.eval()\n    _,pred = torch.max(model(test),1)\n    submission[\"Label\"][i] = pred.item()\n    \n\nsubmission.to_csv(\"submission.csv\", index=False)","metadata":{"execution":{"iopub.status.busy":"2023-01-30T14:58:12.606915Z","iopub.execute_input":"2023-01-30T14:58:12.607445Z","iopub.status.idle":"2023-01-30T14:58:37.860962Z","shell.execute_reply.started":"2023-01-30T14:58:12.607352Z","shell.execute_reply":"2023-01-30T14:58:37.860008Z"},"trusted":true},"execution_count":null,"outputs":[]}]}