Repository navigation
Conversation
|
The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update. |
vasqu
left a comment
There was a problem hiding this comment.
Ok long review but trying to summarize my key points here
- The cache handling imo should happen at the same update where we call the base cache. It's a bit weird to hide this (with a different cache name). It would be nice if we really could just hide it within the update
- Similar for the masking, I'd rather we hide this in the masking utils. We already pass the cache there so it should be unifiable
- There are a lot of unrelated changes to refactor the code. In some cases it might be necessary but in others it's just to make the code refactored. In my eyes as reviewer it's hard to judge what is truly necessary now. Additionally, we risk potentially being very breaking, a lot of other libraries rely on our existing functions so renames or removals will be a high risk. Better to isolate what is truly necessary
| _use_top_left_mask = flash_attn_supports_top_left_mask() | ||
|
|
||
|
|
||
| def get_target_dtype(query: torch.Tensor, module: torch.nn.Module) -> torch.dtype: |
There was a problem hiding this comment.
removing this is breaking, any reason we don't keep the same order and just pass the extracted target dtype? (as before)
There was a problem hiding this comment.
I just found the design weird TBH: target_dtype is computed here, but it is not used before entering the modeling_flash_attention_utils file, which itself calls a function to do the cast, as soon as _flash_attention_forward is entered. It seems to make sense just to cast the tensors before entering the _flash_attention_forward and to fuse get_target_dtype and the casting fn, both of which are only used once.
But I agree I went a little too fast and this is breaking, so reverting, but this could simplify the code a bit.
| # This might slowdown training & inference so it is recommended to not cast the LayerNorms | ||
| # in fp32. (usually our RMSNorm modules handle it correctly) | ||
| target_dtype = get_target_dtype(query, module) | ||
| # _flash_attention_forward needs non-transposed inputs, with shape [batch_size, seq_len, num_heads, head_dim] |
There was a problem hiding this comment.
| # _flash_attention_forward needs non-transposed inputs, with shape [batch_size, seq_len, num_heads, head_dim] | |
| # FA uses non-transposed inputs |
let's keep it simple no?
There was a problem hiding this comment.
If it's ok for you I prefer to leave some shape hints, it's always one of the most confusing part when reading the code IMO. Simplified the beginning tho.
| @torch.compiler.disable | ||
| def _uncompiled_flash_attention_forward(**kwargs) -> torch.Tensor: | ||
| return _flash_attention_forward(**kwargs) |
There was a problem hiding this comment.
I feel like im missing context here: why are we intentionally introducing a graph break here? Ideally the modeling flash attn utils should mark those portions only no? i assume it's due to paged FA doing something compile incompatible
There was a problem hiding this comment.
Exactly. I think before I marked the whole function because I already had a graph break at the update, so adding a second graph break just around the attention actually made things worst. But now that the update is outside the second flash attention function, it makes less sense.
| # Compile is disabled because the cache update mutates in place aliased views of the cache tensor, which compile's | ||
| # functionalization handles by making a copy of the full cache for every layer. |
There was a problem hiding this comment.
ok here it is then, but I feel like we tackle this too early and modeling flash attn utils should differentiate between paged call or not and mark it only there. this feels to early / too preemptive
There was a problem hiding this comment.
I see what you mean. Will run some benchmarks to see where it's best to put it.
| if attention_mask is not None: | ||
| padded_out = torch.zeros((batch_size * query_length, *out.shape[1:]), device=out.device, dtype=out.dtype) | ||
| padded_out[indices_q] = out | ||
| return padded_out.view(batch_size, query_length, *out.shape[1:]) |
There was a problem hiding this comment.
this is weird as well was this _pad before?
There was a problem hiding this comment.
Yes but it is called only once, and it is 3 lines of code, might as well inline it no?
| query_length: int, | ||
| is_causal: bool, | ||
| dropout: float = 0.0, | ||
| position_ids: torch.Tensor | None = None, | ||
| softmax_scale: float | None = None, | ||
| sliding_window: int | None = None, | ||
| use_top_left_mask: bool = False, | ||
| softcap: float | None = None, | ||
| deterministic: bool | None = None, | ||
| cu_seq_lens_q: torch.LongTensor | None = None, | ||
| cu_seq_lens_k: torch.LongTensor | None = None, | ||
| max_length_q: int | None = None, | ||
| max_length_k: int | None = None, | ||
| target_dtype: torch.dtype | None = None, |
There was a problem hiding this comment.
A lot of breaking stuff happening here, changing the signature and all, also not sure if it's completely necessary. As mentioned before let's keep the diff to a minimum?
There was a problem hiding this comment.
A lot of those were deleted because they are always passed as a kwarg, and only used in the processing kwarg. So it's exactly the same behavior, unless someone call this with only positionnal arguments. WDYT ?
| # It is safe to use `flash_varlen_fn` knowing we already have all necessary the kwargs. | ||
|
|
||
| is_fa_with_varlen_kwargs = None not in (cu_seq_lens_q, cu_seq_lens_k, max_length_q, max_length_k) | ||
| is_fa_with_block_table = None not in (k_cache, v_cache, cache_seqlens, block_table) |
There was a problem hiding this comment.
Imo the only portion we need is a block after varlen and before the base fa where we check that these kwargs indeed exist
| ) | ||
|
|
||
| # Extract the flash attention kwargs that have been requested (and are supported by the implementation) | ||
| flash_kwargs = partial( |
There was a problem hiding this comment.
we delay this call either way so doesn't hurt to keep?
There was a problem hiding this comment.
Yes but it is not used for the paged version. Although I could unify the two.
There was a problem hiding this comment.
We probably do need to freeze this tho to keep some deprecation cycle in (so not immediate delete)
|
[For maintainers] Suggested jobs to run (before merge) run-slow: bark, falcon, gpt_neo, gptj |
CI recapDashboard: View test results in Grafana
|
|
Not discarding this PR, but closing in favor of a stack of PR starting with #49069 |
Draft