Image classification model only predicting one class

I'm trying to build a deep learning model to predict image classes from the Kaggle competition. I'm using the Xception model as the top layers and then putting the last layer into a dense layer with the softmax output of 4. No matter what I try with the model, it only predicts one class, the first-class 'healthy', even on the training set which gets a high accuracy. The data set is imbalanced in the multiple_diseases class, but even when I use RandomOverSampler, I get the same problem. There has to be an error in the way I am uploading my images or feeding them into the model. predict function. Anyway, here is the code:

healthy: 516 multiple_diseases: 91 rust: 622 scab: 592

train_df = pd.read_csv('train.csv')
test_df = pd.read_csv('test.csv')
targets = train_df[['healthy', 'multiple_diseases', 'rust', 'scab']]

print(train_df.describe())
print(test_df.describe())

           healthy  multiple_diseases         rust         scab
count  1821.000000        1821.000000  1821.000000  1821.000000
mean      0.283361           0.049973     0.341571     0.325096
std       0.450754           0.217948     0.474367     0.468539
min       0.000000           0.000000     0.000000     0.000000
25%       0.000000           0.000000     0.000000     0.000000
50%       0.000000           0.000000     0.000000     0.000000
75%       1.000000           0.000000     1.000000     1.000000
max       1.000000           1.000000     1.000000     1.000000

from keras.preprocessing.image import load_img
from keras.preprocessing.image import img_to_array
from tqdm.notebook import tqdm

path = '/content/images/'
num_img = train_df.shape[0]
size = 224
train_images = np.ndarray(shape=(train_len, size, size, 3))
    for i in tqdm(range(num_img)):
      img = load_img(path + f'Train_{i}.jpg', target_size=(size, size))
      train_images[i] = np.float32(img_to_array(img))

test_images = np.ndarray(shape=(test_len, size, size, 3))
    for i in tqdm(range(num_img)):
      img = load_img(path + f'Test_{i}.jpg', target_size=(size, size))
      test_images[i] = np.float32(img_to_array(img))

from keras_preprocessing.image import ImageDataGenerator
train_datagen = ImageDataGenerator(rescale = 1./255,
      rotation_range=40,
      horizontal_flip=True,
      vertical_flip=True,
      fill_mode='nearest')

validation_datagen = ImageDataGenerator(rescale = 1./255)

train_generator = train_datagen.flow(
    x = x_train, 
    y = y_train,
    batch_size = 32
    )

validation_generator = validation_datagen.flow(
    x = x_test,
    y = y_test,
    batch_size = 32
    )

def create_model():
  pretrained_model = tf.keras.applications.Xception(input_shape=[*[224, 224], 3], include_top=False)
  pretrained_model.trainable = True
  model = tf.keras.Sequential([
      pretrained_model,
      tf.keras.layers.GlobalAveragePooling2D(),
      tf.keras.layers.Dense(4, activation='softmax')
      ])

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

model = create_model()

