TensorFlow
tf.data.Dataset
interleave()
map()
flat_map()

How exactly does tf.data.Dataset.interleave differ from map and flat_map?

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

Introduction

map(), flat_map(), and interleave() are three tf.data.Dataset transformation methods that apply a function to each element. map() applies a function one-to-one. flat_map() applies a function that returns a dataset per element and flattens them sequentially. interleave() does the same as flat_map() but reads from multiple sub-datasets concurrently, interleaving their elements for better I/O throughput. The key difference is parallelism.

map() — One-to-One Transformation

map() applies a function to each element independently, producing one output per input:

python
1import tensorflow as tf
2
3dataset = tf.data.Dataset.range(5)
4# [0, 1, 2, 3, 4]
5
6mapped = dataset.map(lambda x: x * 10)
7# [0, 10, 20, 30, 40]
8
9# Each element is transformed independently
10for item in mapped:
11    print(item.numpy(), end=" ")
12# 0 10 20 30 40

map() does not change the number of elements — it transforms each one.

flat_map() — One-to-Many, Sequential

flat_map() applies a function that returns a Dataset per element, then flattens all sub-datasets into one stream sequentially:

python
1dataset = tf.data.Dataset.range(3)
2# [0, 1, 2]
3
4def expand(x):
5    return tf.data.Dataset.range(x, x + 3)
6
7flat = dataset.flat_map(expand)
8# Element 0 → [0, 1, 2]
9# Element 1 → [1, 2, 3]
10# Element 2 → [2, 3, 4]
11# Flattened sequentially: [0, 1, 2, 1, 2, 3, 2, 3, 4]
12
13for item in flat:
14    print(item.numpy(), end=" ")
15# 0 1 2 1 2 3 2 3 4

flat_map() exhausts each sub-dataset completely before moving to the next one. There is no parallelism — it reads from one sub-dataset at a time.

interleave() — One-to-Many, Parallel

interleave() also applies a function returning a Dataset per element, but it reads from multiple sub-datasets at once, interleaving their outputs:

python
1dataset = tf.data.Dataset.range(3)
2
3def expand(x):
4    return tf.data.Dataset.range(x, x + 3)
5
6interleaved = dataset.interleave(
7    expand,
8    cycle_length=3,       # Read from 3 sub-datasets concurrently
9    block_length=1,       # Take 1 element from each before cycling
10    num_parallel_calls=3  # Use 3 threads for parallel I/O
11)
12# Round-robin across 3 sub-datasets:
13# Sub-0: [0, 1, 2], Sub-1: [1, 2, 3], Sub-2: [2, 3, 4]
14# Take 1 from each: 0, 1, 2, 1, 2, 3, 2, 3, 4
15
16for item in interleaved:
17    print(item.numpy(), end=" ")
18# 0 1 2 1 2 3 2 3 4

With block_length=2, it takes 2 elements from each sub-dataset before cycling:

python
1interleaved = dataset.interleave(expand, cycle_length=3, block_length=2)
2# Take 2 from Sub-0: 0, 1
3# Take 2 from Sub-1: 1, 2
4# Take 2 from Sub-2: 2, 3
5# Take remaining from Sub-0: 2
6# Take remaining from Sub-1: 3
7# Take remaining from Sub-2: 4
8# Result: 0, 1, 1, 2, 2, 3, 2, 3, 4

Real-World Example: Reading Multiple Files

The main use case for interleave() is reading from multiple data files in parallel:

python
1# List of TFRecord files
2file_dataset = tf.data.Dataset.list_files("data/train-*.tfrecord")
3
4# flat_map: reads files one at a time (slow I/O)
5dataset_sequential = file_dataset.flat_map(
6    lambda f: tf.data.TFRecordDataset(f)
7)
8
9# interleave: reads from multiple files concurrently (fast I/O)
10dataset_parallel = file_dataset.interleave(
11    lambda f: tf.data.TFRecordDataset(f),
12    cycle_length=4,
13    block_length=16,
14    num_parallel_calls=tf.data.AUTOTUNE
15)
16
17# Then parse and preprocess
18dataset_parallel = dataset_parallel.map(parse_fn, num_parallel_calls=tf.data.AUTOTUNE)
19dataset_parallel = dataset_parallel.batch(32).prefetch(tf.data.AUTOTUNE)

With flat_map, the pipeline reads one file completely before starting the next — I/O is sequential and the GPU may starve. With interleave, multiple files are read concurrently, hiding I/O latency.

Comparison Table

Featuremap()flat_map()interleave()
Input/output ratio1:11:many (flattened)1:many (flattened)
ParallelismOptional (num_parallel_calls)NoneYes (cycle_length, num_parallel_calls)
Output orderPreserves input orderSequential (sub-dataset by sub-dataset)Interleaved (round-robin across sub-datasets)
Primary use caseElement-wise transformsSequential chainingParallel I/O from multiple sources

When to Use Each

python
1# map: transform each element (decode, resize, normalize)
2dataset = dataset.map(lambda img, label: (tf.image.resize(img, [224, 224]), label))
3
4# flat_map: expand each element into multiple (e.g., sliding windows)
5dataset = dataset.flat_map(
6    lambda seq: tf.data.Dataset.from_tensor_slices(
7        tf.signal.frame(seq, frame_length=10, frame_step=5)
8    )
9)
10
11# interleave: read from multiple data sources concurrently
12dataset = file_dataset.interleave(
13    tf.data.TFRecordDataset,
14    cycle_length=8,
15    num_parallel_calls=tf.data.AUTOTUNE
16)

Common Pitfalls

  • Using flat_map when interleave is needed: flat_map reads files one at a time. For multi-file datasets, interleave with num_parallel_calls=tf.data.AUTOTUNE gives significantly higher throughput because it overlaps I/O across files.
  • Setting cycle_length too high: Reading from too many files concurrently increases memory usage and may cause disk thrashing. A value of 4-16 is typical; use tf.data.AUTOTUNE to let TensorFlow decide.
  • Forgetting num_parallel_calls in interleave: Without it, interleave cycles through sub-datasets but still reads sequentially (one thread). Add num_parallel_calls=tf.data.AUTOTUNE for actual parallel I/O.
  • Non-deterministic output order with parallel interleave: When num_parallel_calls > 1 and deterministic=False, elements arrive in non-deterministic order. This is faster but makes debugging harder. Set deterministic=True for reproducible pipelines.
  • Confusing map with flat_map for variable-length outputs: map() cannot change the number of elements. If your function produces a variable number of outputs per input (e.g., splitting a sentence into words), use flat_map or interleave, not map.

Summary

  • map() transforms each element 1:1 — use for preprocessing (resize, normalize, decode)
  • flat_map() maps each element to a sub-dataset and flattens sequentially — use for expanding elements
  • interleave() maps each element to a sub-dataset and reads from multiple in parallel — use for reading multiple data files
  • Set num_parallel_calls=tf.data.AUTOTUNE in both map() and interleave() for automatic parallelism
  • cycle_length controls how many sub-datasets interleave reads from concurrently
  • block_length controls how many elements to take from each sub-dataset before rotating

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

All Rights Reserved.