Image preprocessing in convolutional neural networ

2019-08-26 04:59发布

问题:

I'm trying to convert this tflearn DCNN sample (using image preprocessing and augmemtation) to keras:

Tflearn sample:

import tflearn
from tflearn.data_utils import shuffle, to_categorical
from tflearn.layers.core import input_data, dropout, fully_connected
from tflearn.layers.conv import conv_2d, max_pool_2d
from tflearn.layers.estimator import regression
from tflearn.data_preprocessing import ImagePreprocessing
from tflearn.data_augmentation import ImageAugmentation

# Data loading and preprocessing
from tflearn.datasets import cifar10
(X, Y), (X_test, Y_test) = cifar10.load_data()
X, Y = shuffle(X, Y)
Y = to_categorical(Y, 10)
Y_test = to_categorical(Y_test, 10)

# Real-time data preprocessing
img_prep = ImagePreprocessing()
img_prep.add_featurewise_zero_center()
img_prep.add_featurewise_stdnorm()

# Real-time data augmentation
img_aug = ImageAugmentation()
img_aug.add_random_flip_leftright()
img_aug.add_random_rotation(max_angle=25.)

# Convolutional network building
network = input_data(shape=[None, 32, 32, 3],
                     data_preprocessing=img_prep,
                     data_augmentation=img_aug)
network = conv_2d(network, 32, 3, activation='relu')
network = max_pool_2d(network, 2)
network = conv_2d(network, 64, 3, activation='relu')
network = conv_2d(network, 64, 3, activation='relu')
network = max_pool_2d(network, 2)
network = fully_connected(network, 512, activation='relu')
network = dropout(network, 0.5)
network = fully_connected(network, 10, activation='softmax')
network = regression(network, optimizer='adam',
                     loss='categorical_crossentropy',
                     learning_rate=0.001)

# Train using classifier
model = tflearn.DNN(network, tensorboard_verbose=0)
model.fit(X, Y, n_epoch=50, shuffle=True, validation_set=(X_test, Y_test),
          show_metric=True, batch_size=96, run_id='cifar10_cnn')

This yielded the following results after 50 epochs:

Training Step: 26050  | total loss: 0.35260 | time: 144.306s
| Adam | epoch: 050 | loss: 0.35260 - acc: 0.8785 | val_loss: 0.64622 - val_acc: 0.8212 -- iter: 50000/50000

I then tried to convert it to Keras using the same DCNN layers, parameters and image preprocessing/augmentation:

import numpy as np
from keras.datasets import cifar10
from keras.callbacks import TensorBoard
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation, Flatten
from keras.layers import Conv2D, MaxPooling2D, AveragePooling2D, UpSampling2D, AtrousConvolution2D
from keras.layers.advanced_activations import LeakyReLU, PReLU
from keras.utils import np_utils
from keras.preprocessing.image import ImageDataGenerator
from keras import backend as K
import matplotlib
from matplotlib import pyplot as plt

np.random.seed(1337)

batch_size = 96 # how many images to process at once
nb_classes = 10 # how many types of objects we can detect in this set
nb_epoch = 50 # how long we train the system
img_rows, img_cols = 32, 32 # image dimensions
nb_filters = 32 # number of convolutional filters to use
pool_size = (2, 2) # size of pooling area for max pooling
kernel_size = (3, 3) # convolution kernel size

(X_train, Y_train), (X_test, Y_test) = cifar10.load_data()
X_train = X_train.reshape(X_train.shape[0], img_rows, img_cols, 3)
X_test = X_test.reshape(X_test.shape[0], img_rows, img_cols, 3)
input_shape = (img_rows, img_cols, 3)
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')
X_train /= 255
X_test /= 255
print('X_train shape:', X_train.shape)
print(X_train.shape[0], 'train samples')
print(X_test.shape[0], 'test samples')
# convert class vectors to binary class matrices
Y_train = np_utils.to_categorical(Y_train, nb_classes)
Y_test = np_utils.to_categorical(Y_test, nb_classes)

datagen = ImageDataGenerator(featurewise_center=True,
                             featurewise_std_normalization=True,
                             horizontal_flip=True,
                             rotation_range=25)
datagen.fit(X_train)

model = Sequential()
model.add(Conv2D(nb_filters, kernel_size, padding='valid', input_shape=input_shape, activation='relu'))
model.add(MaxPooling2D(pool_size=pool_size))
model.add(Conv2D(nb_filters*2, kernel_size, activation='relu'))
model.add(Conv2D(nb_filters*2, kernel_size, activation='relu'))
model.add(MaxPooling2D(pool_size=pool_size))
model.add(Flatten())
model.add(Dense(512, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(nb_classes, activation='softmax'))

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

# Set up TensorBoard
tb = TensorBoard(log_dir='./logs')

history = model.fit_generator(datagen.flow(X_train, Y_train, batch_size=batch_size), epochs=nb_epoch, shuffle=True, verbose=1, validation_data=(X_test, Y_test), callbacks=[tb])
score = model.evaluate(X_test, Y_test, verbose=0)
print('Test score:', score[0])
print("Accuracy: %.2f%%" % (score[1]*100))

plt.plot(history.epoch,history.history['val_acc'],'-o',label='validation')
plt.plot(history.epoch,history.history['acc'],'-o',label='training')
plt.legend(loc=0)
plt.xlabel('epochs')
plt.ylabel('accuracy')
plt.grid(True)
plt.show()

This yielded far worse validation accuracy results:

Epoch 50/50
521/521 [==============================] - 84s 162ms/step - loss: 0.4723 - acc: 0.8340 - val_loss: 3.2970 - val_acc: 0.2729
Test score: 3.2969648239135743
Accuracy: 27.29%

Can anyone help me understand why? Have I misapplied/misunderstood image preprocessing/augmentation in Keras?

回答1:

In your Keras model, you have forgotten to normalize the validation data as well. You can do this either by using datagen.mean and datagen.std computed over the training data:

# normalize test data; add a small constant to avoid division by zero,
# you can alternatively use `keras.backend.epsilon()`
X_test = (X_test - datagen.mean) / (datagen.std + 1e-8) 

or you can use the datagen.standardize() method to normalize test data:

X_test = datagen.standardize(X_test)

Look at this question on SO for more info: How does data normalization work in keras during prediction?

Don't forget that you should normalize test data by the statistics computed over the training data. NEVER EVER normalize test data by its own statistics.

Caveat: It seems that standardize alters its argument as well... yes, you can confirm this in the source code.