【问题标题】:Using tensorflow's Dataset pipeline, how do I *name* the results of a `map` operation?使用 tensorflow 的 Dataset 管道,我如何 *name* `map` 操作的结果?
【发布时间】:2018-07-06 09:40:17
【问题描述】:

我有下面的 map 函数(可运行示例),它输入 string 并输出 stringinteger

tf.data.Dataset.from_tensor_slices 中,我将原始输入命名为'filenames'。但是当我从映射函数map_element_counts 返回值时,我只能返回一个元组(返回字典会产生异常)。

有没有办法命名从我的map_element_counts 函数返回的 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

【问题讨论】:

  • 返回字典有什么异常?
  • 我将它添加到问题的底部。
  • 你能放完整的堆栈跟踪吗?

标签: python dictionary tensorflow mapping tensorflow-datasets


【解决方案1】:

为了后代,我提出了这个问题的最终解决方案。下面的代码是一个复制/粘贴示例,适用于该问题解决的最复杂条件(请注意,其他两个答案不是复制/粘贴代码示例):

代码的目标是:

  • 获取(大)文件列表并将其拆分为块(文件名/索引对)
  • 使用映射操作处理每个块(生成器在这里不是一个可行的解决方案,请参阅:https://github.com/tensorflow/tensorflow/issues/16343
  • 从仅将 1 个文件/块作为输入的映射操作输出多个样本。
  • 在整个过程中维护元素命名

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}

【讨论】:

    【解决方案2】:

    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}
    

    【讨论】:

      【解决方案3】:

      在这种情况下不需要tf.py_func,因为Dataset#map 中的map_func 适用于字典和其他结构:

      map_func:将张量嵌套结构(具有由self.output_shapesself.output_types 定义的形状和类型)映射到另一个张量嵌套结构的函数。

      这是一个例子:

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

      【讨论】:

      • 假设 map_element_counts 需要执行在 tensorflow 中不可能执行的功能(例如从自定义文件格式读取),然后我应该用 map_element_counts 包装 tf.py_func 以便我可以返回tf.py_func 之后的 map_element_counts 中的字典将张量值作为未命名的元组返回?问题是 fnames 作为张量出现,但我需要将其转换为字符串进行处理。
      • 你能应用map里面的函数吗? fnames['filenames'] 是张量
      • 是的,这行得通,因为 rAyyy 在示例中也正确指出。
      猜你喜欢
      • 2018-08-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-29
      • 2023-03-03
      • 2019-06-13
      • 1970-01-01
      相关资源
      最近更新 更多