Skip to content

[Perf] Use SDPA for BLIP-2 Q-Former attention - #55285

Merged
Isotr0py merged 3 commits into
vllm-project:mainfrom
Levius-Fubuki:perf/blip2-qformer-sdpa
Sep 6, 2026
Merged

Isotr0py merged 3 commits into
vllm-project:mainfrom
Levius-Fubuki:perf/blip2-qformer-sdpa

Conversation

@Levius-Fubuki

@Levius-Fubuki Levius-Fubuki commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Purpose

BLIP-2 Q-Former attention currently materializes the attention scores, applies
scaling and softmax separately, and launches a second matrix multiplication:

before: {matmul: 2, mul: 1, softmax: 1, dropout: 1}
after:  {scaled_dot_product_attention: 1}

This PR uses standard torch.nn.functional.scaled_dot_product_attention for
both Q-Former self-attention and cross-attention. It preserves the existing
scale and training dropout behavior while allowing PyTorch to dispatch fused
attention kernels.

This removes the score-sized attention intermediate and the separate scale,
softmax, dropout, and value-matmul launches. It keeps one portable PyTorch path
with no custom kernel, architecture gate, device branch, or device-specific
tuning.

I searched the open PRs for BLIP-2, Q-Former, and SDPA changes and found no
active PR addressing this attention path.

Test Plan

Lint

ruff check vllm/model_executor/models/blip2.py
ruff format --check vllm/model_executor/models/blip2.py
git diff --check origin/main..HEAD

RTX 4090 default eager encoder benchmark

The performance harness constructs the real
Blip2ForConditionalGeneration class with BLIP-2-compatible dimensions and
invokes its real embed_multimodal boundary. Both variants use identical,
finite, deterministic weights.

Hardware/software: NVIDIA RTX 4090, CUDA 13.0, PyTorch 2.13.0+cu130.
Timing uses 25 warmups, 200 iterations, and five alternating repeats.

Dtype Batch Scope Old p50 (us) New p50 (us) Speedup
FP16 1 Q-Former 1519.28 1049.77 1.45x
FP16 4 Q-Former 1521.30 1006.97 1.51x
BF16 1 Q-Former 1504.88 1052.73 1.43x
BF16 4 Q-Former 1565.29 1088.26 1.44x
FP16 1 embed_multimodal 2797.99 2322.34 1.20x
FP16 4 embed_multimodal 2744.05 2196.03 1.25x
BF16 1 embed_multimodal 2691.73 2248.67 1.20x
BF16 4 embed_multimodal 2748.79 2177.32 1.26x

The Q-Former geometric-mean speedup is 1.48x for FP16 and 1.43x for BF16.
All eight rows passed numerical, finite-value, repeatability, shape, and
input-mutation validation with no performance regression.

Q-Former peak extra allocation decreased from 1,579,008 to 1,237,504 bytes at
batch 1, and from approximately 7.3 MiB to 5.1 MiB at batch 4.

Profiler results replace 80 aten::bmm calls and 40 separate softmax calls per
ten Q-Former invocations with 40 aten::scaled_dot_product_attention calls.
All candidate calls dispatch to aten::_flash_attention_forward.

The harness, raw CSV, gate result, and profiler summary are available in the
benchmark artifact Gist.

Test Result

ruff-check, ruff-format, and git diff --check passed.

Limitations

These results come from one RTX 4090 run with deterministic weights, not a
full pretrained BLIP-2 checkpoint or end-to-end request throughput benchmark.

Current BLIP-2 does not implement SupportsEncoderCudaGraph, and runtime hooks
confirmed that Q-Former executes on the default eager multimodal encoder path.
No CUDA Graph performance claim is made. If BLIP-2 gains encoder CUDA Graph
support later, batch-1 short-key shapes should be benchmarked again before
enabling capture.

No performance claim is made for other architectures, devices, or PyTorch
versions. Full upstream cross-backend CI still requires a maintainer ready
or verified label.

AI assistance

AI assistance was used during implementation, testing, benchmarking, and PR
drafting. The human contributor reviewed and takes responsibility for the
change and evidence.

