web-dev-qa-db-fra.com

Float16 plus lent que float32 en keras

Je teste mon nouveau NVIDIA Titan V, qui prend en charge les opérations float16. J'ai remarqué que pendant l'entraînement, float16 est beaucoup plus lent (~ 800 ms/step) que float32 (~ 500 ms/step).

Pour effectuer des opérations float16, j'ai changé mon fichier keras.json en:

{
"backend": "tensorflow",
"floatx": "float16",
"image_data_format": "channels_last",
"epsilon": 1e-07
}

Pourquoi les opérations float16 sont-elles tellement plus lentes? Dois-je apporter des modifications à mon code et pas seulement au fichier keras.json?

J'utilise CUDA 9.0, cuDNN 7.0, tensorflow 1.7.0 et keras 2.1.5 sous Windows 10. Mon code python 3.5 est ci-dessous:

img_width, img_height = 336, 224

train_data_dir = 'C:\\my_dir\\train'
test_data_dir = 'C:\\my_dir\\test'
batch_size=128

datagen = ImageDataGenerator(rescale=1./255,
    horizontal_flip=True,   # randomly flip the images 
    vertical_flip=True) 

train_generator = datagen.flow_from_directory(
    train_data_dir,
    target_size=(img_height, img_width),
    batch_size=batch_size,
    class_mode='binary')

test_generator = datagen.flow_from_directory(
    test_data_dir,
    target_size=(img_height, img_width),
    batch_size=batch_size,
    class_mode='binary')

# Architecture of NN
model = Sequential()
model.add(Conv2D(32,(3, 3), input_shape=(img_height, img_width, 3),padding='same',kernel_initializer='lecun_normal'))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(32,(3, 3),padding='same'))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

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

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

model.add(AveragePooling2D(pool_size=(2,2)))
model.add(Flatten())
model.add(Dense(1))
model.add(Activation('sigmoid'))

my_rmsprop = keras.optimizers.RMSprop(lr=0.0001, rho=0.9, epsilon=1e-04, decay=0.0)
model.compile(loss='binary_crossentropy',
          optimizer=my_rmsprop,
          metrics=['accuracy'])

# Training 
nb_Epoch = 32
nb_train_samples = 512
nb_test_samples = 512

model.fit_generator(
    train_generator,
    steps_per_Epoch=nb_train_samples/batch_size,
    epochs=nb_Epoch,
    verbose=1,
    validation_data=test_generator,
    validation_steps=nb_test_samples/batch_size)

# Evaluating on the testing set
model.evaluate_generator(test_generator, nb_test_samples)
17
Mark

J'ai mis à jour CUDA 10.0, cuDNN 7.4.1, tensorflow 1.13.1, keras 2.2.4 et python 3.7.3. En utilisant le même code que dans l'OP, le temps de formation était légèrement plus rapide avec float16 sur float32.

Je m'attends à ce qu'une architecture de réseau plus complexe montre une plus grande différence de performances, mais je n'ai pas testé cela.

0
Mark

Dans la documentation de cuDNN (section 2.7, sous-section Conversion de type ), vous pouvez voir:

Remarque: Les accumulateurs sont des entiers 32 bits qui se terminent par un débordement.

et que cela vaut pour le type de données INT8 standard des éléments suivants: l'entrée de données, l'entrée de filtre et la sortie.

Dans ces hypothèses, @jiandercy a raison de dire qu'il y a une conversion float16 vers float32 puis une conversion inverse avant de renvoyer le résultat, et float16 serait plus lent.

2
IftahP