Pavel's answer works great if you don't mind the order of interleaving. If you do care...
Option 1
A variant on mrry's answer that works with an arbitrary number of input datasets:
ds0 = tf.data.Dataset.range(0, 10, 3)
ds1 = tf.data.Dataset.range(1, 10, 3)
ds2 = tf.data.Dataset.range(2, 10, 3)
datasets = (ds0, ds1, ds2)
# Note: `datasets` should be a *tuple*, not a list.
datasets_zipped = tf.data.Dataset.zip(datasets)
# Each element of the dataset will now be a tuple, e.g. (0, 1, 2).
datasets_zipped_tensor = datasets_zipped.map(lambda *args: tf.stack(args))
# Each element will now be a Tensor, e.g. Tensor([0, 1, 2]).
datasets_interleaved = datasets_zipped_tensor.unbatch()
However, note that because of the way zip works, the dataset this produces limited by the length of the shortest input dataset. For example, using the above code with
datasets = [
tf.data.Dataset.from_tensor_slices([1, 2, 3, 4, 5]),
tf.data.Dataset.from_tensor_slices([10, 20]),
)
would yield a dataset comprising just [1, 10, 2, 20].
Option 2
Dataset.interleave doesn't suffer from this problem. In some cases you can use interleave with:
# Note: `datasets` should be a *list*, not a tuple
tf.data.Dataset.from_tensor_slices(datasets).interleave(lambda x: x)
But this doesn't seem to work for all kinds of dataset; calling from_tensor_slices on your datasets may not work.
Option 3
If option 2 doesn't work, you might be able to use interleave at an earlier stage of your dataset pipeline. For example, you might be able to change from calling interleave on pre-existing datasets to calling interleave on the file names from which the individual datasets were created:
filenames = ['foo', 'bar']
filesnames_dataset = tf.data.Dataset.from_tensor_slices(filenames)
def read_dataset(filename): ...
interleaved_dataset = filenames_dataset.interleave(read_dataset)
But this will only work if your read_dataset function accepts a Tensor argument.
Option 4
If none of the other options work for you, I think the only solution is to implement the interleaving yourself, with something like:
element_spec = datasets[0].element_spec
assert all(dataset.element_spec == element_spec for dataset in datasets)
def interleave_generator():
iters_not_exhausted = [iter(dataset) for dataset in datasets]
while iters_not_exhausted:
for dataset_iter in iters_not_exhausted:
try:
x = next(dataset_iter)
except StopIteration:
iters_not_exhausted.remove(dataset_iter)
else:
yield x
datasets_interleaved = tf.data.Dataset.from_generator(
interleave_generator,
output_signature=element_spec,
)