Keras image classifier has very low accuracy

Viewed 107

I'm working on the kaggle dog breeds dataset, 120 classes with ~10k images. Both my train and validation accuracy can't get out of 1-2% range. Sometimes val accuracy stays exactly the same every epoch.

I began with adjusting the optimizer between SGD and Adam with varying learning rates (0.01-0.7). No change. Then I tried adjusting miscellaneous parameters to see if anything would stick (trainable base model, batch size, pooling layer). No change. Then I double checked the final train and val datasets. Images and labels look correct.

What am I missing here?

Data prep

BATCH_SIZE = 32
IMG_SIZE = [224, 224]
DATA_ROOT = "" #should have training folder and csv

train_dir = DATA_ROOT + 'train\\'

# Reading csv
labels = pd.read_csv(DATA_ROOT + 'labels.csv')
print(labels.head) 

# Creating array of image paths
img_paths = []
for id in labels['id']:
   img_paths.append(train_dir + id + ".jpg")

# Creating integer classes
le = LabelEncoder()
int_input = le.fit_transform(labels.iloc[:,1].values)
labels['int_class'] = int_input

# Creating one hot encoded labels
cat_count = 120  #depth or the number of categories
oh_input = tf.one_hot(int_input, cat_count) #apply one-hot encoding 
print(oh_input.numpy())

Dataset creation

def read_and_decode2(filename, label):
    # Returns a tensor with byte values of the entire contents of the input filename.
    img = tf.io.read_file(filename)
    # Decoding raw JPEG tensor data into 3D (RGB) uint8 pixel value tensor
    img = tf.io.decode_jpeg(img, channels=3)
    # Converting from uint8 [0,256] pixel values to float32 [0, 1] pixel values
    img = tf.image.convert_image_dtype(img, tf.float32)
    # Resize for various architectures
    img = tf.image.resize(img, IMG_SIZE)
    
    return img, label

ds_oh = tf.data.Dataset.from_tensor_slices((img_paths, oh_input))

ds_oh = ds_oh.map(read_and_decode2)


def ds_split(ds, ds_size, shuffle_size, train_split=0.8, val_split=0.1, shuffle=True):
    assert (train_split + val_split) == 1
    
    if shuffle:
        ds = ds.shuffle(shuffle_size, seed=99)
    
    train_size = int(train_split * ds_size)
    val_size = int(val_split * ds_size)
    
    train_ds = ds.take(train_size)    
    val_ds = ds.skip(train_size).take(val_size)
    
    return train_ds, val_ds

train_ds_oh, val_ds_oh = ds_split(ds_oh, len(img_paths), len(img_paths), train_split=0.85, val_split=0.15, shuffle=True)

#Optimization
train_ds_oh = train_ds_oh.cache()
train_ds_oh = train_ds_oh.shuffle(buffer_size=len(img_paths), reshuffle_each_iteration=True)
train_ds_oh = train_ds_oh.batch(BATCH_SIZE)
train_ds_oh = train_ds_oh.prefetch(tf.data.AUTOTUNE)

val_ds_oh = val_ds_oh.cache()
val_ds_oh = val_ds_oh.batch(BATCH_SIZE)
val_ds_oh = val_ds_oh.prefetch(tf.data.AUTOTUNE)

Model

# Augmentation Layers
data_augmentation = keras.Sequential(
    [
        layers.RandomFlip("horizontal"),
        layers.RandomRotation(0.1),
        layers.RandomZoom(0.1),
        layers.RandomContrast(0.1),
    ]
)

# initial layers
inputs = tf.keras.Input(shape=(224, 224, 3))
x = data_augmentation(inputs)

base_model = ResNet50(weights="imagenet", include_top=False, input_shape=(224, 224, 3))(x)

# creating our new model head to combine with the ResNet base model
head_model = MaxPool2D(pool_size=(4, 4))(base_model)
head_model = Flatten(name='flatten')(head_model)
head_model = Dense(1024, activation='relu')(head_model)
head_model = Dropout(0.3)(head_model)
head_model = Dense(512, activation='relu')(head_model)
head_model = Dropout(0.3)(head_model)
head_model = Dense(120, activation='softmax')(head_model)

# final configuration
model = Model(inputs, head_model)

model.layers[2].trainable = False

optimizer = Adam(learning_rate=0.001, beta_1=0.9, beta_2=0.999)
model.compile(loss="categorical_crossentropy", optimizer=optimizer, metrics=["accuracy"])
INITIAL_EPOCHS = 35

history = model.fit(train_ds_oh,
                    epochs=INITIAL_EPOCHS,
                    validation_data=val_ds_oh)

Output

Epoch 1/35
272/272 [==============================] - 94s 239ms/step - loss: 51.9541 - accuracy: 0.0098 - val_loss: 4.8061 - val_accuracy: 0.0065
Epoch 2/35
272/272 [==============================] - 52s 190ms/step - loss: 4.8134 - accuracy: 0.0085 - val_loss: 4.7982 - val_accuracy: 0.0091
Epoch 3/35
272/272 [==============================] - 52s 190ms/step - loss: 5.7584 - accuracy: 0.0090 - val_loss: 4.7900 - val_accuracy: 0.0117
Epoch 4/35
272/272 [==============================] - 52s 190ms/step - loss: 5.1382 - accuracy: 0.0089 - val_loss: 4.7872 - val_accuracy: 0.0117
Epoch 5/35
272/272 [==============================] - 52s 190ms/step - loss: 4.8702 - accuracy: 0.0099 - val_loss: 4.7915 - val_accuracy: 0.0117
Epoch 6/35
272/272 [==============================] - 52s 190ms/step - loss: 4.8109 - accuracy: 0.0106 - val_loss: 4.7806 - val_accuracy: 0.0150
Epoch 7/35
272/272 [==============================] - 52s 190ms/step - loss: 4.8281 - accuracy: 0.0098 - val_loss: 4.7884 - val_accuracy: 0.0078
Epoch 8/35
272/272 [==============================] - 52s 189ms/step - loss: 7.1733 - accuracy: 0.0098 - val_loss: 4.8050 - val_accuracy: 0.0091
Epoch 9/35
272/272 [==============================] - 52s 189ms/step - loss: 4.9872 - accuracy: 0.0092 - val_loss: 4.7985 - val_accuracy: 0.0098
Epoch 10/35
272/272 [==============================] - 52s 190ms/step - loss: 4.8193 - accuracy: 0.0091 - val_loss: 4.7924 - val_accuracy: 0.0124
Epoch 11/35
272/272 [==============================] - 52s 190ms/step - loss: 4.8296 - accuracy: 0.0079 - val_loss: 4.7937 - val_accuracy: 0.0124
Epoch 12/35
272/272 [==============================] - 52s 189ms/step - loss: 4.8051 - accuracy: 0.0075 - val_loss: 4.7941 - val_accuracy: 0.0078
Epoch 13/35
272/272 [==============================] - 52s 189ms/step - loss: 4.8087 - accuracy: 0.0099 - val_loss: 4.7943 - val_accuracy: 0.0124
Epoch 14/35
272/272 [==============================] - 52s 189ms/step - loss: 4.8051 - accuracy: 0.0086 - val_loss: 4.7848 - val_accuracy: 0.0124
...
0 Answers
Related