3

I want to create a machine learning model with Tensorflow which detects flowers. I went in the nature and took pictures of 4 different species (~600 per class, one class got 700).

I load these images with Tensorflow Train Generator:

 train_datagen = ImageDataGenerator(rescale=1./255,
        shear_range=0.2,
        zoom_range=0.15, 
        brightness_range=[0.7, 1.4], 
        fill_mode='nearest', 
        vertical_flip=True,  
        horizontal_flip=True,
        rotation_range=15, 
        
        
        width_shift_range=0.1, 
        height_shift_range=0.1, 
    
        validation_split=0.2) 

    train_generator = train_datagen.flow_from_directory(
        pfad,
        target_size=(imageShape[0],imageShape[1]),
        batch_size=batchSize,
        class_mode='categorical',
        subset='training',
        seed=1,
        shuffle=False,
        #save_to_dir=r'G:\test'
        ) 
    
    validation_generator = train_datagen.flow_from_directory(
        pfad, 
        target_size=(imageShape[0],imageShape[1]),
        batch_size=batchSize,
        shuffle=False,
        seed=1,
        class_mode='categorical',
        subset='validation')

Then I am creating a simple model looking like this:

model = tf.keras.Sequential([
      
     
      
      keras.layers.Conv2D(128, (3,3), activation='relu', input_shape=(imageShape[0], imageShape[1],3)),
      keras.layers.MaxPooling2D(2,2),
      keras.layers.Dropout(0.5),
      
      keras.layers.Conv2D(256, (3,3), activation='relu'),
      
      keras.layers.MaxPooling2D(2,2), 
     
      keras.layers.Conv2D(512, (3,3), activation='relu'),
      
      keras.layers.MaxPooling2D(2,2),
     
      keras.layers.Flatten(),

      
      
      
      
      keras.layers.Dense(280, activation='relu'),
      
      keras.layers.Dense(4, activation='softmax')
    ])
    
    
    opt = tf.keras.optimizers.SGD(learning_rate=0.001,decay=1e-5)
    model.compile(loss='categorical_crossentropy',
                  optimizer= opt,
                  metrics=['accuracy'])

And want to start the training process (CPU):

history=model.fit(
        train_generator,
        steps_per_epoch = train_generator.samples // batchSize,
        validation_data = validation_generator, 
        validation_steps = validation_generator.samples // batchSize,
        epochs = 200,callbacks=[checkpoint,early,tensorboard],workers=-1)

The result should be that my validation Accuracy improves, but it starts with 0.3375 and stays at this level the whole training process. Validation loss (1.3737) decreases by 0.001. Accuracy start with 0.15 but increases.

Why is my validation accuracy stuck? Am I using the right loss? Or do I build my model wrong? Is my Tensorflow Train Generator hot encoding the labels?

Thanks

Mare Seestern
  • 335
  • 1
  • 3
  • 13
  • 1
    I would guess, that something bad happens at the train_datagen generator, unforutnately I am not familiar with that. I just wanted to add, using an Optimizer like RmsProp or Adam might help you converge better. – MichaelJanz Aug 12 '20 at 08:50
  • Okay, thanks for your response. I checked the images by saving them into a folder, all of them looked "normal". I tried it with different Optimizer. – Mare Seestern Aug 12 '20 at 08:54
  • Have you tested your parameters in ImageDataGenerator like brightness_range for other values and checked them? Also you might want to check how the images look in the datagenerator, to see if some function changes the pictures in a bad way – MichaelJanz Aug 12 '20 at 09:02
  • Yes, I saved them to a folder and they looked "normal". Furthermore, I tried it without any parameters in ImageDataGenerator. (just loading them) – Mare Seestern Aug 12 '20 at 09:08
  • Try to use less channels in Conv layers, start with 64 and go max 256, try to use batch norm instead of dropout, your model is so complex. and you only have 2400 pictures, you need a simpler model. – erentknn Aug 12 '20 at 09:45
  • I will try and write you. – Mare Seestern Aug 12 '20 at 09:46

