<jupyter_start><jupyter_text>[![Kaggle](https://kaggle.com/static/images/open-in-kaggle.svg)](https://www.kaggle.com/rishitdagli/identify-plant-diseases-tensorflow)<jupyter_code>!nvidia-smi<jupyter_output>Thu Apr  1 04:07:08 2021       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 450.51.06    Driver Version: 450.51.06    CUDA Version: 11.0     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  Tesla P100-PCIE...  Off  | 00000000:00:04.0 Off |                    0 |
| N/A   40C    P0    28W / 250W |      0MiB / 16280MiB |      0%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
                                                                            [...]<jupyter_text>Identify Plant DiseasesWe use the PlantVillage dataset [1] by Hughes et al. consists of about 87,000 healthy and unhealthy leaf images divided into 38 categories by species and disease. Here we provide a subset of our experiments on working with this data. We also end up transfer learning from MobileNet and use the weights from pre-training on ImageNet.* ![PlantVillage Dataset Samples](https://i.imgur.com/Zcxdrlc.png)Figure 1. PlantVillage Dataset Samples ClassesThe following 38 classes are availaible in the dataset- `Apple___Apple_scab` - `Apple___Black_rot` - `Apple___Cedar_apple_rust` - `Apple___healthy` - `Blueberry___healthy` - `Cherry_(including_sour)___Powdery_mildew` - `Cherry_(including_sour)___healthy` - `Corn_(maize)___Cercospora_leaf_spot Gray_leaf_spot` - `Corn_(maize)___Common_rust_` - `Corn_(maize)___Northern_Leaf_Blight` - `Corn_(maize)___healthy', 'Grape___Black_rot` - `Grape___Leaf_blight_(Isariopsis_Leaf_Spot)` - `Grape___healthy` - `Orange___Haunglongbing_(Citrus_greening)` - `Peach___Bacterial_spot` - `Peach___healthy` - `Pepper,_bell___Bacterial_spot` - `Pepper,_bell___healthy` - `Potato___Early_blight` - `Potato___Late_blight` - `Potato___healthy` - `Raspberry___healthy` - `Soybean___healthy` - `Squash___Powdery_mildew` - `Strawberry___Leaf_scorch` - `Strawberry___healthy` - `Tomato___Bacterial_spot` - `Tomato___Late_blight` - `Tomato___Leaf_Mold` - `Tomato___Septoria_leaf_spot` - `Tomato___Spider_mites Two-spotted_spider_mite` - `Tomato___Target_Spot` - `Tomato___Tomato_Yellow_Leaf_Curl_Virus` - `Tomato___Tomato_mosaic_virus` - `Tomato___healthy` References[1] Hughes, <NAME>., and <NAME>. “An Open Access Repository of Images on Plant Health to Enable the Development of Mobile Disease Diagnostics.” ArXiv:1511.08060 [Cs], Apr. 2016. arXiv.org, http://arxiv.org/abs/1511.08060.[2] Howard, <NAME>., et al. “MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications.” ArXiv:1704.04861 [Cs], Apr. 2017. arXiv.org, http://arxiv.org/abs/1704.04861.  Setup<jupyter_code>import tensorflow as tf
from tensorflow import keras

import matplotlib.pyplot as plt
import numpy as np

import os
image_size = 224
target_size = (image_size, image_size)
input_shape = (image_size, image_size, 3)

batch_size = 32
epochs = 25<jupyter_output><empty_output><jupyter_text>Get dataIn order to make the most of our few training examples, we will "augment" them via a number of random transformations, so that our model would never see twice the exact same picture. This helps prevent overfitting and helps the model generalize better.In TensorFlow this can be done via the `tf.keras.preprocessing.image.ImageDataGenerator` class. This class allows you to:- configure random transformations and normalization operations to be done on your image data during training- instantiate generators of augmented image batches (and their labels) via `.flow(data, labels)` or `.flow_from_directory(directory)`. These generators can then be used with the `tf.keras` model methods that accept data generators as inputs, `fit`, `evaluate` and `predict`.<jupyter_code>base_dir = "../input/new-plant-diseases-dataset/new plant diseases dataset(augmented)/New Plant Diseases Dataset(Augmented)"
train_dir = os.path.join(base_dir,"train")
test_dir = os.path.join(base_dir,"valid")<jupyter_output><empty_output><jupyter_text>We make the following augmentations to the images:- `width_shift` and `height_shift` are ranges (as a fraction of total width or height) within which to randomly translate pictures vertically or horizontally- `rescale` is a value by which we will multiply the data before any other processing. Our original images consist in RGB coefficients in the 0-255, but such values would be too high for our models to process (given a typical learning rate), so we target values between 0 and 1 instead by scaling with a 1/255. factor.- `shear_range` is for randomly applying shearing transformations- `zoom_range` is for randomly zooming inside pictures- `fill_mode` is the strategy used for filling in newly created pixels, which can appear after a rotation or a width/height shift.<jupyter_code>train_datagen = keras.preprocessing.image.ImageDataGenerator(rescale = 1/255.0,
                                                             shear_range = 0.2,
                                                             zoom_range = 0.2,
                                                             width_shift_range = 0.2,
                                                             height_shift_range = 0.2,
                                                             fill_mode="nearest")

test_datagen = keras.preprocessing.image.ImageDataGenerator(rescale = 1/255.0)<jupyter_output><empty_output><jupyter_text>Let's prepare our data. We will use `.flow_from_directory()` to generate batches of image data (and their labels) directly from our images in their respective folders.<jupyter_code>train_data = train_datagen.flow_from_directory(train_dir,
                                               target_size = (image_size, image_size),
                                               batch_size = batch_size,
                                               class_mode = "categorical")

test_data = test_datagen.flow_from_directory(test_dir,
                                             target_size = (image_size, image_size),
                                             batch_size = batch_size,
                                             class_mode = "categorical")<jupyter_output>Found 70295 images belonging to 38 classes.
Found 17572 images belonging to 38 classes.<jupyter_text>Create a classes index fileWe also want to know which class corresponds to which species and disease so we also create a `json` file which shows corresponding labels and class indices.<jupyter_code>categories = list(train_data.class_indices.keys())
print(train_data.class_indices)
import json
with open('class_indices.json','w') as f:
  json.dump(train_data.class_indices, f)

from IPython.display import FileLink
FileLink(r'class_indices.json')<jupyter_output><empty_output><jupyter_text>TrainingWe first get the base MobileNet model without including the top layers since we want to use it for 38 classes and us the pre-trained weights for ImageNet.<jupyter_code>base_model = tf.keras.applications.MobileNet(weights = "imagenet",
                                             include_top = False,
                                             input_shape = input_shape)

base_model.trainable = False<jupyter_output>Downloading data from https://storage.googleapis.com/tensorflow/keras-applications/mobilenet/mobilenet_1_0_224_tf_no_top.h5
17227776/17225924 [==============================] - 0s 0us/step<jupyter_text>We now create a small upstream model on top of the MobileNet using the functional API<jupyter_code>inputs = keras.Input(shape = input_shape)

x = base_model(inputs, training = False)
x = tf.keras.layers.GlobalAveragePooling2D()(x)
x = tf.keras.layers.Dropout(0.2)(x)
x = tf.keras.layers.Dense(len(categories), 
                          activation="softmax")(x)

model = keras.Model(inputs = inputs, 
                    outputs = x, 
                    name="LeafDisease_MobileNet")<jupyter_output><empty_output><jupyter_text>In our multiple experiments we found out Adam optimizer to work really well with it's default learning rate, $\beta_1$, $\beta_2$ and $\epsilon$ values<jupyter_code>optimizer = tf.keras.optimizers.Adam()

model.compile(optimizer = optimizer,
              loss = tf.keras.losses.CategoricalCrossentropy(from_logits = True),
              metrics=[keras.metrics.CategoricalAccuracy(), 
                       'accuracy'])
history = model.fit(train_data,
                    validation_data=test_data,
                    epochs=epochs,
                    steps_per_epoch=150,
                    validation_steps=100)<jupyter_output>Epoch 1/25
150/150 [==============================] - 101s 651ms/step - loss: 2.9674 - categorical_accuracy: 0.2649 - accuracy: 0.2649 - val_loss: 0.8529 - val_categorical_accuracy: 0.7894 - val_accuracy: 0.7894
Epoch 2/25
150/150 [==============================] - 91s 606ms/step - loss: 0.8498 - categorical_accuracy: 0.7780 - accuracy: 0.7780 - val_loss: 0.5021 - val_categorical_accuracy: 0.8694 - val_accuracy: 0.8694
Epoch 3/25
150/150 [==============================] - 87s 584ms/step - loss: 0.5840 - categorical_accuracy: 0.8334 - accuracy: 0.8334 - val_loss: 0.3919 - val_categorical_accuracy: 0.8866 - val_accuracy: 0.8866
Epoch 4/25
150/150 [==============================] - 84s 559ms/step - loss: 0.5198 - categorical_accuracy: 0.8445 - accuracy: 0.8445 - val_loss: 0.3315 - val_categorical_accuracy: 0.8994 - val_accuracy: 0.8994
Epoch 5/25
150/150 [==============================] - 81s 538ms/step - loss: 0.4232 - categorical_accuracy: 0.8756 - accuracy: 0.8756 - val_loss: 0.2891 - [...]<jupyter_text>Review the training process<jupyter_code>loss = history.history['loss']
val_loss = history.history['val_loss']

epochs = range(len(loss))

fig = plt.figure(figsize=(10,6))
plt.plot(epochs,loss,c="red",label="Training")
plt.plot(epochs,val_loss,c="blue",label="Validation")
plt.xlabel("Epochs")
plt.ylabel("Loss")
plt.legend()
acc = history.history['categorical_accuracy']
val_acc = history.history['val_categorical_accuracy']

epochs = range(len(acc))

fig = plt.figure(figsize=(10,6))
plt.plot(epochs,acc,c="red",label="Training")
plt.plot(epochs,val_acc,c="blue",label="Validation")
plt.xlabel("Epochs")
plt.ylabel("Accuracy")
plt.legend()<jupyter_output><empty_output><jupyter_text>Save the modelWe finally save the model in the standard TensorFlow 2 SavedModel format.<jupyter_code>model.save('plant_disease')<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.13601236476043277, 'fraction_numerical': 0.038458041640149106, 'mean_word_length': 3.008746355685131, 'pattern_counts': {'":': 0, '<': 44, '<?xml version=': 0, '>': 44, 'https://': 4, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 1, 'word_list_counts': {'cursed_substrings.json': 37, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '11', 'dir': 'jupyter-structured-clean-dedup', 'id': '232753', 'license': 'Apache-2.0', 'n_tokens_mistral': 3624, 'n_tokens_neox': 3173, 'n_words': 823, 'path': 'notebooks/plant-diseases-training.ipynb', 'repo_name': 'Rishit-dagli/Greenathon-Plant-AI', 'size': '11010'}