Non-deterministic behavior of TensorFlow while_loop
ML System Design practice on Codemia
Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.
Introduction
tf.while_loop can exhibit non-deterministic behavior due to parallel execution of loop iterations, GPU thread scheduling, floating-point operation ordering, and XLA optimizations. This means running the same code twice can produce slightly different numerical results. The non-determinism primarily affects operations inside the loop body that use parallel reductions (like tf.reduce_sum on GPU) or access shared state. To get deterministic results, set tf.config.experimental.enable_op_determinism(), use parallel_iterations=1, or switch to CPU execution.
Understanding tf.while_loop
tf.while_loop takes a condition function, a body function, and loop variables. It repeatedly executes the body while the condition returns True. Unlike Python while, it operates on TensorFlow tensors and supports automatic differentiation.
Sources of Non-Determinism
The parallel_iterations parameter (default 10) allows TensorFlow to execute multiple loop iterations simultaneously. When these iterations share accumulation variables or use non-associative floating-point operations, the order of additions varies between runs.
Demonstrating Non-Determinism
The differences are small (last few decimal places) but can compound over many iterations, especially in gradient computations during training.
Fix 1: Set parallel_iterations=1
Setting parallel_iterations=1 forces sequential execution, eliminating ordering non-determinism within the loop. This slows execution but guarantees reproducibility.
Fix 2: Enable Global Determinism
enable_op_determinism() forces all TensorFlow operations to produce deterministic results. This affects the entire session and may slow down GPU operations that normally use non-deterministic parallel reductions.
Fix 3: Set Random Seeds
Setting tf.random.set_seed makes random number generation deterministic. Combined with parallel_iterations=1, this ensures the random values are generated in the same order every run.
Non-Determinism in Training Loops
RNN layers (LSTM, GRU) use tf.while_loop internally to iterate over time steps. Non-determinism in the loop affects gradient computation, causing different training outcomes across runs.
shape_invariants for Dynamic Shapes
When loop variables change shape across iterations, use shape_invariants to declare which dimensions are dynamic. Without this, TensorFlow raises a shape mismatch error.
Common Pitfalls
- Assuming while_loop is sequential by default:
parallel_iterationsdefaults to 10, meaning up to 10 iterations can run concurrently. This improves performance but introduces non-determinism when iterations modify shared accumulators. Setparallel_iterations=1for deterministic behavior. - Floating-point ordering on GPU:
tf.reduce_sumon GPU uses atomic additions that execute in non-deterministic order. Due to floating-point non-associativity,(a + b) + cmay differ froma + (b + c). Useenable_op_determinism()or run on CPU for exact reproducibility. - Not setting seeds for random ops in loop:
tf.randomfunctions insidetf.while_loopwithout a global seed produce different sequences each run. Settf.random.set_seed()before the loop and useparallel_iterations=1to ensure consistent random number generation order. - Forgetting shape_invariants for dynamic tensors: If a loop variable changes shape (e.g., concatenating to a growing tensor),
tf.while_loopraises an error unlessshape_invariantsdeclares the variable dimensions. Usetf.TensorShape([None])for dimensions that grow. - Gradients amplify non-determinism: Small numerical differences in the forward pass become larger differences in gradients during backpropagation. A model trained with non-deterministic
while_loopmay converge to different solutions across runs, making debugging and benchmarking unreliable.
Summary
tf.while_loopcan produce non-deterministic results due to parallel iteration execution and GPU floating-point ordering- Set
parallel_iterations=1to force sequential execution within the loop - Use
tf.config.experimental.enable_op_determinism()for global determinism (TF 2.9+) - Set
tf.random.set_seed()to make random operations inside loops reproducible - RNN layers (LSTM, GRU) use
while_loopinternally and are affected by the same non-determinism - Use
shape_invariantswhen loop variables change shape across iterations
Related reading
- Non-smooth and non-differentiable customized loss function tensorflow
- None dimension raise ValueError in batch_norm with Tensorflow
- nosetests with tensorflow lots of debugging output, how to disable
- Not able to import tensorflow_datasets module in jupyter notebook
- Non-linear multivariate time-series response prediction using `RNN`
- Non-linear regression in C
- Not able to load weights for fine tuning in Keras with ResNet50
- Not fully connected layer in tensorflow
.png&w=3840&q=75)
Tackling System Design Interview Problems
A short course that equips you with the skills to approach system design interviews methodically.
Start the free courseTrack 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.