Building an Image Classification Model with CNN
By: Eunjoo Byeon
Tags: Convolutional Network, Keras, Image Classification, Medical, Data Science

First Model

As our baseline model, we will build a simple convolutional neural network that takes in images after resizing them to be a square matrix and normalizing all pixel values to range from 0 to 1. The full step is shown below.

Now I will explain each step in detail.

1. Scaling Data

keras.image.ImageDataGenerator() takes images and create augmented data based on the parameters. Here we are just asking it to rescale all pixel values to be 0 to 1 without specifying any other augmentation parameters. Combined with flow_from_directory , the generator calls images from the directory in the assigned format, then creates rescaled data.

2. Building a Model Architecture

keras.models.Sequential() initiates a sequential model. This model will sequentially process the added layers.

Conv2D layers are the convolutional layers, which takes the input and runs them through the assigned number of filters. Kernel size refers to the dimension of filters. So in this example, each consecutive group of 3*3 pixels in our 256*256*1 image (1 referring to the number of channels, RGB images have 3 channels, while grayscale images have 1 channel) will run through 32 filters generating 32 feature maps with a size of 256*256*1.

padding = ‘same' is used to add equal paddings around our window since 256 is not divisible by 3.

activation = 'relu' means that we are assigning the rectified linear unit as our activation function. Simply put, we are telling the layer to convert all our negative values to 0.

We then feed these outputs from convolutional layers into the pooling layer. The MaxPooling2D layer abstracts the convolved outputs by only leaving the maximum value of each of the 2*2 matrices of the convolved output. Now we would have 32 feature maps with the size of 128*128*1.

Now we need to narrow down these 4-dimensional outputs to a single number that can tell us whether to classify the image as pneumonia or normal. We do this by first flattening the layer into a single dimension then running them subsequently through smaller and smaller dense layers. A sigmoid function is applied as an activation function on the final layer because we now want the model to output a probability of whether the output is pneumonia or not.

3. Configuration

We have defined the architecture of our model. The next step is to decide the goal of this model and how we want it to get there. Using model.compile , we tell the model to minimize the binary cross-entropy loss (the log-loss, think logistic regression) using the gradient-descent. Here we are using the RMSprop algorithm to optimize this process by adaptively decreasing the learning rate. In the later model, I used the AMSGrad algorithm, which performed better for our problem.

4. Fitting Data

Finally, we finished constructing our model. It’s time to fit our training data! Each epoch will run 32 batches by default. We are setting EarlyStopping to prevent overfitting. This model will stop running if our validation loss is not reduced for 5 consecutive epochs. I set the restore_best_weights to be true so it will revert to the highest performing weights after those 5 epochs. It tests its performance on the validation generator we created earlier.

5. Evaluation

Our first model showed 94% accuracy predicting the class of validation data with the log loss of 0.11. Based on the below graph, we can see that training loss has room to improve so we can probably increase the complexity of the model. Also, the validation loss seems to be hovering around 0.1. We can try to improve generalizability by imitating adding more data using data augmentation.

Here’s a full code to plot the loss graph and accuracy graph from the fitted model.