Dans le pipeline tensorflow Dataset
, j'aimerais définir une fonction de carte personnalisée qui prend un seul élément d'entrée (échantillon de données) et renvoie plusieurs éléments (échantillons de données).
Le code ci-dessous est ma tentative, avec les résultats souhaités.
Je ne pouvais pas suivre suffisamment la documentation sur tf.data.Dataset().flat_map()
pour savoir si elle était applicable ici ou non.
import tensorflow as tf
input = [10, 20, 30]
def my_map_func(i):
return [[i, i+1, i+2]] # Fyi [[i], [i+1], [i+2]] throws an exception
ds = tf.data.Dataset.from_tensor_slices(input)
ds = ds.map(map_func=lambda input: tf.py_func(
func=my_map_func, inp=[input], Tout=[tf.int64]
))
element = ds.make_one_shot_iterator().get_next()
with tf.Session() as sess:
for _ in range(9):
print(sess.run(element))
Résultats:
(array([10, 11, 12]),)
(array([20, 21, 22]),)
(array([30, 31, 32]),)
Les résultats souhaités:
(10)
(11)
(12)
(20)
(21)
(22)
(30)
(31)
(32)
Deux étapes supplémentaires étaient nécessaires pour y parvenir. Premièrement, la fonction map doit renvoyer un tableau numpy, pas une liste.
Ensuite, vous pouvez utiliser flat_map
combiné avec Dataset().from_tensor_slices()
pour les aplatir. Le code ci-dessous produit maintenant le résultat souhaité:
Testé dans Tensorflow 1.5 (exemple exécutable copier/coller)
import tensorflow as tf
import numpy as np
input = [10, 20, 30]
def my_map_func(i):
return np.array([i, i + 1, i + 2])
ds = tf.data.Dataset.from_tensor_slices(input)
ds = ds.map(map_func=lambda input: tf.py_func(
func=my_map_func, inp=[input], Tout=[tf.int64]
))
ds = ds.flat_map(lambda x: tf.data.Dataset().from_tensor_slices(x))
element = ds.make_one_shot_iterator().get_next()
with tf.Session() as sess:
for _ in range(9):
print(sess.run(element))
Voici une méthode pour ce faire si vous avez plusieurs variables à renvoyer. Dans cet exemple, je saisis une chaîne (telle qu'un nom de fichier) et les multiples en sortie de chaînes et d'entiers. Dans ce cas, je répète la chaîne pour chacun des entiers de [10, 20, 30].
Copier/coller un exemple exécutable:
import tensorflow as tf
import numpy as np
input = [b'testA', b'testB', b'testC']
def my_map_func(input):
return np.array([input, input, input]), np.array([10, 20, 30])
ds = tf.data.Dataset.from_tensor_slices(input)
ds = ds.map(map_func=lambda input: tf.py_func(
func=my_map_func, inp=[input], Tout=[tf.string, tf.int64]))
ds = ds.flat_map(lambda mystr, myint: tf.data.Dataset().Zip((
tf.data.Dataset().from_tensor_slices(mystr),
tf.data.Dataset().from_tensor_slices(myint))
))
element = ds.make_one_shot_iterator().get_next()
with tf.Session() as sess:
for _ in range(9):
print(sess.run(element))
une solution propre utilisant flat_map
et from_tensor_slices
import tensorflow as tf
input = [10, 20, 30]
ds = tf.data.Dataset.from_tensor_slices(input)
ds = ds.flat_map(lambda x: tf.data.Dataset.from_tensor_slices([x, x+1, x+2]))
element = ds.make_one_shot_iterator().get_next()
with tf.Session() as sess:
for _ in range(9):
print(sess.run(element))
# 10
# 11
# 12
# 20
# 21
# 22
# 30
# 31
# 32