Flower recognition
Classfication of flowers using pytorch
Here, we will be learning about classification of flowers using pytorch using the kaggle dataset.
In this tutorial we will be using conv2d neural network using pytorch to classify the flowers.
We follow the following tutorial and change our code according to our requirements.
Importing necessary packages
import torch
import torchvision
import torchvision.transforms as transforms
import os
import random
import pandas as pd
import numpy as np
import shutil
pytorch package will not be available, so we have install it explicitly, the following command can be used to install pytorch.
For windows:
For Mac:
conda install pytorch torchvision torchaudio -c pytorch
Splitting the Data into Train and Test
conda install pytorch torchvision torchaudio -c pytorch
We now, create necessary folders to train and split, in the tutorial we are following, they have not shown how they split their data. So, we are using our own login to split the data into train and test folders. Our data folder have 5 subfolders of each flower in which we have images of the respective flowers.
'daisy', 'dandelion', 'rose', 'sunflower', 'tulip'
following is the logic I used to split the data.
Img_dir_Test = 'C:/Users/ajays/OneDrive/Desktop/Data mining/Assignment1 New/test'
_, dirs, _ = next(os.walk(Img_dir_train))
train_ratio = 0.77
images_per_class = np.zeros(5) # 5 is number of classes
for i in range(len(images_per_class)):
path = os.path.join(Img_dir_train,dirs[i])
files = np.asarray(os.listdir(path))
images_per_class[i] = len(files)
test_counter = np.round(images_per_class * (1-train_ratio))
# transfer files
for i in range(len(images_per_class)):
source = os.path.join(Img_dir_train, dirs[i])
destination = os.path.join(Img_dir_Test, dirs[i])
if not os.path.exists(destination):
os.makedirs(destination)
files = np.asarray(os.listdir(source))
for j in range(int(test_counter[i])):
dst = os.path.join(destination, files[j])
src = os.path.join(source, files[j])
shutil.move(src,dst)
Normalize and load the data
As we have created the train and test datasets, next thing is to normalize the data. Normalizing the data is a key step in the process. We might have images in different aspect ratio, sizes etc., So, we normalize them by making their properties similar.
Following is the logic used to normalize
transform = transforms.Compose(
[transforms.Resize(256),
transforms.CenterCrop(256),
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
And the next step is to load data that is transformed. The transformed data will be loaded into train and test loaders respectively.
batch_size = 4
trainset = torchvision.datasets.ImageFolder(root=Img_dir_train,transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=batch_size,shuffle=True, num_workers=2)
testset = torchvision.datasets.ImageFolder(root=Img_dir_Test,transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=batch_size,shuffle=True, num_workers=2)
let's have a look at some of the images
import matplotlib.pyplot as plt
import numpy as np
# functions to show an image
def imshow(img):
img = img / 2 + 0.5 # unnormalize
npimg = img.numpy()
plt.imshow(np.transpose(npimg, (1, 2, 0)))
plt.show()
# get some random training images
dataiter = iter(trainloader)
images, labels = dataiter.next()
# show images
imshow(torchvision.utils.make_grid(images))
# print labels
print(' '.join(f'{classes[labels[j]]:5s}' for j in range(batch_size)))
accur=[]
Output:
sunflower rose tulip daisy
Define a convolutional neural network
In this step, we will be defining our model. Here we are using the same model that is
used in the tutorial we are following, following are the parameters we have used in our
model.
import torch.nn as nn
import torch.nn.functional as F
class Net(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(3, 6, 5)
self.pool = nn.MaxPool2d(2, 2)
self.conv2 = nn.Conv2d(6, 18, 5)
self.fc1 = nn.Linear(18 * 61 * 61, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 5)
def forward(self, x):
x = self.pool(F.relu(self.conv1(x)))
x = self.pool(F.relu(self.conv2(x)))
x = torch.flatten(x, 1) # flatten all dimensions except batch
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
net = Net()
Define optimizer and loss function
import torch.optim as optim
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
Train the network
This is the main part in the process, here we will be iterating the model over the dataset multiple times, so
that the model optimizes itself by calculating loss and then reduces the loss.
for epoch in range(25): # loop over the dataset multiple times
running_loss = 0.0
for i, data in enumerate(trainloader, 0):
# get the inputs; data is a list of [inputs, labels]
inputs, labels = data[0],data[1]
# zero the parameter gradients
optimizer.zero_grad()
# forward + backward + optimize
outputs = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
# print statistics
running_loss += loss.item()
if i % 200 == 199: # print every 2000 mini-batches
print(f'[{epoch + 1}, {i + 1:5d}] loss: {running_loss / 200:.3f}')
running_loss = 0.0
print('Finished Training')
Output :
Test the model using the test data
we have trained the model multiple times, at first I have trained the model using 2 epoch's and
then gradually increased it to 10 and 20, finally at last I got a gradual increase from 52 to 55.
correct = 0
total = 0
# since we're not training, we don't need to calculate the gradients for our outputs
with torch.no_grad():
for data in testloader:
inputs, labels = data[0],data[1]
# calculate outputs by running images through the network
outputs = net(inputs)
# the class with the highest energy is what we choose as prediction
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print(f'Accuracy of the network on the test images: {100 * correct // total} %')
accur.append(100* correct // total)
Output:
Accuracy of the network on the test images: 55 %
checking accuracy for each class,
# prepare to count predictions for each class
correct_pred = {classname: 0 for classname in classes}
total_pred = {classname: 0 for classname in classes}
# again no gradients needed
with torch.no_grad():
for data in testloader:
images, labels = data[0],data[1]
outputs = net(images)
_, predictions = torch.max(outputs, 1)
# collect the correct predictions for each class
for label, prediction in zip(labels, predictions):
if label == prediction:
correct_pred[classes[label]] += 1
total_pred[classes[label]] += 1
# print accuracy for each class
for classname, correct_count in correct_pred.items():
accuracy = 100 * float(correct_count) / total_pred[classname]
print(f'Accuracy for class: {classname:5s} is {accuracy:.1f} %')
Output:
Accuracy for class: daisy is 46.6 % Accuracy for class: dandelion is 62.4 % Accuracy for class: rose is 46.1 % Accuracy for class: sunflower is 63.3 % Accuracy for class: tulip is 57.1 %Experimenting
Plotting accuracy over different epoch values.Plotting accuracy's for different classes.References:
My contribution :
In the tutorial we have followed, they didn't show how they split their data, butwe have built our own logic to split data into train and test folders.Trained multiple times, with multiple epoch values to improve accuracy over aperiod of time.Challenge :
Initially, I had very less accuracy and model was not training well and as expected, Itried everything but finally found out that I forgot to shuffle the training data, thenI shuffled data which made training well and got a good accuracy and also choosing thehyperparameters and number of layers was challenge which I got them after multiple attempts.
Comments
Post a Comment