You are browsing as a guest. Sign up (or log in) to start making projects!

1h 16m 5s logged

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

  1. Context Resolution Pipeline: Added a new private utility helper _get_num_replicas_in_sync() inside tensorflow/python/ops/nn_impl_distribute.py. This helper modifies the strategy discovery topology to prioritize checking the lightweight, per-thread active environment handle distribute_lib.get_replica_context(). This context is guaranteed to be populated inside strategy.run() and cleanly survives the Python frame switches involved in XLA function tracing.
  2. Defensive Invariants: Added type and range validation assertions to ensure the resolved replica integer count is a strictly positive Python int to catch structural strategy bugs prior to HLO constant generation.
  3. Caller Redirection: Refactored compute_average_loss to route dynamic scaling factor discovery through the new _get_num_replicas_in_sync() pipeline.
  4. Testing Harness expansion: Appended comprehensive unit and integration regression test suites (TestGetNumReplicasInSync and TestComputeAverageLossXLAContextMasking) directly to tensorflow/python/ops/nn_loss_scaling_utilities_test.py to 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_compile checks.
  • Code style preserves the 2-space baseline indentation layout standard to the internal package architecture.
0
1

Comments 0

No comments yet. Be the first!