Lesson 5 - Convolutional Neural Networks

Glaucoma is a disease caused by high intraoccular pressure that leads to degenertation of the optic nerve and visual perspective

Below is an example of the degenerative visual effects of glaucoma

1) Import the necessary libraries

We will be predicitng a advanced, early, and control glaucoma based on eye fundus images.

To begin, we need to right libraries

  • os is what we will use to modify file names and create new directories

  • tensorflow is what we will use to build our neural networks

  • matplotlib helps to plot data and visualize the data

  • numpy helps us make our training and test set arrays

  • keras helps us to make our neural networks

import os

#Import TensorFlow and Keras
import tensorflow as tf
from tensorflow import keras

#Helper libraries
import numpy as np
import matplotlib.pyplot as plt

2) Download the data and create necessary directories

Download the data from here

  • Make sure to import additional necessary libraries like random.
# organize dataset into a useful structure
from os import makedirs
from os import listdir
from shutil import copyfile
from random import seed
from random import random


# create directories
dataset_home = 'Downloads/Eye_Fundus_Images_Validation/'
subdirs = ['train/', 'test/']
for subdir in subdirs:
    # create label subdirectories
    labeldirs = ['advanced_glaucoma/', 'early_glaucoma/', 'normal_control/']
    for labldir in labeldirs:
        newdir = dataset_home + subdir + labldir
        makedirs(newdir, exist_ok=True)

3) Split the data into test and training sets

  • Define the validation ratio. In this case, we are trainig on 75% of the data and testing on 25%
# seed random number generator
seed(1)
# define ratio of pictures to use for validation
val_ratio = 0.25
# copy training dataset images into subdirectories
src_directory = 'Downloads/Eye_Fundus_Images'

for label in labeldirs:

    new_src_directory = src_directory + '/' + label
    print(new_src_directory)

    for file in listdir(new_src_directory):
        oldFileName = new_src_directory + file

        newFileName = new_src_directory + '/' + label[:-1] + file



        os.rename(oldFileName, newFileName)

        newFileIndividualName = label[:-1] + file

        dst_dir = 'train/'
        if random() < val_ratio:
            dst_dir = 'test/'
        if newFileIndividualName.startswith(label[:-1]):
            dst = dataset_home + dst_dir + label  + newFileIndividualName
            copyfile(newFileName, dst)
Downloads/Eye_Fundus_Images/advanced_glaucoma/
Downloads/Eye_Fundus_Images/early_glaucoma/
Downloads/Eye_Fundus_Images/normal_control/

4) Create a class names array

class_names = ['advanced glaucoma', 'early glaucoma' , 'normal control']

5) Use an image generator to

  • rescale the images to a pixel value between 0 and 1.
  • generate new, augmented images by horizontally flipping the images
  • resize the images to 240*240 pixels
  • Also store the information in the iterators as arrays for further processing
from keras.preprocessing.image import ImageDataGenerator



datagen = ImageDataGenerator(
      rescale = 1./255,
      horizontal_flip=True)

#training directory iterator
train_it = datagen.flow_from_directory( dataset_home + 'train/',
	class_mode='categorical', target_size=(240, 240))


#testing directory iterator
test_it = datagen.flow_from_directory(dataset_home + 'test/',
	class_mode='categorical', target_size=(240, 240))

#Convert to arrays
x, y = train_it.next()
X, Y = test_it.next()
Found 1185 images belonging to 3 classes.
Found 359 images belonging to 3 classes.

6) Make the model

This model consists of

  • 4 Convolutional layers, each followed by maxpooling
  • Every layer regularizes the weights using Xavier regularization
  • There are 3 fully connected layers.
  • Before connecting to the fully connected layers, we use a dropout function with 0.5


