【问题标题】:How to use Dataset API to read TFRecords file of lists of variant length?如何使用 Dataset API 读取变体长度列表的 TFRecords 文件?
【发布时间】:2018-06-04 23:47:27
【问题描述】:

我想使用 Tensorflow 的 Dataset API 来读取变体长度列表的 TFRecords 文件。这是我的代码。

def _int64_feature(value):
    # value must be a numpy array.
    return tf.train.Feature(int64_list=tf.train.Int64List(value=value))
def main1():
    # Write an array to TFrecord.
    # a is an array which contains lists of variant length.
    a = np.array([[0, 54, 91, 153, 177],
                 [0, 50, 89, 147, 196],
                 [0, 38, 79, 157],
                 [0, 49, 89, 147, 177],
                 [0, 32, 73, 145]])

    writer = tf.python_io.TFRecordWriter('file')

    for i in range(a.shape[0]): # i = 0 ~ 4
        x_train = a[i]
        feature = {'i': _int64_feature(np.array([i])), 'data': _int64_feature(x_train)}

        # Create an example protocol buffer
        example = tf.train.Example(features=tf.train.Features(feature=feature))

        # Serialize to string and write on the file
        writer.write(example.SerializeToString())

    writer.close()

    # Check TFRocord file.
    record_iterator = tf.python_io.tf_record_iterator(path='file')
    for string_record in record_iterator:
        example = tf.train.Example()
        example.ParseFromString(string_record)

        i = (example.features.feature['i'].int64_list.value)
        data = (example.features.feature['data'].int64_list.value)
        #data = np.fromstring(data_string, dtype=np.int64)
        print(i, data)

    # Use Dataset API to read the TFRecord file.
    def _parse_function(example_proto):
        keys_to_features = {'i'   :tf.FixedLenFeature([], tf.int64),
                            'data':tf.FixedLenFeature([], tf.int64)}
        parsed_features = tf.parse_single_example(example_proto, keys_to_features)
        return parsed_features['i'], parsed_features['data']

    ds = tf.data.TFRecordDataset('file')
    iterator = ds.map(_parse_function).make_one_shot_iterator()
    i, data = iterator.get_next()
    with tf.Session() as sess:
        print(i.eval())
        print(data.eval())

检查 TFRecord 文件

[0] [0, 54, 91, 153, 177]
[1] [0, 50, 89, 147, 196]
[2] [0, 38, 79, 157]
[3] [0, 49, 89, 147, 177]
[4] [0, 32, 73, 145]

但当我尝试使用 Dataset API 读取 TFRecord 文件时,它显示以下错误。

tensorflow.python.framework.errors_impl.InvalidArgumentError:名称: ,键:数据,索引:0。int64 值的数量!= 预期。 值大小:5 但输出形状:[]

谢谢。
更新: 我尝试使用以下代码通过 Dataset API 读取 TFRecord,但都失败了。

def _parse_function(example_proto):
    keys_to_features = {'i'   :tf.FixedLenFeature([], tf.int64),
                        'data':tf.VarLenFeature(tf.int64)}
    parsed_features = tf.parse_single_example(example_proto, keys_to_features)
    return parsed_features['i'], parsed_features['data']

ds = tf.data.TFRecordDataset('file')
iterator = ds.map(_parse_function).make_one_shot_iterator()
i, data = iterator.get_next()
with tf.Session() as sess:
    print(sess.run([i, data]))

def _parse_function(example_proto):
    keys_to_features = {'i'   :tf.VarLenFeature(tf.int64),
                        'data':tf.VarLenFeature(tf.int64)}
    parsed_features = tf.parse_single_example(example_proto, keys_to_features)
    return parsed_features['i'], parsed_features['data']

ds = tf.data.TFRecordDataset('file')
iterator = ds.map(_parse_function).make_one_shot_iterator()
i, data = iterator.get_next()
with tf.Session() as sess:
    print(sess.run([i, data]))

还有错误:

