Skip to content

graph: pad the KV dimension of the no-cache attention to 256 - #30416

Merged
ServeurpersoCom merged 1 commit into
masterfrom
pascal/no-cache-kv-pad
Oct 12, 2026
Merged

ServeurpersoCom merged 1 commit into
masterfrom
pascal/no-cache-kv-pad

Conversation

@ServeurpersoCom

Copy link
Copy Markdown
Contributor

Overview

Embedding and encoder models run attention without a KV cache, and that path did not pad the keys/values to a multiple of 256 like the KV cache does. Some CUDA flash attention kernels (head size 512, e.g. EmbeddingGemma 2) need that padding, so attention silently fell back to the CPU for most input lengths, and -fa auto turned flash attention off entirely.

This pads the mask and K/V to 256 in the no-cache path. With EmbeddingGemma 2 on CUDA, 3841 tokens goes from 363 ms to 58 ms, -fa auto keeps flash attention on, and the embeddings are unchanged.

Additional information

Fixes #30398

Requirements

The no-cache path builds a [n_tokens, n_tokens] mask and passes K and V
unpadded, so FLASH_ATTN_EXT sees K->ne[1] == n_tokens. The CUDA kernels
for head size 512 require a multiple of FATTN_KQ_STRIDE, so the op falls
back to the CPU for most lengths, and the -fa auto probe (1 token)
disables flash attention for such models.

Pad the mask like llama_kv_cache::get_n_kv and pad K and V with zeros up
to the KV dimension of the mask. clef builds its own causal mask and
pads it the same way.
@ServeurpersoCom
ServeurpersoCom requested a review from CISC as a code owner October 12, 2026 20:18
@github-actions github-actions Bot added the model Model specific label Oct 12, 2026
@CISC
CISC requested a review from ggerganov October 12, 2026 20:26
@ServeurpersoCom
ServeurpersoCom merged commit 358a420 into master Oct 12, 2026
15 of 18 checks passed
@ggerganov
ggerganov deleted the pascal/no-cache-kv-pad branch October 13, 2026 07:48
@deadprogram

Copy link
Copy Markdown
Contributor

Hello, I ran into a failure in the yzma test suite, and tracked it back here. The following is an edited version of my automated analysis.

The T5 encoder now aborts in llama_encode since #30416

ggml.c:2072: GGML_ASSERT(ggml_can_repeat(b, a)) failed
  llm_graph_context::build_attn_mha
  llm_graph_context::build_attn(llm_graph_input_attn_no_cache *, ...)
  llama_model_t5::graph<true>
  llama_model_t5encoder::build_arch_graph
  llama_context::encode

T5 passes a relative position bias as kq_b, built from pos_bucket_enc with shape [n_tokens, n_tokens]. The mask and K/V are now padded to 256, so kq is [n_kv, n_tokens] and the add with kq_b fails. With the pad now unconditional it fails for every batch size.

b11574 works and b11576 and b11583 fail. You can repro with https://huggingface.co/callgg/t5-base-encoder-f32/resolve/main/t5base-encoder-q4_0.gguf by calling llama_encode on any short prompt.

Thank you.

@deadprogram

Copy link
Copy Markdown
Contributor

Please see above @ggerganov

@ServeurpersoCom

Copy link
Copy Markdown
Contributor Author

Hello, I ran into a failure in the yzma test suite, and tracked it back here. The following is an edited version of my automated analysis.

The T5 encoder now aborts in llama_encode since #30416

ggml.c:2072: GGML_ASSERT(ggml_can_repeat(b, a)) failed
  llm_graph_context::build_attn_mha
  llm_graph_context::build_attn(llm_graph_input_attn_no_cache *, ...)
  llama_model_t5::graph<true>
  llama_model_t5encoder::build_arch_graph
  llama_context::encode

T5 passes a relative position bias as kq_b, built from pos_bucket_enc with shape [n_tokens, n_tokens]. The mask and K/V are now padded to 256, so kq is [n_kv, n_tokens] and the add with kq_b fails. With the pad now unconditional it fails for every batch size.

b11574 works and b11576 and b11583 fail. You can repro with https://huggingface.co/callgg/t5-base-encoder-f32/resolve/main/t5base-encoder-q4_0.gguf by calling llama_encode on any short prompt.

Thank you.

Thanks for the report and the precise analysis! The T5 relative position bias was not padded along with K and V, it's fixed in #30446. I tested it with the t5-base-encoder q4_0 you linked: lengths from 2 to 511 tokens now work on CUDA and CPU, and the lengths that already worked give bit exact results. Could you also give it a try with the yzma test suite and confirm it works on your side?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

model Model specific

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Eval bug: EmbeddingGemma 2 with -fa on runs attention on the CPU unless the token count is a multiple of 256

4 participants