model = keras.Sequential([

    keras.layers.Conv2D(64, (3,3), activation='relu', input_shape=(240, 240, 3), kernel_initializer = 'glorot_normal'),
    keras.layers.MaxPooling2D(2,2),
    # The second convolution
    keras.layers.Conv2D(64, (3,3), activation='relu' , kernel_initializer = 'glorot_normal'),
    keras.layers.MaxPooling2D(2,2),
    keras.layers.Conv2D(128, (3,3), activation='relu' , kernel_initializer = 'glorot_normal'),
    keras.layers.MaxPooling2D(2,2),
    keras.layers.Conv2D(128, (3,3), activation='relu' , kernel_initializer = 'glorot_normal'),
    keras.layers.MaxPooling2D(2,2),
    # Flatten the results to feed into a DNN
    keras.layers.Flatten(),
    keras.layers.Dropout(0.5),
    # 512 neuron hidden layer
    #keras.layers.Dense(512, kernel_initializer = "glorot_uniform") ,
    keras.layers.Dense(32, activation='relu' , kernel_initializer = 'glorot_normal') ,
    keras.layers.Dense(64, activation = 'relu' , kernel_initializer = 'glorot_normal'
                      ) ,
    keras.layers.Dense(3, activation='softmax')
])


model.summary()

model.compile(loss = 'categorical_crossentropy', optimizer='adagrad', metrics=['accuracy'])

