Repository navigation
[generate] Fix CUDAGraphs tensor overwrite for encoder-decoder static cache #48199
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
7d2a05a
0e9de38
a611fca
564e3fa
f544b29
892f355
347b9fc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1885,9 +1885,34 @@ def _prepare_static_cache( | |
| "offloading": offload_cache, | ||
| } | ||
| cache = EncoderDecoderCache(cache, StaticCache(**cross_attention_cache_kwargs)) | ||
|
|
||
| if self.config.is_encoder_decoder: | ||
| assert isinstance(cache, EncoderDecoderCache) # always true: assigned above when is_encoder_decoder | ||
| # Eagerly initialize the K/V buffers so that `mark_static_address` is applied before any | ||
| # `torch.compile` / CUDAGraph capture context. Without this, `lazy_initialization` runs inside | ||
| # graph capture (where `is_torchdynamo_compiling()` is True), causing `mark_static_address` to | ||
| # be skipped. CUDAGraphs then treats those tensors as pooled memory and can overwrite them | ||
| # between runs, raising: | ||
| # "accessing tensor output of CUDAGraphs that has been overwritten by a subsequent run" | ||
| # BOTH self-attention and cross-attention caches need early init: cross-attention K/V are | ||
| # computed from encoder hidden states on the first decode step, which happens inside the | ||
| # compiled graph, so they suffer the same lazy-init-inside-capture problem. | ||
| # Skipped when the cache cannot be initialized on a single device. | ||
| init_shape = self._get_static_cache_init_shape() | ||
| if init_shape is not None: | ||
| num_heads, head_dim = init_shape | ||
| early_init_kwargs = { | ||
| "batch_size": batch_size, | ||
| "num_heads": num_heads, | ||
| "head_dim": head_dim, | ||
| "dtype": self.dtype, | ||
| "device": self.device, | ||
| } | ||
| cache.self_attention_cache.early_initialization(**early_init_kwargs) | ||
| cache.cross_attention_cache.early_initialization(**early_init_kwargs) | ||
|
Comment on lines
+1888
to
+1912
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Cyrilvallez Let me know if you still want to have this fix only in T5 modeling code. I think the issue is there for all encoder-decoder models, but among them, only T5 has
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
For 1. I could also see some adjustments for
Comment on lines
+1891
to
+1912
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't get it, I believe all this comment is wrong since prefill is never compiled - since it's an AI comment, I believe the AI probably hallucinated it
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the note! To clarify: "the compiled graph" in the comment refers to the compiled decoder step, not the encoder. The encoder runs eagerly, but the cross-attention K/V computation (and lazy_initialization) happens on the first decoder step, which is inside the compiled graph — that's where mark_static_address gets skipped. |
||
| elif prefill_chunk_size is not None: | ||
| # Chunked prefill compiles the prefill, so eagerly init the fresh cache to avoid a recompile next call | ||
| # (#46421). Skipped (-> lazy init) when it can't be initialized on a single device. | ||
| # Chunked prefill compiles the prefill, so eagerly init the fresh cache to avoid a recompile | ||
| # next call (#46446). Skipped (-> lazy init) when it can't be initialized on a single device. | ||
| init_shape = self._get_static_cache_init_shape() | ||
| if init_shape is not None: | ||
| num_heads, head_dim = init_shape | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this
isinstance(cache, EncoderDecoderCache)is to avoid Pyright (check_types.py) complain (fail)