Skip to content

criticallycode/tasty-fruits360-with-pytorch

Repository files navigation

tasty-fruiits360-with-pytorch

An image classifier designed with PyTorch, operates on the Fruits-360 dataset.

This repo demonstrates how to create an image classification model with PyTorch. The dataset used for this repo is the Fruits-360 dataset, available HERE. This repo contains a Jupyter Notebook that allows you to run the cells and experiment with the model. It also acts a tutorial for the process of creating and training an image classification model with PyTorch, explaining the various code blocks.

First, the data is loaded and transformed.

import os
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.utils.data import Dataset
from torchvision import datasets, transforms

# Set main directory for use in getting training/testing data

main_dir = "./fruits-360/"

 Declare transforms for train and test data

train_transforms = transforms.Compose([
    transforms.Resize((32, 32)),
    transforms.RandomHorizontalFlip(),
    transforms.RandomRotation(25),
    transforms.ToTensor(),
    transforms.Normalize((0.5,0.5,0.5),
                         (0.5,0.5,0.5)),
])

test_transforms = transforms.Compose([transforms.Resize((32, 32)),
    transforms.ToTensor(),
    transforms.Normalize((0.5,0.5,0.5),
                         (0.5,0.5,0.5)),])

# Set the directories for the training and testing data, create the datasets with the transforms

train_data = datasets.ImageFolder(os.path.join(main_dir, 'Train/'), transform=train_transforms)
test_data = datasets.ImageFolder(os.path.join(main_dir, 'Test/'), transform=test_transforms)

# Use the dataloaders to create iterable objects out of the datasets

train_loader = torch.utils.data.DataLoader(train_data, batch_size=64, shuffle=True)
test_loader = torch.utils.data.DataLoader(test_data, batch_size=64, shuffle=True)

After this, the model is created and instantiated with various required arguments.

# Set the number of classes
classes = 118

# Specify the device to use
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

# Create the Model to use for training

class Model(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(3, 8, kernel_size=5, stride=1, padding=2)
        self.conv2 = nn.Conv2d(8, 16, kernel_size=5, stride=1, padding=2)
        self.fc1 = nn.Linear(8*8*16, 300)
        self.fc2 = nn.Linear(300, classes)
        self.conv1_bn = nn.BatchNorm2d(8)
        self.conv2_bn = nn.BatchNorm2d(16)
        self.pool = nn.MaxPool2d(2, 2)

    # Can combine layers and activations if you want:
    # Ex. X = self.conv1_bn(self.conv1(X))

    def forward(self, X):
        X = self.conv1(X)
        X = self.conv1_bn(X)
        X = F.relu(X)
        X = self.pool(X)
        X = self.conv2(X)
        X = self.conv2_bn(X)
        X = F.relu(X)
        X = self.pool(X)
        X = X.view(-1, 8*8*16)
        X = self.fc1(X)
        X = F.relu(X)
        X = F.dropout(X)
        X = self.fc2(X)

        return X
    
    # Set number of training epochs and learning rate
# May also want to use learning rate scheduler

epochs = 40
learning_rate = 0.0001

# Declare the model, loss criterion, and chosen optimizer

model = Model().to(device)
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), learning_rate, weight_decay=0.0001)

Finally, the training is carried out:

# Declare variables to hold the training and testing loss
# Which will be updated over the course of the epoch

epoch_loss_train = []
epoch_loss_test = []


# For our chosen number of epochs, train and check performance on test set

for i in range(epochs):

    # Declare variables to hold metrics

    train_loss = 0.0
    train_total = 0
    train_correct = 0

    # For the features and labels in the train loader
    for x, y in train_loader:

        # Declare the inputs and labels, zero the gradients,
        # run the inputs through the model and calculate the loss
        inputs, labels = x.to(device), y.to(device)
        optimizer.zero_grad()
        outputs = model(inputs)
        loss = criterion(outputs, labels)

        # Get the most likely prediction
        # Do backprop to calculate gradient and optimize
        _, prediction = torch.max(outputs.data, 1)
        loss.backward()
        optimizer.step()

        # Update the values
        train_loss += loss.item()
        train_total += labels.size(0)
        train_correct += (prediction == labels).sum().item()

    else:

        test_loss = 0.0
        test_total = 0
        test_correct = 0

        # Set to no_grad for purposes of evaluation

        with torch.no_grad():
            for test_images, test_targets in test_loader:
                images, targets = test_images.to(device), test_targets.to(device)
                test_outputs = model(images)
                difference = criterion(test_outputs, targets)
                test_loss += difference.item()
                _, test_pred = torch.max(test_outputs.data, 1)
                test_total += targets.size(0)
                test_correct += (test_pred == targets).sum().item()

        epoch_loss_train.append(train_loss/len(train_loader))
        epoch_loss_test.append(test_loss/len(test_loader))

        print("---------")
        print("End Epoch")
        print('Training Accuracy: {:.2f}%'.format(100 * train_correct / train_total))
        print('Testing Accuracy: {:.2f}%'.format(100 * test_correct / test_total))

About

An image classifier designed with PyTorch, operates on the Fruits-360 dataset.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published