CNN loss isn't reducing, and the model misclassifies half of the cats and dogs dataset

Hello.

Here is my model:

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(in_channels=3, out_channels=6, kernel_size=5)
        self.pool = nn.MaxPool2d(kernel_size=2, stride=2)
        self.conv2 = nn.Conv2d(in_channels=6, out_channels=16, kernel_size=5)
        
        self.fc1 = nn.Linear(in_features=16 * 61 * 61, out_features=120)
        self.fc2 = nn.Linear(in_features=120, out_features=84)
        self.out = nn.Linear(in_features=84, out_features=NUM_CLASSES)

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = x.view(-1, 16 * 61 * 61)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.out(x)
        return x

… and its use:

    model = Net().to(device)
    criterion = nn.CrossEntropyLoss()
    optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)

    model.train()
    running_loss = 0.0

    # define training loop
    n_total_steps = len(train_loader)
    for epoch in range(num_epochs): # loop over the number of epochs
        for i, (images, labels) in enumerate(train_loader): # loop over the training loaders
            images = images.to(device) # push images and labels to device to get CPU support
            labels = labels.to(device)

            # Forward pass
            optimizer.zero_grad()
            outputs = model(images)
            loss = criterion(outputs, labels)
            loss.backward()
            optimizer.step()
                        
            running_loss += loss.item()

            if (i+1) % 20 == 0:
                print (f"Epoch [{epoch+1}/{num_epochs}], Step [{i+1}/{n_total_steps}], Running Loss: {running_loss:.4f}")
                running_loss = 0.0

These are the results:

Epochs: 5, Learning rate: 0.001

Epoch [1/5], Step [20/40], Running Loss: 13.9385
Epoch [1/5], Step [40/40], Running Loss: 13.9349
Epoch 1 of 5 completed…
Epoch [2/5], Step [20/40], Running Loss: 13.8513
Epoch [2/5], Step [40/40], Running Loss: 13.9098
Epoch 2 of 5 completed…
Epoch [3/5], Step [20/40], Running Loss: 13.8609
Epoch [3/5], Step [40/40], Running Loss: 13.8211
Epoch 3 of 5 completed…
Epoch [4/5], Step [20/40], Running Loss: 13.7967
Epoch [4/5], Step [40/40], Running Loss: 13.8098
Epoch 4 of 5 completed…
Epoch [5/5], Step [20/40], Running Loss: 13.7332
Epoch [5/5], Step [40/40], Running Loss: 13.7854
Epoch 5 of 5 completed…
Finished Training
Total training time: 3.3 minutes
train samples: 800, test samples :800

Accuracy of CAT: 95.7%, of 390 cases
Accuracy of DOG: 3.7%, of 410 cases
Classification report:
precision recall f1-score support

     CAT       0.47      0.88      0.62       390
     DOG       0.39      0.07      0.12       410

accuracy                           0.47       800

macro avg 0.43 0.48 0.37 800
weighted avg 0.43 0.47 0.36 800

Confusion matrix:
[[344 46]
[381 29]]

So running the model does not show a reduction in loss, and results in a poorly preforming model. Any suggestions welcome…

The code looks generally alright, so try to play around with some hyperparameters such as the learning rate.
If you get stuck, scale down the problem a bit and try to overfit a small dataset (e.g. just 10 samples) first to make sure there are no hidden bugs in the rest of the code.