简体   繁体   中英

Do we need to rescale image before predicting with model, trained with ImageDataGen 1./255?

I have trained my own simple single class CNN on image datagen with rescale 1./255.
Accuracy on train and test looks fine.
When I'm predicting on some new images using test datagen with rescale - results pretty good.
But when I'm trying to predict by single images - I'm having troubles. If I use manual rescale /255 - results very poor. If I skip this step and pass to model original image - predict seems fine.
What I'm doing wrong?
It is logical to me that if model trained on rescaled data [0..1] (as it should for neural networks), predict also should be on rescaled data. No?

My datagens:

train_datagen = ImageDataGenerator(rescale = 1./255,
                                   rotation_range=35,
                                   shear_range = 0.15,
                                   zoom_range = 0.15,
                                   brightness_range=[0.5,1.1],
                                   horizontal_flip = False,
                                   preprocessing_function = apply_mask)

valid_datagen = ImageDataGenerator(rescale = 1./255)

training_set = train_datagen.flow_from_directory(path_train,
                                                 target_size = img_size, 
                                                 batch_size = batch_size,
                                                 class_mode = "binary")

valid_set = valid_datagen.flow_from_directory(path_test,
                                            target_size = img_size,
                                            batch_size = batch_size,
                                            class_mode = "binary")

Network:

initializer = glorot_normal()
classifier = Sequential()
classifier.add(Conv2D(32, (3, 3), input_shape = (img_size[0], img_size[1], 3), activation = 'relu', kernel_initializer=initializer, padding='same')) #, padding='same'
classifier.add(MaxPooling2D(pool_size = (2, 2)))
classifier.add(Conv2D(64, (3, 3), activation = 'relu', kernel_initializer=initializer))
classifier.add(MaxPooling2D(pool_size=(2, 2)))
classifier.add(Conv2D(64, (3, 3), activation = 'relu', kernel_initializer=initializer))
classifier.add(MaxPooling2D(pool_size=(2, 2)))
classifier.add(Dropout(0.4))
classifier.add(Flatten())
classifier.add(Dense(units = 128, activation = 'relu', kernel_initializer=identity()))
classifier.add(Dense(1))
classifier.add(Activation('sigmoid'))

Training network:

history = classifier.fit_generator(training_set,
                         steps_per_epoch = 1 * int(np.ceil(nb_train_samples / batch_size)),
                         epochs = 150,
                         validation_data = valid_set, 
                         validation_steps = 1 * int(np.ceil(nb_validation_samples / batch_size)),
                         callbacks=[earlyStopping, mcp_save, reduce_lr_loss])

Predct by datagen:

test_generator = ImageDataGenerator(rescale = 1./255)
test_data_generator = test_generator.flow_from_directory(path_test,
                                            target_size = img_size,
                                            batch_size = batch_size,
                                            shuffle = False,
                                            class_mode = "binary")
test_steps_per_epoch = np.math.ceil(test_data_generator.samples / test_data_generator.batch_size)
predictions = model.predict_generator(test_data_generator, steps=test_steps_per_epoch)

Predict using manual image import:

valid_images = [".jpg", ".jpeg", ".png"]

for filename in os.listdir(predict_path):        
    ext = os.path.splitext(filename)[1]
    if ext.lower() not in valid_images:
        continue                
    file = predict_path + "/" + filename
    test_image = tensorflow.keras.preprocessing.image.load_img(file, target_size = img_size)
    test_image = tensorflow.keras.preprocessing.image.img_to_array(test_image).astype(np.float32)
    test_image /= 255.
    test_image = np.expand_dims(test_image, axis = 0)
    result = model.predict(test_image)
    print(result)
    if result[0][0] == 1:
        prediction = 'True'
    else:
        prediction = 'Not True'
    print(prediction)
    img = Image.open(file)
    display(img)
    print("\n")
    print("\n")

More interesting - if I use image normalization before predict - sigmoid predicted results became float [0..1], if I just comment test_image /= 255. - results again binary 0,1.

You're checking if the output layer is '1' or not. Sigmoid normally generates a number between 0 and 1. It can be '1' or can be less than 1. You should use a threshold value. And the threshold can be 0.5 or any other value which can be decided by judging the data. Let's say your threshold value is 0.5. If your model output is greater than 0.5, then it's 1 otherwise consider it 0.

In your code, you're comparing with 1. So, your threshold is 1.0. You will barely get output value 1 from your model with sigmoid activation. Set the threshold lower. Try with 0.5 first.

Everything else seems fine. If you're using scaled input for training, then you should scale the input before prediction too.

The last activation should be 'ReLU' layer not sigmoid , now do the same thing.

Should resolve your problem, actually 'sigmoid' layer gives a fractional output between 0-1. You are comparing results with 1 only. That's a problem. Using 'relu' instead

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM