如何在 tf.data.Dataset 中输入不同大小的列表列表
Posted
技术标签:
【中文标题】如何在 tf.data.Dataset 中输入不同大小的列表列表【英文标题】:How to input a list of lists with different sizes in tf.data.Dataset 【发布时间】:2018-05-14 19:27:39 【问题描述】:我有一长串整数列表(代表句子,每个都有不同的大小),我想使用 tf.data 库提供这些列表。每个列表(列表的列表)都有不同的长度,我得到一个错误,我可以在这里重现:
t = [[4,2], [3,4,5]]
dataset = tf.data.Dataset.from_tensor_slices(t)
我得到的错误是:
ValueError: Argument must be a dense tensor: [[4, 2], [3, 4, 5]] - got shape [2], but wanted [2, 2].
有没有办法做到这一点?
编辑 1:为了清楚起见,我不想填充列表的输入列表(它是包含超过一百万个元素的句子列表,长度不一)我想使用 tf.data 库来提供,以适当的方式,具有不同长度的列表列表。
【问题讨论】:
如果您将句子列表(字符串列表)传递给tf.data.Dataset.from_tensor_slices
,它应该可以工作,然后您应该能够使用dataset.map(your_function)
将每个句子转换为整数列表。然后您可以使用dataset.padded_batch
自动添加填充。
这个例子很有用:github.com/tensorflow/nmt#data-input-pipeline
嗨@OlivierMoindrot,我看过那个例子。我担心的是:当您在训练中运行图形时(即每次向模型提供新数据时),它们会执行映射函数,还是在训练之前在整个数据集上执行,然后输入结果?在我看来,第一个训练比第二个慢得多,这就是我想要避免的。
这是tf.data
的重点,它在后台使用队列,只根据需要处理数据。您可以“预取”数据以确保您的 GPU 永远不会等待数据并且以 100% 的速度工作。由于数据在一端被消耗(用于训练),因此之前的队列被数据填满。您甚至可以使用num_parallel_calls
拥有多个工作人员。
dataset.prefetch
【参考方案1】:
对于那些使用 TensorFlow 2 并正在寻找答案的人 我发现以下内容可以直接使用参差不齐的张量。 只要整个数据集适合内存,它应该比生成器快得多。
t = [[[4,2]],
[[3,4,5]]]
rt=tf.ragged.constant(t)
dataset = tf.data.Dataset.from_tensor_slices(rt)
for x in dataset:
print(x)
生产
<tf.RaggedTensor [[4, 2]]> <tf.RaggedTensor [[3, 4, 5]]>
出于某种原因,在单个数组上至少有 2 个维度是非常特别的。
【讨论】:
+1 但 tf 2.1 仅供参考,不再需要额外的括号【参考方案2】:除了@mrry 的回答,如果您想创建(图像、标签)对,也可以使用以下代码:
import itertools
data = tf.data.Dataset.from_generator(lambda: itertools.izip_longest(images, labels),
output_types=(tf.float32, tf.float32),
output_shapes=(tf.TensorShape([None, None, 3]),
tf.TensorShape([None])))
iterator = dataset.make_one_shot_iterator()
next_element = iterator.get_next()
with tf.Session() as sess:
image, label = sess.run(next_element) # ==> shape: [320, 420, 3], [20]
image, label = sess.run(next_element) # ==> shape: [1280, 720, 3], [40]
【讨论】:
【参考方案3】:您可以使用tf.data.Dataset.from_generator()
将任何可迭代的Python 对象(如列表列表)转换为Dataset
:
t = [[4, 2], [3, 4, 5]]
dataset = tf.data.Dataset.from_generator(lambda: t, tf.int32, output_shapes=[None])
iterator = dataset.make_one_shot_iterator()
next_element = iterator.get_next()
with tf.Session() as sess:
print(sess.run(next_element)) # ==> '[4, 2]'
print(sess.run(next_element)) # ==> '[3, 4, 5]'
【讨论】:
@mrry,我也在做同样的想法,来自生成器的数据集可以批量化,我的意思是小批量化?【参考方案4】:我认为 tensorflow 不支持在给定维度上具有不同数量元素的张量。
但是,一个简单的解决方案是用尾随零填充嵌套列表(在必要时):
t = [[4,2], [3,4,5]]
max_length = max(len(lst) for lst in t)
t_pad = [lst + [0] * (max_length - len(lst)) for lst in t]
print(t_pad)
dataset = tf.data.Dataset.from_tensor_slices(t_pad)
print(dataset)
输出:
[[4, 2, 0], [3, 4, 5]]
<TensorSliceDataset shapes: (3,), types: tf.int32>
零对于模型来说应该不是什么大问题:从语义上讲,它们只是每个实际句子列表末尾的大小为零的额外句子。
【讨论】:
您好,感谢您的回答,由于列表的大小,我无法填充整个列表。我会为每个批次做填充,但不是为由数百万个句子组成的整个数据集。以上是关于如何在 tf.data.Dataset 中输入不同大小的列表列表的主要内容,如果未能解决你的问题,请参考以下文章
tf.data.Dataset.padded_batch 以不同的方式填充每个功能
如何在 keras 自定义回调中访问 tf.data.Dataset?
tf.keras 模型 多个输入 tf.data.Dataset
如何将 tf.data.Dataset 与 kedro 一起使用?
如何在 tensorboard 中显示 Tensorflow 2.0 中的 tf.data.Dataset.map 子图?