From 32a1d950fae87a076f19e694e49eda2d67a2dc3f Mon Sep 17 00:00:00 2001 From: douses Date: Sat, 28 Dec 2024 15:42:34 +0000 Subject: [PATCH 01/11] Quick few debug steps --- main.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/main.py b/main.py index fc7ad7d..5448ed5 100644 --- a/main.py +++ b/main.py @@ -41,7 +41,8 @@ def __getitem__(self, idx): img_name = os.path.join(self.root_dir, self.data_frame.iloc[idx, 1]) # grabs the filepath column from the csv image = Image.open(img_name).convert('RGB') # Load image and converts into RGB values from grabbed filepath label = torch.tensor(self.data_frame.iloc[idx]['numeric_label'], dtype=torch.long) # gets the numeric version of the label from the label column of the csv - + print(idx) + if self.transform: image = self.transform(image) @@ -77,6 +78,9 @@ def __init__(self): def forward(self, x): x = self.act1(self.conv1(x)) + print(x) + print(f"NaNs in tensor: {torch.isnan(x).any()}, Infs in tensor: {torch.isinf(x).any()}") + print(x.shape) x = self.drop1(x) x = self.act2(self.conv2(x)) x = self.pool2(x) @@ -100,9 +104,9 @@ def forward(self, x): valid_dataset = WildcatDataset(csv_file=r'cats-in-the-wild-image-classification\versions\1\WILDCATS.csv', root_dir=r'cats-in-the-wild-image-classification\versions\1', dataset_type='valid', transform=transform) test_dataset = WildcatDataset(csv_file=r'cats-in-the-wild-image-classification\versions\1\WILDCATS.csv', root_dir=r'cats-in-the-wild-image-classification\versions\1', dataset_type='test', transform=transform) -train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True) -valid_loader = DataLoader(valid_dataset, batch_size=32, shuffle=False) -test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False) +train_loader = DataLoader(train_dataset, batch_size=16, shuffle=False) +valid_loader = DataLoader(valid_dataset, batch_size=16, shuffle=False) +test_loader = DataLoader(test_dataset, batch_size=16, shuffle=False) #Creates the model model = BigCatModel() From 1370050f63b7723b0f544827c436089663fcc0e8 Mon Sep 17 00:00:00 2001 From: "Seb Douse (douses)" Date: Mon, 30 Dec 2024 12:21:24 +0000 Subject: [PATCH 02/11] Update main.py --- main.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/main.py b/main.py index 5448ed5..c3b3fdb 100644 --- a/main.py +++ b/main.py @@ -41,7 +41,12 @@ def __getitem__(self, idx): img_name = os.path.join(self.root_dir, self.data_frame.iloc[idx, 1]) # grabs the filepath column from the csv image = Image.open(img_name).convert('RGB') # Load image and converts into RGB values from grabbed filepath label = torch.tensor(self.data_frame.iloc[idx]['numeric_label'], dtype=torch.long) # gets the numeric version of the label from the label column of the csv +<<<<<<< Updated upstream print(idx) +======= + if (idx+1) % 16 == 0: + print(f"Batch:{(idx+1)/16}") +>>>>>>> Stashed changes if self.transform: image = self.transform(image) @@ -124,4 +129,10 @@ def forward(self, x): loss = criterion(outputs, labels) loss.backward() optimizer.step() - print(f"Epoch {epoch+1}/{epochs}, Loss: {loss.item()}") \ No newline at end of file + print(f"Epoch {epoch+1}/{epochs}, Loss: {loss.item()}")<<<<<<< Updated upstream + print(f"Epoch {epoch+1}/{epochs}, Loss: {loss.item()}") +======= + print(f"Epoch {epoch+1}/{epochs}, Loss: {loss.item()}") +print("Training Complete!") +torch.save(model, 'bigcat_model.pth') +>>>>>>> Stashed changes From cfc12230760d46c246e2170efb3a00837e867de1 Mon Sep 17 00:00:00 2001 From: "Seb Douse (douses)" Date: Mon, 30 Dec 2024 12:24:12 +0000 Subject: [PATCH 03/11] Update main.py Removed conflicts --- main.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/main.py b/main.py index c3b3fdb..cfebd00 100644 --- a/main.py +++ b/main.py @@ -41,12 +41,8 @@ def __getitem__(self, idx): img_name = os.path.join(self.root_dir, self.data_frame.iloc[idx, 1]) # grabs the filepath column from the csv image = Image.open(img_name).convert('RGB') # Load image and converts into RGB values from grabbed filepath label = torch.tensor(self.data_frame.iloc[idx]['numeric_label'], dtype=torch.long) # gets the numeric version of the label from the label column of the csv -<<<<<<< Updated upstream - print(idx) -======= if (idx+1) % 16 == 0: print(f"Batch:{(idx+1)/16}") ->>>>>>> Stashed changes if self.transform: image = self.transform(image) @@ -129,10 +125,6 @@ def forward(self, x): loss = criterion(outputs, labels) loss.backward() optimizer.step() - print(f"Epoch {epoch+1}/{epochs}, Loss: {loss.item()}")<<<<<<< Updated upstream - print(f"Epoch {epoch+1}/{epochs}, Loss: {loss.item()}") -======= print(f"Epoch {epoch+1}/{epochs}, Loss: {loss.item()}") print("Training Complete!") torch.save(model, 'bigcat_model.pth') ->>>>>>> Stashed changes From 6fc5c5b674b4009af0727f4c2e64252068558972 Mon Sep 17 00:00:00 2001 From: "Seb Douse (douses)" Date: Mon, 30 Dec 2024 12:30:38 +0000 Subject: [PATCH 04/11] remove excessive debugging print statements --- main.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/main.py b/main.py index cfebd00..eda889d 100644 --- a/main.py +++ b/main.py @@ -79,9 +79,6 @@ def __init__(self): def forward(self, x): x = self.act1(self.conv1(x)) - print(x) - print(f"NaNs in tensor: {torch.isnan(x).any()}, Infs in tensor: {torch.isinf(x).any()}") - print(x.shape) x = self.drop1(x) x = self.act2(self.conv2(x)) x = self.pool2(x) From 7c6340fa9c3545b78a2e541b43ca313fc318521e Mon Sep 17 00:00:00 2001 From: "Seb Douse (douses)" Date: Mon, 30 Dec 2024 13:33:01 +0000 Subject: [PATCH 05/11] add bigcat_model.pth --- bigcat_model.pth | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 bigcat_model.pth diff --git a/bigcat_model.pth b/bigcat_model.pth new file mode 100644 index 0000000..90055cb --- /dev/null +++ b/bigcat_model.pth @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d019ae8fbe0ef10d9206d5e191293b37fb053692993fa87a464003b45f855266 +size 822486910 From 5393ceed6ff1e1babec090bee37b017e1f12d2c6 Mon Sep 17 00:00:00 2001 From: "Seb Douse (douses)" Date: Mon, 30 Dec 2024 13:39:43 +0000 Subject: [PATCH 06/11] Trained Model contained --- .gitattributes | 1 + main.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..ec4a626 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.pth filter=lfs diff=lfs merge=lfs -text diff --git a/main.py b/main.py index eda889d..51e8384 100644 --- a/main.py +++ b/main.py @@ -42,7 +42,7 @@ def __getitem__(self, idx): image = Image.open(img_name).convert('RGB') # Load image and converts into RGB values from grabbed filepath label = torch.tensor(self.data_frame.iloc[idx]['numeric_label'], dtype=torch.long) # gets the numeric version of the label from the label column of the csv if (idx+1) % 16 == 0: - print(f"Batch:{(idx+1)/16}") + print(f"Batch: {int((idx+1)/16)} / 147") if self.transform: image = self.transform(image) From d956854698b6f6a2345bac4680e67de6584e8218 Mon Sep 17 00:00:00 2001 From: "Seb Douse (douses)" Date: Mon, 30 Dec 2024 14:19:31 +0000 Subject: [PATCH 07/11] removed bigcat_model.pth, added tester script entire model uploading is being abandoned as an option due to its security risks and its unnecessarily large file sizes by pytorch therefore it can no longer be used as a consistent solution to saving. --- bigcat_model.pth | 3 -- main.py | 3 +- tester.py | 120 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+), 4 deletions(-) delete mode 100644 bigcat_model.pth create mode 100644 tester.py diff --git a/bigcat_model.pth b/bigcat_model.pth deleted file mode 100644 index 90055cb..0000000 --- a/bigcat_model.pth +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d019ae8fbe0ef10d9206d5e191293b37fb053692993fa87a464003b45f855266 -size 822486910 diff --git a/main.py b/main.py index 51e8384..0187c4d 100644 --- a/main.py +++ b/main.py @@ -124,4 +124,5 @@ def forward(self, x): optimizer.step() print(f"Epoch {epoch+1}/{epochs}, Loss: {loss.item()}") print("Training Complete!") -torch.save(model, 'bigcat_model.pth') +# Save the state dictionary +torch.save(model.state_dict(), 'bigcat_model_state.pth') diff --git a/tester.py b/tester.py new file mode 100644 index 0000000..6e0e5c9 --- /dev/null +++ b/tester.py @@ -0,0 +1,120 @@ +import torch +import torch.nn as nn +import torch.optim as optim +import torchvision +import os +import pandas as pd +from PIL import Image +from torch.utils.data import Dataset, DataLoader +from torchvision import transforms + +import matplotlib.pyplot as plt +import matplotlib.image as mpimg + + + +class BigCatModel(nn.Module): + """ + Args: + nn.Module (library call) + """ + def __init__(self): + super().__init__() + self.conv1 = nn.Conv2d(3, 32, kernel_size=(3, 3), stride=1, padding=1) + self.act1 = nn.ReLU() + self.drop1 = nn.Dropout(0.3) + + self.conv2 = nn.Conv2d(32, 64, kernel_size=(3, 3), stride=1, padding=1) + self.act2 = nn.ReLU() + self.pool2 = nn.MaxPool2d(kernel_size=(2, 2)) + + self.conv3 = nn.Conv2d(64, 128, kernel_size=(3, 3), stride=1, padding=1) + self.act3 = nn.ReLU() + self.pool3 = nn.MaxPool2d(kernel_size=(2, 2)) + + self.flat = nn.Flatten() + + self.fc1 = nn.Linear(128 * 56 * 56, 512) # Adjust dimensions for your input + self.act4 = nn.ReLU() + self.drop4 = nn.Dropout(0.5) + + self.fc2 = nn.Linear(512, 10) # 5 classes for big cats + + def forward(self, x): + x = self.act1(self.conv1(x)) + x = self.drop1(x) + x = self.act2(self.conv2(x)) + x = self.pool2(x) + x = self.act3(self.conv3(x)) + x = self.pool3(x) + x = self.flat(x) + x = self.act4(self.fc1(x)) + x = self.drop4(x) + x = self.fc2(x) + return x + +# Recreate the model +model = BigCatModel() + +# Load the state dictionary +model.load_state_dict(torch.load('bigcat_model_state.pth')) + +# Set to evaluation mode +model.eval() + +# Test with dummy data +img = mpimg.imread('exit-ramp.jpg') +plt.imshow(img) +plt.show() + +#Cleans input +# Define your transformations (e.g., resize, normalization) in case an image or not the correct format +transform = transforms.Compose([ + transforms.Resize((224, 224)), + transforms.ToTensor(), + transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) # Normalize for pre-trained models +]) +img_name = 'cats-in-the-wild-image-classification\versions\1\test\AFRICAN LEOPARD\1.jpg' +image = Image.open(img_name).convert('RGB') +test_input = transform(image) +output = model(test_input) +predicted_class = torch.argmax(output, dim=1).item() +print(f"Predicted class: {predicted_class}") + +""" +class WildcatDataset(Dataset): + def __init__(self, csv_file, root_dir, dataset_type, transform=None): + + self.data_frame = pd.read_csv(csv_file) #gets csv and reads it + self.root_dir = root_dir + self.transform = transform + self.dataset_type = dataset_type # 'train', 'valid', or 'test' + +# Filter the data based on the 'dataset' column + self.data_frame = self.data_frame[self.data_frame['data set'] == self.dataset_type] + + #Converts the labels that determine what something is (AFRICAN LEOPARD, etc) into a unique number to perform + # Create a mapping from labels to numeric class indices + self.label_to_idx = {label: idx for idx, label in enumerate(self.data_frame['labels'].unique())} + + # Add a new column with numeric labels + self.data_frame['numeric_label'] = self.data_frame['labels'].map(self.label_to_idx) + + def __len__(self): + return len(self.data_frame) #returns the number of rows in the csv + + def __getitem__(self, idx): + img_name = os.path.join(self.root_dir, self.data_frame.iloc[idx, 1]) # grabs the filepath column from the csv + image = Image.open(img_name).convert('RGB') # Load image and converts into RGB values from grabbed filepath + label = torch.tensor(self.data_frame.iloc[idx]['numeric_label'], dtype=torch.long) # gets the numeric version of the label from the label column of the csv + + if self.transform: + image = self.transform(image) + + return image, label + + +test_dataset = WildcatDataset(csv_file=r'cats-in-the-wild-image-classification\versions\1\WILDCATS.csv', root_dir=r'cats-in-the-wild-image-classification\versions\1', dataset_type='test', transform=transform) +test_loader = DataLoader(test_dataset, batch_size=1, shuffle=True) + +""" \ No newline at end of file From aba98560d0cebb27ffafd582d68b320f84ab1937 Mon Sep 17 00:00:00 2001 From: "Seb Douse (douses)" Date: Mon, 30 Dec 2024 15:12:43 +0000 Subject: [PATCH 08/11] Add state dictionary of model instead of model itself --- bigcat_model_state.pth | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 bigcat_model_state.pth diff --git a/bigcat_model_state.pth b/bigcat_model_state.pth new file mode 100644 index 0000000..4956270 --- /dev/null +++ b/bigcat_model_state.pth @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3dd34d96dfee62144c2a6b68319ecf78f2096737c1af215e96556eb15f9be5a3 +size 822483154 From c542f66c0e0a2887d5ca669d3c4776b2bd438b87 Mon Sep 17 00:00:00 2001 From: "Seb Douse (douses)" Date: Mon, 30 Dec 2024 16:04:17 +0000 Subject: [PATCH 09/11] Tweaked the tester to allow the testing of single images and link the num label to the associated big cat --- main.py | 1 - tester.py | 22 +++++++++++++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/main.py b/main.py index 0187c4d..7ff08ae 100644 --- a/main.py +++ b/main.py @@ -43,7 +43,6 @@ def __getitem__(self, idx): label = torch.tensor(self.data_frame.iloc[idx]['numeric_label'], dtype=torch.long) # gets the numeric version of the label from the label column of the csv if (idx+1) % 16 == 0: print(f"Batch: {int((idx+1)/16)} / 147") - if self.transform: image = self.transform(image) diff --git a/tester.py b/tester.py index 6e0e5c9..347bbd3 100644 --- a/tester.py +++ b/tester.py @@ -53,6 +53,19 @@ def forward(self, x): x = self.fc2(x) return x +BigCatLabel = { + 0 : "African Leopard", + 1 : "Caracal", + 2 : "Cheeta", + 3 : "Clouded Leopard", + 4 : "Jaguar", + 5 : "Lions", + 6 : "Ocelot", + 7 : "Puma", + 8 : "Snow Leopard", + 9 : "Tiger" +} +path = r'cats-in-the-wild-image-classification\versions\1\test\SNOW LEOPARD\2.jpg' # Recreate the model model = BigCatModel() @@ -63,7 +76,7 @@ def forward(self, x): model.eval() # Test with dummy data -img = mpimg.imread('exit-ramp.jpg') +img = mpimg.imread(path) plt.imshow(img) plt.show() @@ -74,12 +87,11 @@ def forward(self, x): transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) # Normalize for pre-trained models ]) -img_name = 'cats-in-the-wild-image-classification\versions\1\test\AFRICAN LEOPARD\1.jpg' -image = Image.open(img_name).convert('RGB') -test_input = transform(image) +image = Image.open(path).convert('RGB') +test_input = transform(image).unsqueeze(0) # Add batch dimension: [1, 3, 224, 224] output = model(test_input) predicted_class = torch.argmax(output, dim=1).item() -print(f"Predicted class: {predicted_class}") +print(f"Predicted class: {BigCatLabel[predicted_class]}") """ class WildcatDataset(Dataset): From 7b13aec3c876c9b4c68eee550a83e054256856f1 Mon Sep 17 00:00:00 2001 From: "Seb Douse (douses)" Date: Wed, 1 Jan 2025 12:57:13 +0000 Subject: [PATCH 10/11] Update README.md --- README.md | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 15686b7..df8d69a 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,17 @@ # Winter-Mini-Project + Welcome to my image classification project to learn ML better +Deep learning can be very CPU intensive and memory intensive so a PC with a GPU and/or with a good amount of memory is strongly recommended for the running of this projects main code +It also has a version that uses the CUDA Deep Learning Network libraries which will need to be installed for optimal training speed of the model. +Another option in situations where a good PC may not be available is the use of cloud computing Session Log: 1. 20/12/2024: - -Research on convolutional neural networks. Layed out design of CNN and how it can be used to create an image classifyer. Installed libraries and selected a big cat database from Kaggle + -Research on convolutional neural networks: Layed out design of CNN and how it can be used to create an image classifyer + -Installed libraries and selected a big cat database from Kaggle -**Worked Part-Time job between these dates** + *Worked Part-Time job between these dates* 2. 23/12/2024: -Ran into library issues and corruption with pytorch (Corrupted version and file path too long to be recognisable by terminal). Debugged the problem by doing as such: @@ -15,7 +20,7 @@ Session Log: -Committed code to convert image to tensor -Created this file -4. 24/12/2024 (Christmas Eve): +3. 24/12/2024 (Christmas Eve): - Huge progress: Custom Dataset and CNN Model creation. Learned a lot today - Added example code using simple greyscale matrix for convolution and pooling - CNN model class: @@ -28,9 +33,18 @@ Session Log: - Instantiates column values in the CSV as variables to access - Combined the model and the dataset together to iterate through epochs of training data through the model to train it including backpropogation techniques (with cross entropy loss) - *NEXT TASK* -> Debug code +4. 28/12/2024: + - Debugging code, replaced the labels with unique numeric labelling as is compatible with pytorch + - Finding solutions for quicker training methods such as GPU use using NVIDIA CUDA and cuDLNN. Both were unsuccessful. Searching for better option however in the meantime just using the CPU on my higher performance PC instead of my work laptop + - Script officially runnable but havent saved the created model +5. 30/12/2024: + - Researched cloud computing solutions for training DL models quicker. Found google colab but was unsuccessful in integrating it due to compatability issues. If I wanted to use this as a solution, I should have started with google colab. Continued with slower unparalleled CPU training + - Saved state dictionary of the model (saved the model) as a .pth file and uploaded it to github using Git LFS + - Created testing script using the created model + - Testing script integration (with tweaking so that the model can process a single image instead of a batch of images) is without errors. Reverted the numeric label to the actual big cat representation and added matplotlib to display the current image being processed. + *CURRENT ISSUE* --> Overfitting: Model predicts every big cat to be a snow leopard. Find a way to stop this overfitting and make the model accurate. References used: - https://machinelearningmastery.com/building-a-convolutional-neural-network-in-pytorch/ @@ -38,6 +52,23 @@ References used: - https://www.kaggle.com/datasets/gpiosenka/cats-in-the-wild-image-classification/code - https://pytorch.org/tutorials/beginner/data_loading_tutorial.html - https://deeplizard.com/learn/video/Zi-0rlM4RDs#:~:text=The%20training%20set%20is%20what%20it%20sounds%20like. + - https://docs.github.com/en/repositories/working-with-files/managing-large-files + - https://stackoverflow.com/questions/59097657/in-pytorch-how-to-test-simple-image-with-my-loaded-model + - https://stackoverflow.com/questions/58779759/how-can-i-display-an-image-on-vs-code-and-pycharm + NOTE: ChatGPT was used in aiding in the understanding of concepts for CNNs and understanding the function of sections of code used in referenced resources +Libraries required for running (copy and paste into terminal): + +pip install torch +pip install torchvision +pip install pillow +pip install pandas + +(If you want to use cuda to speed up the training process, run this then install cuda and cnDLNN from the internet) +pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118 +pip install torch pip install torchvision pip install pillow pip install pandas + + + From 3efff2a338bb803265642d5b6030b36dd0b2dad9 Mon Sep 17 00:00:00 2001 From: "Seb Douse (douses)" Date: Wed, 1 Jan 2025 14:18:00 +0000 Subject: [PATCH 11/11] Comment more --- .../tester proposed addition.py | 37 +++++++++++++++++ main.py | 28 +++++++------ tester.py | 40 +------------------ 3 files changed, 54 insertions(+), 51 deletions(-) create mode 100644 Test and Example Code/tester proposed addition.py diff --git a/Test and Example Code/tester proposed addition.py b/Test and Example Code/tester proposed addition.py new file mode 100644 index 0000000..cdcae6f --- /dev/null +++ b/Test and Example Code/tester proposed addition.py @@ -0,0 +1,37 @@ +""" +class WildcatDataset(Dataset): + def __init__(self, csv_file, root_dir, dataset_type, transform=None): + + self.data_frame = pd.read_csv(csv_file) #gets csv and reads it + self.root_dir = root_dir + self.transform = transform + self.dataset_type = dataset_type # 'train', 'valid', or 'test' + +# Filter the data based on the 'dataset' column + self.data_frame = self.data_frame[self.data_frame['data set'] == self.dataset_type] + + #Converts the labels that determine what something is (AFRICAN LEOPARD, etc) into a unique number to perform + # Create a mapping from labels to numeric class indices + self.label_to_idx = {label: idx for idx, label in enumerate(self.data_frame['labels'].unique())} + + # Add a new column with numeric labels + self.data_frame['numeric_label'] = self.data_frame['labels'].map(self.label_to_idx) + + def __len__(self): + return len(self.data_frame) #returns the number of rows in the csv + + def __getitem__(self, idx): + img_name = os.path.join(self.root_dir, self.data_frame.iloc[idx, 1]) # grabs the filepath column from the csv + image = Image.open(img_name).convert('RGB') # Load image and converts into RGB values from grabbed filepath + label = torch.tensor(self.data_frame.iloc[idx]['numeric_label'], dtype=torch.long) # gets the numeric version of the label from the label column of the csv + + if self.transform: + image = self.transform(image) + + return image, label + + +test_dataset = WildcatDataset(csv_file=r'cats-in-the-wild-image-classification\versions\1\WILDCATS.csv', root_dir=r'cats-in-the-wild-image-classification\versions\1', dataset_type='test', transform=transform) +test_loader = DataLoader(test_dataset, batch_size=1, shuffle=True) + +""" \ No newline at end of file diff --git a/main.py b/main.py index 7ff08ae..d60c204 100644 --- a/main.py +++ b/main.py @@ -8,8 +8,8 @@ from torch.utils.data import Dataset, DataLoader from torchvision import transforms -##IMPORTANT TASK: CREATING CUSTOM PYTORCH DATASET FOR BIG CAT CLASSIF. +##KEY DETAIL: The wildcat custom dataset class WildcatDataset(Dataset): def __init__(self, csv_file, root_dir, dataset_type, transform=None): """ @@ -20,33 +20,37 @@ def __init__(self, csv_file, root_dir, dataset_type, transform=None): transform (callable, optional): Optional transform to be applied on a sample. """ self.data_frame = pd.read_csv(csv_file) #gets csv and reads it - self.root_dir = root_dir - self.transform = transform + self.root_dir = root_dir #Stores root directory + self.transform = transform #Stores required image size in case the image is misshapen self.dataset_type = dataset_type # 'train', 'valid', or 'test' # Filter the data based on the 'dataset' column - self.data_frame = self.data_frame[self.data_frame['data set'] == self.dataset_type] + self.data_frame = self.data_frame[self.data_frame['data set'] == self.dataset_type] #Sets it so the only data being considered is the data linked to its specific purpose. E.g: when training, it will only consider data where its data set column is "train" - #Converts the labels that determine what something is (AFRICAN LEOPARD, etc) into a unique number to perform - # Create a mapping from labels to numeric class indices - self.label_to_idx = {label: idx for idx, label in enumerate(self.data_frame['labels'].unique())} + #Converts the labels that determine what something is (AFRICAN LEOPARD, etc) into a unique number to operate supervised learning operations on + self.label_to_idx = {label: idx for idx, label in enumerate(self.data_frame['labels'].unique())} - # Add a new column with numeric labels + # Add a new column "numeric_label" to store the newly created numberic representation of its label (LION --> 4, AFRICAN LEOPARD --> 0, ...) self.data_frame['numeric_label'] = self.data_frame['labels'].map(self.label_to_idx) def __len__(self): - return len(self.data_frame) #returns the number of rows in the csv + return len(self.data_frame) #returns the number of rows in the csv in case it is needed (common practise in dataset creation) def __getitem__(self, idx): img_name = os.path.join(self.root_dir, self.data_frame.iloc[idx, 1]) # grabs the filepath column from the csv image = Image.open(img_name).convert('RGB') # Load image and converts into RGB values from grabbed filepath label = torch.tensor(self.data_frame.iloc[idx]['numeric_label'], dtype=torch.long) # gets the numeric version of the label from the label column of the csv + + #For debugging and measuring progress in an epoch in a human readable way + length = self.__len__() if (idx+1) % 16 == 0: - print(f"Batch: {int((idx+1)/16)} / 147") - if self.transform: + print(f"Batch: {int((idx+1)/16)} / {length // 16}") #Displays progress in number of batches per epoch completed + + #If the image is not the correct size and format, reshape it so it is as such + if self.transform: image = self.transform(image) - return image, label + return image, label #Output the RGB representation of the image and what it is in numeric representation class BigCatModel(nn.Module): diff --git a/tester.py b/tester.py index 347bbd3..d6ae44c 100644 --- a/tester.py +++ b/tester.py @@ -91,42 +91,4 @@ def forward(self, x): test_input = transform(image).unsqueeze(0) # Add batch dimension: [1, 3, 224, 224] output = model(test_input) predicted_class = torch.argmax(output, dim=1).item() -print(f"Predicted class: {BigCatLabel[predicted_class]}") - -""" -class WildcatDataset(Dataset): - def __init__(self, csv_file, root_dir, dataset_type, transform=None): - - self.data_frame = pd.read_csv(csv_file) #gets csv and reads it - self.root_dir = root_dir - self.transform = transform - self.dataset_type = dataset_type # 'train', 'valid', or 'test' - -# Filter the data based on the 'dataset' column - self.data_frame = self.data_frame[self.data_frame['data set'] == self.dataset_type] - - #Converts the labels that determine what something is (AFRICAN LEOPARD, etc) into a unique number to perform - # Create a mapping from labels to numeric class indices - self.label_to_idx = {label: idx for idx, label in enumerate(self.data_frame['labels'].unique())} - - # Add a new column with numeric labels - self.data_frame['numeric_label'] = self.data_frame['labels'].map(self.label_to_idx) - - def __len__(self): - return len(self.data_frame) #returns the number of rows in the csv - - def __getitem__(self, idx): - img_name = os.path.join(self.root_dir, self.data_frame.iloc[idx, 1]) # grabs the filepath column from the csv - image = Image.open(img_name).convert('RGB') # Load image and converts into RGB values from grabbed filepath - label = torch.tensor(self.data_frame.iloc[idx]['numeric_label'], dtype=torch.long) # gets the numeric version of the label from the label column of the csv - - if self.transform: - image = self.transform(image) - - return image, label - - -test_dataset = WildcatDataset(csv_file=r'cats-in-the-wild-image-classification\versions\1\WILDCATS.csv', root_dir=r'cats-in-the-wild-image-classification\versions\1', dataset_type='test', transform=transform) -test_loader = DataLoader(test_dataset, batch_size=1, shuffle=True) - -""" \ No newline at end of file +print(f"Predicted class: {BigCatLabel[predicted_class]}") \ No newline at end of file