from_tensor_slices from data batch machine-learning tensorflow deep-learning keras keras-layer

machine learning - from - ¿Cómo puede hacer que TensorFlow+Keras sea rápido con un conjunto de datos TFRecord?



tf dataset batch (2)

La actualización 2018-08-29 ahora se admite directamente en keras, consulte el siguiente ejemplo:

https://github.com/keras-team/keras/blob/master/examples/mnist_tfrecord.py

Respuesta original:

TFRecords son compatibles mediante el uso de una pérdida externa. Aquí están las líneas clave que construyen una pérdida externa:

# tf yield ops that supply dataset images and labels x_train_batch, y_train_batch = read_and_decode_recordinput(...) # create a basic cnn x_train_input = Input(tensor=x_train_batch) x_train_out = cnn_layers(x_train_input) model = Model(inputs=x_train_input, outputs=x_train_out) loss = keras.losses.categorical_crossentropy(y_train_batch, x_train_out) model.add_loss(loss) model.compile(optimizer=''rmsprop'', loss=None)

Aquí hay un ejemplo para Keras 2. Funciona después de aplicar el pequeño parche #7060 :

''''''MNIST dataset with TensorFlow TFRecords. Gets to 99.25% test accuracy after 12 epochs (there is still a lot of margin for parameter tuning). '''''' import os import copy import time import numpy as np import tensorflow as tf from tensorflow.python.ops import data_flow_ops from keras import backend as K from keras.models import Model from keras.layers import Dense from keras.layers import Dropout from keras.layers import Flatten from keras.layers import Input from keras.layers import Conv2D from keras.layers import MaxPooling2D from keras.callbacks import EarlyStopping from keras.callbacks import TensorBoard from keras.objectives import categorical_crossentropy from keras.utils import np_utils from keras.utils.generic_utils import Progbar from keras import callbacks as cbks from keras import optimizers, objectives from keras import metrics as metrics_module from keras.datasets import mnist if K.backend() != ''tensorflow'': raise RuntimeError(''This example can only run with the '' ''TensorFlow backend for the time being, '' ''because it requires TFRecords, which '' ''are not supported on other platforms.'') def images_to_tfrecord(images, labels, filename): def _int64_feature(value): return tf.train.Feature(int64_list=tf.train.Int64List(value=[value])) def _bytes_feature(value): return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value])) """ Save data into TFRecord """ if not os.path.isfile(filename): num_examples = images.shape[0] rows = images.shape[1] cols = images.shape[2] depth = images.shape[3] print(''Writing'', filename) writer = tf.python_io.TFRecordWriter(filename) for index in range(num_examples): image_raw = images[index].tostring() example = tf.train.Example(features=tf.train.Features(feature={ ''height'': _int64_feature(rows), ''width'': _int64_feature(cols), ''depth'': _int64_feature(depth), ''label'': _int64_feature(int(labels[index])), ''image_raw'': _bytes_feature(image_raw)})) writer.write(example.SerializeToString()) writer.close() else: print(''tfrecord %s already exists'' % filename) def read_and_decode_recordinput(tf_glob, one_hot=True, classes=None, is_train=None, batch_shape=[1000, 28, 28, 1], parallelism=1): """ Return tensor to read from TFRecord """ print ''Creating graph for loading %s TFRecords...'' % tf_glob with tf.variable_scope("TFRecords"): record_input = data_flow_ops.RecordInput( tf_glob, batch_size=batch_shape[0], parallelism=parallelism) records_op = record_input.get_yield_op() records_op = tf.split(records_op, batch_shape[0], 0) records_op = [tf.reshape(record, []) for record in records_op] progbar = Progbar(len(records_op)) images = [] labels = [] for i, serialized_example in enumerate(records_op): progbar.update(i) with tf.variable_scope("parse_images", reuse=True): features = tf.parse_single_example( serialized_example, features={ ''label'': tf.FixedLenFeature([], tf.int64), ''image_raw'': tf.FixedLenFeature([], tf.string), }) img = tf.decode_raw(features[''image_raw''], tf.uint8) img.set_shape(batch_shape[1] * batch_shape[2]) img = tf.reshape(img, [1] + batch_shape[1:]) img = tf.cast(img, tf.float32) * (1. / 255) - 0.5 label = tf.cast(features[''label''], tf.int32) if one_hot and classes: label = tf.one_hot(label, classes) images.append(img) labels.append(label) images = tf.parallel_stack(images, 0) labels = tf.parallel_stack(labels, 0) images = tf.cast(images, tf.float32) images = tf.reshape(images, shape=batch_shape) # StagingArea will store tensors # across multiple steps to # speed up execution images_shape = images.get_shape() labels_shape = labels.get_shape() copy_stage = data_flow_ops.StagingArea( [tf.float32, tf.float32], shapes=[images_shape, labels_shape]) copy_stage_op = copy_stage.put( [images, labels]) staged_images, staged_labels = copy_stage.get() return images, labels def save_mnist_as_tfrecord(): (X_train, y_train), (X_test, y_test) = mnist.load_data() X_train = X_train[..., np.newaxis] X_test = X_test[..., np.newaxis] images_to_tfrecord(images=X_train, labels=y_train, filename=''train.mnist.tfrecord'') images_to_tfrecord(images=X_test, labels=y_test, filename=''test.mnist.tfrecord'') def cnn_layers(x_train_input): x = Conv2D(32, (3, 3), activation=''relu'', padding=''valid'')(x_train_input) x = Conv2D(64, (3, 3), activation=''relu'')(x) x = MaxPooling2D(pool_size=(2, 2))(x) x = Dropout(0.25)(x) x = Flatten()(x) x = Dense(128, activation=''relu'')(x) x = Dropout(0.5)(x) x_train_out = Dense(classes, activation=''softmax'', name=''x_train_out'')(x) return x_train_out sess = tf.Session() K.set_session(sess) save_mnist_as_tfrecord() batch_size = 100 batch_shape = [batch_size, 28, 28, 1] epochs = 3000 classes = 10 parallelism = 10 x_train_batch, y_train_batch = read_and_decode_recordinput( ''train.mnist.tfrecord'', one_hot=True, classes=classes, is_train=True, batch_shape=batch_shape, parallelism=parallelism) x_test_batch, y_test_batch = read_and_decode_recordinput( ''test.mnist.tfrecord'', one_hot=True, classes=classes, is_train=True, batch_shape=batch_shape, parallelism=parallelism) x_batch_shape = x_train_batch.get_shape().as_list() y_batch_shape = y_train_batch.get_shape().as_list() x_train_input = Input(tensor=x_train_batch, batch_shape=x_batch_shape) x_train_out = cnn_layers(x_train_input) y_train_in_out = Input(tensor=y_train_batch, batch_shape=y_batch_shape, name=''y_labels'') cce = categorical_crossentropy(y_train_batch, x_train_out) train_model = Model(inputs=[x_train_input], outputs=[x_train_out]) train_model.add_loss(cce) train_model.compile(optimizer=''rmsprop'', loss=None, metrics=[''accuracy'']) train_model.summary() tensorboard = TensorBoard() # tensorboard disabled due to Keras bug train_model.fit(batch_size=batch_size, epochs=epochs) # callbacks=[tensorboard]) train_model.save_weights(''saved_wt.h5'') K.clear_session() # Second Session, pure Keras (X_train, y_train), (X_test, y_test) = mnist.load_data() X_train = X_train[..., np.newaxis] X_test = X_test[..., np.newaxis] x_test_inp = Input(batch_shape=(None,) + (X_test.shape[1:])) test_out = cnn_layers(x_test_inp) test_model = Model(inputs=x_test_inp, outputs=test_out) test_model.load_weights(''saved_wt.h5'') test_model.compile(optimizer=''rmsprop'', loss=''categorical_crossentropy'', metrics=[''accuracy'']) test_model.summary() loss, acc = test_model.evaluate(X_test, np_utils.to_categorical(y_test), classes) print(''/nTest accuracy: {0}''.format(acc))

