TensorFlow
Machine Learning
Training Data
Validation Data
Data Queues

Tensorflow Queues - Switching between train and validation data

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

In TensorFlow 1.x, queue-based input pipelines were a common way to feed data into a training graph. If you needed to switch between training data and validation data, the clean approach was to build separate input sources and select between them explicitly instead of trying to rewire one queue in place.

Why Switching Is Needed

Training and validation typically have different behavior:

  • training input is often shuffled and repeated
  • validation input is usually deterministic
  • augmentation may apply only to training data

That means a single queue configuration is rarely appropriate for both. The safest design is to create one queue pipeline for training, one for validation, and switch at the dequeue point.

Minimal Queue-Based Example

The following tf.compat.v1 example shows the idea without extra file readers. Two queues are filled with different values, and a boolean placeholder selects which one to read from.

python
1import tensorflow as tf
2
3tf.compat.v1.disable_eager_execution()
4
5train_queue = tf.queue.FIFOQueue(capacity=8, dtypes=[tf.int32])
6val_queue = tf.queue.FIFOQueue(capacity=8, dtypes=[tf.int32])
7
8train_enqueue = train_queue.enqueue_many([[1, 2, 3, 4]])
9val_enqueue = val_queue.enqueue_many([[100, 200]])
10
11use_validation = tf.compat.v1.placeholder_with_default(False, shape=())
12next_item = tf.cond(
13    use_validation,
14    lambda: val_queue.dequeue(),
15    lambda: train_queue.dequeue()
16)
17
18with tf.compat.v1.Session() as sess:
19    sess.run(train_enqueue)
20    sess.run(val_enqueue)
21
22    print(sess.run(next_item))
23    print(sess.run(next_item))
24    print(sess.run(next_item, feed_dict={use_validation: True}))

The first two reads come from the training queue. The last read switches to the validation queue because use_validation is True.

Extending The Pattern To Real Training

In a real training graph, each queue would usually contain feature tensors and labels rather than integers. You might also use RandomShuffleQueue for training and FIFOQueue for validation.

python
1train_batch = train_queue.dequeue_many(32)
2val_batch = val_queue.dequeue_many(32)
3
4features, labels = tf.cond(
5    use_validation,
6    lambda: val_batch,
7    lambda: train_batch
8)

Once the selected tensors are wired into the model, the rest of the graph does not need to know whether the batch came from training or validation data.

That separation is important. It keeps data-source switching outside the model logic.

Queue Runners And Coordination

Many older TensorFlow pipelines also used queue runners. If your input pipeline reads files asynchronously, you need to start the background threads before calling sess.run on the model.

python
1coord = tf.train.Coordinator()
2threads = tf.compat.v1.train.start_queue_runners(coord=coord)
3
4try:
5    # training loop here
6    pass
7finally:
8    coord.request_stop()
9    coord.join(threads)

If you forget to start queue runners, your session will block while waiting for input that never arrives.

Better Architecture For Evaluation

Even in TensorFlow 1.x, it was often cleaner to keep training and validation in separate loops:

  1. run several training steps with use_validation=False
  2. run evaluation steps with use_validation=True
  3. aggregate metrics separately

That avoids mixing shuffling, dropout, and evaluation state in the same step. Validation should be predictable and reproducible.

Historical Context: Why Many Teams Moved Away From Queues

Queue pipelines worked, but they were difficult to debug and easy to deadlock. Later TensorFlow versions made tf.data the preferred input mechanism because it expresses switching and batching more cleanly.

For example, a modern equivalent would typically use two datasets and separate iterators or a reinitializable iterator. The conceptual lesson is unchanged: training and validation are different streams, so model them as different inputs.

Common Pitfalls

A common mistake is trying to reuse the exact same queue for both training and validation by mutating file lists or enqueue operations during a running session. That tends to create nondeterministic behavior and debugging pain.

Another issue is using shuffled validation input. That is not always wrong, but it makes evaluation harder to compare across runs and can hide data accounting bugs.

Queue starvation is also common. If the enqueue threads are not running, or the validation queue is never filled before switching, the graph can hang on a dequeue call.

Finally, remember that many queue-based examples on the internet target TensorFlow 1.x graph mode. If you are maintaining old code, the pattern above is still useful. If you are starting fresh, a dataset-based pipeline is usually the better design.

Summary

  • In queue-based TensorFlow input pipelines, keep training and validation as separate queues.
  • Switch between them at dequeue time with a flag such as tf.cond.
  • Use shuffling for training input and deterministic ordering for validation when possible.
  • Start queue runners when your pipeline depends on background enqueue threads.
  • For new projects, prefer dataset-based input pipelines, but the same separation-of-streams idea still applies.

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.