Plant Disease Detection Using Convolutional Neural Networks with PyTorch

Manthan Bhikadiya šŸ’”
Analytics Vidhya
Published in
7 min readMar 17, 2021

Machine learning, Deep learning, and Artificial intelligence are the Future. We use these technologies in almost every field. In the Farming sector, we can also use this technology for the Preparation of soil, adding fertilizers, sowing of seed, Irrigation, weed protection, harvesting, disease prediction, etc.

Read Full Blog AI In Agriculture.

Credits: Unsplash

Overview :

We are using Deep Learning for Plant disease detection based on images of a leaf of a plant. We are using deep learning for this task because here we are working with image data. Deep learning has a Convolution neural network that is used to find features from the leaf of the plant.

Prerequisites :

PyTorch

Convolutional Neural Networks

Learn PyTorch from Here :

(1) Aladdin Person Youtube Playlist

(2) Python Engineer Youtube Playlist

Learn CNN From Here :

(1) Convolutional Neural Networks (CNNs) explained by Deeplizard

(2) Simple Explanation Of Convolutional Neural Network by CodeBasics

Dataset :

In this data-set, 39 different classes of plant leaf and background images are available. The data-set containing 61,486 images. We used six different augmentation techniques for increasing the data-set size. The techniques are image flipping, Gamma correction, noise injection, PCA color augmentation, rotation, and Scaling.

There is a total of 39 Classes that we have to predict using the CNN Model.

Download the Dataset. ( Plant Village Dataset )

Code Implementation :

Import Dependencies:

# General
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# Torch
import torch
from torchvision import datasets, transforms # datsets , transforms
from torch.utils.data.sampler import SubsetRandomSampler
import torch.nn as nn
import torch.nn.functional as F
from datetime import datetime

Transforms are used for Data Augmentation like cropping the image, resize the image, convert the image to tensor, rotate the image, and many more. Transforms work as a filter for all images. We are using the following code to transform the images.

transform = transforms.Compose(
[transforms.Resize(255), transforms.CenterCrop(224), transforms.ToTensor()]
)

datasets class is used to create or import datasets. In datasets, it has many famous datasets like MNIST, CIFAR-10, CIFAR-100, KMNIST, etc.

Check out all dataset lists here.

We use the dataset for making our own dataset from images and for that we are using the ImageFolder method from datasets.

The folder where I stored all images is named as ā€˜Datasetā€™. We also apply our transform to all images.

dataset = datasets.ImageFolder("Dataset", transform=transform)

Train Test Split :

indices = list(range(len(dataset)))split = int(np.floor(0.85 * len(dataset)))  # train_sizevalidation = int(np.floor(0.70 * split))  # validationnp.random.shuffle(indices)train_indices, validation_indices, test_indices = (
indices[:validation],
indices[validation:split],
indices[split:],
)

Here in the above code we first getting indices and then split the data into train , test and validation data. Total 36584 for train , 15679 for validaiton and remaining images for testing.

train_sampler = SubsetRandomSampler(train_indices)
validation_sampler = SubsetRandomSampler(validation_indices)
test_sampler = SubsetRandomSampler(test_indices)

SubsetRandomSampler is used to sample our data. Here we are creating an object of SubsetRandomSampler Object and later we will use this sampler in train data loader and test data loader.

batch_size = 64train_loader = torch.utils.data.DataLoader(
dataset, batch_size=batch_size, sampler=train_sampler
)
test_loader = torch.utils.data.DataLoader(
dataset, batch_size=batch_size, sampler=test_sampler
)
validation_loader = torch.utils.data.DataLoader(
dataset, batch_size=batch_size, sampler=validation_sampler
)

As we discussed we use train_sampler for train-loader and vice-versa.

Now our dataset is ready for training and testingā€¦!!

Model Creation :

We use a convolutional neural network for model creation. We create model layers as mentioned below the image. We also specified filter size for the Conv layer and Pool layer and the shape on each layer.

shape = ( channels , height , width )

In PyTorch shape is not automatically calculated we manually have to take care of shape on each layer. At the First Fully connected layer we have to mention output size as per the shape of the convolutional layer. This calculation is also called Convolutional Arithmetic.

Here is Equation for Convolutional Arithmetic:

Here for this project dilation = 0.

For model code do check out My Github repo here

model = CNN(targets_size) # targets_size = 39

