Skip to content

[JAX] Compare the attention tutorial to its baseline on a shorter sequence - #3828

Merged
KshitijLakhani merged 4 commits into
NVIDIA:mainfrom
aybchan:fix/jax-attention-tutorial-test-memory
Nov 7, 2026
Merged

KshitijLakhani merged 4 commits into
NVIDIA:mainfrom
aybchan:fix/jax-attention-tutorial-test-memory

Conversation

@aybchan

@aybchan aybchan commented Nov 6, 2026 •

Copy link
Copy Markdown
Member

The native baseline in the attention tutorial materializes fp32 scores, so at the tutorial's 4K sequence its backward pass needs a ~49 GiB buffer. That does not fit when CI runs several test workers per GPU, and test_bshd_gqa_swa_matches_baseline fails with RESOURCE_EXHAUSTED. Compare TE to the baseline on a 1K prefix instead.

https://github.com/NVIDIA/JAX-Toolbox/actions/runs/42178106901/job/127809077177#step:3:15983

Trace
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.416831307Z =================================== FAILURES ===================================
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.416836347Z ______________________ test_bshd_gqa_swa_matches_baseline ______________________
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.416842027Z [gpu1_worker0] linux -- Python 3.12.3 /usr/bin/python3
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.416845937Z 
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.416851197Z     @requires_hopper_or_newer
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.416856327Z     def test_bshd_gqa_swa_matches_baseline():
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.416861867Z         import attention
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.416865888Z     
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.416870448Z >       attention.compare_te_to_baseline()
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.416874908Z 
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.416879048Z opt/transformer-engine/docs/examples/jax/test_attention.py:50: 
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.416883268Z _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.416891618Z opt/transformer-engine/docs/examples/jax/attention.py:203: in compare_te_to_baseline
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.416897348Z     jax.block_until_ready((loss_ref, grads_ref, loss_te, grads_te, out_ref, out_te))
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.416901888Z _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.416905958Z 
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.416911638Z x = (<[JaxRuntimeError("RESOURCE_EXHAUSTED: Out of memory while trying to allocate 33.00GiB with allocator GPU_0_bfc on de..., dtype=bfloat16)), Array(shape=(2, 4096, 128, 128), dtype=bfloat16), Array(shape=(2, 4096, 128, 128), dtype=bfloat16))
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.416915538Z 
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.416926109Z     def block_until_ready(x):
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.416930599Z       """
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.416934759Z       Tries to call a ``block_until_ready`` method on pytree leaves.
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.416939129Z     
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.416943639Z       Args:
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.416948969Z         x: a pytree, usually with at least some JAX array instances at its leaves.
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.416953379Z     
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.416987910Z       Returns:
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.416992400Z         A pytree with the same structure and values of the input, where the values
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.416996460Z         of all JAX array leaves are ready.
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.417000491Z       """
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.417004501Z       def try_to_block(x):
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.417008701Z         try:
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.417012461Z           return x.block_until_ready()
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.417016191Z         except AttributeError:
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.417019561Z           return x
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.417023031Z     
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.417026661Z       arrays = []
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.417030801Z       for leaf in tree_leaves(x):
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.417034421Z         if isinstance(leaf, array.ArrayImpl):
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.417037781Z           arrays.append(leaf)
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.417041132Z         else:
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.417044732Z           try_to_block(leaf)
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.417048072Z     
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.417051652Z       if not arrays:
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.417055252Z         # `arrays` will be empty if tree_leaves(x) is empty or all leaves are not
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.417058662Z         # jax.Array.
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.417062002Z         pass
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.417065392Z       elif len(arrays) == 1:
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.417073062Z         # Fast path for single array.
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.417076562Z         try_to_block(arrays[0])
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.417079902Z       else:
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.417083282Z         # Optimized for multiple arrays.
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.417086633Z >       xc.batched_block_until_ready(arrays)
  [pod/te-l0-jax-unittest-42178106901-1-slice-0-0-7s5ds/gpu-image] 2026-11-06T10:03:52.417091123Z E       jax.errors.JaxRuntimeError: RESOURCE_EXHAUSTED: Out of memory while trying to allocate 33.00GiB with allocator GPU_0_bfc on device 0. [tf-allocator-allocation-error=''] [executable_name='jit_loss_fn']

Description

Please include a brief summary of the changes, relevant motivation and context.

Fixes # (issue)

Type of change

  • Documentation change (change only to the documentation, either a fix or a new content)
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Infra/Build change
  • Code refactoring

Changes

Please list the changes introduced in this PR:

  • Set attention sequence explicilty so that the test fits in memory

Checklist:

  • I have read and followed the contributing guidelines
  • The functionality is complete
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

…uence

The native baseline in the attention tutorial materializes fp32 scores,
so at the tutorial's 4K sequence its backward pass needs a ~49 GiB
buffer. That does not fit when CI runs several test workers per GPU,
and test_bshd_gqa_swa_matches_baseline fails with RESOURCE_EXHAUSTED.
Compare TE to the baseline on a 1K prefix instead.

Signed-off-by: Alex Y. Chan <alechan@nvidia.com>
@greptile-apps

greptile-apps Bot commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Low impact] The PR appears safe to merge.

Summary

The PR compares attention outputs and gradients on a 1,024-token prefix to reduce GPU memory use.

  • The attention comparison checks matching 1,024-token prefixes.

Reviews (4) · Last reviewed commit: "[JAX] Generalize the attention tutorial ..." · Reviewed by Greptile

@jberchtold-nvidia

Copy link
Copy Markdown
Collaborator

/te-ci L1 jax

@KshitijLakhani KshitijLakhani left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this change, Alex !

This change also does not affect the rendered tutorial (4k) and the static numbers displayed for it (for 4k) as well. So the tutorial users will see a cohesive tutorial.

@aybchan test_single_gpu_benchmark also uses the same sizes but of course I do not think it might be retaining the native buffers for a comparison at the end and so you might not see the same issue that you are fixing in this PR for test_bshd_gqa_swa_matches_baseline intest_single_gpu_benchmark - but it would be good to confirm and if needed, add that change in this PR as well. However, I'd expect it be fine as is - in which case we should be good to go

assert out.dtype == attention.dtype


@requires_hopper_or_newer

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

requires_hopper_or_newer = pytest.mark.skipif(
    get_device_compute_capability(0) < 90,
    reason="the 4K native JAX baseline requires more than 48 GiB of device memory",
)

Which would technically not be true for this case (1k instead of 4k) so maybe add a single line comment for this here.

Comment thread docs/examples/jax/test_attention.py Outdated
Comment on lines +51 to +53
# The native baseline materializes fp32 attention scores, so at the tutorial's 4K
# sequence its backward pass needs a ~49 GiB buffer, which does not fit when CI runs
# several test workers per GPU. Compare on a 1K prefix instead (1/16 of the memory).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# The native baseline materializes fp32 attention scores, so at the tutorial's 4K
# sequence its backward pass needs a ~49 GiB buffer, which does not fit when CI runs
# several test workers per GPU. Compare on a 1K prefix instead (1/16 of the memory).
# The native baseline materializes fp32 attention scores, so at the tutorial's 4K
# sequence its backward pass needs a much larger buffer, which does not fit when CI runs
# several test workers per GPU. Compare on a smaller prefix instead

nit: make this a bit generic with the wording as these numbers can change based on how XLA/JAX decides to build in the future so a general note is fine :)

@aybchan

aybchan commented Nov 6, 2026

Copy link
Copy Markdown
Member Author

I have not seen that failure on our side but I will bear it in mind if we do come across it.

Describe the native baseline's backward buffer without a specific size,
since the allocation XLA makes can change between versions, and note
that the Hopper skip reason refers to the 4K baseline rather than the
1K comparison.

Signed-off-by: Alex Y. Chan <alechan@nvidia.com>
@KshitijLakhani
KshitijLakhani merged commit 3a6ea8f into NVIDIA:main Nov 7, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants