web-dev-qa-db-fra.com

Comment fonctionne la normalisation des données en kéros lors de la prédiction?

Je vois que l'imageDataGenerator me permet de spécifier différents styles de normalisation des données, par exemple featurewise_center, samplewise_center, etc.

Je vois dans les exemples que si je spécifie l'une de ces options, alors je dois appeler la méthode d'ajustement sur le générateur afin de permettre au générateur de calculer des statistiques comme l'image moyenne sur le générateur.

(X_train, y_train), (X_test, y_test) = cifar10.load_data()
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,
    rotation_range=20,
    width_shift_range=0.2,
    height_shift_range=0.2,
    horizontal_flip=True)

# compute quantities required for featurewise normalization
# (std, mean, and principal components if ZCA whitening is applied)
datagen.fit(X_train)

# fits the model on batches with real-time data augmentation:
model.fit_generator(datagen.flow(X_train, Y_train, batch_size=32),
                samples_per_Epoch=len(X_train), nb_Epoch=nb_Epoch)

Ma question est, comment fonctionne la prédiction si j'ai spécifié la normalisation des données pendant la formation? Je ne vois pas comment, dans le cadre, je transmettrais même la connaissance de l'écart moyen/std de l'ensemble de formation pour prévoir de me permettre de normaliser mes données de test moi-même, mais je ne vois pas non plus dans le code de formation où se trouvent ces informations stocké.

Les statistiques d'image nécessaires à la normalisation sont-elles stockées dans le modèle afin de pouvoir être utilisées lors de la prédiction?

17
Alex Taylor

Oui - c'est un très gros inconvénient de Keras.ImageDataGenerator Que vous ne pouviez pas fournir vous-même les statistiques de standardisation. Mais - il existe une méthode simple pour surmonter ce problème.

En supposant que vous avez une fonction normalize(x) qui normalise une image lot (rappelez-vous que le générateur ne fournit pas une image simple mais un tableau d'images - un lot = avec la forme (nr_of_examples_in_batch, image_dims ..) vous pouvez créer votre propre générateur avec normalisation en utilisant:

def gen_with_norm(gen, normalize):
    for x, y in gen:
        yield normalize(x), y

Ensuite, vous pouvez simplement utiliser gen_with_norm(datagen.flow, normalize) au lieu de datagen.flow.

De plus, vous pouvez récupérer les mean et std calculées par une méthode fit en les récupérant à partir des champs appropriés dans datagen (par exemple datagen.mean Et datagen.std).

21
Marcin Możejko

Utilisez la méthode standardize du générateur pour chaque élément. Voici un exemple complet pour CIFAR 10:

#!/usr/bin/env python

import keras
from keras.datasets import cifar10
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D

# input image dimensions
img_rows, img_cols, img_channels = 32, 32, 3
num_classes = 10

batch_size = 32
epochs = 1

# The data, shuffled and split between train and test sets:
(x_train, y_train), (x_test, y_test) = cifar10.load_data()
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')

# Convert class vectors to binary class matrices.
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)

model = Sequential()

model.add(Conv2D(32, (3, 3), padding='same', activation='relu',
                 input_shape=x_train.shape[1:]))
model.add(Conv2D(32, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))

model.add(Conv2D(64, (3, 3), padding='same', activation='relu'))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))

model.add(Flatten())
model.add(Dense(512, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='softmax'))

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

x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255

datagen = ImageDataGenerator(zca_whitening=True)

# Compute principal components required for ZCA
datagen.fit(x_train)

# Apply normalization (ZCA and others)
print(x_test.shape)
for i in range(len(x_test)):
    # this is what you are looking for
    x_test[i] = datagen.standardize(x_test[i])
print(x_test.shape)

# Fit the model on the batches generated by datagen.flow().
model.fit_generator(datagen.flow(x_train, y_train,
                                 batch_size=batch_size),
                    steps_per_Epoch=x_train.shape[0] // batch_size,
                    epochs=epochs,
                    validation_data=(x_test, y_test))
21
Martin Thoma

J'utilise le datagen.fit fonctionne lui-même.

from keras.preprocessing.image import ImageDataGenerator

train_datagen = ImageDataGenerator(
    featurewise_center=True,
    featurewise_std_normalization=True)
train_datagen.fit(train_data)

test_datagen = ImageDataGenerator(  
    featurewise_center=True, 
    featurewise_std_normalization=True)
test_datagen.fit(train_data)

Idéalement avec ça, test_datagen monté sur le jeu de données de formation apprendra les statistiques des jeux de données de formation. Il utilisera ensuite ces statistiques pour normaliser les données de test.

3
Hari

J'ai également eu le même problème et je l'ai résolu en utilisant la même fonctionnalité que celle utilisée par ImageDataGenerator:

# Load Cifar-10 dataset
(trainX, trainY), (testX, testY) = cifar10.load_data()
generator = ImageDataGenerator(featurewise_center=True, 
                               featurewise_std_normalization=True)

# Calculate statistics on train dataset
generator.fit(trainX)
# Apply featurewise_center to test-data with statistics from train data
testX -= generator.mean
# Apply featurewise_std_normalization to test-data with statistics from train data
testX /= (generator.std + K.epsilon())

# Do your regular fitting
model.fit_generator(..., validation_data=(testX, testY), ...)

Notez que cela n'est possible que si vous disposez d'un petit ensemble de données raisonnable, comme CIFAR-10. Sinon la solution proposée par Marcin sonne bien plus raisonnable.

1
Alexander Pacha