4 Answers4

2

I solved the problem by using RMSprop() without any parameters.

So I changed from:

opt = tf.keras.optimizers.SGD(learning_rate=0.001,decay=1e-5)
model.compile(loss='categorical_crossentropy',optimizer= opt, metrics=['accuracy'])

to:

    opt = tf.keras.optimizers.RMSprop()
    model.compile(loss='categorical_crossentropy',
                  optimizer= opt,
                  metrics=['accuracy'])
Mare Seestern
  • 335
  • 1
  • 3
  • 13
1

This is a similar example, except that for 4 categorical classes, the below is binary. You may want to change the loss to categorical cross entropy, class_mode from binary to categorical in the train and test generators and final dense layer activation to softmax. I am still able to use model.fit_generator()

image_dataGen = ImageDataGenerator(rotation_range=20,
                                width_shift_range=0.2,height_shift_range=0.2,shear_range=0.1,
                                zoom_range=0.1,fill_mode='nearest',horizontal_flip=True,
                                vertical_flip=True,rescale=1/255)

train_images = image_dataGen.flow_from_directory(train_path,target_size = image_shape[:2],
                                                color_mode = 'rgb',class_mode = 'binary')
                                            
test_images = image_dataGen.flow_from_directory(test_path,target_size = image_shape[:2],
                                               color_mode = 'rgb',class_mode = 'binary',
                                               shuffle = False)
model = Sequential()

model.add(Conv2D(filters = 32, kernel_size = (3,3),input_shape = image_shape,activation = 'relu'))
model.add(MaxPool2D(pool_size = (2,2)))

model.add(Conv2D(filters = 48, kernel_size = (3,3),input_shape = image_shape,activation = 'relu'))
model.add(MaxPool2D(pool_size = (2,2)))

model.add(Flatten())
model.add(Dense(units = 128,activation = 'relu'))
model.add(Dropout(0.5))

model.add(Dense(units = 1, activation = 'sigmoid'))

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

results = model.fit_generator(train_images, epochs = 10, callbacks = [early_stop],
                             validation_data = test_images)
Praks
  • 67
  • 1
  • 1
  • 4
1

Maybe your learning rate is too high.

Use learning rate = 0.000001 and if that does not work then try another optimizer like Adam.

Vijeth Rai
  • 321
  • 2
  • 10
0

use model.fit_generator() instead of model.fit() Also below points could be helpful.

In order to use .flow_from_directory, you must organize the images in sub-directories. This is an absolute requirement, otherwise the method won't work. The directories should only contain images of one class, so one folder per class of images. Also could you check if the path for the training data and test data is correct ? They cannot point to the same location. I have used the ImageGenerator class for classification problem. You can also try changing the optimizer to 'Adam'

Structure Needed: Image Data Folder Class 1 0.jpg 1.jpg ... Class 2 0.jpg 1.jpg ... ... Class n

Praks
  • 67
  • 1
  • 1
  • 4
  • Thanks for your answer. I already organized the folder structure right. I use model.fit() because model.fit_generator() says that it is depcrated and I should use model.fit() – Mare Seestern Aug 12 '20 at 12:11
  • I am not sure how the metrics reflect on the training data. if it is performing well on training but not so much on validation, then the model is definitely overfitting on the training data. one probable reason could be whether the training data is balanced with respect to instances of the 4 different types of flowers. starting with a validation loss of more than 10% with the initial training is good and as you mentioned it started off with well above 30% accuracy. another doubt I have is that both the training and validation data generator have the same dir "pfad" , what is len of each datset – Praks Aug 12 '20 at 14:27
  • Using the same path is answered in: https://stackoverflow.com/questions/42443936/keras-split-train-test-set-when-using-imagedatagenerator – Mare Seestern Aug 12 '20 at 16:55