Computer Vision Applications
Deep Learning for Plant Disease Classification using Images
Author: Alina Cherkas
- This notebook is used to develop a Convolutional Neural Network for plant disease classification using Plant Leaf Diseases Dataset from [1]. The dataset contains over 55k images of 14 different plants affected by various diseases, resulting in 39 classes in total.
- Using a simple 6-layer CNN, I achieve 85% accuracy and 82% macro-average F1-score on the test set for this multi-class classification problem. I find that the model does an excellent job at identifying the plant type and distinguishing between healthy and infected leaves, but it sometimes confuses various types of diseases for a given plant, e.g. confusing
Corn___Cercospora_leaf_spot Gray_leaf_spotwithCorn___Northern_Leaf_Blight. - This notebook also uses popular explainable AI methods like LIME [2], Integrated Gradients [3], Grad-CAM++ [4], and to interpret model predictions.
- Tested with Python 3.9.6
References
[1] G. G. and A. P. J., ‘Identification of plant leaf diseases using a nine-layer deep convolutional neural network’, Computers & Electrical Engineering, vol. 76, pp. 323–338, Jun. 2019, doi: 10.1016/j.compeleceng.2019.04.011.
[2] M. T. Ribeiro, S. Singh, and C. Guestrin, ‘“Why Should I Trust You?”: Explaining the Predictions of Any Classifier’. arXiv, Aug. 09, 2016. doi: 10.48550/arXiv.1602.04938.
[3] M. Sundararajan, A. Taly, and Q. Yan, ‘Axiomatic Attribution for Deep Networks’. arXiv, Jun. 12, 2017. doi: 10.48550/arXiv.1703.01365.
[4] A. Chattopadhyay, A. Sarkar, P. Howlader, and V. N. Balasubramanian, ‘Grad-CAM++: Improved Visual Explanations for Deep Convolutional Networks’, in 2018 IEEE Winter Conference on Applications of Computer Vision (WACV), Mar. 2018, pp. 839–847. doi: 10.1109/WACV.2018.00097.
Libraries
# install specific package versions
# !pip install -q -r requirements.txt
# !pip show tensorflow# standard packages
import os
# wrangling
import numpy as np
import pandas as pd
# visualisation
import plotly.express as px
import plotly.io as pio
# deep learning and explainability
import tensorflow as tf
from tensorflow.keras.utils import image_dataset_from_directory
from tensorflow.keras import layers
from tensorflow.keras.optimizers.legacy import Adam
from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint
from sklearn.metrics import classification_report, confusion_matrix
from sklearn.utils.class_weight import compute_class_weight
from omnixai.data.image import Image
from omnixai.explainers.vision import VisionExplainer
# local utils.py
import utils
# plotting settings
pio.templates.default = 'plotly_white'
pio.renderers.default = 'plotly_mimetype'1. Data Preparation
The code in this section downloads the data and creates dataset for training, validation and testing using TensorFlow image_dataset_from_directory utility.
The next code cell downloads the original dataset (without augmentations) from Mendeley.
%%bash
export dataset=Plant_leaf_diseases_dataset_without_augmentation.zip
curl https://data.mendeley.com/public-files/datasets/tywbtsjrjv/files/d5652a28-c1d8-4b76-97f3-72fb80f94efc/file_downloaded -L --output $dataset
mkdir data
unzip -q $dataset -d data
rm $dataset# target image size is smaller to downsize the images
image_size = (64, 64)# create training and validation data loades using 80/20 split
dataset_train, dataset_valid = image_dataset_from_directory(
directory=str(os.path.join('data', 'Plant_leave_diseases_dataset_without_augmentation')),
labels='inferred',
label_mode='int',
# class_names=LABELS,
color_mode='rgb',
batch_size=32,
image_size=image_size,
shuffle=True,
seed=42,
validation_split=.2,
subset='both',
interpolation='bilinear',
follow_links=False,
crop_to_aspect_ratio=False,
)I split the validation set (which contains 20% of the data) equally into test and validation sets, each containing approximately 10% of the original dataset.
# split the validation set into validation and test sets
num_batches = tf.data.experimental.cardinality(dataset_valid).numpy()
dataset_test = dataset_valid.take(num_batches // 2)
dataset_valid = dataset_valid.skip(num_batches // 2)# sanity check for tensor dimensions
images, labels = next(iter(dataset_train))
images.shape, labels.shapeExamples in the dataset are images of leaves, both healthy and infected, taken indoors. There are also some images of background.
# display a sample of images from the first batch
title = 'Figure 1. Actual Labels for Images in the Train Set'
labels = [dataset_train.class_names[label] for label in labels.numpy()]
images, labels = utils.sample_images_and_labels(images=images.numpy(), labels=labels, k=12)
fig = utils.display_images_with_labels(images=images, labels=labels, per_row=4, vertical_spacing=0.06)
fig.update_layout(title=title, height=900, width=1200)
fig.show()The next cells are used to explore the distribution of labels, which, as is common in many real-world cases, are unevenely distributed. There are many more examples for some classes than for others. Admittedly, there are several plants which only appear as either healthy (Soybean___healthy) or infected (Orange___Haunglongbing_(Citrus_greening)).