#tensorflow #tensorflow2.0
Вопрос:
У меня есть набор данных tensorflow ds
, и я хотел бы разделить его на N наборов данных, объединение которых является исходным набором данных и которые не разделяют образцы между собой. Я пытался:
ds_list = [ds.shard(N,index=i) for i in range(N)]
Но, к сожалению, это не случайно: каждый новый набор данных всегда будет получать одни и те же образцы из исходного набора данных. Например, ds_list[0] будет иметь образцы с номерами 0,N,2N,3N…, в то время как ds_list[1] будет иметь 1,N 1,2 N 1,3 N 1…
Существует ли какой-либо способ случайного разбиения исходного набора данных на наборы данных одинакового размера?
К сожалению, простое перетасование ранее не решит проблему:
import tensorflow as tf
import math
ds = tf.data.Dataset.from_tensor_slices([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 ,15, 16, 17, 18, 19, 20])
N=2
ds = ds.shuffle(20)
ds_list = [ds.shard(N,index=i) for i in range(N)]
for ds in ds_list:
shard_set = sorted(set(list(ds.as_numpy_iterator())))
print(shard_set)
Выход:
[3, 5, 6, 8, 11, 12, 14, 15, 19, 20]
[1, 2, 4, 5, 6, 7, 8, 14, 15, 20]
Так же, как:
ds = tf.data.Dataset.from_tensor_slices([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 ,15, 16, 17, 18, 19, 20])
N=2
ds_list = []
ds = ds.shuffle(20)
size = ds.__len__()
sub = math.floor(size/N)
for n in range(N):
ds_sub = ds.take(sub)
remainder = ds.skip(sub)
ds_list.append(ds_sub)
ds = remainder
for ds in ds_list:
shard_set = sorted(set(list(ds.as_numpy_iterator())))
print(shard_set)
Ответ №1:
Возможно (для N осколков):
ds_list = []
ds = ds.shuffle()
size = ds.__len__()
sub = floor(size/N)
for n in range(N):
ds_sub = ds.take(sub)
remainder = ds.skip(sub)
ds_list.append(ds_sub)
ds = remainder
Комментарии:
1. Спасибо за ваш ответ. Предложенное вами решение не работает, потому что оно не гарантирует, что все образцы находятся в одном и только одном наборе данных «разбиения»
2. Я считаю, что это так, так как в конце цикла ds устанавливается на остаток. Таким образом, точки, добавленные в ds_sub, больше никогда не рассматриваются.
3. Я предполагаю, что это из-за перетасовки, так как операция взятия и пропуска может включать образцы в другом порядке. Не стесняйтесь использовать код, который я предоставил в основном вопросе.
4. Нет, перетасовка происходит раньше. Затем вы продолжаете принимать и пропускать, пока все данные не будут назначены.
5. Вы протестировали свой код? Просто попробуйте код, который я ввел в основной вопрос. Вы увидите, что получите осколки, которые разделяют некоторые образцы
Ответ №2:
Вы можете сначала перетасовать набор данных, а затем разделить его на фрагменты:
ds = ds.shuffle(buffer_size)
ds_list = [ds.shard(N,index=i) for i in range(N)]
Вот buffer_size
размер буфера, используемого TF для сортировки. Если размер набора данных невелик, вы можете передать общее количество примеров как buffer_size
. В противном случае будет работать меньшее число (что-то вроде 100), которое может поместиться в память.
Комментарии:
1. Спасибо за ваш ответ. Предложенное вами решение не работает, потому что оно не гарантирует, что все образцы находятся в одном и только одном наборе данных «разбиения»
2. Я думаю, что это так, потому что shuffle не рассматривает один и тот же пример несколько раз (поскольку вы не повторяете набор данных). Можете ли вы привести пример, какая обувь в этом же примере поставляется в нескольких вариантах? Если вы используете повтор перед перемешиванием, то то, что вы говорите, имеет смысл, но поскольку здесь этого не происходит, я думаю, что это должно сработать.
3. Привет, вот возможный код для визуальной проверки. Есть некоторые образцы, которые есть в обоих наборах данных, а некоторые-нет. Я отредактировал основной вопрос