Traceback(最近一次调用最后):文件“/usr/local/lib/python3.5/dist-packages/tensorflow/python/framework/tensor_util.py”, 第 468 行,在 make_tensor_proto 中 str_values = [compat.as_bytes(x) for x in proto_values] 文件 "/usr/local/lib/python3.5/dist-packages/tensorflow/python/framework/tensor_util.py", 第 468 行,在 str_values = [compat.as_bytes(x) for x in proto_values] 文件 "/usr/local/lib/python3.5/dist-packages/tensorflow/python/util/compat.py", 第 65 行,在 as_bytes 中 (bytes_or_text,)) TypeError: Expected binary or unicode string, got

在处理上述异常的过程中,又发生了一个异常:

Traceback(最近一次调用最后一次):文件“2tfrecord.py”,第 126 行,在 main1() 文件“2tfrecord.py”,第 72 行,在 main1 iterator = ds.map(_parse_function).make_one_shot_iterator() 文件 "/usr/local/lib/python3.5/dist-packages/tensorflow/python/data/ops/dataset_ops.py", 第 712 行,在地图中 返回 MapDataset(self, map_func) 文件 "/usr/local/lib/python3.5/dist-packages/tensorflow/python/data/ops/dataset_ops.py", 第 1385 行,在 init 中 self._map_func.add_to_graph(ops.get_default_graph()) 文件 "/usr/local/lib/python3.5/dist-packages/tensorflow/python/framework/function.py", 第 486 行,在 add_to_graph self._create_definition_if_needed() 文件“/usr/local/lib/python3.5/dist-packages/tensorflow/python/framework/function.py”, 第 321 行,在 _create_definition_if_needed self._create_definition_if_needed_impl() 文件“/usr/local/lib/python3.5/dist-packages/tensorflow/python/framework/function.py”, 第 338 行,在 _create_definition_if_needed_impl 输出= self._func(*输入)文件“/usr/local/lib/python3.5/dist-packages/tensorflow/python/data/ops/dataset_ops.py”, 第 1376 行,在 tf_map_func 中 flattened_ret = [ops.convert_to_tensor(t) for t in nest.flatten(ret)] 文件 "/usr/local/lib/python3.5/dist-packages/tensorflow/python/data/ops/dataset_ops.py", 第 1376 行,在 flattened_ret = [ops.convert_to_tensor(t) for t in nest.flatten(ret)] 文件 "/usr/local/lib/python3.5/dist-packages/tensorflow/python/framework/ops.py", 第 836 行,在 convert_to_tensor 中 as_ref=False) 文件 "/usr/local/lib/python3.5/dist-packages/tensorflow/python/framework/ops.py", 第 926 行,internal_convert_to_tensor ret = conversion_func(值,dtype=dtype,name=name,as_ref=as_ref)文件 “/usr/local/lib/python3.5/dist-packages/tensorflow/python/framework/constant_op.py”, 第 229 行,在 _constant_tensor_conversion_function 返回常量(v,dtype=dtype,name=name)文件“/usr/local/lib/python3.5/dist-packages/tensorflow/python/framework/constant_op.py”, 第 208 行,保持不变 值,dtype=dtype,shape=shape,verify_shape=verify_shape)) 文件 "/usr/local/lib/python3.5/dist-packages/tensorflow/python/framework/tensor_util.py", 第 472 行,在 make_tensor_proto 中 “支持的类型。” % (type(values), values)) TypeError: 无法将类型对象转换为张量。 内容: SparseTensor(indices=Tensor("ParseSingleExample/Slice_Indices_i:0", 形状=(?, 1), dtype=int64), values=Tensor("ParseSingleExample/ParseExample/ParseExample:3", 形状=(?,), dtype=int64), dense_shape=Tensor("ParseSingleExample/Squeeze_Shape_i:0", shape=(1,), dtype=int64))。考虑将元素转换为支持的类型。

Python 版本:3.5.2
TensorFlow 版本:1.4.1

