Repository navigation
[Model] Streamline EmbeddingGemma 2 config resolution and harmonize Triton prefill attention - #60289
Conversation
152012d to
3b0fa40
Compare
|
It looks like the HF config doesn't include a |
|
Hi @MatthewBonanni - yes - on the official HF repo (google/embeddinggemma-2), neither in eager PyTorch (SentenceTransformers), an uncapped 262K position embedding works fine because it only allocates memory for the actual tokens in each batch. But in vLLM, which pre-allocates KV cache and scheduler buffers based on the model's intended context length is 8K (as documented in the model card). To handle this cleanly:
this automatically caps unconstrained 262K contexts to 8,192 out of the box, while cleanly honoring explicit user overrides like --max-model-len 16384 without any scheduler-hack overhead. |
…ean up attention ops Signed-off-by: Luciano Martins <lucianommartins@users.noreply.github.com>
…local path, and revert triton diff Signed-off-by: Luciano Martins <lucianommartins@users.noreply.github.com>
68b90df to
dae6406
Compare
|
hey @MatthewBonanni @Isotr0py @ywang96 - could we move forward with this fast follow for the embeddinggemma-2 implementation? |
|
/ci run |
|
✅ @lucianommartins, CI is now available for this PR.
|
|
✅ Triggered Buildkite CI #93324 for commit |
CI selector (shadow): 151 test steps (206 jobs) instead of 65 (97 jobs)Shadow mode: this changes nothing about what CI runs. It shows what the evidence-based selector would pick for this PR, next to today's rules. How it works. Feedback welcome: reply here if it would skip a step this change needs, or runs something unrelated.
Selector would run (151)
Would skip (today's rules run them) (4)
Would add (today's rules do not run them) (90)
AMD mirrors: would skip (4)
AMD mirrors: would add (80)
3 changed files · base |
|
hey @MatthewBonanni @ywang96 - I couldn't find what failed on the other than that, all the checks passed... let's merge it? :D |
…riton prefill attention (vllm-project#60289) Signed-off-by: Luciano Martins <lucianommartins@users.noreply.github.com> Co-authored-by: Luciano Martins <lucianommartins@users.noreply.github.com> Co-authored-by: Matthew Bonanni <mbonanni@redhat.com>
Overview
This fast-follow pull request addresses review feedback and refines the initial EmbeddingGemma 2 (
google/embeddinggemma-2) integration across three focused areas:get_sentence_transformer_tokenizer_configinvllm/transformers_utils/config.py:1142to require only"max_seq_length". This enables vLLM's standardModelConfigpipeline to automatically derivemax_model_len: 8192fromsentence_bert_config.jsonwithout ad-hoc disk reads or manual CLI flags.vllm/model_executor/models/config.py(EmbeddingGemma2ModelConfig), letting vLLM's built-in scheduler derivation handle token limits natively.head_dim >= 512) invllm/v1/attention/ops/triton_prefill_attention.py. This eliminates shared memory overflow on NVIDIA Ampere and Ada hardware while composing seamlessly with upstream PR [Perf][ROCm][Attention] Narrow the Triton prefill-attention KV tile on RDNA3/RDNA4 #58225 (AMD RDNA3/4 KV tile narrowing).Claims
--max-model-len 8192on the CLI. Runningvllm serve google/embeddinggemma-2 --runner poolingautomatically resolvesmax_model_lento 8192 fromsentence_bert_config.json.max_num_batched_tokens,max_num_encoder_input_tokens,encoder_cache_size) fromEmbeddingGemma2ModelConfig, restoring canonical vLLM config flow.OutOfResources: shared memoryon NVIDIA A100 / RTX 3090 / RTX 4090 GPUs when executing bidirectional prefill withhead_dim = 512. Reduces shared memory consumption from 294,912 bytes (> 166,912 byte hardware limit) to 98,304 bytes (96 KB)._prefer_narrow_kv_tile()logic. WhenLk >= 512,BLOCKis 32, soBLOCK_N = min(32, 32)evaluates to 32 on AMD RDNA and NVIDIA alike. WhenLk < 512, PR [Perf][ROCm][Attention] Narrow the Triton prefill-attention KV tile on RDNA3/RDNA4 #58225's platform-dependent narrowing is 100% unaltered.Validation
1. Test Suite Execution & Passing Evidence
A. Kernel Attention Suite (including PR #58225 RDNA mock tests)
Result: 25/25 passed in 1.48s.
test_kv_tile_width_is_gated_by_platform[rdna]-> PASSED (BLOCK_N = 32)test_kv_tile_width_is_gated_by_platform[rocm-not-rdna]-> PASSED (BLOCK_N = 128)test_kv_tile_width_is_gated_by_platform[not-rocm]-> PASSED (BLOCK_N = 128)test_kv_tile_width_is_gated_by_platform[rdna-float32]-> PASSED (BLOCK_N = 32)test_rdna_narrows_the_kv_tile_and_nothing_else-> PASSEDB. End-to-End Embeddings Test Suite
Result: 58/58 passed.
C. Multimodal Pooling & Model Config Unit Tests
Result: 21/21 passed.
test_config_capping_and_explicit_limits: Verifies defaultTRITON_ATTNbackend selection and preservation of explicit overrides.test_sentence_transformer_tokenizer_config_max_seq_length: Verifiesget_sentence_transformer_tokenizer_configcorrectly loads configs containing onlymax_seq_length(both synthetically and from real model checkpoints).2. Verified CLI Serving Experience
Users on nightly or latest release can now launch EmbeddingGemma 2 with a clean, standard CLI command:
# Clean launch: no manual --max-model-len required! vllm serve google/embeddinggemma-2 --runner poolingEngine Startup Log Verification:
Details
1. Triton Prefill Attention Block Sizing & Harmonization with PR #58225 (For @MatthewBonanni)
A. Root Cause: Shared Memory Exhaustion on NVIDIA Hardware
In
vllm/v1/attention/ops/triton_prefill_attention.py,context_attention_fwdcomputes prefill attention tiles for encoder/bidirectional attention. For 16-bit dtypes (torch.bfloat16,torch.float16) on CUDA capability >= 80,get_block_size(q.dtype)defaults toBLOCK = 128.EmbeddingGemma 2 features full attention layers with a head dimension of
head_dim = 512(Lk = 512). WithBLOCK_M = 128andBLOCK_N = 128:Qof shape[BLOCK_M, head_dim]in BF16 requires:128 * 512 * 2 bytes = 131,072 bytes (128 KB)Kof shape[BLOCK_N, head_dim]in BF16 requires:128 * 512 * 2 bytes = 131,072 bytes (128 KB)Vof shape[BLOCK_N, head_dim]in BF16 requires:128 * 512 * 2 bytes = 131,072 bytes (128 KB)Even without multi-stage buffering, the shared memory requirement for the tiles and reduction accumulators reaches 294,912 bytes.
However, on NVIDIA Ampere (A100-SXM4-80GB), the maximum dynamic shared memory per thread block is 166,912 bytes (163 KB). Attempting to launch the kernel throws:
B. The Resolution:
if Lk >= 512: BLOCK = min(BLOCK, 32)By capping
BLOCKto 32 whenLk >= 512:Qtile (32 * 512 * 2 bytes) = 32,768 bytes (32 KB)Ktile (32 * 512 * 2 bytes) = 32,768 bytes (32 KB)Vtile (32 * 512 * 2 bytes) = 32,768 bytes (32 KB)32 KB + 32 KB + 32 KB = 98,304 bytes (96 KB)96 KB fits comfortably within the 166,912 byte limit on A100, RTX 3090, and RTX 4090, allowing kernel launch and execution with high occupancy.
C. Harmonious Composition with PR #58225
Upstream PR #58225 introduced
_prefer_narrow_kv_tile()to narrow the KV tile width (BLOCK_N) on AMD RDNA architectures (e.g. gfx1100, gfx1101, gfx1200, gfx1201) while preservingBLOCK_M = 128.In
context_attention_fwd:The table below demonstrates how the two mechanisms interact:
Lk)BLOCK(Initial)Lk >= 512CapBLOCK_M_prefer_narrow_kv_tile()BLOCK_NFormulaBLOCK_NFalseBLOCKFalseBLOCKTruemin(128, 32)FalseBLOCKFalseBLOCKTruemin(32, 32)Key Takeaways:
Lk < 512:BLOCKis unaltered, so PR [Perf][ROCm][Attention] Narrow the Triton prefill-attention KV tile on RDNA3/RDNA4 #58225 behaves identically to upstream main.Lk >= 512:BLOCK = 32, somin(BLOCK, 32)trivially evaluates tomin(32, 32) = 32. BothBLOCK_MandBLOCK_Nbecome 32 on all platforms, guaranteeing correctness and hardware safety.2. Native Sequence Length Auto-Detection & Removal of Manual Clamping (For @rogerwang)
A. The Underlying Issue in
get_sentence_transformer_tokenizer_configIn
vllm/transformers_utils/config.py:In SentenceTransformers,
sentence_bert_config.jsonstores metadata about sentence embedding models. While legacy BERT checkpoints included"do_lower_case", modern autoregressive and bidirectional models (such asgoogle/embeddinggemma-2, modern Qwen, and modern Llama embeddings) do not specify"do_lower_case".Because
"do_lower_case"was missing fromsentence_bert_config.json,all(...)evaluated toFalse. The loader silently discarded the config and returnedNone. As a consequence:config.json, which specifiedmax_position_embeddings: 262144.--max-model-len 8192explicitly to avoid allocating massive KV and scheduler buffers.B. The Fix
We relaxed the condition in
vllm/transformers_utils/config.py:1142to:Since
max_seq_lengthis the sole parameter needed by vLLM to boundmax_model_len, this allows vLLM's existingcreate_model_configlogic:to automatically discover
max_model_len = 8192during engine initialization.C. Removal of 86 Lines of Ad-Hoc Clamping Code
Because
model_config.max_model_lenis now correctly set to 8192 from the beginning of engine startup, vLLM's standard scheduler initialization logic natively sets:scheduler_config.max_num_batched_tokens = 8192scheduler_config.max_num_encoder_input_tokens = 8192scheduler_config.encoder_cache_size = 8192We were able to completely delete the 86 lines of manual JSON parsing, warning loggers, and scheduler clamping from
EmbeddingGemma2ModelConfig.verify_and_update_configinvllm/model_executor/models/config.py. The class now cleanly delegates toGemma4Configand only ensuresattention_config.backenddefaults toTRITON_ATTNif unassigned.Pull Request Checklist
/pr-checklistskill. (Mandatory for agents, optional for humans).ruffandmypy.