{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":77180,"databundleVersionId":9096404,"sourceType":"competition"}],"dockerImageVersionId":30747,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# I used Pytorch again because I had it fresh in my mind after the previous lab\n# I also wasn't getting good accuracy using tensorflow, but that was most likely my fault, haha!\nimport os\nimport pandas as pd\nimport numpy as np\nimport csv\nfrom PIL import Image\nfrom tqdm import tqdm\n\nimport torch\nfrom torch import optim\nfrom torch.utils.data import Dataset, DataLoader\nimport torch.nn as nn\nimport torch.nn.functional as nnf\nfrom torchvision import transforms","metadata":{"execution":{"iopub.status.busy":"2024-08-09T09:36:04.295809Z","iopub.execute_input":"2024-08-09T09:36:04.296483Z","iopub.status.idle":"2024-08-09T09:36:09.692437Z","shell.execute_reply.started":"2024-08-09T09:36:04.296452Z","shell.execute_reply":"2024-08-09T09:36:09.691610Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Class (like from last lab) to import images into proper format\n# Ying's notebook has good suggestions of how to edit this to make it work for this dataset\nclass CustomImageDataset(Dataset):\n    def __init__(self, img_dic, transform=None):\n        self.img_dic = img_dic\n        self.transform = transform\n\n        self.img_names = list(img_dic.keys())\n        self.imgs = []\n        for img_name in tqdm(self.img_names):\n            img = Image.open(img_name)\n            img = self.transform(img)\n            self.imgs.append(img)\n        self.labels = list(img_dic.values())\n\n    def __getitem__(self, index):\n        img = self.imgs[index]\n        label = self.labels[index]\n\n        return img, label\n\n    def __len__(self):\n        return len(self.img_names)","metadata":{"execution":{"iopub.status.busy":"2024-08-09T09:36:13.213478Z","iopub.execute_input":"2024-08-09T09:36:13.214676Z","iopub.status.idle":"2024-08-09T09:36:13.224995Z","shell.execute_reply.started":"2024-08-09T09:36:13.214636Z","shell.execute_reply":"2024-08-09T09:36:13.223846Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Making image dictionaries\n# The 'csv' package is really helpful for stuff like this!\n    # https://docs.python.org/3/library/csv.html\n\ntrain_dic = {}\nwith open('/kaggle/input/d-4-computer-vision/train.csv') as csv:\n    lines = csv.readlines()\nfor line in lines[1:]:\n    items = line.strip().split(',')\n    idx, name, label = items\n    train_dic[os.path.join('/kaggle/input/d-4-computer-vision/images/kaggle/working/Reorganized_Data/images', name)] = int(label)\n       \n        \ntest_dic = {}\nwith open('/kaggle/input/d-4-computer-vision/test.csv') as csv:\n    lines = csv.readlines()\nfor line in lines[1:]:\n    items = line.strip().split(',')\n    idx, name = items\n    test_dic[os.path.join('/kaggle/input/d-4-computer-vision/images/kaggle/working/Reorganized_Data/images', name)] = 999","metadata":{"execution":{"iopub.status.busy":"2024-08-09T09:36:16.256004Z","iopub.execute_input":"2024-08-09T09:36:16.256724Z","iopub.status.idle":"2024-08-09T09:36:16.289903Z","shell.execute_reply.started":"2024-08-09T09:36:16.256692Z","shell.execute_reply":"2024-08-09T09:36:16.288934Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Define transformation\n# I resized the images to make them smaller and also normalized them\n\ntransform = transforms.Compose([\n    transforms.Resize([200,300]),\n    transforms.ToTensor(),\n    transforms.Normalize((0.5, 0.5, 0.5),(0.5, 0.5, 0.5))])","metadata":{"execution":{"iopub.status.busy":"2024-08-09T09:36:20.118017Z","iopub.execute_input":"2024-08-09T09:36:20.118690Z","iopub.status.idle":"2024-08-09T09:36:20.123613Z","shell.execute_reply.started":"2024-08-09T09:36:20.118659Z","shell.execute_reply":"2024-08-09T09:36:20.122516Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Make datasets and dataloader objects\n# The functionality of package 'tqdm' is really nice to have here!\n\ntrain_dataset = CustomImageDataset(train_dic, transform=transform)\ntest_dataset = CustomImageDataset(test_dic, transform=transform)\n\ntrain_dataloader = DataLoader(train_dataset, batch_size=32, shuffle=True)\ntest_dataloader = DataLoader(test_dataset, batch_size=32, shuffle=False)","metadata":{"execution":{"iopub.status.busy":"2024-08-09T09:36:22.973021Z","iopub.execute_input":"2024-08-09T09:36:22.973672Z","iopub.status.idle":"2024-08-09T09:55:04.474462Z","shell.execute_reply.started":"2024-08-09T09:36:22.973639Z","shell.execute_reply":"2024-08-09T09:55:04.473478Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Define the CNN\n# I messed around with different input / output values for layers but kept them multiples of each other\n\nclass ConvNN(nn.Module):\n    def __init__(self):\n        super(ConvNN, self).__init__()\n        self.conv1 = nn.Conv2d(3, 32, 3, padding=1)\n        self.bn1 = nn.BatchNorm2d(32)\n        self.pool = nn.MaxPool2d(2, 2)\n        self.conv2 = nn.Conv2d(32, 64, 3, padding=1)\n        self.bn2 = nn.BatchNorm2d(64)\n        self.fc1 = nn.Linear(64, 128)\n        self.bn3 = nn.BatchNorm1d(128)\n        self.fc2 = nn.Linear(128, 2)\n        self.softmax = nn.Softmax(dim=1)\n        \n    def forward(self, x):\n        batch_size = x.shape[0]\n        out = self.conv1(x)\n        out = nnf.relu(out)\n        out = self.bn1(out)\n        out = self.pool(out)\n        \n        # second set of layers\n        out = self.conv2(out)\n        out = nnf.relu(out)\n        out = self.bn2(out)\n        out = self.pool(out)\n        \n        # Dense layer\n        out = torch.max(torch.max(out, 2).values, 2).values\n        # Ying's notebook gave me the idea for using torch.max! Very helpful!\n        \n        out = self.fc1(out)\n        out = self.bn3(out)\n        out = nnf.relu(out)\n        out = self.fc2(out)\n        out = self.softmax(out)\n        return out","metadata":{"execution":{"iopub.status.busy":"2024-08-09T09:58:40.080549Z","iopub.execute_input":"2024-08-09T09:58:40.080928Z","iopub.status.idle":"2024-08-09T09:58:40.093177Z","shell.execute_reply.started":"2024-08-09T09:58:40.080901Z","shell.execute_reply":"2024-08-09T09:58:40.091952Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create model and define loss measurement / optimizer\n# I played around with different optimizers and found AdamW worked the best for me\n\nmodel = ConvNN()\nloss_ce = nn.CrossEntropyLoss()\noptimizer = optim.AdamW(model.parameters(), lr=0.001)","metadata":{"execution":{"iopub.status.busy":"2024-08-09T09:58:42.872443Z","iopub.execute_input":"2024-08-09T09:58:42.872835Z","iopub.status.idle":"2024-08-09T09:58:42.880904Z","shell.execute_reply.started":"2024-08-09T09:58:42.872809Z","shell.execute_reply":"2024-08-09T09:58:42.879891Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Tell pytorch to use GPU instead of CPU\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\nmodel.to(device)\nprint(device)","metadata":{"execution":{"iopub.status.busy":"2024-08-09T09:58:45.750258Z","iopub.execute_input":"2024-08-09T09:58:45.750728Z","iopub.status.idle":"2024-08-09T09:58:45.759563Z","shell.execute_reply.started":"2024-08-09T09:58:45.750696Z","shell.execute_reply":"2024-08-09T09:58:45.758414Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Train the model, I played around with different amounts of epochs\n# I did the last lab first and really liked the tqdm package!\n\nmodel.train()\nfor epoch in range(15):\n    for images, labels in train_dataloader:\n        images = images.to(device)\n        labels = labels.to(device)\n        outputs = model(images)\n        loss = loss_ce(outputs, labels)\n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()","metadata":{"execution":{"iopub.status.busy":"2024-08-09T09:58:48.586245Z","iopub.execute_input":"2024-08-09T09:58:48.586638Z","iopub.status.idle":"2024-08-09T09:59:55.896802Z","shell.execute_reply.started":"2024-08-09T09:58:48.586603Z","shell.execute_reply":"2024-08-09T09:59:55.895703Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Predict classes for test images with model\n\nmodel.eval()   \ntest_pred = []\nfor images, labels in test_dataloader:\n    images = images.to(device)\n    with torch.no_grad():        \n        outputs = model(images)\n\n    preds = outputs\n    preds = preds.detach().cpu().numpy()\n    test_pred.append(preds)","metadata":{"execution":{"iopub.status.busy":"2024-08-09T10:00:24.659654Z","iopub.execute_input":"2024-08-09T10:00:24.660338Z","iopub.status.idle":"2024-08-09T10:00:25.161684Z","shell.execute_reply.started":"2024-08-09T10:00:24.660304Z","shell.execute_reply":"2024-08-09T10:00:25.160790Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Processing predictions\ntest_pred = np.concatenate(test_pred, axis=0)\n\n# flattening and undoing encoding of classes\npreds_flat = np.argmax(test_pred, axis=1).flatten()\nprint(preds_flat)","metadata":{"execution":{"iopub.status.busy":"2024-08-09T10:00:34.542393Z","iopub.execute_input":"2024-08-09T10:00:34.543612Z","iopub.status.idle":"2024-08-09T10:00:34.553829Z","shell.execute_reply.started":"2024-08-09T10:00:34.543557Z","shell.execute_reply":"2024-08-09T10:00:34.552717Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create DataFrame of predictions\n\ntest = pd.read_csv('/kaggle/input/d-4-computer-vision/test.csv')\nsubmission = pd.DataFrame({'Images': test['Images'], 'Labels': preds_flat})\n\nprint(submission)","metadata":{"execution":{"iopub.status.busy":"2024-08-09T10:00:48.968629Z","iopub.execute_input":"2024-08-09T10:00:48.969042Z","iopub.status.idle":"2024-08-09T10:00:48.995029Z","shell.execute_reply.started":"2024-08-09T10:00:48.969011Z","shell.execute_reply":"2024-08-09T10:00:48.993803Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Write .csv file\nsubmission.to_csv('submission.csv', index=False)","metadata":{"execution":{"iopub.status.busy":"2024-08-09T10:00:57.895660Z","iopub.execute_input":"2024-08-09T10:00:57.896032Z","iopub.status.idle":"2024-08-09T10:00:57.905292Z","shell.execute_reply.started":"2024-08-09T10:00:57.896005Z","shell.execute_reply":"2024-08-09T10:00:57.904483Z"},"trusted":true},"execution_count":null,"outputs":[]}]}