ID: Tensor Flow PR-1
Summary
This PR resolves an optimization trajectory divergence bug (detailed in #120986) that occurs when utilizing tf.nn.compute_average_loss inside a distributed multi-worker training loop (MultiWorkerMirroredStrategy) wrapped with XLA compilation (jit_compile=True).
Root Cause Analysis
The optimization trajectory splits between the non-XLA (reference) and XLA-compiled execution arms because of how active strategy contexts are evaluated across the function tracing boundary.
Historically, compute_average_loss relied exclusively on distribute_lib.get_strategy().num_replicas_in_sync to infer the global batch size scaling constant. This utility queries the thread-local strategy_stack maintained by the eager runtime context. However, during the graph tracing initialization phase of tf.function(jit_compile=True), this eager stack handle can become isolated or masked inside the polymorphic function builder thread space. Furthermore, if a trace is evaluated prematurely or during initialization steps, the stack can appear empty to the compilation tracer frame.
When this handle is masked or evaluates to empty, compute_average_loss silently falls back to a default global_batch_size = 1. Under XLA, this value is permanently constant-folded and baked directly into the HLO binary graph. During actual parallel execution inside strategy.run(), the underlying math executes math_ops.reduce_sum(per_example_loss) / 1 instead of dividing by the correct num_replicas_in_sync (e.g., 2). This permanently doubles the gradient magnitude on the XLA arm, causing stateful optimizers like Adam to immediately diverge.
Implementation Details
-
Context Resolution Pipeline: Added a new private utility helper
_get_num_replicas_in_sync()insidetensorflow/python/ops/nn_impl_distribute.py. This helper modifies the strategy discovery topology to prioritize checking the lightweight, per-thread active environment handledistribute_lib.get_replica_context(). This context is guaranteed to be populated insidestrategy.run()and cleanly survives the Python frame switches involved in XLA function tracing. -
Defensive Invariants: Added type and range validation assertions to ensure the resolved replica integer count is a strictly positive Python
intto catch structural strategy bugs prior to HLO constant generation. -
Caller Redirection: Refactored
compute_average_lossto route dynamic scaling factor discovery through the new_get_num_replicas_in_sync()pipeline. -
Testing Harness expansion: Appended comprehensive unit and integration regression test suites (
TestGetNumReplicasInSyncandTestComputeAverageLossXLAContextMasking) directly totensorflow/python/ops/nn_loss_scaling_utilities_test.pyto formally mock context-masking behavior and assert proper scalar output reductions under isolated tracing simulation environments.
Verification Status
- Syntactic and AST structural verification passes cleanly via
py_compilechecks. - Code style preserves the 2-space baseline indentation layout standard to the internal package architecture.
Comments 0
No comments yet. Be the first!
Sign in to join the conversation.