Search code examples
pythonkerasdeep-learningclassificationmulticlass-classification

How to change my multi-class training to binary in Keras


I'm new to Deep Learning and Keras. With my simple training code below, I was classifying 10 classes. But now I want to re-use this code and convert this code to binary case where I say if an image is my object or not.

I tried to change the activation from softmax to sigmoid, and also changed updated loss='binary_crossentropy'. Is this enough to change? Any other changes?

I get an error saying:

  File "train.py", line 94, in <module>
    shuffle=True, callbacks=callbacks_list)
  File "/usr/local/lib/python3.5/dist-packages/keras/legacy/interfaces.py", line 91, in wrapper
    return func(*args, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/keras/engine/training.py", line 1732, in fit_generator
    initial_epoch=initial_epoch)
  File "/usr/local/lib/python3.5/dist-packages/keras/engine/training_generator.py", line 260, in fit_generator
    callbacks.on_epoch_end(epoch, epoch_logs)
  File "/usr/local/lib/python3.5/dist-packages/keras/callbacks/callbacks.py", line 152, in on_epoch_end
    callback.on_epoch_end(epoch, logs)
  File "/usr/local/lib/python3.5/dist-packages/keras/callbacks/callbacks.py", line 702, in on_epoch_end
    filepath = self.filepath.format(epoch=epoch + 1, **logs)
KeyError: 'acc'

Here is my simple training code for multi-class classification:

#==========================
HEIGHT = 300
WIDTH = 300
TRAIN_DIR = "data"
BATCH_SIZE = 8 #8
steps_per_epoch = 1000 #1000
NUM_EPOCHS = 50 #50
lr= 0.00001
#==========================
FC_LAYERS = [1024, 1024]
dropout = 0.5

def build_finetune_model(base_model, dropout, fc_layers, num_classes):
    for layer in base_model.layers:
        layer.trainable = False

    x = base_model.output
    x = Flatten()(x)
    for fc in fc_layers:
        # New FC layer, random init
        x = Dense(fc, activation='relu')(x) 
        x = Dropout(dropout)(x)

    # New softmax layer
    predictions = Dense(num_classes, activation='softmax')(x) 
    finetune_model = Model(inputs=base_model.input, outputs=predictions)
    return finetune_model

train_datagen =  ImageDataGenerator(preprocessing_function=preprocess_input)
train_generator = train_datagen.flow_from_directory(TRAIN_DIR, 
                                                    target_size=(HEIGHT, WIDTH), 
                                                    batch_size=BATCH_SIZE)
base_model = MobileNetV2(weights='imagenet', include_top=False, input_shape=(HEIGHT, WIDTH, 3))

root=TRAIN_DIR
class_list = [ item for item in os.listdir(root) if os.path.isdir(os.path.join(root, item)) ]
print (class_list)

FC_LAYERS = [1024, 1024]
dropout = 0.5

finetune_model = build_finetune_model(base_model, dropout=dropout, fc_layers=FC_LAYERS, num_classes=len(class_list))
adam = Adam(lr=0.00001)
finetune_model.compile(adam, loss='categorical_crossentropy', metrics=['accuracy'])
filepath="./checkpoints/" + "MobileNetV2_{epoch:02d}_{acc:.2f}" +"_model_weights.h5"
checkpoint = ModelCheckpoint(filepath, monitor=["acc"], verbose=1, mode='max', save_weights_only=True)
callbacks_list = [checkpoint]

history = finetune_model.fit_generator(train_generator, epochs=NUM_EPOCHS, workers=8, 
                                       steps_per_epoch=steps_per_epoch, 
                                       shuffle=True, callbacks=callbacks_list)

Solution

  • Well, you should have only one output node, since it will have the probability of the class (hence 1 - that is the probability of not having that class).

    Changing the activation to sigmoid is correct, since you want to work with a conditional type of probability output, instead of a join probability.

    Binary cross-entropy is correct to apply, since you are dealing with binary target data.

    Finally, the error seems to be the keyword you are passing in monitor. Try replacing it with monitor= "val_accuracy".