model.summary()

Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param    
=================================================================
xception (Model)             (None, 7, 7, 2048)        20861480  
_________________________________________________________________
global_average_pooling2d (Gl (None, 2048)              0         
_________________________________________________________________
dense (Dense)                (None, 4)                 8196      
=================================================================
Total params: 20,869,676
Trainable params: 20,815,148
Non-trainable params: 54,528
_________________________________________________________________

epochs = 12
batch_size = 32
steps_per_epoch = 55

start_lr = 0.00001
min_lr = 0.00001
max_lr = 0.00005
rampup_epochs = 5
sustain_epochs = 0
exp_decay = .8

def lrfn(epoch):
  if epoch  rampup_epochs:
    return (max_lr - start_lr)/rampup_epochs * epoch + start_lr
  elif epoch  rampup_epochs + sustain_epochs:
    return max_lr
  else:
    return (max_lr - min_lr) * exp_decay**(epoch-rampup_epochs-sustain_epochs) + min_lr

lr_callback = tf.keras.callbacks.LearningRateScheduler(lambda epoch: lrfn(epoch), verbose=True)

history = model.fit(
    train_generator,  
    validation_data = validation_generator,
    epochs = epochs,
    steps_per_epoch = steps_per_epoch,
    validation_steps = steps_per_epoch,
    callbacks = [lr_callback],
    verbose=1)

Epoch 00001: LearningRateScheduler reducing learning rate to 1e-05.
Epoch 1/12
55/55 [==============================] - 25s 454ms/step - loss: 1.3612 - accuracy: 0.3166 - val_loss: 1.2711 - val_accuracy: 0.4729 - lr: 1.0000e-05

Epoch 00002: LearningRateScheduler reducing learning rate to 1.8000000000000004e-05.
Epoch 2/12
55/55 [==============================] - 24s 435ms/step - loss: 1.1027 - accuracy: 0.6805 - val_loss: 0.8197 - val_accuracy: 0.7671 - lr: 1.8000e-05

Epoch 00003: LearningRateScheduler reducing learning rate to 2.6000000000000002e-05.
Epoch 3/12
55/55 [==============================] - 24s 435ms/step - loss: 0.6554 - accuracy: 0.8310 - val_loss: 0.4950 - val_accuracy: 0.8487 - lr: 2.6000e-05

Epoch 00004: LearningRateScheduler reducing learning rate to 3.4000000000000007e-05.
Epoch 4/12
55/55 [==============================] - 24s 435ms/step - loss: 0.3981 - accuracy: 0.8714 - val_loss: 0.4149 - val_accuracy: 0.8696 - lr: 3.4000e-05

Epoch 00005: LearningRateScheduler reducing learning rate to 4.2000000000000004e-05.
Epoch 5/12
55/55 [==============================] - 24s 434ms/step - loss: 0.3024 - accuracy: 0.8991 - val_loss: 0.3442 - val_accuracy: 0.8785 - lr: 4.2000e-05

Epoch 00006: LearningRateScheduler reducing learning rate to 5e-05.
Epoch 6/12
55/55 [==============================] - 24s 436ms/step - loss: 0.2155 - accuracy: 0.9291 - val_loss: 0.3372 - val_accuracy: 0.8910 - lr: 5.0000e-05

Epoch 00007: LearningRateScheduler reducing learning rate to 4.2000000000000004e-05.
Epoch 7/12
55/55 [==============================] - 24s 436ms/step - loss: 0.1778 - accuracy: 0.9435 - val_loss: 0.2799 - val_accuracy: 0.8958 - lr: 4.2000e-05

Epoch 00008: LearningRateScheduler reducing learning rate to 3.5600000000000005e-05.
Epoch 8/12
55/55 [==============================] - 24s 436ms/step - loss: 0.1446 - accuracy: 0.9516 - val_loss: 0.2872 - val_accuracy: 0.9041 - lr: 3.5600e-05

Epoch 00009: LearningRateScheduler reducing learning rate to 3.0480000000000006e-05.
Epoch 9/12
55/55 [==============================] - 24s 436ms/step - loss: 0.1359 - accuracy: 0.9539 - val_loss: 0.2637 - val_accuracy: 0.9017 - lr: 3.0480e-05

Epoch 00010: LearningRateScheduler reducing learning rate to 2.6384000000000004e-05.
Epoch 10/12
55/55 [==============================] - 24s 435ms/step - loss: 0.1164 - accuracy: 0.9596 - val_loss: 0.2602 - val_accuracy: 0.9130 - lr: 2.6384e-05

Epoch 00011: LearningRateScheduler reducing learning rate to 2.3107200000000005e-05.
Epoch 11/12
55/55 [==============================] - 24s 435ms/step - loss: 0.1209 - accuracy: 0.9723 - val_loss: 0.2699 - val_accuracy: 0.9124 - lr: 2.3107e-05

Epoch 00012: LearningRateScheduler reducing learning rate to 2.0485760000000004e-05.
Epoch 12/12
55/55 [==============================] - 24s 435ms/step - loss: 0.0896 - accuracy: 0.9758 - val_loss: 0.2449 - val_accuracy: 0.9113 - lr: 2.0486e-05

probabilities = model.predict(test_images)
print(probabilities)

[[1.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00]
 [1.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00]
 [1.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00]
 ...
 [1.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00]
 [1.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00]
 [1.000000e+00 0.000000e+00 0.000000e+00 5.321019e-38]]

Same thing for training images:

idx = 500
tester = np.reshape(train_images[idx], (1, size, size, 3))
print(tester.shape)
print(train_df.iloc[idx,:])

probabilities = model.predict(tester)
print(probabilities)

[[1. 0. 0. 0.]]

And it does that for all the training images. What is going on here?

Edit: Including a description of the data set.

Topic keras image-classification deep-learning

Category Data Science


You have 1760 samples and you are using a pre-trained model with 12 epochs which has 20,815,148 trainable params. So, do not use the F-35 fighter to kill a mosquito. You better use a simpler model like simpler Neural Networks or even Logistic Regression.

About

Geeks Mental is a community that publishes articles and tutorials about Web, Android, Data Science, new techniques and Linux security.