使用 tensorflow 的数据集管道,我如何 *name* `map` 操作的结果?
Using tensorflow's Dataset pipeline, how do I *name* the results of a `map` operation?
我有下面的映射函数(可运行示例),它输入一个 string
并输出一个 string
和一个 integer
.
在tf.data.Dataset.from_tensor_slices
中我将原始输入命名为'filenames'
。但是当我 return 来自 map 函数的值 map_element_counts
我只能 return 一个元组(return 字典生成异常)。
有没有办法命名从我的 map_element_counts
函数中 return 编辑的 2 个元素?
import tensorflow as tf
filelist = ['fileA_6', 'fileB_10', 'fileC_7']
def map_element_counts(fname):
# perform operations outside of tensorflow
return 'test', 10
ds = tf.data.Dataset.from_tensor_slices({'filenames': filelist})
ds = ds.map(map_func=lambda x: tf.py_func(
func=map_element_counts, inp=[x['filenames']], Tout=[tf.string, tf.int64]
))
element = ds.make_one_shot_iterator().get_next()
with tf.Session() as sess:
print(sess.run(element))
结果:
(b'test', 10)
期望的结果:
{'elementA': b'test', 'elementB': 10)
添加了详细信息:
当我 return {'elementA': 'test', 'elementB': 10}
我得到这个异常:
tensorflow.python.framework.errors_impl.UnimplementedError: Unsupported object type dict
在这种情况下不需要 tf.py_func
,因为 Dataset#map
的 map_func
适用于字典和其他结构:
map_func
: A function mapping a nested structure of tensors (having shapes and types defined by self.output_shapes
and self.output_types
) to another nested structure of tensors.
这是一个例子:
import tensorflow as tf
filelist = ['fileA_6', 'fileB_10', 'fileC_7']
def map_element_counts(fnames):
return {'elementA': b'test', 'elementB': 10, 'file': fnames['filenames']}
ds = tf.data.Dataset.from_tensor_slices({'filenames': filelist})
ds = ds.map(map_func=map_element_counts)
element = ds.make_one_shot_iterator().get_next()
with tf.Session() as sess:
print(sess.run(element))
print(sess.run(element))
print(sess.run(element))
输出:
{'elementA': 'test', 'elementB': 10, 'file': 'fileA_6'}
{'elementA': 'test', 'elementB': 10, 'file': 'fileB_10'}
{'elementA': 'test', 'elementB': 10, 'file': 'fileC_7'}
在 ds.map
中应用 tf.py_func
有效。
我创建了一个非常简单的文件作为示例。我这里只写了10。
dummy_file.txt:
10
这里是脚本:
import tensorflow as tf
filelist = ['dummy_file.txt', 'dummy_file.txt', 'dummy_file.txt']
def py_func(input):
# perform operations outside of tensorflow
parsed_txt_file = int(input)
return 'test', parsed_txt_file
def map_element_counts(fname):
# let tensorflow read the text file
file_string = tf.read_file(fname['filenames'])
# then use python function on the extracted string
a, b = tf.py_func(
func=py_func, inp=[file_string], Tout=[tf.string, tf.int64]
)
return {'elementA': a, 'elementB': b, 'file': fname['filenames']}
ds = tf.data.Dataset.from_tensor_slices({'filenames': filelist})
ds = ds.map(map_element_counts)
element = ds.make_one_shot_iterator().get_next()
with tf.Session() as sess:
print(sess.run(element))
print(sess.run(element))
print(sess.run(element))
输出:
{'file': b'dummy_file.txt', 'elementA': b'test', 'elementB': 10}
{'file': b'dummy_file.txt', 'elementA': b'test', 'elementB': 10}
{'file': b'dummy_file.txt', 'elementA': b'test', 'elementB': 10}
为了后代,我提出了这个问题的最终解决方案。下面的代码是一个 copy/paste 示例,可以在该问题解决的最复杂条件下工作(请注意,其他两个答案不是 copy/pastable 代码示例):
代码的目标是:
- 获取(大)文件列表并将其分成块(filename/index 对)
- 使用映射操作处理每个块(生成器在这里不是可行的解决方案,请参阅:https://github.com/tensorflow/tensorflow/issues/16343)
- 从只需要 1 个 file/chunk 作为输入的映射操作中输出多个样本。
- 在整个过程中维护元素命名
Copy/pastable Tensorflow 1.5 的工作示例 / Python 3.x
import tensorflow as tf
import numpy as np
files = [b'testA', b'testB', b'testC']
def mymap1(x):
result_tensors = tf.py_func(func=mymap2, inp=[x], Tout=[tf.string, tf.int64])
return {'filename': result_tensors[0], 'value': result_tensors[1]}
def mymap2(x):
return np.array([x, x, x]), np.array([10, 20, 30])
def myflatmap(named_elements):
return tf.data.Dataset.zip({
'filename': tf.data.Dataset.from_tensor_slices(named_elements['filename']),
'value': tf.data.Dataset.from_tensor_slices(named_elements['value'])
})
ds = tf.data.Dataset.from_tensor_slices(files)
ds = ds.map(map_func=mymap1)
ds = ds.flat_map(map_func=myflatmap)
element = ds.make_one_shot_iterator().get_next()
with tf.Session() as sess:
for _ in range(9):
print(sess.run(element))
输出:
{'filename': b'testA', 'value': 10}
{'filename': b'testA', 'value': 20}
{'filename': b'testA', 'value': 30}
{'filename': b'testB', 'value': 10}
{'filename': b'testB', 'value': 20}
{'filename': b'testB', 'value': 30}
{'filename': b'testC', 'value': 10}
{'filename': b'testC', 'value': 20}
{'filename': b'testC', 'value': 30}
我有下面的映射函数(可运行示例),它输入一个 string
并输出一个 string
和一个 integer
.
在tf.data.Dataset.from_tensor_slices
中我将原始输入命名为'filenames'
。但是当我 return 来自 map 函数的值 map_element_counts
我只能 return 一个元组(return 字典生成异常)。
有没有办法命名从我的 map_element_counts
函数中 return 编辑的 2 个元素?
import tensorflow as tf
filelist = ['fileA_6', 'fileB_10', 'fileC_7']
def map_element_counts(fname):
# perform operations outside of tensorflow
return 'test', 10
ds = tf.data.Dataset.from_tensor_slices({'filenames': filelist})
ds = ds.map(map_func=lambda x: tf.py_func(
func=map_element_counts, inp=[x['filenames']], Tout=[tf.string, tf.int64]
))
element = ds.make_one_shot_iterator().get_next()
with tf.Session() as sess:
print(sess.run(element))
结果:
(b'test', 10)
期望的结果:
{'elementA': b'test', 'elementB': 10)
添加了详细信息:
当我 return {'elementA': 'test', 'elementB': 10}
我得到这个异常:
tensorflow.python.framework.errors_impl.UnimplementedError: Unsupported object type dict
在这种情况下不需要 tf.py_func
,因为 Dataset#map
的 map_func
适用于字典和其他结构:
map_func
: A function mapping a nested structure of tensors (having shapes and types defined byself.output_shapes
andself.output_types
) to another nested structure of tensors.
这是一个例子:
import tensorflow as tf
filelist = ['fileA_6', 'fileB_10', 'fileC_7']
def map_element_counts(fnames):
return {'elementA': b'test', 'elementB': 10, 'file': fnames['filenames']}
ds = tf.data.Dataset.from_tensor_slices({'filenames': filelist})
ds = ds.map(map_func=map_element_counts)
element = ds.make_one_shot_iterator().get_next()
with tf.Session() as sess:
print(sess.run(element))
print(sess.run(element))
print(sess.run(element))
输出:
{'elementA': 'test', 'elementB': 10, 'file': 'fileA_6'}
{'elementA': 'test', 'elementB': 10, 'file': 'fileB_10'}
{'elementA': 'test', 'elementB': 10, 'file': 'fileC_7'}
在 ds.map
中应用 tf.py_func
有效。
我创建了一个非常简单的文件作为示例。我这里只写了10。
dummy_file.txt:
10
这里是脚本:
import tensorflow as tf
filelist = ['dummy_file.txt', 'dummy_file.txt', 'dummy_file.txt']
def py_func(input):
# perform operations outside of tensorflow
parsed_txt_file = int(input)
return 'test', parsed_txt_file
def map_element_counts(fname):
# let tensorflow read the text file
file_string = tf.read_file(fname['filenames'])
# then use python function on the extracted string
a, b = tf.py_func(
func=py_func, inp=[file_string], Tout=[tf.string, tf.int64]
)
return {'elementA': a, 'elementB': b, 'file': fname['filenames']}
ds = tf.data.Dataset.from_tensor_slices({'filenames': filelist})
ds = ds.map(map_element_counts)
element = ds.make_one_shot_iterator().get_next()
with tf.Session() as sess:
print(sess.run(element))
print(sess.run(element))
print(sess.run(element))
输出:
{'file': b'dummy_file.txt', 'elementA': b'test', 'elementB': 10}
{'file': b'dummy_file.txt', 'elementA': b'test', 'elementB': 10}
{'file': b'dummy_file.txt', 'elementA': b'test', 'elementB': 10}
为了后代,我提出了这个问题的最终解决方案。下面的代码是一个 copy/paste 示例,可以在该问题解决的最复杂条件下工作(请注意,其他两个答案不是 copy/pastable 代码示例):
代码的目标是:
- 获取(大)文件列表并将其分成块(filename/index 对)
- 使用映射操作处理每个块(生成器在这里不是可行的解决方案,请参阅:https://github.com/tensorflow/tensorflow/issues/16343)
- 从只需要 1 个 file/chunk 作为输入的映射操作中输出多个样本。
- 在整个过程中维护元素命名
Copy/pastable Tensorflow 1.5 的工作示例 / Python 3.x
import tensorflow as tf
import numpy as np
files = [b'testA', b'testB', b'testC']
def mymap1(x):
result_tensors = tf.py_func(func=mymap2, inp=[x], Tout=[tf.string, tf.int64])
return {'filename': result_tensors[0], 'value': result_tensors[1]}
def mymap2(x):
return np.array([x, x, x]), np.array([10, 20, 30])
def myflatmap(named_elements):
return tf.data.Dataset.zip({
'filename': tf.data.Dataset.from_tensor_slices(named_elements['filename']),
'value': tf.data.Dataset.from_tensor_slices(named_elements['value'])
})
ds = tf.data.Dataset.from_tensor_slices(files)
ds = ds.map(map_func=mymap1)
ds = ds.flat_map(map_func=myflatmap)
element = ds.make_one_shot_iterator().get_next()
with tf.Session() as sess:
for _ in range(9):
print(sess.run(element))
输出:
{'filename': b'testA', 'value': 10}
{'filename': b'testA', 'value': 20}
{'filename': b'testA', 'value': 30}
{'filename': b'testB', 'value': 10}
{'filename': b'testB', 'value': 20}
{'filename': b'testB', 'value': 30}
{'filename': b'testC', 'value': 10}
{'filename': b'testC', 'value': 20}
{'filename': b'testC', 'value': 30}