Comment combiner correctement L'API D'ensemble de données de TensorFlow et Keras?
Keras'fit_generator()
la méthode du modèle prévoit un générateur qui produit des tuples de la forme (entrée, cibles), où les deux éléments sont des tableaux NumPy. la documentation semble impliquer que si je enroulez simplement un Dataset
iterator dans un générateur, et assurez-vous de convertir les tenseurs à des matrices compactes, je devrais être bon à aller. Ce code, cependant, me donne une erreur:
import numpy as np
import os
import keras.backend as K
from keras.layers import Dense, Input
from keras.models import Model
import tensorflow as tf
from tensorflow.contrib.data import Dataset
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
with tf.Session() as sess:
def create_data_generator():
dat1 = np.arange(4).reshape(-1, 1)
ds1 = Dataset.from_tensor_slices(dat1).repeat()
dat2 = np.arange(5, 9).reshape(-1, 1)
ds2 = Dataset.from_tensor_slices(dat2).repeat()
ds = Dataset.zip((ds1, ds2)).batch(4)
iterator = ds.make_one_shot_iterator()
while True:
next_val = iterator.get_next()
yield sess.run(next_val)
datagen = create_data_generator()
input_vals = Input(shape=(1,))
output = Dense(1, activation='relu')(input_vals)
model = Model(inputs=input_vals, outputs=output)
model.compile('rmsprop', 'mean_squared_error')
model.fit_generator(datagen, steps_per_epoch=1, epochs=5,
verbose=2, max_queue_size=2)
Voici l'erreur que j'obtiens:
Using TensorFlow backend.
Epoch 1/5
Exception in thread Thread-1:
Traceback (most recent call last):
File "/home/jsaporta/anaconda3/lib/python3.6/site-packages/tensorflow/python/client/session.py", line 270, in __init__
fetch, allow_tensor=True, allow_operation=True))
File "/home/jsaporta/anaconda3/lib/python3.6/site-packages/tensorflow/python/framework/ops.py", line 2708, in as_graph_element
return self._as_graph_element_locked(obj, allow_tensor, allow_operation)
File "/home/jsaporta/anaconda3/lib/python3.6/site-packages/tensorflow/python/framework/ops.py", line 2787, in _as_graph_element_locked
raise ValueError("Tensor %s is not an element of this graph." % obj)
ValueError: Tensor Tensor("IteratorGetNext:0", shape=(?, 1), dtype=int64) is not an element of this graph.
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/jsaporta/anaconda3/lib/python3.6/threading.py", line 916, in _bootstrap_inner
self.run()
File "/home/jsaporta/anaconda3/lib/python3.6/threading.py", line 864, in run
self._target(*self._args, **self._kwargs)
File "/home/jsaporta/anaconda3/lib/python3.6/site-packages/keras/utils/data_utils.py", line 568, in data_generator_task
generator_output = next(self._generator)
File "./datagen_test.py", line 25, in create_data_generator
yield sess.run(next_val)
File "/home/jsaporta/anaconda3/lib/python3.6/site-packages/tensorflow/python/client/session.py", line 895, in run
run_metadata_ptr)
File "/home/jsaporta/anaconda3/lib/python3.6/site-packages/tensorflow/python/client/session.py", line 1109, in _run
self._graph, fetches, feed_dict_tensor, feed_handles=feed_handles)
File "/home/jsaporta/anaconda3/lib/python3.6/site-packages/tensorflow/python/client/session.py", line 413, in __init__
self._fetch_mapper = _FetchMapper.for_fetch(fetches)
File "/home/jsaporta/anaconda3/lib/python3.6/site-packages/tensorflow/python/client/session.py", line 233, in for_fetch
return _ListFetchMapper(fetch)
File "/home/jsaporta/anaconda3/lib/python3.6/site-packages/tensorflow/python/client/session.py", line 340, in __init__
self._mappers = [_FetchMapper.for_fetch(fetch) for fetch in fetches]
File "/home/jsaporta/anaconda3/lib/python3.6/site-packages/tensorflow/python/client/session.py", line 340, in <listcomp>
self._mappers = [_FetchMapper.for_fetch(fetch) for fetch in fetches]
File "/home/jsaporta/anaconda3/lib/python3.6/site-packages/tensorflow/python/client/session.py", line 241, in for_fetch
return _ElementFetchMapper(fetches, contraction_fn)
File "/home/jsaporta/anaconda3/lib/python3.6/site-packages/tensorflow/python/client/session.py", line 277, in __init__
'Tensor. (%s)' % (fetch, str(e)))
ValueError: Fetch argument <tf.Tensor 'IteratorGetNext:0' shape=(?, 1) dtype=int64> cannot be interpreted as a Tensor. (Tensor Tensor("IteratorGetNext:0", shape=(?, 1), dtype=int64) is not an element of this graph.)
Traceback (most recent call last):
File "./datagen_test.py", line 34, in <module>
verbose=2, max_queue_size=2)
File "/home/jsaporta/anaconda3/lib/python3.6/site-packages/keras/legacy/interfaces.py", line 87, in wrapper
return func(*args, **kwargs)
File "/home/jsaporta/anaconda3/lib/python3.6/site-packages/keras/engine/training.py", line 2011, in fit_generator
generator_output = next(output_generator)
StopIteration
assez étrangement, ajoutant un ligne contenant next(datagen)
directement après où j'initialise datagen
le code fonctionne très bien, avec pas d'erreurs.
Pourquoi mon code ne fonctionne pas? Pourquoi cela commence-t-il à fonctionner quand j'ajoute cette ligne à mon code? Y a-t-il un moyen plus efficace d'utiliser L'API Data Set de TensorFlow avec Keras qui n'implique pas de convertir les tenseurs en tableaux NumPy et vice-versa?
4 réponses
il existe en effet un moyen plus efficace d'utiliser Dataset
sans avoir à convertir les tenseurs en tableaux minuscules. Cependant, il n'est pas (pas encore?) sur la documentation officielle. De la note de version, c'est une fonctionnalité introduite dans Keras 2.0.7. Vous pourriez avoir à installer keras>=2.0.7 pour l'utiliser.
x = np.arange(4).reshape(-1, 1).astype('float32')
ds_x = Dataset.from_tensor_slices(x).repeat().batch(4)
it_x = ds_x.make_one_shot_iterator()
y = np.arange(5, 9).reshape(-1, 1).astype('float32')
ds_y = Dataset.from_tensor_slices(y).repeat().batch(4)
it_y = ds_y.make_one_shot_iterator()
input_vals = Input(tensor=it_x.get_next())
output = Dense(1, activation='relu')(input_vals)
model = Model(inputs=input_vals, outputs=output)
model.compile('rmsprop', 'mse', target_tensors=[it_y.get_next()])
model.fit(steps_per_epoch=1, epochs=5, verbose=2)
Plusieurs différences:
- Alimentation
tensor
argumentInput
calque. Keras va lire les valeurs de ce tenseur, et l'utiliser comme entrée pour l'ajustement du modèle. - Alimentation
target_tensors
argumentModel.compile()
. - N'oubliez pas de convertir x et y en
float32
. Dans l'usage normal, Keras fera cette conversion pour vous. Mais maintenant tu vas devoir le faire toi-même. - la taille du lot est spécifiée lors de la construction de
Dataset
. Utilisezsteps_per_epoch
etepochs
pour contrôler quand arrêter le raccord du modèle.
en bref, utilisez Input(tensor=...)
,model.compile(target_tensors=...)
et model.fit(x=None, y=None, ...)
si vos données doivent être lues à partir de tenseur.
Mettre À Jour Le 09 Juin 2018
- à partir de Tensorflow 1.9, on peut passer
tf.data.Dataset
objet directement danskeras.Model.fit()
et il serait agissent de façon similaire àfit_generator
. - Un exemple complet peut être trouvé sur ce gist.
# Load mnist training data
(x_train, y_train), _ = tf.keras.datasets.mnist.load_data()
training_set = tfdata_generator(x_train, y_train,is_training=True)
model = # your keras model here
model.fit(
training_set.make_one_shot_iterator(),
steps_per_epoch=len(x_train) // 128,
epochs=5,
verbose = 1)
tfdata_generator
est une fonction qui renvoie untf.data.Dataset
.
def tfdata_generator(images, labels, is_training, batch_size=128):
'''Construct a data generator using `tf.Dataset`. '''
def map_fn(image, label):
'''Preprocess raw data to trainable input. '''
x = tf.reshape(tf.cast(image, tf.float32), (28, 28, 1))
y = tf.one_hot(tf.cast(label, tf.uint8), _NUM_CLASSES)
return x, y
dataset = tf.data.Dataset.from_tensor_slices((images, labels))
if is_training:
dataset = dataset.shuffle(1000) # depends on sample size
dataset = dataset.map(map_fn)
dataset = dataset.batch(batch_size)
dataset = dataset.repeat()
dataset = dataset.prefetch(tf.contrib.data.AUTOTUNE)
return dataset
Ancienne Solution:
en plus de la réponse de @Yu-Yang, vous pouvez également modifier tf.data.Dataset
pour devenir un générateur pour l' fit_generator
suivant
from tensorflow.contrib.learn.python.learn.datasets import mnist
data = mnist.load_mnist()
model = # your Keras model
model.fit_generator(generator = tfdata_generator(data.train.images, data.train.labels),
steps_per_epoch=200,
workers = 0 , # This is important
verbose = 1)
def tfdata_generator(images, labels, batch_size=128, shuffle=True,):
def map_func(image, label):
'''A transformation function'''
x_train = tf.reshape(tf.cast(image, tf.float32), image_shape)
y_train = tf.one_hot(tf.cast(label, tf.uint8), num_classes)
return [x_train, y_train]
dataset = tf.data.Dataset.from_tensor_slices((images, labels))
dataset = dataset.map(map_func)
dataset = dataset.shuffle().batch(batch_size).repeat()
iterator = dataset.make_one_shot_iterator()
next_batch = iterator.get_next()
while True:
yield K.get_session().run(next_batch)
Vous pouvez également convertir le modèle Keras en un estimateur, ils supportent les ensembles de données:
estimator = tf.keras.estimator.model_to_estimator(keras_model=model,
model_dir=model_dir)
input_name = model.layers[0].input.op.name
def input_fn(dataset):
dataset = dataset.map(lambda X,y: {input_name: X}, y)
return dataset.make_one_shot_iterator().get_next()
train_spec = tf.estimator.TrainSpec(
input_fn=lambda: input_fn(train_set), max_steps=100)
eval_spec = tf.estimator.EvalSpec(
input_fn=lambda: input_fn(test_set))
tf.estimator.train_and_evaluate(estimator, train_spec, eval_spec)
Voici une solution si vous créez un ensemble de données TensorFlow en utilisant la bibliothèque Pandas. Notez que ce code ne fonctionnera pas sans tf.reshape()
puisque pour une raison quelconque les tenseurs viennent de tf.py_func()
Je n'ai pas d'information sur la forme. Si cela ne fonctionne pas avec tuple
. Quelqu'un at-il une solution de contournement?
def _get_input_data_for_dataset(file_name):
df_input=pd.read_csv(file_name.decode(),usecols=['Wind_MWh'])
X_data = df_input.as_matrix()
return X_data.astype('float32', copy=False)
X_dataset = tf.data.Dataset.from_tensor_slices(file_names)
X_dataset = X_dataset.flat_map(lambda file_name: tf.data.Dataset.from_tensor_slices(
tf.reshape(tf.py_func(_get_input_data_for_dataset,[file_name], tf.float32),[-1,1])))
X_dataset = X_dataset.batch(5)
X_iter = X_dataset.make_one_shot_iterator()
X_batch = X_iter.get_next()
input_X1 = Input(tensor= X_batch ,name='input_X1')
y1 = Dense(units=64, activation='relu',kernel_initializer=tf.keras.initializers.Constant(1),name='layer_FC1')(input_X1)