TensorFlow
feed_dict
machine learning
neural networks
data input

Tensorflow When should I use or not use feed_dict?

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

feed_dict was a central mechanism in TensorFlow 1.x for passing runtime values into placeholders during Session.run. It provided flexibility for experiments, debugging, and dynamic inputs, but it also introduced overhead and complexity. In TensorFlow 2.x, eager execution and tf.data pipelines replaced most feed_dict use cases.

If you maintain legacy graph-based code, understanding when feed_dict is appropriate still matters. If you build new systems, you should generally avoid it and use modern input pipelines. The right choice depends on TensorFlow version, workload size, and performance requirements.

Core Sections

1. When feed_dict is useful (legacy TensorFlow 1.x)

feed_dict works well for small experiments where input values change per run call.

python
1# TensorFlow 1.x style
2import tensorflow as tf
3
4tf.compat.v1.disable_eager_execution()
5
6x = tf.compat.v1.placeholder(tf.float32, shape=[None, 2])
7w = tf.Variable([[2.0], [3.0]])
8y = tf.matmul(x, w)
9
10with tf.compat.v1.Session() as sess:
11    sess.run(tf.compat.v1.global_variables_initializer())
12    out = sess.run(y, feed_dict={x: [[1.0, 1.0], [2.0, 2.0]]})
13    print(out)

This is convenient for quick checks, synthetic inputs, and notebook debugging.

2. When not to use feed_dict

For production training/inference with large datasets, feed_dict is often a bottleneck because data transfer and Python-side orchestration occur at each step. Prefer tf.data pipelines and native Keras training loops.

python
1import tensorflow as tf
2
3features = tf.random.uniform((10000, 2))
4labels = tf.reduce_sum(features, axis=1, keepdims=True)
5
6dataset = tf.data.Dataset.from_tensor_slices((features, labels))
7dataset = dataset.shuffle(1000).batch(64).prefetch(tf.data.AUTOTUNE)
8
9model = tf.keras.Sequential([
10    tf.keras.layers.Input(shape=(2,)),
11    tf.keras.layers.Dense(16, activation="relu"),
12    tf.keras.layers.Dense(1)
13])
14model.compile(optimizer="adam", loss="mse")
15model.fit(dataset, epochs=3)

This approach scales better and integrates cleanly with accelerators.

3. Migration pattern from placeholders to TensorFlow 2

If you have 1.x code, migrate incrementally:

  • replace placeholders with function arguments or dataset elements,
  • remove Session.run loops in favor of model.fit or @tf.function,
  • keep compatibility mode only where necessary.

Example of function-style inference:

python
1import tensorflow as tf
2
3@tf.function
4def predict_step(x, w):
5    return tf.matmul(x, w)
6
7x = tf.constant([[1.0, 1.0], [2.0, 2.0]])
8w = tf.constant([[2.0], [3.0]])
9print(predict_step(x, w))

This keeps computation in TensorFlow graph execution without placeholder feeding overhead.

Common Pitfalls

  • Using feed_dict in high-throughput training loops where Python input feeding limits GPU utilization.
  • Mixing eager execution with placeholder-style code in TensorFlow 2, leading to confusing compatibility issues.
  • Forgetting that feed_dict keys must match exact graph tensors/placeholders, causing runtime key errors.
  • Assuming feed_dict performance is acceptable at scale because it works in small notebook examples.
  • Delaying migration from TF1 patterns, which increases maintenance burden and limits API compatibility.

Summary

Use feed_dict mainly for legacy TensorFlow 1.x debugging or small dynamic experiments. For modern TensorFlow workloads, avoid it in favor of tf.data, eager execution, and tf.function-based pipelines. Migrating away from placeholders improves performance, readability, and long-term maintainability.

If you still maintain TF1 graphs for regulated or long-lived systems, isolate feed_dict usage behind a narrow adapter rather than spreading placeholders throughout business logic. This creates a single migration seam where you can later switch to dataset-driven execution without rewriting model consumers. It also makes profiling easier because data feeding overhead is measured in one location.

For modernization planning, start by converting inference paths first, then training loops. Inference usually has fewer moving parts and gives immediate operational wins (simpler deployment, fewer session bugs). Once inference is stable in TF2 style, migrate training input pipelines and callback logic. Incremental migration lowers risk and avoids long-lived mixed paradigms that are hard to test.

Where migration is blocked, measure step time with and without feeding from Python to quantify overhead. Concrete benchmarks often make the case for moving to tf.data far more effectively than style arguments alone.

Even in legacy systems, tightening this boundary improves observability and maintainability.

That usually yields immediate runtime wins.

Plan migrations early.


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.