history = model.fit_generator(train_it, epochs=25, validation_data = test_it, verbose = 1)
Model: "sequential_3"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_12 (Conv2D)           (None, 238, 238, 64)      1792      
_________________________________________________________________
max_pooling2d_12 (MaxPooling (None, 119, 119, 64)      0         
_________________________________________________________________
conv2d_13 (Conv2D)           (None, 117, 117, 64)      36928     
_________________________________________________________________
max_pooling2d_13 (MaxPooling (None, 58, 58, 64)        0         
_________________________________________________________________
conv2d_14 (Conv2D)           (None, 56, 56, 128)       73856     
_________________________________________________________________
max_pooling2d_14 (MaxPooling (None, 28, 28, 128)       0         
_________________________________________________________________
conv2d_15 (Conv2D)           (None, 26, 26, 128)       147584    
_________________________________________________________________
max_pooling2d_15 (MaxPooling (None, 13, 13, 128)       0         
_________________________________________________________________
flatten_3 (Flatten)          (None, 21632)             0         
_________________________________________________________________
dropout_3 (Dropout)          (None, 21632)             0         
_________________________________________________________________
dense_7 (Dense)              (None, 32)                692256    
_________________________________________________________________
dense_8 (Dense)              (None, 64)                2112      
_________________________________________________________________
dense_9 (Dense)              (None, 3)                 195       
=================================================================
Total params: 954,723
Trainable params: 954,723
Non-trainable params: 0
_________________________________________________________________
Epoch 1/25
WARNING:tensorflow:From C:\Users\coder\Anaconda3\envs\TensorFlow\lib\site-packages\tensorflow_core\python\keras\optimizer_v2\adagrad.py:107: calling Constant.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.
Instructions for updating:
Call initializer instance with the dtype argument instead of passing it to the constructor


WARNING:tensorflow:From C:\Users\coder\Anaconda3\envs\TensorFlow\lib\site-packages\tensorflow_core\python\keras\optimizer_v2\adagrad.py:107: calling Constant.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.
Instructions for updating:
Call initializer instance with the dtype argument instead of passing it to the constructor


37/38 [============================>.] - ETA: 2s - loss: 0.9074 - acc: 0.5950Epoch 1/25
38/38 [==============================] - 114s 3s/step - loss: 0.8999 - acc: 0.6008 - val_loss: 0.7370 - val_acc: 0.6992
Epoch 2/25
37/38 [============================>.] - ETA: 2s - loss: 0.6713 - acc: 0.7025Epoch 1/25
38/38 [==============================] - 113s 3s/step - loss: 0.6763 - acc: 0.6987 - val_loss: 0.6985 - val_acc: 0.7047
Epoch 3/25
37/38 [============================>.] - ETA: 2s - loss: 0.7061 - acc: 0.6895Epoch 1/25
38/38 [==============================] - 114s 3s/step - loss: 0.7096 - acc: 0.6861 - val_loss: 0.7560 - val_acc: 0.6657
Epoch 4/25
37/38 [============================>.] - ETA: 2s - loss: 0.6705 - acc: 0.7042Epoch 1/25
38/38 [==============================] - 113s 3s/step - loss: 0.6669 - acc: 0.7055 - val_loss: 0.6312 - val_acc: 0.7298
Epoch 5/25
37/38 [============================>.] - ETA: 2s - loss: 0.6216 - acc: 0.7112Epoch 1/25
38/38 [==============================] - 112s 3s/step - loss: 0.6181 - acc: 0.7139 - val_loss: 0.6163 - val_acc: 0.7354
Epoch 6/25
37/38 [============================>.] - ETA: 2s - loss: 0.6287 - acc: 0.7190Epoch 1/25
38/38 [==============================] - 112s 3s/step - loss: 0.6338 - acc: 0.7156 - val_loss: 0.8917 - val_acc: 0.5543
Epoch 7/25
37/38 [============================>.] - ETA: 2s - loss: 0.6188 - acc: 0.7259Epoch 1/25
38/38 [==============================] - 113s 3s/step - loss: 0.6167 - acc: 0.7274 - val_loss: 0.6232 - val_acc: 0.7437
Epoch 8/25
37/38 [============================>.] - ETA: 2s - loss: 0.5830 - acc: 0.7251Epoch 1/25
38/38 [==============================] - 114s 3s/step - loss: 0.5848 - acc: 0.7266 - val_loss: 0.6059 - val_acc: 0.7382
Epoch 9/25
37/38 [============================>.] - ETA: 2s - loss: 0.6555 - acc: 0.7173Epoch 1/25
38/38 [==============================] - 114s 3s/step - loss: 0.6553 - acc: 0.7148 - val_loss: 0.6076 - val_acc: 0.7493
Epoch 10/25
37/38 [============================>.] - ETA: 2s - loss: 0.5799 - acc: 0.7355Epoch 1/25
38/38 [==============================] - 114s 3s/step - loss: 0.5825 - acc: 0.7342 - val_loss: 0.6506 - val_acc: 0.7187
Epoch 11/25
37/38 [============================>.] - ETA: 2s - loss: 0.6558 - acc: 0.7138Epoch 1/25
38/38 [==============================] - 112s 3s/step - loss: 0.6545 - acc: 0.7131 - val_loss: 0.6354 - val_acc: 0.7521
Epoch 12/25
37/38 [============================>.] - ETA: 2s - loss: 0.6003 - acc: 0.7348Epoch 1/25
38/38 [==============================] - 111s 3s/step - loss: 0.6295 - acc: 0.7342 - val_loss: 0.6961 - val_acc: 0.6602
Epoch 13/25
37/38 [============================>.] - ETA: 2s - loss: 0.5906 - acc: 0.7398Epoch 1/25
38/38 [==============================] - 111s 3s/step - loss: 0.5895 - acc: 0.7384 - val_loss: 0.6284 - val_acc: 0.7493
Epoch 14/25
37/38 [============================>.] - ETA: 2s - loss: 0.5707 - acc: 0.7389Epoch 1/25
38/38 [==============================] - 112s 3s/step - loss: 0.5738 - acc: 0.7350 - val_loss: 0.6031 - val_acc: 0.7437
Epoch 15/25
37/38 [============================>.] - ETA: 2s - loss: 0.5726 - acc: 0.7320Epoch 1/25
38/38 [==============================] - 111s 3s/step - loss: 0.5747 - acc: 0.7300 - val_loss: 0.6104 - val_acc: 0.7131
Epoch 16/25
37/38 [============================>.] - ETA: 2s - loss: 0.5765 - acc: 0.7389Epoch 1/25
38/38 [==============================] - 112s 3s/step - loss: 0.5740 - acc: 0.7401 - val_loss: 0.5782 - val_acc: 0.7437
Epoch 17/25
37/38 [============================>.] - ETA: 2s - loss: 0.6235 - acc: 0.7407Epoch 1/25
38/38 [==============================] - 116s 3s/step - loss: 0.6212 - acc: 0.7409 - val_loss: 0.5976 - val_acc: 0.7382
Epoch 18/25
37/38 [============================>.] - ETA: 2s - loss: 0.6068 - acc: 0.7528Epoch 1/25
38/38 [==============================] - 114s 3s/step - loss: 0.6034 - acc: 0.7544 - val_loss: 0.5938 - val_acc: 0.7577
Epoch 19/25
37/38 [============================>.] - ETA: 2s - loss: 0.5923 - acc: 0.7459Epoch 1/25
38/38 [==============================] - 113s 3s/step - loss: 0.5916 - acc: 0.7460 - val_loss: 0.5792 - val_acc: 0.7493
Epoch 20/25
37/38 [============================>.] - ETA: 2s - loss: 0.5736 - acc: 0.7346Epoch 1/25
38/38 [==============================] - 113s 3s/step - loss: 0.5723 - acc: 0.7376 - val_loss: 0.5896 - val_acc: 0.7549
Epoch 21/25
37/38 [============================>.] - ETA: 2s - loss: 0.5867 - acc: 0.7407Epoch 1/25
38/38 [==============================] - 113s 3s/step - loss: 0.5851 - acc: 0.7426 - val_loss: 0.5850 - val_acc: 0.7242
Epoch 22/25
37/38 [============================>.] - ETA: 2s - loss: 0.5800 - acc: 0.7502Epoch 1/25
38/38 [==============================] - 115s 3s/step - loss: 0.5785 - acc: 0.7511 - val_loss: 0.5861 - val_acc: 0.7354
Epoch 23/25
37/38 [============================>.] - ETA: 2s - loss: 0.5584 - acc: 0.7520Epoch 1/25
38/38 [==============================] - 114s 3s/step - loss: 0.5609 - acc: 0.7519 - val_loss: 0.5837 - val_acc: 0.7577
Epoch 24/25
37/38 [============================>.] - ETA: 2s - loss: 0.5614 - acc: 0.7450Epoch 1/25
38/38 [==============================] - 115s 3s/step - loss: 0.5627 - acc: 0.7460 - val_loss: 0.5843 - val_acc: 0.7632
Epoch 25/25
37/38 [============================>.] - ETA: 2s - loss: 0.5483 - acc: 0.7546Epoch 1/25
38/38 [==============================] - 115s 3s/step - loss: 0.5475 - acc: 0.7544 - val_loss: 0.5899 - val_acc: 0.7354

7) Plot the training and validation accuracy

# Plot training & validation accuracy values
plt.plot(history.history['acc'])
plt.plot(history.history['val_acc'])
plt.title('Model accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.legend(['Train', 'Test'], loc='upper left')
plt.show()

png

8) Test the model on the testing data


predicitions = model.predict_generator(test_it)
loss, acc = model.evaluate_generator(test_it)

9) Print the model’s accuracy on the test data

print("The model's accuracy on the test data is: " + str(acc))
The model's accuracy on the test data is: 0.73816156

10) Define functions for plotting the image and the probability value array

import matplotlib.pyplot as plt

def plot_image(i , predictions_array, true_label, img) :
    predictions_array, true_label, img = predictions_array, true_label[i], img[i]
    plt.grid(False)
    plt.xticks([])
    plt.yticks([])

    plt.imshow(img, cmap=plt.cm.binary)

    predicted_label = np.argmax(predictions_array)

    true_label_index = np.argmax(true_label)
    predited_label = np.argmax(predictions_array)
    if predicted_label == true_label_index:
        color = 'blue'
    else :
        color = 'red'

    plt.xlabel("{} {:2.0f}% ({})".format(class_names[predicted_label],
                                100*np.max(predictions_array),
                                class_names[true_label_index]),
                                color=color)

def plot_value_array(i, predictions_array, true_label) :
    predictions_array, true_label = predictions_array, true_label[i]
    plt.grid(False)
    plt.xticks(range(3))
    plt.yticks([])
    thisplot = plt.bar(range(3), predictions_array , color = "#777777")
    plt.ylim([0,1])
    predicted_label = np.argmax(predictions_array)

    true_label_index = np.argmax(true_label)

    thisplot[predicted_label].set_color('red')
    thisplot[true_label_index].set_color('blue')

11) Now let’s plot several images with their predictions

Correct predictions are in blue. Incorrect predictions are in red.



num_rows = 5
num_cols = 3
num_images = num_rows*num_cols
plt.figure(figsize=(2*2*num_cols, 2*num_rows))
for i in range(num_images) :
    plt.subplot(num_rows, 2*num_cols, 2*i+1)
    plot_image(i, predicitions[i], Y, X)
    plt.subplot(num_rows, 2*num_cols, 2*i+2)
    plot_value_array(i, predicitions[i], Y)
plt.tight_layout()
plt.show()

png

Resources

Previous
Next