Comment faire pour que TensorFlow + Kera soit rapide avec un ensemble de données TFRecord?

Quel est un exemple d'utilisation D'un TensorFlow TFRecord avec un modèle Keras et tf.session.run() tout en gardant l'ensemble de données dans tensors w/ queue runners?

ci-Dessous est un extrait de code qui fonctionne mais il faut les améliorations suivantes:

  • API Model
  • spécifier un Input()
  • Charger un jeu de données à partir d'un TFRecord
  • exécuter un ensemble de données en parallèle (comme avec un queuerunner)

Voici l'extrait, il y a plusieurs lignes TODO indiquant ce qui est nécessaire:

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}))

Pourquoi cette question est-elle pertinente?

  • pour un entraînement de haute performance sans retourner à python
    • aucun TFRecord to numpy pour tenseur des conversions
  • Keras feront bientôt partie de tensorflow
  • montrer comment Keras Modèle (classes peut accepter des tenseurs pour les données d'entrée correctement.

<!-Voici quelques informations de base pour un exemple de problème de segmentation sémantique:

  • exemple Unet Keras model unet.py, se trouve être pour la segmentation sémantique.
  • Keras + TensorFlow Blog Post
  • essayer d'exécuter le modèle unet une session tf Avec TFRecords et un modèle Keras (pas de de travail)
  • Code pour créer les TFRecords:tf_records.py
  • une tentative d'exécuter le modèle unet une session tf Avec TFRecords et un modèle Keras est en densenet_fcn.py (not working)
15
demandé sur Community 2017-02-12 09:33:52

2 réponses

Je n'utilise pas le format de données tfrecord, donc je ne discute pas sur les avantages et les inconvénients, mais je me suis intéressé à étendre Keras pour soutenir la même chose.

github.com/indraforyou/keras_tfrecord est le référentiel. Expliquera brièvement les principaux changements.

création et chargement des ensembles de données

data_to_tfrecord et read_and_decodeici s'occupe de créer un ensemble de données tfrecord et de le charger. Une attention particulière doit être à mettre en œuvre l' read_and_decode autrement vous allez faire face à des erreurs cryptiques pendant l'entraînement.

Initialisation et Keras modèle

tf.train.shuffle_batch et Keras Input la couche renvoie le tenseur. Mais celle retournée par tf.train.shuffle_batch N'ont pas les métadonnées nécessaires à Keras en interne. Comme il s'avère, tout tenseur peut être facilement transformé en un tenseur avec keras métadonnées en appelant Input couche avec tensor param.

Donc cela prend soins de initialisation:

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)

x_train_inp n'importe quel modèle keras peut être développé.

Formation (simple)

Permet de dire train_out est le tenseur de sortie de votre modèle keras. Vous pouvez facilement écrire une formation personnalisée boucle sur les lignes suivantes:

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()

Formation (keras style)

une des caractéristiques de keras qui le rend si lucratif est son mécanisme d'entraînement généralisé avec le callback.

mais pour soutenir la formation de type tfrecords il y a plusieurs changements qui sont nécessaires dans le fit function

  • exécution de la file d'attente des threads
  • pas d'alimentation dans le lot de données par le biais de feed_dict
  • la prise en charge de la validation devient délicate car les données de validation vont également passer par un autre tenseur un modèle différent doit être créé en interne avec des couches supérieures partagées et un tenseur de validation alimenté par d'autres tfrecord reader.

mais tout cela peut être facilement supporté par un autre paramètre flag. Ce qui fait que les choses décoiffent sont les caractéristiques de keras sample_weight et class_weight ils sont utilisés pour peser chaque échantillon et de peser chaque classe. Pour ce compile() keras crée des espaces réservés (ici) et les placeholders sont aussi implicitement créés pour les cibles (ici) qui n'est pas nécessaire dans notre cas, les étiquettes sont déjà nourris par tfrecord lecteurs. Ils les placeholders doivent être introduits pendant l'exécution de la session, ce qui n'est pas nécessaire dans notre cae.

donc en tenant compte de ces changements,compile_tfrecord (ici et fit_tfrecord (ici) sont l'extension de compile et fit et les actions représentent 95% du code.

Ils peuvent être utilisés de la façon suivante:

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')

vous êtes invités à améliorer les requêtes code et pull.

22
répondu indraforyou 2017-02-19 21:25:59

mise à jour 2018-08-29 ceci est maintenant directement supporté dans keras, voir l'exemple suivant:

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

Réponse Originale:

les TFRecords sont supportés par une perte externe. Voici les lignes clés qui construisent une perte externe:

# 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)

Voici un exemple pour Keras 2. Il fonctionne après l'application du patch petit #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))

j'ai aussi travaillé à améliorer le support de TFRecords dans le numéro suivant et la demande de pull:

  • n ° 6928 Yield Op support: high Performance Large Dataets via TFRecords, et RecordInput
  • #7102 Keras Entrée du Tenseur de Conception d'API Proposition

Enfin, il est possible d'utiliser