0
$\begingroup$

I am learning ML and am working on a CNN problem where I need to classify images of CATS and DOGS.

The way I have setup the labels is that cats are 1 and dogs are 0. I have made the final output layer length 1 ( So I get only 1 output).

When I measure my accuracy I seem to be getting 0% even when my loss is low. I am not sure what I am doing wrong.

'''

import torch 
from torch import nn 
import torchvision
from torchvision import datasets
from torchvision import transforms 
from torchvision.transforms import ToTensor
from torchvision.transforms import v2
from torch.utils.data import DataLoader
import numpy as np



import matplotlib.pyplot as plt
import os
import pandas as pd
from torch.utils.data import Dataset
from skimage import io
from PIL import Image

class CatsAndDogsDataset(Dataset):
    def __init__(self,csv_file,root_dir,transform=None):
        self.annotations =pd.read_csv(csv_file)
        self.root_dir = root_dir
        self.transform = transform

    def __len__(self):
        return len(self.annotations)

    def __getitem__(self,index):
        img_path=os.path.join(self.root_dir,self.annotations.iloc[index,0])
        image=io.imread(img_path)
        y_label= torch.tensor(float(self.annotations.iloc[index,1]))

        if self.transform:
            image=self.transform(image)

        return (image,y_label)

def accuracy_fn(y_true, y_pred):
    correct = torch.eq(y_true, y_pred).sum().item() # torch.eq() calculates where two tensors are equal
    acc = (correct / len(y_pred)) * 100 
    return acc

dataset= CatsAndDogsDataset(csv_file = r'C:\Users\hbhavnag\Documents\Hussain\ASU\collision detection\Home work\output.csv', root_dir='train', transform=transforms.ToTensor())

train_set, test_set = torch.utils.data.random_split(dataset,[2000,955])
train_loader=DataLoader(dataset=train_set, batch_size=10, shuffle=True)
test_loader = DataLoader(dataset=test_set, batch_size=10, shuffle=True)

torch.manual_seed(42)
fig = plt.figure(figsize=(9,9))
rows, cols = 5,5

for i in range(1,rows*cols+1):
    random_idx = torch.randint(0,len(train_set),size=[1]).item()
    img,label =train_set[random_idx]
    fig.add_subplot(rows,cols,i)
    plt.imshow(img.permute(1,2,0))
    #plt.title(label)
    plt.axis(False)

    
train_img_batch , train_labels_batch = next(iter(train_loader))


# Building the model

class CatsAndDogsModel(nn.Module):
    """
    Model architecture replicates Tiny vgg
    """
    def __init__(self,input_shape:int,hidden_units:int,output_shape:int):
        super().__init__()
        self.conv_block_1=nn.Sequential(
            nn.Conv2d(in_channels=input_shape,
                      out_channels=hidden_units,
                      kernel_size=3,
                      stride=1,
                      padding=1),
            nn.ReLU(),
            nn.Conv2d(in_channels=hidden_units,
                      out_channels=hidden_units,
                      kernel_size=3,
                      stride=1,
                      padding=1),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2)
        )
        self.conv_block_2= nn.Sequential(
            nn.Conv2d(in_channels=hidden_units,
                      out_channels=hidden_units,
                      kernel_size=3,
                      stride=1,
                      padding=1),
            nn.ReLU(),
            nn.Conv2d(in_channels=hidden_units,
                      out_channels=hidden_units,
                      kernel_size=3,
                      stride=1,
                      padding=1),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2)

        )
        self.classifier = nn.Sequential(
            nn.Flatten(),
            nn.Linear(in_features=hidden_units*93*125,
                      out_features=output_shape),
            nn.Sigmoid()
        )
    def forward(self,x):
        x= self.conv_block_1(x)
        print(x.shape) 
        x= self.conv_block_2(x)
        print(x.shape)
        x= self.classifier(x)
        print(x.shape)
        return x.squeeze()
        
torch.manual_seed(42)
model_2=CatsAndDogsModel(input_shape=3,
                         hidden_units=10,
                         output_shape=1)
             
# setup loss function 

loss_fn = nn.BCELoss()
optimizer = torch.optim.SGD(params=model_2.parameters(),lr=0.01)
from tqdm.auto import tqdm
torch.manual_seed(42)

epochs=3

for epoch in tqdm(range(epochs)):
    print(f'Epoch:{epoch}\n-------')

    train_loss=0
    for batch,(X,y) in enumerate(train_loader):
        print(y)
        model_2.train()
        y_pred = model_2(X)
        print(y_pred)
        loss = loss_fn(y_pred,y)
        train_loss=train_loss+loss
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

    train_loss/= len(train_loader)

    test_loss,test_acc=0,0
    model_2.eval()
    with torch.inference_mode():
        for X,y in test_loader:
            test_pred=model_2(X)
            test_loss+=loss_fn(test_pred,y)
            test_acc+=accuracy_fn(y_true=y,y_pred=test_pred)
            test_loss/=len(test_loader)
            test_acc /= len(test_loader)
    
    print(f"\n Train loss:{train_loss:.5f} | Test loss:{test_loss:.5f},Test acc: {test_acc:.2f}%\n")

'''

Please let me know if my code is confusing, any help is much appreciated

Thanks!

$\endgroup$

1 Answer 1

1
$\begingroup$

Your accuracy function is wrong. y_pred from the model will be a float value between 0 and 1, while y_true is an integer value 0 or 1. You need to convert y_pred to a hard value using a threshold (ie y_pred>0.5)

Also separately

test_acc+=accuracy_fn(y_true=y,y_pred=test_pred)
test_acc /= len(test_loader)

Is aggregating the results incorrectly.

$\endgroup$
3
  • $\begingroup$ Is there a function that does that or can I just add a for loop and run through the y_pred values and change them? $\endgroup$ Oct 16 at 5:19
  • $\begingroup$ I am also thinking about making the last output dimension as two and change my labels to become a tensor with [1,0] for cats and [0,1] for dogs and then use a softmax for the last layer. Is that a good idea ? $\endgroup$ Oct 16 at 5:20
  • $\begingroup$ A friend asked me to use softmax function, do you think this would be useful ? $\endgroup$ Oct 18 at 5:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.