1
$\begingroup$

I'm a novice in machine learning. I was following this Keras blog to train image classifier using Keras. Though this blog only demonstrates how to train only two classes using binary_crossentropy, I was hoping to train a model using my own custom multi-class(6) image datasets using categorial_crossentropy along with one hot encoded vector. So, here is what I tried so far:

import os
import numpy as np
from keras import applications
from keras import Model
from keras.models import Sequential
from keras.layers import Activation, Dropout, Flatten, Dense
from keras.layers import Input
from keras.preprocessing.image import ImageDataGenerator, img_to_array, load_img
from keras import optimizers
import cv2


img_width, img_height = 150, 150

class_indics = 'class_indices.npy'
bottleneck_train_path = 'bottleneck_features_train.npy'
bottleneck_validation_path = 'bottleneck_features_validation.npy'
top_model_weights_path = 'bottleneck_fc_model.h5'
train_data_dir = 'data/train'
validation_data_dir = 'data/validation/'

nb_train_samples = 4800
nb_validation_samples = 1200

epochs = 50
batch_size = 15


def generate_class_indics():
    datagen = ImageDataGenerator(rescale=1. / 255)

    generator_top = datagen.flow_from_directory(train_data_dir,
                                                    target_size=(img_width, img_height),
                                                    batch_size=batch_size,
                                                    class_mode='categorical',
                                                    shuffle=False)

    # save the class indices to use later in predictions
    np.save(class_indics, generator_top.class_indices)

