onnxruntime
727256f8 - Fix tf.function retracing in TensorFlow benchmark (#27665)

Commit
105 days ago
Fix tf.function retracing in TensorFlow benchmark (#27665) ## Summary - Move `tf.function`-decorated forward functions out of the inner benchmark loop to prevent unnecessary graph retracing on every `(batch_size, sequence_length)` iteration - Update deprecated `experimental_compile` to `jit_compile` (available since TF 2.4) - Hoist `import random` out of the inner loop Fixes #14953 ## Motivation When `run_with_tf_optimizations` is used as a decorator inside the innermost `(batch_size, sequence_length)` loop, each iteration creates a new Python function object. Since `tf.function` keys its trace cache on function identity, a new object means a forced retrace every iteration — the cached graph is never reused. This defeats the purpose of `tf.function` and adds significant overhead from repeated graph construction and optimization passes. The [TensorFlow documentation on tracing](https://www.tensorflow.org/guide/function#rules_of_tracing) explicitly warns against defining `tf.function`-decorated functions inside loops. ## Changes **`onnxruntime/python/tools/transformers/benchmark.py`** (1 file, ~35 insertions / ~31 deletions): 1. **Hoisted forward function definitions** (`encoder_forward`, `encoder_decoder_forward`, `lxmert_forward`) from the inner `batch_size × sequence_length` loop to the per-model scope. They are now defined once per model, and the `@run_with_tf_optimizations` decorator (which applies `@tf.function`) is only invoked once per model. 2. **Changed forward functions to accept `input_ids` as a parameter** instead of closing over the loop variable. This lets `tf.function` trace based on the tensor's `(dtype, shape)` spec and reuse cached concrete functions when shapes repeat across iterations. 3. **Updated `experimental_compile=use_xla`** to **`jit_compile=use_xla`**. The `experimental_compile` parameter was deprecated in TF 2.4 (Dec 2020) and removed in TF 2.12. 4. **Moved `import random`** from the innermost loop body to before the outer model loop — the module only needs to be imported once. 5. **Moved inference function selection** (`if config.is_encoder_decoder ... elif isinstance(config, LxmertConfig) ...`) outside the batch/sequence loops since it depends only on the model config, not on batch size or sequence length. The original priority order (`is_encoder_decoder` checked before `LxmertConfig`) is preserved. ## Test Plan - [x] `lintrunner -a` passes cleanly (no RUFF or RUFF-FORMAT violations) - [x] `python -m py_compile benchmark.py` — syntax verified - [x] Change is purely structural — function behavior (inputs, outputs, control flow) is identical - [ ] Manual verification with TensorFlow installed (TF is an optional dependency not present in the standard CI matrix; this code path is exercised via `python benchmark.py -e tensorflow`)
Author
Parents
Loading