Float16 más lento que float32 en keras

Estoy probando mi nuevo NVIDIA Titan V, que es compatible con las operaciones de float16. Noté que durante el entrenamiento, float16 es mucho más lento (~ 800 ms / paso) que float32 (~ 500 ms / paso).

Para hacer las operaciones de float16, cambié mi archivo keras.json a:

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

¿Por qué las operaciones float16 son mucho más lentas? ¿Debo realizar modificaciones en mi código y no solo en el archivo keras.json?

Estoy usando CUDA 9.0, cuDNN 7.0, tensorflow 1.7.0 y keras 2.1.5 en Windows 10. El código de mi python 3.5 está debajo:

 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) 

En la documentación de cuDNN (sección 2.7, subsección Tipo Conversión ) puede ver:

Nota: Los acumuladores son enteros de 32 bits que se ajustan al desbordamiento.

y que esto es válido para el tipo de datos INT8 estándar de lo siguiente: la entrada de datos, la entrada de filtro y la salida.

Bajo esos supuestos, @jiandercy tiene razón en que hay una conversión de float16 a float32 y luego una conversión inversa antes de devolver el resultado, y float16 sería más lento.

Actualicé a CUDA 10.0, cuDNN 7.4.1, tensorflow 1.13.1, keras 2.2.4 y python 3.7.3. Usando el mismo código que en el OP, el tiempo de entrenamiento fue ligeramente más rápido con float16 sobre float32.

Espero que una architecture de red más compleja muestre una mayor diferencia en el rendimiento, pero no probé esto.