【问题讨论】:

    标签: python tensorflow tfrecord


    【解决方案1】:

    错误很简单。你的data 不是FixedLenFeature 它是VarLenFeature。替换你的行:

     'data':tf.FixedLenFeature([], tf.int64)}
    

     'data':tf.VarLenFeature(tf.int64)}
    

    此外,当您调用 print(i.eval())print(data.eval()) 时,您将调用迭代器两次。第一个print 将打印0,但第二个将打印第二行的值[ 0, 50, 89, 147, 196]。您可以通过print(sess.run([i, data])) 获取同一行的idata

    【讨论】:

    • 您好,您的代码运行成功了吗?我在使用'data':tf.VarLenFeature(tf.int64)} 时遇到了另一个错误。请查看我更新的问题。谢谢
    【解决方案2】:

    经过数小时的搜索和尝试,我相信答案已经浮出水面。下面是我的代码。

    def _int64_feature(value):
        # value must be a numpy array.
        return tf.train.Feature(int64_list=tf.train.Int64List(value=value.flatten()))
    
    # Write an array to TFrecord.
    # a is an array which contains lists of variant length.
    a = np.array([[0, 54, 91, 153, 177],
                  [0, 50, 89, 147, 196],
                  [0, 38, 79, 157],
                  [0, 49, 89, 147, 177],
                  [0, 32, 73, 145]])
    
    writer = tf.python_io.TFRecordWriter('file')
    
    for i in range(a.shape[0]): # i = 0 ~ 4
        x_train = np.array(a[i])
        feature = {'i'   : _int64_feature(np.array([i])), 
                   'data': _int64_feature(x_train)}
    
        # Create an example protocol buffer
        example = tf.train.Example(features=tf.train.Features(feature=feature))
    
        # Serialize to string and write on the file
        writer.write(example.SerializeToString())
    
    writer.close()
    
    # Check TFRocord file.
    record_iterator = tf.python_io.tf_record_iterator(path='file')
    for string_record in record_iterator:
        example = tf.train.Example()
        example.ParseFromString(string_record)
    
        i = (example.features.feature['i'].int64_list.value)
        data = (example.features.feature['data'].int64_list.value)
        print(i, data)
    
    # Use Dataset API to read the TFRecord file.
    filenames = ["file"]
    dataset = tf.data.TFRecordDataset(filenames)
    def _parse_function(example_proto):
        keys_to_features = {'i':tf.VarLenFeature(tf.int64),
                            'data':tf.VarLenFeature(tf.int64)}
        parsed_features = tf.parse_single_example(example_proto, keys_to_features)
        return tf.sparse_tensor_to_dense(parsed_features['i']), \
               tf.sparse_tensor_to_dense(parsed_features['data'])
    # Parse the record into tensors.
    dataset = dataset.map(_parse_function)
    # Shuffle the dataset
    dataset = dataset.shuffle(buffer_size=1)
    # Repeat the input indefinitly
    dataset = dataset.repeat()  
    # Generate batches
    dataset = dataset.batch(1)
    # Create a one-shot iterator
    iterator = dataset.make_one_shot_iterator()
    i, data = iterator.get_next()
    with tf.Session() as sess:
        print(sess.run([i, data]))
        print(sess.run([i, data]))
        print(sess.run([i, data]))
    

    有几件事需要注意。
    1. 这个SO 问题很有帮助。
    2. tf.VarLenFeature 会返回 SparseTensor,因此需要使用 tf.sparse_tensor_to_dense 转换为稠密张量。
    3. 在我的代码中,parse_single_example() 不能替换为parse_example(),这让我困扰了一天。我不知道为什么parse_example() 不起作用。有谁知道原因,请赐教。

    【讨论】:

    • Ad3 @Lion Lai 。因为 dataset.map 函数接受一个对单个 TFRecord 示例进行操作的函数!不在这些集合上(这些集合形成一个完整的 TFRecord 文件)。即使您将使用 parse_example 并将示例编号设置为 1 - 它仍然会期望一个列表作为参数并且它会得到单个示例。
    • @Pietrko 我不明白你的意思。你能告诉我如何在我的情况下使用parse_example()吗?
    • 我的意思是你使用 parse_single_examplemap 函数做得对。 TFRecord 文件包含其中的示例集合。什么函数 Dataset.map 将你发送给它的函数应用到 TFRecord 的所有元素
    猜你喜欢
    • 2018-02-11
    • 1970-01-01
    • 2018-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多