Here we have to classify the images into 39 Categories so thatā€™s why we used categorical cross-entropy as loss and adam optimizer. In the Model, we are using ReLU as activation but for the last layer, we have to use Softmax activation. In PyTorch, we have a cross-entropy loss which is a mixture of softmax and category cross-entropy loss.

criterion = nn.CrossEntropyLoss()  
optimizer = torch.optim.Adam(model.parameters())

Batch Gradient Descent:

def batch_gd(model, criterion, train_loader, test_laoder, epochs):
train_losses = np.zeros(epochs)
test_losses = np.zeros(epochs)
for e in range(epochs):
t0 = datetime.now()
train_loss = []
for inputs, targets in train_loader:
inputs, targets = inputs.to(device), targets.to(device)
optimizer.zero_grad()output = model(inputs)loss = criterion(output, targets)train_loss.append(loss.item()) # torch to numpy worldloss.backward()
optimizer.step()
train_loss = np.mean(train_loss)validation_loss = []for inputs, targets in validation_loader:inputs, targets = inputs.to(device), targets.to(device)output = model(inputs)loss = criterion(output, targets)validation_loss.append(loss.item()) # torch to numpy worldvalidation_loss = np.mean(validation_loss)train_losses[e] = train_loss
validation_losses[e] = validation_loss
dt = datetime.now() - t0print(
f"Epoch : {e+1}/{epochs} Train_loss:{train_loss:.3f} Test_loss:{validation_loss:.3f} Duration:{dt}"
)
return train_losses, validation_losses

As you can see above function is used for Batch Gradient Descent. batch_gd() is the function where all the learning happened.

def accuracy(loader):
n_correct = 0
n_total = 0
for inputs, targets in loader:
inputs, targets = inputs.to(device), targets.to(device)
outputs = model(inputs)_, predictions = torch.max(outputs, 1)n_correct += (predictions == targets).sum().item()
n_total += targets.shape[0]
acc = n_correct / n_total
return acc
train_acc = accuracy(train_loader)
test_acc = accuracy(test_loader)
validation_acc = accuracy(validation_loader)

The above function is used for finding the accuracy of the model. It is very simple to understand code. You can check the full code at My Github.

By Using this Current Model we are getting accuracy

87 % on Train data, 84 % On Validation data and 83% on Test data.

For this practical we use test data as completely new data. We were not used test data on any phase it was made only for final testing.

Working of Model :

If you know the working of CNN then You get my point about what I do in this project. This section is for those who donā€™t understand. Basically, First we Resize every image into 224 x 224. After that this image feed into the Convolutional Neural Network. We feed color image so it has 3 channels RGB. First conv layer we apply 32 filter size or output channels. That means 32 different filters apply to the images and try to find features and after that using 32 features, we create a features map that has channels 32. So from 3 x 224 x 224 it will become 32 x 222 x 222. After that we are applying ReLU activation function to remove non linearity and after that we are applying Batch Normalization to normalize the weights of the neuron. After that this image we feed to the max pool layer which takes only the most relevant features only so that why we get the output image in shape 32 x 112 x 112. After that, we feed this image to the next convolutional layer and its process is the same as mentioned above. At last, we flatten the final max pool layer output and feed to the next linear layer which is also called a fully connected layer, and finally, as a final layer, we predict 39 categories. So as a model output we get tensor 1x39 size. And from that tensor, we take an index of the maximum value in the tensor. That particular index is our main prediction. Thatā€™s how everything works...!!

Hope you will understandā€¦šŸ‘šŸ»šŸ˜Š

Flask Web App :

After Creating this Model We create on web application on flask and deployed it on heroku cloud sever.

Coding of flask framework is also available on my github repo here.

Plant-Disease-Detection-AI.Herokuapp.com

Code :

LinkedIn :

Conclusion :

This model is working great without Transfer learning. But I will use transfer learning and many other methods to improve the accuracy of the model.

I hope you enjoyed this project šŸ™.

More Blogs and Projects :

Projects :

Blogs :

Final Note :

Thanks for reading! If you enjoyed this article, please hit the clap šŸ‘button as many times as you can. It would mean a lot and encourage me to keep sharing my knowledge. If you like my content follow me on medium I will try to post as many blogs as I can.

--

--

Manthan Bhikadiya šŸ’”
Analytics Vidhya

Beyond the code lies magic. šŸŖ„ Unveiling AI's potential with Generative AI, ML, DL, NLP, CV. Explore my blog's insights!