También he estado trabajando para mejorar el soporte para TFRecords en el siguiente problema y solicitud de extracción:

  • github.com/fchollet/keras/pull/6928 Compatibilidad con rendimiento de rendimiento: conjuntos de datos grandes de alto rendimiento a través de TFRecords y RecordInput
  • #7102 Propuesta de diseño de Keras Input Tensor API

Finalmente, es posible usar tf.contrib.learn.Experiment para entrenar modelos Keras en TensorFlow.

¿Qué es un ejemplo de cómo utilizar un TFRecord TensorFlow con un modelo Keras y tf.session.run () mientras se mantiene el conjunto de datos en tensores con corredores de cola?

A continuación se muestra un fragmento de código que funciona pero necesita las siguientes mejoras:

  • Usa el modelo API
  • especifique una entrada ()
  • Cargar un conjunto de datos desde un TFRecord
  • Ejecutar a través de un conjunto de datos en paralelo (como con un queuerunner)

Aquí está el fragmento, hay varias líneas TODO que indican lo que se necesita:

from keras.models import Model import tensorflow as tf from keras import backend as K from keras.layers import Dense, Input from keras.objectives import categorical_crossentropy from tensorflow.examples.tutorials.mnist import input_data sess = tf.Session() K.set_session(sess) # Can this be done more efficiently than placeholders w/ TFRecords? img = tf.placeholder(tf.float32, shape=(None, 784)) labels = tf.placeholder(tf.float32, shape=(None, 10)) # TODO: Use Input() x = Dense(128, activation=''relu'')(img) x = Dense(128, activation=''relu'')(x) preds = Dense(10, activation=''softmax'')(x) # TODO: Construct model = Model(input=inputs, output=preds) loss = tf.reduce_mean(categorical_crossentropy(labels, preds)) # TODO: handle TFRecord data, is it the same? mnist_data = input_data.read_data_sets(''MNIST_data'', one_hot=True) train_step = tf.train.GradientDescentOptimizer(0.5).minimize(loss) sess.run(tf.global_variables_initializer()) # TODO remove default, add queuerunner with sess.as_default(): for i in range(1000): batch = mnist_data.train.next_batch(50) train_step.run(feed_dict={img: batch[0], labels: batch[1]}) print(loss.eval(feed_dict={img: mnist_data.test.images, labels: mnist_data.test.labels}))

