diff --git a/.gitignore b/.gitignore index db4f44e..eadee56 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ __pycache__ -.vscode - +sauce/ training_summaries +.* +*.zip diff --git a/README.md b/README.md index 9cd7cf4..75fe12a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ACM AI Projects Skeleton Code +# 50Whales Skeleton Code ## Setup diff --git a/constants.py b/constants.py index 987c6c9..c55ce45 100644 --- a/constants.py +++ b/constants.py @@ -1,3 +1,4 @@ -EPOCHS = 100 -BATCH_SIZE = 32 -N_EVAL = 100 +EPOCHS = 1 +BATCH_SIZE = 16 +N_EVAL = 2 +DATA = "../50whales/sauce" \ No newline at end of file diff --git a/data/ImageAugment.py b/data/ImageAugment.py new file mode 100644 index 0000000..3d2874c --- /dev/null +++ b/data/ImageAugment.py @@ -0,0 +1,86 @@ +import torch +from PIL import Image +from PIL import ImageOps +import pandas as pd +import constants +import torchvision +import torchvision.transforms.functional +import numpy as np + + +class ImageAugment(torch.utils.data.Dataset): + + def __init__(self, path): + self.path = path + self.data = pd.read_csv(constants.DATA + "/train.csv") + self.data.rename(columns=self.data.iloc[0]).drop(self.data.index[0]) + self.images = self.data.iloc[:, 0] + self.labels = self.data.iloc[:, 1] + self.transition = list(set(self.labels)) + self.whales = self.labels.replace(self.transition, list(range(5005))) + + self.transform1 = torchvision.transforms.RandomResizedCrop(size = (448,224), scale = (0.5, 0.75)) + + self.transform2 = torchvision.transforms.ColorJitter() + + self.transform3 = torchvision.transforms.RandomAffine(180) + + self.augmentedimages = [] + self.augmentedlabels = [] + + + def __getitem__(self, index): + image = Image.open(constants.DATA + self.path + self.images[index]) + + label = self.whales[index] + + image = image.resize((448, 224)) + image = ImageOps.grayscale(image) + + image = torchvision.transforms.ToTensor()(np.array(image)) + + return image, label + + + def __len__(self): + return len(self.labels) + + def cutout(self, image): + size = 30 + x = np.random.randint(448) + y = np.random.randint(224) + y1 = np.clip(y - size // 2, 0, 224) + y2 = np.clip(y + size // 2, 0, 224) + x1 = np.clip(x - size // 2, 0, 448) + x2 = np.clip(x + size // 2, 0, 448) + image[y1:y2, x1:x2] = 0 + + + + def augment(self, index): + image = Image.open(constants.DATA + self.path + self.images[index]) + + image = image.resize((448,224)) + + self.augmentedimages.append(torchvision.transforms.ToTensor()(np.array(self.transform1(image)))) + self.augmentedlabels.append(index) + + self.augmentedimages.append(torchvision.transforms.ToTensor()(np.array(self.transform2(image)))) + self.augmentedlabels.append(index) + + self.augmentedimages.append(torchvision.transforms.ToTensor()(np.array(self.transform2(image)))) + self.augmentedlabels.append(index) + + self.augmentedimages.append(torchvision.transforms.ToTensor()(np.array(self.transform3(image)))) + self.augmentedlabels.append(index) + + self.augmentedimages.append(torchvision.transforms.ToTensor()(np.array(self.transform3(image)))) + self.augmentedlabels.append(index) + + self.augmentedimages.append(torchvision.transforms.ToTensor()(np.array(image + torch.std(image)*torch.randn(image.size)))) + self.augmentedlabels.append(index) + + self.augmentedimages.append(torchvision.transforms.ToTensor()(np.array(self.cutout(self, image)))) + + + diff --git a/data/StartingDataset.py b/data/StartingDataset.py index 232485f..095e37e 100644 --- a/data/StartingDataset.py +++ b/data/StartingDataset.py @@ -1,4 +1,10 @@ +import os import torch +from PIL import Image +from PIL import ImageOps +import pandas as pd +import constants +import torchvision class StartingDataset(torch.utils.data.Dataset): @@ -6,14 +12,24 @@ class StartingDataset(torch.utils.data.Dataset): Dataset that contains 100000 3x224x224 black images (all zeros). """ - def __init__(self): - pass + def __init__(self, path): + self.path = path + self.data = pd.read_csv(constants.DATA + "/train.csv") + self.data.rename(columns=self.data.iloc[0]).drop(self.data.index[0]) + self.images = self.data.iloc[:, 0] + self.labels = self.data.iloc[:, 1] + self.transition = list(set(self.labels)) + self.whales = self.labels.replace(self.transition, list(range(5005))) def __getitem__(self, index): - inputs = torch.zeros([3, 224, 224]) - label = 0 + image = Image.open(constants.DATA + self.path + self.images[index]) + label = self.whales[index] + + image = image.resize((448, 224)) + image = ImageOps.grayscale(image) + + return torchvision.transforms.functional.pil_to_tensor(image), label - return inputs, label def __len__(self): - return 10000 + return len(self.labels) diff --git a/data/tempCodeRunnerFile.py b/data/tempCodeRunnerFile.py new file mode 100644 index 0000000..e5acf1f --- /dev/null +++ b/data/tempCodeRunnerFile.py @@ -0,0 +1,17 @@ + def augment(self, index): + image, label = ImageAugment.__getitem__(index) + + self.images.append(self.transform1(image)) + self.labels.append(index) + + self.images.append(self.transform2(image)) + self.labels.append(index) + + self.images.append(self.transform2(image)) + self.labels.append(index) + + self.images.append(self.transform3(image)) + self.labels.append(index) + + self.images.append(self.transform3(image)) + self.labels.append(index) \ No newline at end of file diff --git a/main.ipynb b/main.ipynb new file mode 100644 index 0000000..4760b74 --- /dev/null +++ b/main.ipynb @@ -0,0 +1,488 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# Tejas Kamtam\n", + "# Anand Gowda\n", + "# Austin Yang\n", + "# Anish" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "# constants\n", + "EPOCHS = 1\n", + "BATCH_SIZE = 16\n", + "N_EVAL = 1\n", + "DATA = \"../50whales/sauce\"" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/anand/opt/anaconda3/envs/acm/lib/python3.8/site-packages/torchvision/io/image.py:11: UserWarning: Failed to load image Python extension: dlopen(/Users/anand/opt/anaconda3/envs/acm/lib/python3.8/site-packages/torchvision/image.so, 6): Library not loaded: @rpath/libjpeg.9.dylib\n", + " Referenced from: /Users/anand/opt/anaconda3/envs/acm/lib/python3.8/site-packages/torchvision/image.so\n", + " Reason: Incompatible library version: image.so requires version 14.0.0 or later, but libjpeg.9.dylib provides version 12.0.0\n", + " warn(f\"Failed to load image Python extension: {e}\")\n" + ] + } + ], + "source": [ + "# data processing\n", + "import torch\n", + "from PIL import Image\n", + "from PIL import ImageOps\n", + "import pandas as pd\n", + "import torchvision\n", + "\n", + "\n", + "class StartingDataset(torch.utils.data.Dataset):\n", + " \"\"\"\n", + " Dataset that contains 100000 3x224x224 black images (all zeros).\n", + " \"\"\"\n", + "\n", + " def __init__(self, path):\n", + " self.path = path\n", + " self.data = pd.read_csv(DATA + \"/train.csv\")\n", + " self.data.rename(columns=self.data.iloc[0]).drop(self.data.index[0])\n", + " self.images = self.data.iloc[:, 0]\n", + " self.labels = self.data.iloc[:, 1]\n", + " self.transition = list(set(self.labels))\n", + " self.whales = self.labels.replace(self.transition, list(range(5005)))\n", + "\n", + " def __getitem__(self, index):\n", + " image = Image.open(DATA + self.path + self.images[index])\n", + " label = self.whales[index]\n", + "\n", + " image = image.resize((448, 224))\n", + " image = ImageOps.grayscale(image)\n", + "\n", + " return torchvision.transforms.functional.pil_to_tensor(image), label\n", + "\n", + "\n", + " def __len__(self):\n", + " return len(self.labels)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import torch\n", + "from PIL import Image\n", + "from PIL import ImageOps\n", + "import pandas as pd\n", + "import constants\n", + "import torchvision\n", + "import torchvision.transforms.functional\n", + "import numpy as np\n", + "\n", + "\n", + "class ImageAugment(torch.utils.data.Dataset):\n", + "\n", + " def __init__(self, path):\n", + " self.path = path\n", + " self.data = pd.read_csv(constants.DATA + \"/train.csv\")\n", + " self.data.rename(columns=self.data.iloc[0]).drop(self.data.index[0])\n", + " self.images = self.data.iloc[:, 0]\n", + " self.labels = self.data.iloc[:, 1]\n", + " self.transition = list(set(self.labels))\n", + " self.whales = self.labels.replace(self.transition, list(range(5005)))\n", + "\n", + " self.transform1 = torchvision.transforms.RandomResizedCrop(size = (448,224), scale = (0.5, 0.75))\n", + "\n", + " self.transform2 = torchvision.transforms.ColorJitter()\n", + "\n", + " self.transform3 = torchvision.transforms.RandomAffine(180)\n", + "\n", + " self.augmentedimages = []\n", + " self.augmentedlabels = []\n", + " \n", + "\n", + " def __getitem__(self, index):\n", + " image = Image.open(constants.DATA + self.path + self.images[index])\n", + "\n", + " label = self.whales[index]\n", + "\n", + " image = image.resize((448, 224))\n", + " image = ImageOps.grayscale(image)\n", + "\n", + " image = torchvision.transforms.ToTensor()(np.array(image))\n", + "\n", + " return image, label\n", + "\n", + "\n", + " def __len__(self):\n", + " return len(self.labels)\n", + "\n", + " def augment(self, index):\n", + " image = Image.open(constants.DATA + self.path + self.images[index])\n", + "\n", + " image = image.resize((448,224))\n", + "\n", + " self.augmentedimages.append(torchvision.transforms.ToTensor()(np.array(self.transform1(image))))\n", + " self.augmentedlabels.append(index)\n", + "\n", + " self.augmentedimages.append(torchvision.transforms.ToTensor()(np.array(self.transform2(image))))\n", + " self.augmentedlabels.append(index)\n", + "\n", + " self.augmentedimages.append(torchvision.transforms.ToTensor()(np.array(self.transform2(image))))\n", + " self.augmentedlabels.append(index)\n", + "\n", + " self.augmentedimages.append(torchvision.transforms.ToTensor()(np.array(self.transform3(image))))\n", + " self.augmentedlabels.append(index)\n", + "\n", + " self.augmentedimages.append(torchvision.transforms.ToTensor()(np.array(self.transform3(image))))\n", + " self.augmentedlabels.append(index)\n", + "\n", + " self.augmentedimages.append(torchvision.transforms.ToTensor()(np.array(image + torch.std(image)*torch.randn(image.size()))))\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "# neural network\n", + "import torch\n", + "import torch.nn as nn\n", + "import torch.nn.functional as F\n", + "\n", + "class StartingNetwork(nn.Module):\n", + " \"\"\"\n", + " Basic logistic regression on 224x224x3 images.\n", + " \"\"\"\n", + "\n", + " def __init__(self):\n", + " super().__init__()\n", + " \n", + " self.conv1 = nn.Conv2d(1, 4, kernel_size = 5, padding = 2)\n", + " self.conv2 = nn.Conv2d(4, 8, kernel_size = 3, padding = 1)\n", + " self.conv3 = nn.Conv2d(8, 16, kernel_size = 3, padding = 1)\n", + " \n", + " self.pool = nn.MaxPool2d(2, 2)\n", + " \n", + " self.fc1 = nn.Linear(16 * 56 * 28, 5005)\n", + " # self.fc2 = nn.Linear(20020, 10010)\n", + " # self.fc3 = nn.Linear(10010 ,5005)\n", + "\n", + " def forward(self, x):\n", + " x = x.float()\n", + "\n", + " #Forward porp\n", + " # (n, 1, 448, 224)\n", + " x = self.conv1(x)\n", + " x = F.relu(x)\n", + " # (n, 4, 448, 224)\n", + " x = self.pool(x)\n", + " # (n, 4, 224, 112)\n", + " x = self.conv2(x)\n", + " x = F.relu(x)\n", + " # (n, 8, 224, 112)\n", + " x = self.pool(x)\n", + " # (n, 8, 112, 56)\n", + " x = self.conv3(x)\n", + " x = F.relu(x)\n", + " # (n, 16, 112, 56)\n", + " x = self.pool(x)\n", + " # (n, 16, 56, 28)\n", + "\n", + " x = torch.reshape(x, (-1, 16 * 56 * 28))\n", + " # (n, 8 * 112 * 56)\n", + " x = self.fc1(x)\n", + " # x = F.relu(x)\n", + " # (n, 20020)\n", + " # x = self.fc2(x)\n", + " # x = F.relu(x)\n", + " # (n, 10010)\n", + " # x = self.fc3(x)\n", + " # (n, 5005)\n", + " return x\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "# train function\n", + "import torch\n", + "import torch.nn as nn\n", + "import torch.optim as optim\n", + "from tqdm import tqdm\n", + "# from torch.utils.tensorboard import SummaryWriter\n", + "\n", + "\n", + "def starting_train(train_dataset, val_dataset, model, hyperparameters, n_eval, device):\n", + " \"\"\"\n", + " Trains and evaluates a model.\n", + "\n", + " Args:\n", + " train_dataset: PyTorch dataset containing training data.\n", + " val_dataset: PyTorch dataset containing validation data.\n", + " model: PyTorch model to be trained.\n", + " hyperparameters: Dictionary containing hyperparameters.\n", + " n_eval: Interval at which we evaluate our model.\n", + " \"\"\"\n", + "\n", + " # Get keyword arguments\n", + " batch_size, epochs = hyperparameters[\"batch_size\"], hyperparameters[\"epochs\"]\n", + "\n", + " # Initialize dataloaders\n", + " train_loader = torch.utils.data.DataLoader(\n", + " train_dataset, batch_size=batch_size, shuffle=True\n", + " )\n", + " val_loader = torch.utils.data.DataLoader(\n", + " val_dataset, batch_size=batch_size, shuffle=True\n", + " )\n", + "\n", + " # Initalize optimizer (for gradient descent) and loss function\n", + " optimizer = optim.Adam(model.parameters())\n", + " loss_fn = nn.CrossEntropyLoss()\n", + "\n", + " # Move the model to the GPU\n", + " model = model.to(device)\n", + "\n", + " step = 1\n", + "\n", + " # tb = SummaryWriter()\n", + " for epoch in range(epochs):\n", + " print(f\"Epoch {epoch + 1} of {epochs}\")\n", + "\n", + " # Loop over each batch in the dataset\n", + " for batch in tqdm(train_loader):\n", + " # TODO: Backpropagation and gradient descent\n", + " images, labels = batch\n", + " labels = torch.stack(list(labels), dim=0)\n", + "\n", + " images = images.to(device)\n", + " labels = labels.to(device)\n", + "\n", + " outputs = model(images)\n", + "\n", + " loss = loss_fn(outputs, labels)\n", + " loss.backward() # Compute gradients\n", + " optimizer.step() # Update all the weights with the gradients you just calculated\n", + " optimizer.zero_grad()\n", + "\n", + " # Periodically evaluate our model + log to Tensorboard\n", + " # if step % n_eval == 0:\n", + " # TODO:\n", + " # Compute training loss and accuracy.\n", + " # Log the results to Tensorboard.\n", + "\n", + " # with torch.no_grad():\n", + " # images = images.to(device)\n", + " # labels = labels.to(device)\n", + "\n", + " # predictions = torch.argmax(outputs, dim=1)\n", + "\n", + " # accuracy = compute_accuracy(predictions, labels)\n", + " # print('Accuracy: ', accuracy)\n", + "\n", + " # TODO:\n", + " # Compute validation loss and accuracy.\n", + " # Log the results to Tensorboard.\n", + " # Don't forget to turn off gradient calculations!\n", + "\n", + " step += 1\n", + "\n", + " print('Epoch:', epoch, 'Loss:', loss.item())\n", + " evaluate(val_loader, model, loss_fn, device)\n", + " # tb.close()\n", + "\n", + "\n", + "def compute_accuracy(outputs, labels):\n", + " \"\"\"\n", + " Computes the accuracy of a model's predictions.\n", + "\n", + " Example input:\n", + " outputs: [0.7, 0.9, 0.3, 0.2]\n", + " labels: [1, 1, 0, 1]\n", + "\n", + " Example output:\n", + " 0.75\n", + " \"\"\"\n", + "\n", + " n_correct = (outputs == labels).int().sum()\n", + " n_total = len(outputs)\n", + " return n_correct / n_total\n", + "\n", + "\n", + "def evaluate(val_loader, model, loss_fn, device):\n", + " \"\"\"\n", + " Computes the loss and accuracy of a model on the validation dataset.\n", + " \"\"\"\n", + "\n", + " model.eval()\n", + "\n", + " correct = 0\n", + " total = 0\n", + " loss = 0\n", + " with torch.no_grad(): # IMPORTANT: turn off gradient computations\n", + " for batch in val_loader:\n", + " images, labels = batch\n", + " images = images.to(device)\n", + " labels = labels.to(device)\n", + "\n", + " outputs = model(images)\n", + " predictions = torch.argmax(outputs, dim=1)\n", + "\n", + " # labels == predictions does an elementwise comparison\n", + " # e.g. labels = [1, 2, 3, 4]\n", + " # predictions = [1, 4, 3, 3]\n", + " # labels == predictions = [1, 0, 1, 0] (where 1 is true, 0 is false)\n", + " # So the number of correct predictions is the sum of (labels == predictions)\n", + " correct += (labels == predictions).int().sum()\n", + " total += len(predictions)\n", + " loss += loss_fn(outputs, labels)\n", + "\n", + " \n", + " print(correct / total)\n", + " model.train()\n", + "\n", + " # tb.add_scalar(\"Loss\", loss, epoch)\n", + " # tb.add_scalar(\"Correct\", correct, epoch)\n", + " # tb.add_scalar(\"Accuracy\", correct / total, epoch)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Epochs: 1\n", + "Batch size: 16\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " 0%| | 0/1110 [00:00\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 33\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 34\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0m__name__\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"__main__\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 35\u001b[0;31m \u001b[0mmain\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36mmain\u001b[0;34m()\u001b[0m\n\u001b[1;32m 22\u001b[0m \u001b[0mtrain_dataset\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mval_dataset\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtorch\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mutils\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrandom_split\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mtrain_size\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtest_size\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 23\u001b[0m \u001b[0mmodel\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mStartingNetwork\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 24\u001b[0;31m starting_train(\n\u001b[0m\u001b[1;32m 25\u001b[0m \u001b[0mtrain_dataset\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mtrain_dataset\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 26\u001b[0m \u001b[0mval_dataset\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mval_dataset\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repos/50whales/train_functions/starting_train.py\u001b[0m in \u001b[0;36mstarting_train\u001b[0;34m(train_dataset, val_dataset, model, hyperparameters, n_eval, device)\u001b[0m\n\u001b[1;32m 56\u001b[0m \u001b[0mloss\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbackward\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# Compute gradients\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 57\u001b[0m \u001b[0moptimizer\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstep\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# Update all the weights with the gradients you just calculated\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 58\u001b[0;31m \u001b[0moptimizer\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mzero_grad\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 59\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 60\u001b[0m \u001b[0;31m# Periodically evaluate our model + log to Tensorboard\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/opt/anaconda3/envs/acm/lib/python3.8/site-packages/torch/optim/optimizer.py\u001b[0m in \u001b[0;36mzero_grad\u001b[0;34m(self, set_to_none)\u001b[0m\n\u001b[1;32m 215\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 216\u001b[0m \u001b[0mp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgrad\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrequires_grad_\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 217\u001b[0;31m \u001b[0mp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgrad\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mzero_\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 218\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 219\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mstep\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mclosure\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mKeyboardInterrupt\u001b[0m: " + ] + } + ], + "source": [ + "# main\n", + "import torch\n", + "from train_functions.starting_train import starting_train\n", + "from PIL import Image\n", + "\n", + "\n", + "def main():\n", + " # Get command line arguments\n", + " hyperparameters = {\"epochs\": EPOCHS, \"batch_size\": BATCH_SIZE}\n", + "\n", + " # Add GPU support. This line of code might be helpful.\n", + " device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n", + " # device = torch.device(\"cpu\")\n", + "\n", + " print(\"Epochs:\", EPOCHS)\n", + " print(\"Batch size:\", BATCH_SIZE)\n", + "\n", + " # Initalize dataset and model. Then train the model!\n", + " data = StartingDataset(\"/train/\")\n", + " train_size = int(0.7 * len(data))\n", + " test_size = len(data) - train_size\n", + " train_dataset, val_dataset = torch.utils.data.random_split(data, [train_size, test_size])\n", + " model = StartingNetwork()\n", + " starting_train(\n", + " train_dataset=train_dataset,\n", + " val_dataset=val_dataset,\n", + " model=model,\n", + " hyperparameters=hyperparameters,\n", + " n_eval=N_EVAL,\n", + " device = device\n", + " )\n", + "\n", + "\n", + "if __name__ == \"__main__\":\n", + " main()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "interpreter": { + "hash": "e9b712ea729e402836c5595724b4e6d35efa45a29af25a2578c0523890674d22" + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.5" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/main.py b/main.py index 820f0b1..033586f 100644 --- a/main.py +++ b/main.py @@ -1,24 +1,33 @@ import os import constants +from data.ImageAugment import ImageAugment +import torch from data.StartingDataset import StartingDataset from networks.StartingNetwork import StartingNetwork from train_functions.starting_train import starting_train +from PIL import Image def main(): # Get command line arguments hyperparameters = {"epochs": constants.EPOCHS, "batch_size": constants.BATCH_SIZE} - # TODO: Add GPU support. This line of code might be helpful. - # device = torch.device("cuda" if torch.cuda.is_available() else "cpu") + # Add GPU support. This line of code might be helpful. + device = torch.device("cuda" if torch.cuda.is_available() else "cpu") + # device = torch.device("cpu") print("Epochs:", constants.EPOCHS) print("Batch size:", constants.BATCH_SIZE) # Initalize dataset and model. Then train the model! - train_dataset = StartingDataset() - val_dataset = StartingDataset() + data = ImageAugment("/train/") + currentlen = len(data) + for i in range(currentlen): + data.augment(i) + train_size = int(0.7 * len(data)) + test_size = len(data) - train_size + train_dataset, val_dataset = torch.utils.data.random_split(data, [train_size, test_size]) model = StartingNetwork() starting_train( train_dataset=train_dataset, @@ -26,6 +35,7 @@ def main(): model=model, hyperparameters=hyperparameters, n_eval=constants.N_EVAL, + device = device ) diff --git a/networks/StartingNetwork.py b/networks/StartingNetwork.py index 9924108..5e10af4 100644 --- a/networks/StartingNetwork.py +++ b/networks/StartingNetwork.py @@ -1,20 +1,55 @@ import torch import torch.nn as nn +import torch.nn.functional as F -class StartingNetwork(torch.nn.Module): +class StartingNetwork(nn.Module): """ Basic logistic regression on 224x224x3 images. """ def __init__(self): super().__init__() - self.flatten = nn.Flatten() - self.fc = nn.Linear(224 * 224 * 3, 1) - self.sigmoid = nn.Sigmoid() + + self.conv1 = nn.Conv2d(1, 4, kernel_size = 5, padding = 2) + self.conv2 = nn.Conv2d(4, 8, kernel_size = 3, padding = 1) + self.conv3 = nn.Conv2d(8, 16, kernel_size = 3, padding = 1) + + self.pool = nn.MaxPool2d(2, 2) + + self.fc1 = nn.Linear(16 * 56 * 28, 5005) + # self.fc2 = nn.Linear(20020, 10010) + # self.fc3 = nn.Linear(10010 ,5005) def forward(self, x): - x = self.flatten(x) - x = self.fc(x) - x = self.sigmoid(x) + x = x.float() + + #Forward porp + # (n, 1, 448, 224) + x = self.conv1(x) + x = F.relu(x) + # (n, 4, 448, 224) + x = self.pool(x) + # (n, 4, 224, 112) + x = self.conv2(x) + x = F.relu(x) + # (n, 8, 224, 112) + x = self.pool(x) + # (n, 8, 112, 56) + x = self.conv3(x) + x = F.relu(x) + # (n, 16, 112, 56) + x = self.pool(x) + # (n, 16, 56, 28) + + x = torch.reshape(x, (-1, 16 * 56 * 28)) + # (n, 8 * 112 * 56) + x = self.fc1(x) + # x = F.relu(x) + # (n, 20020) + # x = self.fc2(x) + # x = F.relu(x) + # (n, 10010) + # x = self.fc3(x) + # (n, 5005) return x diff --git a/runs/Feb07_19-29-01_Austins-MacBook-Air.local/events.out.tfevents.1644290941.Austins-MacBook-Air.local.44461.0 b/runs/Feb07_19-29-01_Austins-MacBook-Air.local/events.out.tfevents.1644290941.Austins-MacBook-Air.local.44461.0 new file mode 100644 index 0000000..c85dfe8 Binary files /dev/null and b/runs/Feb07_19-29-01_Austins-MacBook-Air.local/events.out.tfevents.1644290941.Austins-MacBook-Air.local.44461.0 differ diff --git a/runs/Feb07_19-40-35_Austins-MacBook-Air.local/events.out.tfevents.1644291635.Austins-MacBook-Air.local.44676.0 b/runs/Feb07_19-40-35_Austins-MacBook-Air.local/events.out.tfevents.1644291635.Austins-MacBook-Air.local.44676.0 new file mode 100644 index 0000000..d1eba93 Binary files /dev/null and b/runs/Feb07_19-40-35_Austins-MacBook-Air.local/events.out.tfevents.1644291635.Austins-MacBook-Air.local.44676.0 differ diff --git a/runs/Feb07_19-42-19_Austins-MacBook-Air.local/events.out.tfevents.1644291739.Austins-MacBook-Air.local.44770.0 b/runs/Feb07_19-42-19_Austins-MacBook-Air.local/events.out.tfevents.1644291739.Austins-MacBook-Air.local.44770.0 new file mode 100644 index 0000000..0e949c1 Binary files /dev/null and b/runs/Feb07_19-42-19_Austins-MacBook-Air.local/events.out.tfevents.1644291739.Austins-MacBook-Air.local.44770.0 differ diff --git a/runs/Feb07_19-42-42_Austins-MacBook-Air.local/events.out.tfevents.1644291762.Austins-MacBook-Air.local.44795.0 b/runs/Feb07_19-42-42_Austins-MacBook-Air.local/events.out.tfevents.1644291762.Austins-MacBook-Air.local.44795.0 new file mode 100644 index 0000000..2d3970a Binary files /dev/null and b/runs/Feb07_19-42-42_Austins-MacBook-Air.local/events.out.tfevents.1644291762.Austins-MacBook-Air.local.44795.0 differ diff --git a/runs/Feb07_19-46-45_Austins-MacBook-Air.local/events.out.tfevents.1644292005.Austins-MacBook-Air.local.44871.0 b/runs/Feb07_19-46-45_Austins-MacBook-Air.local/events.out.tfevents.1644292005.Austins-MacBook-Air.local.44871.0 new file mode 100644 index 0000000..edb442e Binary files /dev/null and b/runs/Feb07_19-46-45_Austins-MacBook-Air.local/events.out.tfevents.1644292005.Austins-MacBook-Air.local.44871.0 differ diff --git a/runs/Feb07_19-48-59_Austins-MacBook-Air.local/events.out.tfevents.1644292139.Austins-MacBook-Air.local.44905.0 b/runs/Feb07_19-48-59_Austins-MacBook-Air.local/events.out.tfevents.1644292139.Austins-MacBook-Air.local.44905.0 new file mode 100644 index 0000000..444d300 Binary files /dev/null and b/runs/Feb07_19-48-59_Austins-MacBook-Air.local/events.out.tfevents.1644292139.Austins-MacBook-Air.local.44905.0 differ diff --git a/runs/Feb07_19-49-23_Austins-MacBook-Air.local/events.out.tfevents.1644292163.Austins-MacBook-Air.local.44927.0 b/runs/Feb07_19-49-23_Austins-MacBook-Air.local/events.out.tfevents.1644292163.Austins-MacBook-Air.local.44927.0 new file mode 100644 index 0000000..1d49ec7 Binary files /dev/null and b/runs/Feb07_19-49-23_Austins-MacBook-Air.local/events.out.tfevents.1644292163.Austins-MacBook-Air.local.44927.0 differ diff --git a/runs/Feb07_19-53-46_Austins-MacBook-Air.local/events.out.tfevents.1644292426.Austins-MacBook-Air.local.45032.0 b/runs/Feb07_19-53-46_Austins-MacBook-Air.local/events.out.tfevents.1644292426.Austins-MacBook-Air.local.45032.0 new file mode 100644 index 0000000..433f691 Binary files /dev/null and b/runs/Feb07_19-53-46_Austins-MacBook-Air.local/events.out.tfevents.1644292426.Austins-MacBook-Air.local.45032.0 differ diff --git a/runs/Feb07_19-55-10_Austins-MacBook-Air.local/events.out.tfevents.1644292510.Austins-MacBook-Air.local.45063.0 b/runs/Feb07_19-55-10_Austins-MacBook-Air.local/events.out.tfevents.1644292510.Austins-MacBook-Air.local.45063.0 new file mode 100644 index 0000000..3aa95ab Binary files /dev/null and b/runs/Feb07_19-55-10_Austins-MacBook-Air.local/events.out.tfevents.1644292510.Austins-MacBook-Air.local.45063.0 differ diff --git a/runs/Feb07_19-57-43_Austins-MacBook-Air.local/events.out.tfevents.1644292663.Austins-MacBook-Air.local.45120.0 b/runs/Feb07_19-57-43_Austins-MacBook-Air.local/events.out.tfevents.1644292663.Austins-MacBook-Air.local.45120.0 new file mode 100644 index 0000000..1721c5e Binary files /dev/null and b/runs/Feb07_19-57-43_Austins-MacBook-Air.local/events.out.tfevents.1644292663.Austins-MacBook-Air.local.45120.0 differ diff --git a/runs/Feb07_20-18-47_Austins-MacBook-Air.local/events.out.tfevents.1644293927.Austins-MacBook-Air.local.45471.0 b/runs/Feb07_20-18-47_Austins-MacBook-Air.local/events.out.tfevents.1644293927.Austins-MacBook-Air.local.45471.0 new file mode 100644 index 0000000..f386ff1 Binary files /dev/null and b/runs/Feb07_20-18-47_Austins-MacBook-Air.local/events.out.tfevents.1644293927.Austins-MacBook-Air.local.45471.0 differ diff --git a/runs/Feb10_18-14-19_Austins-MacBook-Air.local/events.out.tfevents.1644545659.Austins-MacBook-Air.local.57953.0 b/runs/Feb10_18-14-19_Austins-MacBook-Air.local/events.out.tfevents.1644545659.Austins-MacBook-Air.local.57953.0 new file mode 100644 index 0000000..d72bd36 Binary files /dev/null and b/runs/Feb10_18-14-19_Austins-MacBook-Air.local/events.out.tfevents.1644545659.Austins-MacBook-Air.local.57953.0 differ diff --git a/runs/Feb10_18-30-34_Austins-MacBook-Air.local/events.out.tfevents.1644546634.Austins-MacBook-Air.local.58453.0 b/runs/Feb10_18-30-34_Austins-MacBook-Air.local/events.out.tfevents.1644546634.Austins-MacBook-Air.local.58453.0 new file mode 100644 index 0000000..d13e732 Binary files /dev/null and b/runs/Feb10_18-30-34_Austins-MacBook-Air.local/events.out.tfevents.1644546634.Austins-MacBook-Air.local.58453.0 differ diff --git a/runs/Feb10_18-31-18_Austins-MacBook-Air.local/events.out.tfevents.1644546678.Austins-MacBook-Air.local.58482.0 b/runs/Feb10_18-31-18_Austins-MacBook-Air.local/events.out.tfevents.1644546678.Austins-MacBook-Air.local.58482.0 new file mode 100644 index 0000000..a108a2e Binary files /dev/null and b/runs/Feb10_18-31-18_Austins-MacBook-Air.local/events.out.tfevents.1644546678.Austins-MacBook-Air.local.58482.0 differ diff --git a/runs/Feb10_18-33-33_Austins-MacBook-Air.local/events.out.tfevents.1644546813.Austins-MacBook-Air.local.58547.0 b/runs/Feb10_18-33-33_Austins-MacBook-Air.local/events.out.tfevents.1644546813.Austins-MacBook-Air.local.58547.0 new file mode 100644 index 0000000..7826b2d Binary files /dev/null and b/runs/Feb10_18-33-33_Austins-MacBook-Air.local/events.out.tfevents.1644546813.Austins-MacBook-Air.local.58547.0 differ diff --git a/runs/Feb10_18-48-20_Austins-MacBook-Air.local/events.out.tfevents.1644547700.Austins-MacBook-Air.local.58736.0 b/runs/Feb10_18-48-20_Austins-MacBook-Air.local/events.out.tfevents.1644547700.Austins-MacBook-Air.local.58736.0 new file mode 100644 index 0000000..d253bdc Binary files /dev/null and b/runs/Feb10_18-48-20_Austins-MacBook-Air.local/events.out.tfevents.1644547700.Austins-MacBook-Air.local.58736.0 differ diff --git a/runs/Feb10_18-50-47_Austins-MacBook-Air.local/events.out.tfevents.1644547847.Austins-MacBook-Air.local.58802.0 b/runs/Feb10_18-50-47_Austins-MacBook-Air.local/events.out.tfevents.1644547847.Austins-MacBook-Air.local.58802.0 new file mode 100644 index 0000000..9db16d7 Binary files /dev/null and b/runs/Feb10_18-50-47_Austins-MacBook-Air.local/events.out.tfevents.1644547847.Austins-MacBook-Air.local.58802.0 differ diff --git a/runs/Feb10_18-51-05_Austins-MacBook-Air.local/events.out.tfevents.1644547865.Austins-MacBook-Air.local.58831.0 b/runs/Feb10_18-51-05_Austins-MacBook-Air.local/events.out.tfevents.1644547865.Austins-MacBook-Air.local.58831.0 new file mode 100644 index 0000000..be5dace Binary files /dev/null and b/runs/Feb10_18-51-05_Austins-MacBook-Air.local/events.out.tfevents.1644547865.Austins-MacBook-Air.local.58831.0 differ diff --git a/runs/Feb10_19-02-22_Austins-MacBook-Air.local/events.out.tfevents.1644548542.Austins-MacBook-Air.local.59001.0 b/runs/Feb10_19-02-22_Austins-MacBook-Air.local/events.out.tfevents.1644548542.Austins-MacBook-Air.local.59001.0 new file mode 100644 index 0000000..1656fde Binary files /dev/null and b/runs/Feb10_19-02-22_Austins-MacBook-Air.local/events.out.tfevents.1644548542.Austins-MacBook-Air.local.59001.0 differ diff --git a/runs/Feb10_19-03-32_Austins-MacBook-Air.local/events.out.tfevents.1644548612.Austins-MacBook-Air.local.59043.0 b/runs/Feb10_19-03-32_Austins-MacBook-Air.local/events.out.tfevents.1644548612.Austins-MacBook-Air.local.59043.0 new file mode 100644 index 0000000..aff55b8 Binary files /dev/null and b/runs/Feb10_19-03-32_Austins-MacBook-Air.local/events.out.tfevents.1644548612.Austins-MacBook-Air.local.59043.0 differ diff --git a/runs/Feb10_19-06-43_Austins-MacBook-Air.local/events.out.tfevents.1644548803.Austins-MacBook-Air.local.59121.0 b/runs/Feb10_19-06-43_Austins-MacBook-Air.local/events.out.tfevents.1644548803.Austins-MacBook-Air.local.59121.0 new file mode 100644 index 0000000..4f69be1 Binary files /dev/null and b/runs/Feb10_19-06-43_Austins-MacBook-Air.local/events.out.tfevents.1644548803.Austins-MacBook-Air.local.59121.0 differ diff --git a/runs/Feb10_19-07-46_Austins-MacBook-Air.local/events.out.tfevents.1644548866.Austins-MacBook-Air.local.59151.0 b/runs/Feb10_19-07-46_Austins-MacBook-Air.local/events.out.tfevents.1644548866.Austins-MacBook-Air.local.59151.0 new file mode 100644 index 0000000..a0c2b92 Binary files /dev/null and b/runs/Feb10_19-07-46_Austins-MacBook-Air.local/events.out.tfevents.1644548866.Austins-MacBook-Air.local.59151.0 differ diff --git a/runs/Feb10_19-08-12_Austins-MacBook-Air.local/events.out.tfevents.1644548892.Austins-MacBook-Air.local.59180.0 b/runs/Feb10_19-08-12_Austins-MacBook-Air.local/events.out.tfevents.1644548892.Austins-MacBook-Air.local.59180.0 new file mode 100644 index 0000000..9fd5de6 Binary files /dev/null and b/runs/Feb10_19-08-12_Austins-MacBook-Air.local/events.out.tfevents.1644548892.Austins-MacBook-Air.local.59180.0 differ diff --git a/runs/Feb10_19-09-32_Austins-MacBook-Air.local/events.out.tfevents.1644548972.Austins-MacBook-Air.local.59206.0 b/runs/Feb10_19-09-32_Austins-MacBook-Air.local/events.out.tfevents.1644548972.Austins-MacBook-Air.local.59206.0 new file mode 100644 index 0000000..a377624 Binary files /dev/null and b/runs/Feb10_19-09-32_Austins-MacBook-Air.local/events.out.tfevents.1644548972.Austins-MacBook-Air.local.59206.0 differ diff --git a/train_functions/starting_train.py b/train_functions/starting_train.py index 9bab2a9..20a18f9 100644 --- a/train_functions/starting_train.py +++ b/train_functions/starting_train.py @@ -2,9 +2,11 @@ import torch.nn as nn import torch.optim as optim from tqdm import tqdm +from torch.utils.tensorboard import SummaryWriter +writer = SummaryWriter() -def starting_train(train_dataset, val_dataset, model, hyperparameters, n_eval): +def starting_train(train_dataset, val_dataset, model, hyperparameters, n_eval, device): """ Trains and evaluates a model. @@ -31,32 +33,60 @@ def starting_train(train_dataset, val_dataset, model, hyperparameters, n_eval): optimizer = optim.Adam(model.parameters()) loss_fn = nn.CrossEntropyLoss() - step = 0 + # Move the model to the GPU + model = model.to(device) + + step = 1 + + # tb = SummaryWriter() for epoch in range(epochs): print(f"Epoch {epoch + 1} of {epochs}") # Loop over each batch in the dataset for batch in tqdm(train_loader): # TODO: Backpropagation and gradient descent + images, labels = batch + labels = torch.stack(list(labels), dim=0) + + images = images.to(device) + labels = labels.to(device) + + outputs = model(images) + + loss = loss_fn(outputs, labels) + loss.backward() # Compute gradients + optimizer.step() # Update all the weights with the gradients you just calculated + optimizer.zero_grad() # Periodically evaluate our model + log to Tensorboard if step % n_eval == 0: + model.eval() # TODO: # Compute training loss and accuracy. # Log the results to Tensorboard. + tloss, taccuracy = evaluate(train_loader, model, loss_fn, device) + writer.add_scalar("Loss/train", tloss, epoch + 1) + writer.add_scalar("Accuracy/train", taccuracy, epoch + 1) + # TODO: # Compute validation loss and accuracy. # Log the results to Tensorboard. # Don't forget to turn off gradient calculations! - evaluate(val_loader, model, loss_fn) + + vloss, vaccuracy= evaluate(val_loader, model, loss_fn, device) + writer.add_scalar("Loss/val", vloss, epoch + 1) + writer.add_scalar("Accuracy/val", vaccuracy, epoch + 1) + model.train() step += 1 - print() + print('Epoch:', epoch, 'Loss:', loss.item()) + + writer.flush() -def compute_accuracy(outputs, labels): +async def compute_accuracy(outputs, labels): """ Computes the accuracy of a model's predictions. @@ -68,15 +98,37 @@ def compute_accuracy(outputs, labels): 0.75 """ - n_correct = (torch.round(outputs) == labels).sum().item() + n_correct = (outputs == labels).int().sum() n_total = len(outputs) return n_correct / n_total -def evaluate(val_loader, model, loss_fn): +async def evaluate(loader, model, loss_fn, device): """ Computes the loss and accuracy of a model on the validation dataset. - - TODO! """ - pass + correct = 0 + total = 0 + loss = 0 + with torch.no_grad(): # IMPORTANT: turn off gradient computations + for batch in loader: + images, labels = batch + images = images.to(device) + labels = labels.to(device) + + outputs = model(images) + predictions = torch.argmax(outputs, dim=1) + + # labels == predictions does an elementwise comparison + # e.g. labels = [1, 2, 3, 4] + # predictions = [1, 4, 3, 3] + # labels == predictions = [1, 0, 1, 0] (where 1 is true, 0 is false) + # So the number of correct predictions is the sum of (labels == predictions) + correct += (labels == predictions).int().sum() + total += len(predictions) + loss += loss_fn(outputs, labels) + + accuracy = correct / total + + return loss, accuracy +