TensorFlow
session.run
performance
first run
optimization

First tf.session.run performs dramatically different from later runs. Why?

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, the first tf.Session.run() is often much slower than later runs. That is not usually a mystery bug in your model; it is the cost of warming up the execution environment, allocating resources, and preparing kernels that can be reused on subsequent iterations.

What happens on the first run

TensorFlow 1.x separates graph construction from graph execution. By the time you call session.run, the graph already exists, but the runtime still has real work to do before steady-state performance appears.

Typical first-run costs include:

  • allocating device memory
  • initializing variables and buffers
  • setting up execution state
  • creating GPU or accelerator contexts
  • performing backend autotuning for some kernels

Once these steps are done, later runs can reuse much of that work.

A simple timing example

The easiest way to see the warm-up effect is to time several identical runs.

python
1import time
2import tensorflow as tf
3
4tf.compat.v1.disable_eager_execution()
5
6with tf.compat.v1.Graph().as_default():
7    a = tf.compat.v1.random_normal([1000, 1000])
8    b = tf.compat.v1.random_normal([1000, 1000])
9    c = tf.matmul(a, b)
10
11    with tf.compat.v1.Session() as sess:
12        times = []
13        for _ in range(5):
14            start = time.perf_counter()
15            sess.run(c)
16            times.append(time.perf_counter() - start)
17
18        print(times)

On many systems, the first value in times will be noticeably larger than the rest.

GPU setups amplify the difference

The warm-up gap is often bigger on GPU than CPU. The first execution may create the CUDA context, load kernels, and select algorithms for operations such as convolution or matrix multiplication.

That is why benchmarks that include the very first run can give misleading numbers. If you are measuring model throughput or latency, use explicit warm-up iterations before recording results.

Variable initialization versus execution overhead

Sometimes people attribute the slower first run only to variable initialization. That can be part of the story, but it is not the whole story.

For example, even if variables were already initialized, the first real execution can still be slower because the runtime is performing placement, allocating device buffers, and preparing low-level execution resources.

If your code includes a separate initializer run such as sess.run(tf.global_variables_initializer()), that call itself may absorb some of the startup cost, but not always all of it.

Proper benchmarking pattern

A more reliable benchmark warms up the graph first and then measures repeated runs.

python
1import time
2import tensorflow as tf
3
4tf.compat.v1.disable_eager_execution()
5
6x = tf.compat.v1.placeholder(tf.float32, shape=[None, 128])
7y = tf.reduce_sum(x * x, axis=1)
8
9with tf.compat.v1.Session() as sess:
10    feed = {x: [[1.0] * 128] * 1024}
11
12    for _ in range(3):
13        sess.run(y, feed_dict=feed)
14
15    start = time.perf_counter()
16    for _ in range(10):
17        sess.run(y, feed_dict=feed)
18    end = time.perf_counter()
19
20    print((end - start) / 10)

This does not remove all noise, but it avoids treating one-time startup work as steady-state runtime.

Why later runs can still vary

Even after warm-up, later runs are not guaranteed to be identical. Caching effects, thread scheduling, input-pipeline behavior, and GPU contention can still move the numbers around.

But the dramatic difference between the first run and the rest is usually a startup effect, not proof that TensorFlow is changing the graph semantics between calls.

Common Pitfalls

A common mistake is benchmarking only a single session.run and reporting that number as model latency. In TF1 that often measures startup overhead more than real inference cost.

Another issue is forgetting that data input can dominate timing. If the first run includes disk reads, queue startup, or dataset setup, the result reflects more than the compute graph.

It is also easy to compare CPU and GPU numbers unfairly without warm-up. GPU startup penalties are often larger even when steady-state execution is much faster.

Summary

  • The first tf.Session.run() is often slower because TensorFlow is still warming up runtime resources.
  • Common one-time costs include memory allocation, backend setup, kernel preparation, and device-context creation.
  • GPU workloads usually show the effect more strongly than CPU workloads.
  • Use warm-up iterations before benchmarking steady-state performance.
  • Do not confuse startup overhead with the real long-run speed of the model.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the 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.