Signed-off-by: levius <2114377220@qq.com>
Copilot AI lite review requested due to automatic review settings September 4, 2026 04:36

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@mergify mergify Bot added the multi-modality Related to multi-modality (#4194) label Sep 4, 2026
@coderabbitai

coderabbitai Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Team

Run ID: 20356b14-3a4b-473a-aa9b-099cd07e5ffd

📥 Commits

Reviewing files that changed from the base of the PR and between 8a72866 and a355307.

📒 Files selected for processing (2)
  • tests/models/multimodal/test_blip2_qformer_attention.py
  • vllm/model_executor/models/blip2.py

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Summary

Summary by CodeRabbit

  • Performance

    • Improved BLIP-2 Q-Former attention execution by using PyTorch’s optimized scaled dot-product attention.
  • Bug Fixes

    • Preserved attention scaling and training-time dropout behavior for self- and cross-attention.
  • Tests

    • Added CPU coverage validating attention outputs, optimized attention usage, output properties, and dropout behavior.

Walkthrough

Blip2QFormerMultiHeadAttention.forward now uses F.scaled_dot_product_attention with explicit scaling and training-aware dropout. New CPU tests cover self-attention, cross-attention, reference parity, output properties, SDPA usage, and dropout behavior.

Changes

Q-Former SDPA attention

Layer / File(s) Summary
Replace manual attention with SDPA
vllm/model_executor/models/blip2.py
The forward pass replaces manual score calculation, softmax, dropout, and value aggregation with F.scaled_dot_product_attention.
Validate attention outputs and dropout
tests/models/multimodal/test_blip2_qformer_attention.py
CPU tests compare self- and cross-attention outputs with a reference implementation. The tests also verify SDPA usage, output properties, finite values, and training-mode dropout variation.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to 37e27

Q-Former attention now uses PyTorch scaled dot-product attention while preserving scaling, output layout, and training-only dropout behavior. Self- and cross-attention parity and dropout coverage support merge readiness with no identified current risk.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 6 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely describes the main change: using SDPA for BLIP-2 Q-Former attention.
Description check ✅ Passed The description directly explains the SDPA implementation, preserved behavior, tests, benchmarks, and limitations. It is relevant to the changeset.
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

attention_probs_dropped = self.dropout(attention_probs)

context_layer = torch.matmul(attention_probs_dropped, value_layer)
context_layer = F.scaled_dot_product_attention(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this in the Transformers code? cc @hmellor

@hmellor hmellor Sep 4, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Not really, but it could.

Blip2QFormerMultiHeadAttention in Transformers uses the ALL_ATTENTION_FUNCTIONS registry but the Blip2QFormerConfig does not specify _attn_implementation. So, it falls back to eager_attention_forward:

def eager_attention_forward(
    module: nn.Module,
    query: torch.Tensor,
    key: torch.Tensor,
    value: torch.Tensor,
    attention_mask: torch.Tensor | None,
    scaling: float,
    dropout: float = 0.0,
    **kwargs,
):
    attn_weights = torch.matmul(query, key.transpose(-1, -2)) * scaling
    if attention_mask is not None:
        attn_weights = attn_weights + attention_mask

    attn_weights = nn.functional.softmax(attn_weights, dim=-1)
    attn_weights = nn.functional.dropout(attn_weights, p=dropout, training=module.training)

    attn_output = torch.matmul(attn_weights, value)
    attn_output = attn_output.transpose(1, 2).contiguous()

    return attn_output, attn_weights

However if the config had been configured with "sdpa" then it would have called sdpa_attention_forward in Transformers.

@DarkLight1337 DarkLight1337 Sep 4, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I wonder whether we could simply use vllm-native MMEncoderAttention for this? @Isotr0py

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we can use MMEncoderAttention since it's just a normal bidirectional attention here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Would MMEncoderAttention also support the Q-Former cross-attention case where q_len != kv_len (e.g. 32 vs 257)? I may be missing something, but the current Flash/Triton wrappers seem to reuse sequence metadata derived from q_len for K/V.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I see, let's use F.sdpa here then

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please remove this redundant test

@Isotr0py
Isotr0py enabled auto-merge (squash) September 6, 2026 03:37
@Isotr0py

Isotr0py commented Sep 6, 2026

Copy link
Copy Markdown
Member

/ci run

@github-actions github-actions Bot added the ready ONLY add when PR is ready to merge/full CI is needed label Sep 6, 2026
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown

✅ Triggered Buildkite CI #87415 for commit 37e277184138.

@Levius-Fubuki

Copy link
Copy Markdown
Contributor Author

Hi @Isotr0py, the full Buildkite CI has passed. It looks like the earlier pre-run-check failure is still blocking the PR because it ran before the ready label was added. Would you mind rerunning it when convenient?

@DarkLight1337

Copy link
Copy Markdown
Member

Retrying

@Isotr0py
Isotr0py merged commit a1541f5 into vllm-project:main Sep 6, 2026
104 of 105 checks passed
ItsRoy69 pushed a commit to ItsRoy69/vllm that referenced this pull request Sep 10, 2026
Signed-off-by: levius <2114377220@qq.com>
Signed-off-by: Isotr0py <Isotr0py@outlook.com>
Co-authored-by: Isotr0py <Isotr0py@outlook.com>
Signed-off-by: Jyotirmoy Roy <jyotirmoyroy649@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

multi-modality Related to multi-modality (#4194) ready ONLY add when PR is ready to merge/full CI is needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants