如何拆分Tensorflow数据集?

Luk*_*yer 14 tensorflow tensorflow-datasets

我有一个基于一个.tfrecord文件的tensorflow数据集.如何将数据集拆分为测试和训练数据集?例如70%的火车和30%的测试?

编辑:

我的Tensorflow版本:1.8我已经检查过,没有可能重复中提到的"split_v"功能.我也在使用tfrecord文件.

Nic*_*Lee 35

这个问题类似于这一个这一个,恐怕我们还没有一个满意的答案。

  • 使用take()skip()需要知道数据集大小。如果我不知道或者不想知道怎么办?

  • shard()仅使用1 / num_shards数据集。如果我想要剩下的怎么办?

我尝试在下面提供一个更好的解决方案,仅在TensorFlow 2上进行测试。假设您已经有一个混洗的数据集,那么您可以使用filter()将其拆分为两个:

import tensorflow as tf

all = tf.data.Dataset.from_tensor_slices(list(range(1, 21))) \
        .shuffle(10, reshuffle_each_iteration=False)

test_dataset = all.enumerate() \
                    .filter(lambda x,y: x % 4 == 0) \
                    .map(lambda x,y: y)

train_dataset = all.enumerate() \
                    .filter(lambda x,y: x % 4 != 0) \
                    .map(lambda x,y: y)

for i in test_dataset:
    print(i)

print()

for i in train_dataset:
    print(i)
Run Code Online (Sandbox Code Playgroud)

参数reshuffle_each_iteration=False很重要。它确保原始数据集被打乱一次,不再打乱。否则,两个结果集可能会有一些重叠。

使用enumerate()添加索引。

使用filter(lambda x,y: x % 4 == 0)取1个样品选自4.同样地,x % 4 != 0需要3出4。

使用map(lambda x,y: y)剥离索引和恢复原始样品。

此示例实现了 75/25 的拆分。

x % 5 == 0x % 5 != 0给出 80/20 的分割。

如果你真的想要一个70:30的比例分摊,x % 10 < 3x % 10 >= 3应该做的。

更新:

从 TensorFlow 2.0.0 开始,由于AutoGraph 的限制,上述代码可能会导致一些警告。要消除这些警告,请分别声明所有 lambda 函数:

def is_test(x, y):
    return x % 4 == 0

def is_train(x, y):
    return not is_test(x, y)

recover = lambda x,y: y

test_dataset = all.enumerate() \
                    .filter(is_test) \
                    .map(recover)

train_dataset = all.enumerate() \
                    .filter(is_train) \
                    .map(recover)
Run Code Online (Sandbox Code Playgroud)

这在我的机器上没有任何警告。与制作is_train()not is_test()绝对是一个很好的做法。

  • 你不应该使用“all”作为变量名,因为它会覆盖Python的内置“all(enum)”函数 (4认同)
  • 值得一提的是,使用模 7 也可以对训练/验证/测试数据集进行 70/20/10% 的分割。 ```test_dataset = dataset.enumerate().filter(lambda x,y: x%10 ==7).map(lambda x,y: y) val_dataset = dataset.enumerate().filter(lambda x,y: x%10&gt;7).map(lambda x,y: y) train_dataset = dataset.enumerate ().filter(lambda x,y: x%10&lt;7).map(lambda x,y: y)``` (2认同)

ted*_*ted 20

您可以使用Dataset.take()Dataset.skip():

train_size = int(0.7 * DATASET_SIZE)
val_size = int(0.15 * DATASET_SIZE)
test_size = int(0.15 * DATASET_SIZE)

full_dataset = tf.data.TFRecordDataset(FLAGS.input_file)
full_dataset = full_dataset.shuffle()
train_dataset = full_dataset.take(train_size)
test_dataset = full_dataset.skip(train_size)
val_dataset = test_dataset.skip(test_size)
test_dataset = test_dataset.take(test_size)
Run Code Online (Sandbox Code Playgroud)

为了更加通用,我给出了一个使用70/15/15训练/值/测试分割的示例,但如果您不需要测试或val集,则忽略最后2行.

:

使用此数据集中的最多count个元素创建数据集.

跳过:

创建一个从此数据集中跳过count个元素的数据集.

您可能还想查看Dataset.shard():

创建仅包含此数据集的1/num_shards的数据集.

  • 请注意,skip 实际上会遍历数据集,因此可能会导致大型数据集的延迟很大 (6认同)
  • 我不建议这样做,因为训练集和测试集不是不相交的:测试集恰好包含训练集的元素 (4认同)
  • 如果数据集比改组缓冲区的大小大很多,这里是否存在随机性问题?由于仅在(相对)较小的缓冲区内对样本进行混洗,这意味着大约前70%的样本将成为训练集,接下来的15%将成为测试集,依此类推。如果以某种方式对数据进行排序,这会导致偏差训练结果。可能的解决方案是将数据分片,然后将其随机排序,然后将其拆分。 (3认同)
  • 我同意。好评论。我想大多数用例只需要一次洗牌整个数据集,但要真正可扩展,你是对的 (2认同)
  • 您需要设置 shuffle(reshuffle_each_iteration=False)。如果没有这一点,每次新的训练迭代开始时,训练集和验证集中的项目将相互洗牌。 (2认同)