Plant Disease Detection Using CNN
All about how to predict common disease in Corn, Potato and Tomato.
Installing Required dependencies
-
Creating separate conda environment for the project:
conda create -n plant python=3.7 -y
-
Activating the conda environment:
conda activate plant
-
Installing the required dependencies:
pip install sklearn
pip install pandas
pip install numpy
pip install matplotlib
pip install tensorflow-gpu
For GPU Onlypip install opencv-python
-
You can find data for this project in this repository and name is dataset.rar
-
Now importing required modules.
import numpy as np
import pandas as pd
import tensorflow
import matplotlib.pyplot as plt
from matplotlib.image import imread
import cv2
import os
import random
from os import listdir
from PIL import Image
from sklearn.preprocessing import label_binarize, LabelBinarizer
from tensorflow.keras.preprocessing import image
from tensorflow.keras.preprocessing.image import img_to_array, array_to_img
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D
from tensorflow.keras.layers import Activation, Flatten, Dropout, Dense
from sklearn.model_selection import train_test_split
from tensorflow.keras.models import model_from_json
from tensorflow.keras.utils import to_categorical
-
Following class is used to keep the log of every pipeline step.
Visualization Log
Training Log
from datetime import datetime
class App_Logger:
def __init__(self):
pass
def log(self, file_object, log_message):
self.now = datetime.now()
self.date = self.now.date()
self.current_time = self.now.strftime("%H:%M:%S")
file_object.write(
str(self.date) + "/" + str(self.current_time) + "\t\t" + log_message +"\n")
- Following Visualize class is used to display the sample images we have for training.
class Visualize:
def __init__(self):
self.log_writer = App_Logger()
self.file_object = open("./Visualization_Logs/VisualizationLog.txt", 'a+')
def plot(self, path):
self.path = path
self.log_writer.log(self.file_object, 'Entered the plot method of the Visualize class')
plt.figure(figsize=(12, 12))
for i in range(1, 17):
plt.subplot(4, 4, i)
plt.tight_layout()
self.rand_img = imread(self.path +'/'+ random.choice(sorted(os.listdir(self.path))))
plt.imshow(self.rand_img)
plt.xlabel(self.rand_img.shape[1], fontsize = 10) # Width of image
plt.ylabel(self.rand_img.shape[0], fontsize = 10) # height of image
plt.show()
- Plotting some sample images of Corn_Common_rust, Potato_Early_blight and Tomato_Bacterial_spot.
path = "./dataset/Corn_Common_rust"
viz = Visualize()
viz.plot(path)
path = "./dataset/Potato_Early_blight"
viz = Visualize()
viz.plot(path)
path = "./dataset/Tomato_Bacterial_spot"
viz = Visualize()
viz.plot(path)
-
This Preprocessor class is used to prepare the data for training and it has one method:
-
convert_image_to_array
This method is used to read image, resize it and converting it to array.
-
class Preprocessor:
def __init__(self):
self.log_writer = App_Logger()
self.file_object = open("./Processing_Logs/ProcessingLog.txt", 'a+')
def convert_image_to_array(self, image_dir):
self.log_writer.log(self.file_object, "Entered the convert_image_to_array method of the Preprocessor class.")
self.image_dir = image_dir
try:
self.log_writer.log(self.file_object, "Reading images.")
self.image = cv2.imread(self.image_dir)
if self.image is not None:
self.image = cv2.resize(self.image, (256, 256))
return img_to_array(self.image)
self.log_writer.log(self.file_object, "Image to array conversion Successful.")
else:
return np.array([])
except Exception as e:
self.log_writer.log(self.file_object, "Exception occured in convert_image_to_array of the Preprocessor class. Exception message: "+str(e))
self.log_writer.log(self.file_object, "Convert image to array Unsuccessful. Exited the convert_image_to_array method of the Preprocessor class")
raise Exception()
-
Following Trainmodel class is used to train our dataset which has three methods :
-
prepare_data : This method is used to prepare the data for training by
- Separating images and labesls.
- Converting them in train and test dataset.
- Normalize them for easy training.
- Changing label to categorical format.
-
model :
This method is the main step where we build our convolutional neural network model by introducing two convolutional followed by two pooling, dense and one flatten layer.
-
train :
In this method we train our model by using the fit method of the model. Also before training we again perform train test split to again increase the performance.
Here we use Adam as a optimizer and catagorical cross entropy as a loss function.
Here we also plot the traing and validation accuracy and loss.
-
class TrainModel:
def __init__(self):
self.log_writer = App_Logger()
self.file_object = open("./Training_Logs/ModelTrainingLog.txt", 'a+')
self.Preprocessor = Preprocessor()
def prepare_data(self):
# Logging the start of training
self.log_writer.log(self.file_object, 'Start of Training')
"""doing the preprocessing"""
self.log_writer.log(self.file_object, 'Doing Preprocessing.')
# Doing necessary preprocessing
self.log_writer.log(self.file_object, 'I enter Preprocessing.')
dir = "./dataset"
root_dir = listdir(dir)
image_list, label_list = [], []
all_labels = ['Corn-Common_rust', 'Potato-Early_blight', 'Tomato-Bacterial_spot']
binary_labels = [0,1,2]
temp = -1
# Reading and converting image to numpy array
for directory in root_dir:
plant_image_list = listdir(f"{dir}/{directory}")
temp += 1
for files in plant_image_list:
image_path = f"{dir}/{directory}/{files}"
image_list.append(self.Preprocessor.convert_image_to_array(image_path))
label_list.append(binary_labels[temp])
# splitting the data into training and test set
self.log_writer.log(self.file_object, 'Doing train_test_split.')
x_train, x_test, y_train, y_test = train_test_split(image_list, label_list, test_size=0.2, random_state = 10)
self.log_writer.log(self.file_object, 'Finish train_test_split.')
# Normalizing the dataset
self.log_writer.log(self.file_object, 'Doing Normalizing.')
x_train = np.array(x_train, dtype=np.float16) / 225.0
x_test = np.array(x_test, dtype=np.float16) / 225.0
x_train = x_train.reshape( -1, 256,256,3)
x_test = x_test.reshape( -1, 256,256,3)
# Changing label to categorical
self.log_writer.log(self.file_object, 'Changing to categorical.')
y_train = to_categorical(y_train)
y_test = to_categorical(y_test)
return x_train, y_train
def model(self):
# Model Building
self.log_writer.log(self.file_object, 'Model Building.')
model = Sequential()
model.add(Conv2D(32, (3, 3), padding="same",input_shape=(256,256,3), activation="relu"))
model.add(MaxPooling2D(pool_size=(3, 3)))
model.add(Conv2D(16, (3, 3), padding="same", activation="relu"))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dense(8, activation="relu"))
model.add(Dense(3, activation="softmax"))
model.summary()
return model
def train(self):
model = self.model()
x_train, y_train = self.prepare_data()
# Compiling Modell
self.log_writer.log(self.file_object, 'Compiling Model.')
model.compile(loss = 'categorical_crossentropy', optimizer = Adam(0.0001), metrics=['accuracy'])
# Again splitting the training dataset into training and validation datasets
self.log_writer.log(self.file_object, 'Again doing train_test_split.')
x_tr, x_val, y_tr, y_val = train_test_split(x_train, y_train, test_size = 0.2)
# Training the model
epochs = 50
batch_size = 20
self.log_writer.log(self.file_object, 'Fitting a model.')
history = model.fit(x_tr, y_tr, batch_size = batch_size, epochs = epochs, validation_data = (x_val, y_val), shuffle=True)
# Saving Model
self.log_writer.log(self.file_object, 'Saving Model.')
model.save("./trained_model/disease.h5")
# Serialize model to json
json_model = model.to_json()
# save the model architechture to JSON file
with open("./dataset/disease.json", "w") as json_file:
json_file.write(json_model)
#saving the weights of the model
model.save_weights("./trained_model/disease_weights.h5")
#Plot the training history
self.log_writer.log(self.file_object, 'Plotting the training history.')
plt.figure(figsize=(12, 5))
plt.plot(history.history['accuracy'], color='r')
plt.plot(history.history['val_accuracy'], color='b')
plt.title('Model Accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epochs')
plt.legend(['train', 'val'])
plt.show()
plt.savefig("./plot_fig/plot.png") # save the figure to file
# logging the successful Training
self.log_writer.log(self.file_object, 'Successful End of Training')
self.file_object.close()
- Now making object of TrainModel and train the model.
trainmodel = TrainModel()
trainmodel.train()
- We can see our model is performing pretty well. So lets see how the web app seems which I built and deployed at heroku: