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
![](https://www.corkeyeclinic.ie/files/UserFiles/glaucoma-field-loss.jpg)
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()
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()
Resources
- https://dataverse.harvard.edu/dataset.xhtml?persistentId=doi:10.7910/DVN/1YRRAC
- https://keras.io/visualization/
- Adapted from the Classify Images of Clothing Website by François Chollet, 2017, MIT
- https://journals.plos.org/plosone/article?id=10.1371%2Fjournal.pone.0207982