def save_bottleneck_features():
    print('Using of bottleneck feature on pretrained model started.')
    datagen = ImageDataGenerator(rescale=1. / 255)

    # build the VGG16 network
    model = applications.VGG16(include_top=False, weights='imagenet')

    generator = datagen.flow_from_directory(
        train_data_dir,
        target_size=(img_width, img_height),
        batch_size=batch_size,
        class_mode='categorical',
        shuffle=False)
    bottleneck_features_train = model.predict_generator(
        generator, nb_train_samples // batch_size)
    np.save(open(bottleneck_train_path, 'wb'),
            bottleneck_features_train)

    generator = datagen.flow_from_directory(
        validation_data_dir,
        target_size=(img_width, img_height),
        batch_size=batch_size,
        class_mode='categorical',
        shuffle=False)
    bottleneck_features_validation = model.predict_generator(
        generator, nb_validation_samples // batch_size)
    np.save(open(bottleneck_validation_path, 'wb'),
            bottleneck_features_validation)
    print('Using of bottleneck feature on pretrained model finished.')


def train_top_model():
    print('Training of top model started.')
    train_data = np.load(open(bottleneck_train_path, 'rb'))
    train_labels = np.array(
        [0] * (nb_train_samples // 2) + [1] * (nb_train_samples // 2))

    validation_data = np.load(open(bottleneck_validation_path, 'rb'))
    validation_labels = np.array(
        [0] * (nb_validation_samples // 2) + [1] * (nb_validation_samples // 2))

    class_dictionary = np.load('class_indices.npy').item()
    num_classes = len(class_dictionary)

    model = Sequential()
    model.add(Flatten(input_shape=train_data.shape[1:]))
    model.add(Dense(256, activation='relu'))
    model.add(Dropout(0.7))
    model.add(Dense(num_classes, activation='softmax')) #sigmoid

    model.compile(optimizer='rmsprop',
                  loss='categorical_crossentropy', metrics=['categorical_accuracy'])

    model.fit(train_data, train_labels,
              epochs=epochs,
              batch_size=batch_size,
              validation_data=(validation_data, validation_labels))
    model.save_weights(top_model_weights_path)
    print('Training of top model completed & saved as: ',top_model_weights_path)


def fine_tune_pretrained_model():
    print('Fine tuning of pretrain model started.')
    # build the VGG16 network
    input_tensor = Input(shape=(150, 150, 3))

    base_model = applications.VGG16(weights='imagenet', include_top=False, input_tensor=input_tensor)

    class_dictionary = np.load('class_indices.npy').item()
    num_classes = len(class_dictionary)

    # build a classifier model to put on top of the convolutional model
    top_model = Sequential()
    top_model.add(Flatten(input_shape=base_model.output_shape[1:]))
    top_model.add(Dense(256, activation='relu'))
    top_model.add(Dropout(0.7))
    top_model.add(Dense(num_classes, activation='softmax')) #sigmoid

    # note that it is necessary to start with a fully-trained
    # classifier, including the top classifier,
    # in order to successfully do fine-tuning
    top_model.load_weights(top_model_weights_path)

    # add the model on top of the convolutional base
    model = Model(inputs=base_model.input, outputs=top_model(base_model.output))

    # set the first 25 layers (up to the last conv block)
    # to non-trainable (weights will not be updated)
    for layer in model.layers[:25]:
        layer.trainable = False

    # compile the model with a SGD/momentum optimizer
    # and a very slow learning rate.
    model.compile(loss='categorical_crossentropy',
                  optimizer=optimizers.SGD(lr=1e-4, momentum=0.9),
                  metrics=['categorical_accuracy'])

    # prepare data augmentation configuration
    train_datagen = ImageDataGenerator(
        rescale=1. / 255,
        shear_range=0.2,
        zoom_range=0.2,
        horizontal_flip=True)

    test_datagen = ImageDataGenerator(rescale=1. / 255)

    train_generator = train_datagen.flow_from_directory(
        train_data_dir,
        target_size=(img_height, img_width),
        batch_size=batch_size,
        class_mode='categorical')

    validation_generator = test_datagen.flow_from_directory(
        validation_data_dir,
        target_size=(img_height, img_width),
        batch_size=batch_size,
        class_mode='categorical')

    # fine-tune the model
    model.fit_generator(
        train_generator,
        steps_per_epoch=nb_train_samples // batch_size, # samples_per_epoch=nb_train_samples,
        epochs=epochs,
        validation_data=validation_generator,
        validation_steps=nb_validation_samples)

    print('Fine tuning of pretrain model completed.')

if __name__ == '__main__':

    if not os.path.exists(class_indics):
        generate_class_indics()

    if not os.path.exists(bottleneck_train_path):
        save_bottleneck_features()

    if not os.path.exists(top_model_weights_path):
        train_top_model()
        fine_tune_pretrained_model()

When I ran this code, save_bottleneck_features() & train_top_model() executed correctly, but when I tried to run fine_tune_pretrained_model() it gives me this error:

Traceback (most recent call last): File "/home/appsbee/PycharmProjects/fruit-classification-master/fruit-classification-master/fruit_classification_new.py", line 266, in fine_tune_pretrained_model() File "/home/appsbee/PycharmProjects/fruit-classification-master/fruit-classification-master/fruit_classification_new.py", line 159, in fine_tune_pretrained_model top_model.load_weights(top_model_weights_path) File "/usr/local/lib/python3.6/dist-packages/keras/engine/network.py", line 1166, in load_weights f, self.layers, reshape=reshape) File "/usr/local/lib/python3.6/dist-packages/keras/engine/saving.py", line 1036, in load_weights_from_hdf5_group str(len(filtered_layers)) + ' layers.') ValueError: You are trying to load a weight file containing 3 layers into a model with 2 layers.

But I can see no extra layer was added on fine_tune_pretrained_model().
So, why I am getting this error? Any help will be appreciated.

$\endgroup$

1 Answer 1

1
$\begingroup$

You dont actually need to define the model architecture and then load weights with model.load_weights API . You could instead ask Keras to load the model with architecture and weights from your h5 file:

model = keras.models.load_model('bottleneck_fc_model.h5')

and then view the architecture:

print(model.summary())

You can then use model.add API to add more layers on top.

Of course you can use this only if you used model.save instead of model.save_weights earlier to save model after training.

$\endgroup$
5
  • $\begingroup$ Could you be me more specific? $\endgroup$
    – Poles
    Commented Dec 6, 2018 at 8:40
  • $\begingroup$ what exactly is your doubt..can you please clarify. $\endgroup$ Commented Dec 8, 2018 at 0:22
  • $\begingroup$ How can you instantiate a model without Sequential in this case, as you said you have to save model first before using load model? So in train_top_model function what should be used to instantiate a model then only you can add those layer at the top? $\endgroup$
    – Poles
    Commented Dec 8, 2018 at 9:57
  • 1
    $\begingroup$ Oh, I assumed that the OP has instantiated and trained the model previously and saved the model as bottleneck_fc_model.h5 using model.save('bottleneck_fc_model.h5') and is facing trouble now in loading the model. If you save your model using model.save instead of model.save_weights, you donot need to instantiate the model to re-load it. Here is the reference from the Keras docs keras.io/getting-started/faq/… Hope this helps :) $\endgroup$ Commented Dec 9, 2018 at 2:29
  • $\begingroup$ Actually the OP hasn't enough point to comment on this. So I'm communicating on behalf of him. Actually, I havn't created the model yet so there is no question on reloading it. I wanna know how can I prepare the model before first save? Thanks. $\endgroup$
    – Poles
    Commented Dec 10, 2018 at 6:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.