J'essaie d'adapter un modèle CNN Keras, en l'alimentant avec des données gérées par l'API Datasets de Tensorflow. Cependant, je trébuche encore et encore sur la même exception, malgré la documentation officielle (voir là ):
test_data, train_data = tfds.load("mnist", split=Split.ALL.subsplit([1, 3])) # [...] Images are normalized using Dataset.map method # [...] Labels are converted into one-hot encodings as well, using tf.one_hot function model = keras.Sequential([ keras.layers.Conv2D( 32, kernel_size=5, padding="same", input_shape=(28, 28, 1), activation="relu", ), keras.layers.MaxPooling2D( (2, 2), padding="same" ), keras.layers.Conv2D( 64, kernel_size=5, padding="same", activation="relu" ), keras.layers.MaxPooling2D( (2, 2), padding="same" ), keras.layers.Flatten(), keras.layers.Dense( 512, activation="relu" ), keras.layers.Dropout(rate=0.4), keras.layers.Dense(10, activation="softmax") ]) model.compile( optimizer=tf.train.AdamOptimizer(0.01), loss="categorical_crossentropy", metrics=["accuracy"] ) train_data = train_data.batch(32).repeat() test_data = test_data.batch(32).repeat() model.fit( train_data, epochs=10, steps_per_epoch=30, validation_data=test_data, validation_steps=3 ) # The exception occurs at this step
J'utilise l'ensemble de données MNIST de tensorflow-datasets
, les images sont normalisées et les étiquettes de classe sont converties en encodages one-hot. Vous pouvez voir un extrait du code ci-dessous.
ValueError: No data provided for "conv2d_8_input". Need data for each key in: ['conv2d_8_input'] # conv2d_8 is the first Conv2D layer of my model, see below
Je ne comprends pas pourquoi cela ne fonctionne pas, j'ai essayé d'alimenter la méthode fit avec des itérateurs one-shot au lieu de les ensembles de données, mais j'obtiens le même résultat. Je ne suis pas habitué à Keras et TensorFlow (je travaille généralement avec PyTorch), donc je pense qu'il me manque peut-être quelque chose d'évident.
3 Réponses :
Ok, je l'ai. J'ai activé une exécution impatiente pour voir si Keras donnerait une exception plus précise, et j'ai obtenu ceci:
train_data = train_data.map(lambda x: tuple(x.values())) test_data = test_data.map(lambda x: tuple(x.values()))
En effet, les composants de mes ensembles de données (images et leurs étiquettes associées) ont des noms ("image "et" label "), car c'est ainsi que tensorflow_datasets
les charge. En conséquence, un itérateur sur les ensembles de données produit un dictionnaire avec deux valeurs: "image" et "label".
Cependant, Keras attend un tuple de deux valeurs (entrées, cibles)
(ou trois valeurs ( entrées, cibles, sample_wheights)
), et il n'aime pas le dictionnaire produit par l'itérateur de l'ensemble de données (d'où l'erreur que j'ai obtenue).
J'ai ajouté le code suivant avant le modèle .fit
:
ValueError: Output of generator should be a tuple `(x, y, sample_weight)` or `(x, y)`. Found: {'image': <tf.Tensor: id=1012, shape=(32, 28, 28, 1), dtype=float64, numpy=array([...])>, 'label': <tf.Tensor: id=1013, shape=(32, 10), dtype=uint8, numpy=array([...]), dtype=uint8)>}
Et ça marche.
Je n'aime pas cette solution pour être honnête, elle ne semble pas propre. Cependant, c'est la seule solution de contournement que j'ai trouvée pour atténuer cette limitation de Keras.
Si vous utilisez la version TF de keras, cela ne devrait idéalement pas être requis. Voir github.com/tensorflow/tensorflow/issues/20698
@Prabindh Je ne suis pas sûr que cela soit entièrement lié, car je n'ai pas de modèle multi-entrées? Dois-je quand même mentionner mon cas sur le problème de github?
Vous pouvez charger des données depuis tensorflow-datasets
directement sous forme de tuple en utilisant as_supervised
test_data, train_data = tfds.load("mnist", split=tfds.Split.ALL.subsplit([1, 3]), as_supervised=True)
Pour ceux qui viennent sur cette page après avoir suivi le tutoriel TF 2.0 Beta sur le chargement d'images ( https : //www.tensorflow.org/beta/tutorials/load_data/images ):
J'ai pu éviter l'erreur en renvoyant un tuple dans la fonction preprocess_image
def preprocess_image(image): image = tf.image.decode_jpeg(image, channels=3) image = tf.image.resize(image, [192, 192]) image /= 255.0 # normalize to [0,1] range return (image,image)
Le jeu de données MNIST est d'une forme différente de 28,28,1. Avez-vous un remodelage quelque part avant le premier conv2d? Par exemple, reportez-vous à tensorflow.org/tutorials/estimators/cnn
@Prabindh bien, on dirait que la forme est bien (28,28,1). Un
. (La première dimension inconnue est la dimension du lot.)
print (train_data)
juste avantmodel.fit (...)
donne la sortie suivante:Je suppose que l'ensemble de données est cassé. Avez-vous testé s'il est non vide / ne renvoie pas simplement
Aucun
?@ xdurch0 Je suis en mesure de récupérer des données valides du jeu de données (avec un itérateur en une seule fois) et d'afficher les images et les étiquettes correspondantes dans un pyplot.