Compare commits

...
10 Commits
Author SHA1 Message Date
KeshavAnandCode bde3b97266 finished CNN, good accruacy overall but not good for minority and harder classes 2026-03-18 18:10:08 -05:00
KeshavAnandCode 4556d8c780 finished model 2026-03-18 18:07:31 -05:00
KeshavAnandCode 5cee36c80e optimizer, loss for tutorial cnn 2026-03-18 18:02:21 -05:00
KeshavAnandCode 255a9aa73c finished CNN class 2026-03-18 17:56:49 -05:00
KeshavAnandCode d756b6bd1a split 2026-03-18 17:33:10 -05:00
KeshavAnandCode 64ed10e95c Torch working 2026-03-18 17:26:52 -05:00
KeshavAnandCode 69e4f4a584 exploring photo 2026-03-18 17:14:00 -05:00
KeshavAnandCode e2406925da exploring data 2026-03-18 17:12:34 -05:00
KeshavAnandCode 8c74fb780d Real hellow world 2026-03-18 17:08:08 -05:00
KeshavAnandCode 9b65795602 hello world 2026-03-18 17:06:05 -05:00
4 changed files with 566 additions and 10 deletions

No files matched your search

+5
View File
@@ -193,3 +193,8 @@ ipython_config.py
data/** data/**
!data/**/ !data/**/
!**/.gitkeep !**/.gitkeep
models/**
!**/.gitkeep
View File
Whitespace-only changes.
+538
View File
@@ -0,0 +1,538 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 2,
"id": "7a37220a",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Hello, World!\n"
]
}
],
"source": [
"print(\"Hello, World!\")"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "d318d1f0",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Van: 1111 images\n",
"Taxi: 748 images\n",
"Bicycle: 1618 images\n",
"Bus: 2133 images\n",
"Car: 6781 images\n",
"Motorcycle: 2986 images\n",
"Truck: 2033 images\n",
"NonVehicles: 8968 images\n"
]
}
],
"source": [
"import os\n",
"\n",
"data_dir = '../data/raw/vehicle_classification'\n",
"\n",
"for class_name in os.listdir(data_dir):\n",
" class_path = os.path.join(data_dir, class_name)\n",
" if os.path.isdir(class_path):\n",
" count = len(os.listdir(class_path))\n",
" print(f\"{class_name}: {count} images\")"
]
},
{
"cell_type": "markdown",
"id": "64122ad4",
"metadata": {},
"source": [
"Check out sample image from dataset"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "5604ace3",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Size: (64, 64)\n",
"Mode: RGB\n"
]
},
{
"data": {
"image/png": "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 truncated
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"from PIL import Image\n",
"import matplotlib.pyplot as plt\n",
"\n",
"# first image in first folder\n",
"first_class = os.listdir(data_dir)[0]\n",
"first_image_path = os.path.join(data_dir, first_class, os.listdir(os.path.join(data_dir, first_class))[0])\n",
"\n",
"img = Image.open(first_image_path)\n",
"print(f\"Size: {img.size}\")\n",
"print(f\"Mode: {img.mode}\")\n",
"plt.imshow(img)\n",
"plt.title(first_class)\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"id": "c19ec00a",
"metadata": {},
"source": [
"Ensure that all images are RGB, all of same resolution"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "3cedd586",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Unique sizes: {(64, 64)}\n",
"Unique modes: {'RGB'}\n"
]
}
],
"source": [
"sizes = set()\n",
"modes = set()\n",
"\n",
"for class_name in os.listdir(data_dir):\n",
" class_path = os.path.join(data_dir, class_name)\n",
" if not os.path.isdir(class_path):\n",
" continue\n",
" for img_name in os.listdir(class_path):\n",
" img = Image.open(os.path.join(class_path, img_name))\n",
" sizes.add(img.size)\n",
" modes.add(img.mode)\n",
"\n",
"print(f\"Unique sizes: {sizes}\")\n",
"print(f\"Unique modes: {modes}\")"
]
},
{
"cell_type": "markdown",
"id": "88ac961b",
"metadata": {},
"source": [
"Ensure that torch works with GPU (5080) [Credit: Claude]"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "8f556b22",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"True\n",
"NVIDIA GeForce RTX 5080\n",
"GPU works! torch.Size([1000, 1000])\n"
]
}
],
"source": [
"import torch\n",
"print(torch.cuda.is_available()) \n",
"print(torch.cuda.get_device_name(0)) \n",
"\n",
"x = torch.randn(1000, 1000).cuda()\n",
"y = x @ x\n",
"print(\"GPU works!\", y.shape)"
]
},
{
"cell_type": "markdown",
"id": "870fadbe",
"metadata": {},
"source": [
"Transform image dataset into tensors. Normalized with 0.5 mean and 0.5 STD (can be differente to use pretrained weights)."
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "37793c77",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['Bicycle', 'Bus', 'Car', 'Motorcycle', 'NonVehicles', 'Taxi', 'Truck', 'Van']\n",
"26378\n"
]
}
],
"source": [
"from torchvision import datasets, transforms\n",
"from torch.utils.data import random_split, DataLoader\n",
"\n",
"transform = transforms.Compose([\n",
" transforms.ToTensor(),\n",
" transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])\n",
"])\n",
"\n",
"dataset = datasets.ImageFolder(root=data_dir, transform=transform)\n",
"\n",
"print(dataset.classes) # should print 8 classes\n",
"print(len(dataset)) # total image count"
]
},
{
"cell_type": "markdown",
"id": "ac33bc21",
"metadata": {},
"source": [
"Split 80-20 and save into 2 variables"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "f68c1a25",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Train: 21102, Test: 5276\n"
]
}
],
"source": [
"import math \n",
"\n",
"train_size = math.floor(len(dataset) * 0.8)\n",
"test_size = len(dataset) - train_size\n",
"\n",
"train_dataset, test_dataset = random_split(dataset, [train_size, test_size])\n",
"\n",
"print(f\"Train: {len(train_dataset)}, Test: {len(test_dataset)}\")"
]
},
{
"cell_type": "markdown",
"id": "2eede814",
"metadata": {},
"source": [
"Load the data into batches for faster loading...use 4 threads on CPU\n",
"\n",
"Shuffling train dataset so as to not overfit on one class"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "e1539eaa",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"8\n"
]
}
],
"source": [
"train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True, num_workers=4)\n",
"test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False, num_workers=4)\n",
"\n",
"classes = ('bicycle', 'bus', 'car', 'motorcycle',\n",
" 'nonvehicles', 'taxi', 'truck', 'van')\n",
"\n",
"print(len(classes))"
]
},
{
"cell_type": "markdown",
"id": "acebe98e",
"metadata": {},
"source": [
"Tutorial CNN architecture implmenetation"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "d1b7d9ca",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Net(\n",
" (conv1): Conv2d(3, 6, kernel_size=(5, 5), stride=(1, 1))\n",
" (pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)\n",
" (conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))\n",
" (fc1): Linear(in_features=2704, out_features=120, bias=True)\n",
" (fc2): Linear(in_features=120, out_features=84, bias=True)\n",
" (fc3): Linear(in_features=84, out_features=8, bias=True)\n",
")\n"
]
}
],
"source": [
"import torch\n",
"import torch.nn as nn\n",
"import torch.nn.functional as F\n",
"\n",
"class Net(nn.Module):\n",
" def __init__(self):\n",
" super().__init__()\n",
" self.conv1 = nn.Conv2d(3, 6, 5) # 3 input channels for RGB, 6 filters [arbitrailly chosen ffrom PyTorch], 5x5 Kernel Size\n",
" self.pool = nn.MaxPool2d(2, 2) # Halves spatial dimensions\n",
" self.conv2 = nn.Conv2d(6, 16, 5) # 6 matches output of first conv layer, 16 arbitrary filter (more than earlier), 5x5 kernel\n",
" self.fc1 = nn.Linear(16 * 13 * 13, 120) # 16 channels from conv layer 2; 13 *13 bc shape after 2 layers and 2 pools, 120 is arbitrary output size from tutorial\n",
" self.fc2 = nn.Linear(120, 84) # 120 output from fc1 --> arbitrary lowering to 84\n",
" self.fc3 = nn.Linear(84, len(classes)) # Bring down to number of classes \n",
"\n",
" def forward(self, x):\n",
" x = self.pool(F.relu(self.conv1(x))) #Conv layer 1 --> relu --> pool \n",
" x = self.pool(F.relu(self.conv2(x))) #Conv layer 1 --> relu --> pool \n",
" x = torch.flatten(x, 1) # Flattedn to 1d\n",
" x = F.relu(self.fc1(x)) #fully connected layer shriking 1\n",
" x = F.relu(self.fc2(x)) # Shrink again\n",
" x = self.fc3(x) # Shrink to number of classes\n",
" return x\n",
"\n",
"device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n",
"model = Net().to(device)\n",
"print(model)"
]
},
{
"cell_type": "markdown",
"id": "22e71032",
"metadata": {},
"source": [
"Loss fn and optimizer"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "54d11a04",
"metadata": {},
"outputs": [],
"source": [
"import torch.optim as optim\n",
"\n",
"criterion = nn.CrossEntropyLoss() # Applied softmax to convert scores --> probabilities --> penalizes model \n",
"\n",
"# SGD is used on tutorial, but Adam optimizer is more popular as well\n",
"optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9) # Defualt learning rate from tutorial: compromise btwn overshoot and training infinitely long, 0.9 --> 90% of update comes from prev. direction\n"
]
},
{
"cell_type": "markdown",
"id": "572d80e3",
"metadata": {},
"source": [
"Tutorial training cell adapted to use 10 epochs "
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "374d0590",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch 1: Loss=1.575, Accuracy=50.54%\n",
"Epoch 2: Loss=1.196, Accuracy=60.35%\n",
"Epoch 3: Loss=1.018, Accuracy=64.98%\n",
"Epoch 4: Loss=0.909, Accuracy=68.58%\n",
"Epoch 5: Loss=0.842, Accuracy=70.87%\n",
"Epoch 6: Loss=0.784, Accuracy=72.83%\n",
"Epoch 7: Loss=0.738, Accuracy=74.24%\n",
"Epoch 8: Loss=0.703, Accuracy=75.30%\n",
"Epoch 9: Loss=0.671, Accuracy=76.30%\n",
"Epoch 10: Loss=0.641, Accuracy=77.64%\n",
"Finished Training\n"
]
}
],
"source": [
"for epoch in range(10): # 10 epochs\n",
" running_loss = 0.0\n",
" correct = 0\n",
" total = 0\n",
"\n",
" for i, data in enumerate(train_loader, 0):\n",
" inputs, labels = data\n",
" inputs, labels = inputs.to(device), labels.to(device) # use GPU\n",
"\n",
" optimizer.zero_grad()\n",
"\n",
" outputs = model(inputs)\n",
" loss = criterion(outputs, labels)\n",
" loss.backward()\n",
" optimizer.step()\n",
"\n",
" # loss tracking\n",
" running_loss += loss.item()\n",
"\n",
" # accuracy tracking\n",
" _, predicted = torch.max(outputs, 1)\n",
" total += labels.size(0)\n",
" correct += (predicted == labels).sum().item()\n",
"\n",
" accuracy = 100 * correct / total\n",
" print(f'Epoch {epoch + 1}: Loss={running_loss / len(train_loader):.3f}, Accuracy={accuracy:.2f}%') # Credit: Claude for printing accuracy in good formatting\n",
"\n",
"print('Finished Training')"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "2bf2b9a2",
"metadata": {},
"outputs": [],
"source": [
"PATH = '../models/tutorial-cnn.pth'\n",
"torch.save(model.state_dict(), PATH)"
]
},
{
"cell_type": "markdown",
"id": "a24dd4f0",
"metadata": {},
"source": [
"Test on test set using Pytorch tutorial method for both total and per class (maybe spot overfitting as well)"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "bc158602",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Test Accuracy: 74.53%\n"
]
}
],
"source": [
"correct = 0\n",
"total = 0\n",
"\n",
"with torch.no_grad():\n",
" for data in test_loader:\n",
" images, labels = data\n",
" images, labels = images.to(device), labels.to(device)\n",
" outputs = model(images)\n",
" _, predicted = torch.max(outputs, 1)\n",
" total += labels.size(0)\n",
" correct += (predicted == labels).sum().item()\n",
"\n",
"print(f'Test Accuracy: {100 * correct / total:.2f}%')"
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "8cc7ed40",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Accuracy for class: Bicycle is 43.5%\n",
"Accuracy for class: Bus is 53.8%\n",
"Accuracy for class: Car is 87.6%\n",
"Accuracy for class: Motorcycle is 75.2%\n",
"Accuracy for class: NonVehicles is 99.0%\n",
"Accuracy for class: Taxi is 20.0%\n",
"Accuracy for class: Truck is 13.9%\n",
"Accuracy for class: Van is 24.7%\n"
]
}
],
"source": [
"correct_pred = {classname: 0 for classname in dataset.classes}\n",
"total_pred = {classname: 0 for classname in dataset.classes}\n",
"\n",
"with torch.no_grad():\n",
" for data in test_loader:\n",
" images, labels = data\n",
" images, labels = images.to(device), labels.to(device)\n",
" outputs = model(images)\n",
" _, predictions = torch.max(outputs, 1)\n",
" for label, prediction in zip(labels, predictions):\n",
" if label == prediction:\n",
" correct_pred[dataset.classes[label]] += 1\n",
" total_pred[dataset.classes[label]] += 1\n",
"\n",
"for classname, correct_count in correct_pred.items():\n",
" accuracy = 100 * float(correct_count) / total_pred[classname]\n",
" print(f'Accuracy for class: {classname:10s} is {accuracy:.1f}%')"
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"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.11.15"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
+23 -10
View File
@@ -1,7 +1,9 @@
appnope==0.1.4
asttokens==3.0.1 asttokens==3.0.1
comm==0.2.3 comm==0.2.3
contourpy==1.3.3 contourpy==1.3.3
cuda-bindings==12.9.4
cuda-pathfinder==1.2.2
cuda-toolkit==12.8.1
cycler==0.12.1 cycler==0.12.1
debugpy==1.8.20 debugpy==1.8.20
decorator==5.2.1 decorator==5.2.1
@@ -14,19 +16,32 @@ ipython==9.10.0
ipython_pygments_lexers==1.1.1 ipython_pygments_lexers==1.1.1
jedi==0.19.2 jedi==0.19.2
Jinja2==3.1.6 Jinja2==3.1.6
joblib==1.5.3
jupyter_client==8.8.0 jupyter_client==8.8.0
jupyter_core==5.9.1 jupyter_core==5.9.1
kiwisolver==1.5.0 kiwisolver==1.5.0
MarkupSafe==3.0.3 MarkupSafe==3.0.2
matplotlib==3.10.8 matplotlib==3.10.8
matplotlib-inline==0.2.1 matplotlib-inline==0.2.1
mpmath==1.3.0 mpmath==1.3.0
nest-asyncio==1.6.0 nest-asyncio==1.6.0
networkx==3.6.1 networkx==3.6.1
numpy==2.4.3 numpy==2.4.3
nvidia-cublas-cu12==12.8.4.1
nvidia-cuda-cupti-cu12==12.8.90
nvidia-cuda-nvrtc-cu12==12.8.93
nvidia-cuda-runtime-cu12==12.8.90
nvidia-cudnn-cu12==9.20.0.48
nvidia-cufft-cu12==11.3.3.83
nvidia-cufile-cu12==1.13.1.3
nvidia-curand-cu12==10.3.9.90
nvidia-cusolver-cu12==11.7.3.90
nvidia-cusparse-cu12==12.5.8.93
nvidia-cusparselt-cu12==0.7.1
nvidia-nccl-cu12==2.29.7
nvidia-nvjitlink-cu12==12.8.93
nvidia-nvshmem-cu12==3.4.5
nvidia-nvtx-cu12==12.8.90
packaging==26.0 packaging==26.0
pandas==3.0.1
parso==0.8.6 parso==0.8.6
pexpect==4.9.0 pexpect==4.9.0
pillow==12.1.1 pillow==12.1.1
@@ -39,16 +54,14 @@ Pygments==2.19.2
pyparsing==3.3.2 pyparsing==3.3.2
python-dateutil==2.9.0.post0 python-dateutil==2.9.0.post0
pyzmq==27.1.0 pyzmq==27.1.0
scikit-learn==1.8.0
scipy==1.17.1
seaborn==0.13.2
six==1.17.0 six==1.17.0
stack-data==0.6.3 stack-data==0.6.3
sympy==1.14.0 sympy==1.14.0
threadpoolctl==3.6.0 torch==2.12.0.dev20260318+cu128
torch==2.10.0 torchaudio==2.11.0.dev20260318+cu128
torchvision==0.25.0 torchvision==0.26.0.dev20260318+cu128
tornado==6.5.5 tornado==6.5.5
traitlets==5.14.3 traitlets==5.14.3
triton==3.6.0+git9844da95
typing_extensions==4.15.0 typing_extensions==4.15.0
wcwidth==0.6.0 wcwidth==0.6.0