Photo by Daniil Kuželev on Unsplash

Using a Neural Network to Prevent Blindness

Andrew Picart
4 min readDec 4, 2019

--

Using a convolutional neural network to detect diabetic retinopathy.

For my capstone project at General Assembly, I choose to use the kaggle competition: APTOS 2019 Blindness Detection.

Diabetic Retinopathy is the leading cause of preventable blindness. According to the National Eye Institute, all forms of diabetic eye disease have the potential to cause severe vision loss and blindness.

The Asia Pacific Tele-Ophthalmology Society has sponsored a kaggle competition. The aim is to help people with diabetes in rural areas of India with the early detection of diabetic retinopathy. The people in rural areas are at higher risk since medical screening is difficult to conduct. If screenings are performed on patients, a medical imaging expert would need to examine and correctly diagnose their image. This would cause a delay in the patient’s treatment and decrease the probability of preventing diabetic retinopathy.

With the help of computer-vision models, patients will not have to rely on a skilled doctor to help stop a preventable disease. With an accurate enough model, a patient would be able to receive a diagnosis just seconds after the retina imaging, and treatment could begin immediately.

Data

The dataset was gathered from kaggle.com. The competition is sponsored by the Asia Pacific Tele-Ophthalmology Society APTOS. APTOS provided the set of 1928 images for training. The images were unaltered from their original collection with some pictures contained artifacts. The photos are pictures of the back of the retina taken using fundus photography.

Each picture was categorized on a scale from 0–4, with 0 being ‘No DR’ and 4 being ‘Severe DR’. The categories were binarized to have a classification of either ‘No DR’ or ‘DR’. The distribution for the two categories is 50.71% ‘No DR’ and 49.29% ‘DR’.

The full dataset can be found here.

Fundus Photography

An image data generator was also used. The datagen helped introduce noise into each of the pictures, as well as help separate from the train and validation set for my model. Introducing noise into an image classification model is important so the model can recognize patterns(aka features) in the pictures, rather than how the pictures are oriented.

datagen=ImageDataGenerator(featurewise_center=True,
featurewise_std_normalization=True,
rotation_range=20,
width_shift_range=0.1,
height_shift_range=0.1,
shear_range=16,
zoom_range=[0.9, 1.1],
fill_mode="constant",
cval=255,
horizontal_flip=True,
vertical_flip=True,
rescale=1./255.)

Convolutional Neural Network

To aid in the classification of Diabetic Retinopathy, a convolution neural network was created. Convolutions are created to act as filters on the image. These filters are simply math matrices that detect the presence of a feature. The calculated weights are then backpropagated through the network to optimize for loss. This is a simple model since this is my first time making a convolutional neural network.

model = models.Sequential()
model.add(layers.Conv2D(16, (3, 3), activation=’relu’, input_shape=(IMG_SIZE, IMG_SIZE, 3)))
model.add(layers.MaxPooling2D(2, 2))
model.add(Dropout(0.25))
model.add(layers.Conv2D(32, (3, 3), activation=’relu’))
model.add(layers.Conv2D(32, (3, 3), activation=’relu’))
model.add(layers.MaxPooling2D(2, 2))
model.add(Dropout(0.25))
model.add(layers.Conv2D(64, (3, 3), activation=’relu’))
model.add(layers.Conv2D(64, (3, 3), activation=’relu’))
model.add(layers.MaxPooling2D(2, 2))
model.add(Dropout(0.4))
model.add(layers.Conv2D(128, (3, 3), activation=’relu’))
model.add(layers.MaxPooling2D(2, 2))
model.add(Dropout(0.4))
model.add(layers.BatchNormalization())

The layers must then be flatted to go from 3D out to 1D.

model.add(layers.Flatten()) #flatten 3D outputs to 1D
model.add(layers.Dense(128, activation='relu'))
model.add(Dropout(rate=0.3))
model.add(layers.Dense(1, activation='sigmoid'))

The model is compiled and then fit.

history = model.fit_generator(generator=train_generator,
steps_per_epoch=STEP_SIZE_TRAIN,
validation_data=valid_generator,
validation_steps=STEP_SIZE_VALID,
class_weight='balanced',
epochs=30,
verbose=1,
callbacks=callbacks_list
)

Model Evaluation

After many hours of trial and error, my model ran after 30 epochs. It scored an f1-score and ROC AUC score of 93%.

While this is a very good metric, I would not be comfortable with deploying the model without further training data. When dealing with actual humans and a condition as permanent as blindness, I would want to have a model that performs even better at classifying unseen test data. I would only recommend using this model for a preliminary screening.

My next step would try to change the model from a binary classification to multi-class classification. In my initial try with the convolutional neural network, the results from the 5-class classification model were not to up to my satisfaction. Given more time on the project, I would try to optimize for the quadratic kappa loss function instead of the standard accuracy, since quadratic kappa loss is how the kaggle competition is graded on.

Luckily, many other teams are working on this project. The online kaggle community is very helpful and is committed to helping tackle the issue of diabetic retinopathy.

--

--