¿Por qué es relevante esta pregunta?

Aquí hay información de inicio para un ejemplo de problema de segmentación semántica:


No uso el formato de conjunto de datos tfrecord, por lo que no voy a discutir los pros y los contras, pero me interesó extender Keras para admitir lo mismo.

github.com/indraforyou/keras_tfrecord es el repositorio. Explicaré brevemente los principales cambios.

Creación y carga de datos

data_to_tfrecord y read_and_decode here se encargan de crear el conjunto de datos tfrecord y cargar el mismo. Se debe tener especial cuidado en implementar el read_and_decode contrario, se enfrentarán a errores crípticos durante el entrenamiento.

Inicialización y modelo de keras.

Ahora tanto tf.train.shuffle_batch como Keras Input layer devuelven tensor. Pero el que devuelve tf.train.shuffle_batch no tiene metadatos necesarios para Keras internamente. Como resultado, cualquier tensor se puede convertir fácilmente en un tensor con metadatos keras llamando a la capa de Input con el parámetro tensor .

Así que esto se encarga de la inicialización:

x_train_, y_train_ = ktfr.read_and_decode(''train.mnist.tfrecord'', one_hot=True, n_class=nb_classes, is_train=True) x_train_batch, y_train_batch = K.tf.train.shuffle_batch([x_train_, y_train_], batch_size=batch_size, capacity=2000, min_after_dequeue=1000, num_threads=32) # set the number of threads here x_train_inp = Input(tensor=x_train_batch)

Ahora con x_train_inp se puede desarrollar cualquier modelo de keras.

Entrenamiento (simple)

Digamos que train_out es el tensor de salida de su modelo keras. Puede escribir fácilmente un bucle de entrenamiento personalizado en las líneas de:

loss = tf.reduce_mean(categorical_crossentropy(y_train_batch, train_out)) train_op = tf.train.GradientDescentOptimizer(0.01).minimize(loss) # sess.run(tf.global_variables_initializer()) sess.run(tf.initialize_all_variables()) with sess.as_default(): coord = tf.train.Coordinator() threads = tf.train.start_queue_runners(sess=sess, coord=coord) try: step = 0 while not coord.should_stop(): start_time = time.time() _, loss_value = sess.run([train_op, loss], feed_dict={K.learning_phase(): 0}) duration = time.time() - start_time if step % 100 == 0: print(''Step %d: loss = %.2f (%.3f sec)'' % (step, loss_value, duration)) step += 1 except tf.errors.OutOfRangeError: print(''Done training for %d epochs, %d steps.'' % (FLAGS.num_epochs, step)) finally: coord.request_stop() coord.join(threads) sess.close()

Entrenamiento (estilo keras)

Una de las características de keras que lo hace tan lucrativo es su mecanismo de entrenamiento generalizado con las funciones de devolución de llamada.

Pero para apoyar el entrenamiento de tipo tfrecords, hay varios cambios que son necesarios en la función de fit

  • ejecutando los hilos de la cola
  • sin alimentación en datos de lotes a través de feed_dict
  • la validación de soporte se vuelve complicada, ya que los datos de validación también ingresarán a través de otro tensor, un modelo diferente debe crearse internamente con capas superiores compartidas y un tensor de validación alimentado por otro lector de tfrecord.

Pero todo esto puede ser fácilmente soportado por otro parámetro de bandera. Lo que hace que las cosas se sample_weight son las características keras sample_weight y class_weight que se usan para pesar cada muestra y para pesar cada clase Para esto, en compile() keras crea marcadores de posición ( here ) y los marcadores de posición también se crean implícitamente para los objetivos ( here ) que no son necesarios en nuestro caso, las etiquetas ya están incorporadas por los lectores de tfrecord. Estos marcadores de posición deben alimentarse durante la ejecución de la sesión, lo cual no es necesario en nuestra caída.

Por lo tanto, teniendo en cuenta estos cambios, compile_tfrecord ( here ) y fit_tfrecord ( here ) son la extensión de compile y fit y las acciones dicen el 95% del código.

Se pueden utilizar de la siguiente manera:

import keras_tfrecord as ktfr train_model = Model(input=x_train_inp, output=train_out) ktfr.compile_tfrecord(train_model, optimizer=''rmsprop'', loss=''categorical_crossentropy'', out_tensor_lst=[y_train_batch], metrics=[''accuracy'']) train_model.summary() ktfr.fit_tfrecord(train_model, X_train.shape[0], batch_size, nb_epoch=3) train_model.save_weights(''saved_wt.h5'')

Le invitamos a mejorar el código y las solicitudes de extracción.