Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
f93fcf4
Enable attention output FP8 fusion for V1 attention backends
gshtras Jun 17, 2025
9417465
reformat
gshtras Jun 17, 2025
f7ac2b8
Merge remote-tracking branch 'origin/main' into attention_fusion_v1
gshtras Jun 17, 2025
845e40c
No longer disabling noop and fusion in V1 graph mode
gshtras Jun 18, 2025
f3eb6cb
Restrict triton attention fusion to per tensor scaling
gshtras Jun 18, 2025
a7e64d7
Merge remote-tracking branch 'origin/main' into attention_fusion_v1
gshtras Jun 18, 2025
01e6130
Fix the fusion pattern to account fot the output tensot ro be initial…
gshtras Jun 19, 2025
61f7551
Merge remote-tracking branch 'origin/main' into attention_fusion_v1
gshtras Jun 25, 2025
f9e195a
V1 unit tests
gshtras Jun 30, 2025
0c94a0d
Using the updated test backend
gshtras Jun 30, 2025
e528023
TEMP fixed tests (except output)
ProExpertProg Jun 27, 2025
a2c2bc2
Cleanup and attempt to use an inverse scale
gshtras Jul 1, 2025
4646027
Another inverted scale for the V1 split attn prefill path
gshtras Jul 1, 2025
97759d3
Using empty tensors with matching dtype
gshtras Jul 1, 2025
3e1f552
Merge remote-tracking branch 'upstream/main' into attention_fusion_v1
gshtras Jul 8, 2025
4ebb561
Merge remote-tracking branch 'origin/main' into attention_fusion_v1
gshtras Jul 14, 2025
15ba786
Fix the new test. Rename parameters
gshtras Jul 14, 2025
76e7a01
Remove deprecated parameter
gshtras Jul 14, 2025
8310c81
Add quant custom op in the test
gshtras Jul 14, 2025
a394548
Rename parameter names at call sites
gshtras Jul 14, 2025
fb8c9f6
I will always press save after pressing reformat
gshtras Jul 14, 2025
2b467a4
Remove memory restrictions
gshtras Jul 14, 2025
96d201f
linter
gshtras Jul 14, 2025
b52e5f0
Merge remote-tracking branch 'origin/main' into attention_fusion_v1
gshtras Jul 16, 2025
62a1451
Skip attn fusion test on CUDA. Fusion is not applicable to the CUDA F…
gshtras Jul 16, 2025
ff5e1b8
Try to force triton attention on cuda in the test
gshtras Jul 16, 2025
16078b7
Format
gshtras Jul 16, 2025
6df13c2
Remove debug leftovers
gshtras Jul 28, 2025
7430120
Try out the process per test decorator
gshtras Jul 28, 2025
3418837
Syntax
gshtras Jul 28, 2025
d148c55
Merge remote-tracking branch 'origin/main' into attention_fusion_v1
gshtras Jul 29, 2025
3bde9ad
Merge remote-tracking branch 'origin/main' into attention_fusion_v1
gshtras Aug 6, 2025
0e8b47f
Remove the print
gshtras Aug 6, 2025
ea3e55a
Merge remote-tracking branch 'origin/main' into attention_fusion_v1
gshtras Aug 6, 2025
becbd2f
Trying to figure out why the test passes on ROCm, but OOMs on CUDA
gshtras Aug 6, 2025
61c34ae
Spawn in itself doesn't seem to work on CUDA
gshtras Aug 7, 2025
8b42595
Trying to fit into the memory constrains of the CI CUDA machines
gshtras Aug 8, 2025
3f309e8
Merge remote-tracking branch 'origin/main' into attention_fusion_v1
gshtras Sep 2, 2025
c99f236
Fixed pattern and unit tests
gshtras Sep 3, 2025
c03d469
Merge remote-tracking branch 'origin/main' into attention_fusion_v1
gshtras Sep 3, 2025
6c46e87
Add dtype to the v0 test
gshtras Sep 4, 2025
4422fcf
Add float16 to test. Gate it on cuda-alike platforms. Refactor common…
gshtras Sep 5, 2025
d33bc75
Merge remote-tracking branch 'origin/main' into attention_fusion_v1
gshtras Sep 5, 2025
f14f017
Less explicit model variables name
gshtras Sep 8, 2025
998421c
Merge remote-tracking branch 'origin/main' into attention_fusion_v1
gshtras Sep 8, 2025
8a1333e
Merge remote-tracking branch 'origin/main' into attention_fusion_v1
gshtras Sep 9, 2025
747d55c
Merge remote-tracking branch 'origin/main' into attention_fusion_v1
gshtras Sep 9, 2025
cb94169
cleanup test checks (#663)
ProExpertProg Sep 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions vllm/attention/ops/chunked_prefill_paged_decode.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

from .prefix_prefill import context_attention_fwd

float8_info = torch.finfo(current_platform.fp8_dtype())


@triton.jit
def cdiv_fn(x, y):
Expand All @@ -34,6 +36,7 @@ def kernel_paged_attention_2d(
scale, # float32
k_scale, # float32
v_scale, # float32
out_scale,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Can we call this out_descale or out_scale_inv?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Arguably this name is now more correct after the inversion since now we're multiplying by it inside the kernel

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Yes but I think the convention in vllm is that x_scale is the scaling factor for x in the quantized representation, and so this is the inverse of the scaling factor.

num_query_heads: tl.constexpr, # int
num_queries_per_kv: tl.constexpr, # int
num_queries_per_kv_padded: tl.constexpr, # int
Expand All @@ -59,7 +62,9 @@ def kernel_paged_attention_2d(
stride_v_cache_3: tl.int64, # int
filter_by_query_len: tl.constexpr, # bool
query_start_len_ptr, # [num_seqs+1]
):
USE_FP8: tl.constexpr,
FP8_MIN: tl.constexpr = float8_info.min,
FP8_MAX: tl.constexpr = float8_info.max):
seq_idx = tl.program_id(0)
kv_head_idx = tl.program_id(1)

Expand Down Expand Up @@ -193,6 +198,9 @@ def kernel_paged_attention_2d(

# epilogue
acc = acc / L[:, None]
if USE_FP8:
acc = acc / tl.load(out_scale)
Comment thread
ProExpertProg marked this conversation as resolved.
Outdated
acc = tl.clamp(acc, FP8_MIN, FP8_MAX)

output_offset = (cur_batch_in_all_start_index * output_stride_0 +
query_head_idx * output_stride_1)
Expand Down Expand Up @@ -223,6 +231,7 @@ def chunked_prefill_paged_decode(
alibi_slopes=None,
sliding_window=None,
sm_scale=None,
output_scale=None,
):

if sm_scale is None:
Expand Down Expand Up @@ -253,6 +262,7 @@ def chunked_prefill_paged_decode(
sliding_window=sliding_window,
sm_scale=sm_scale,
skip_decode=True,
fp8_out_scale=output_scale,
)

block_size = value_cache.shape[3]
Expand Down Expand Up @@ -295,7 +305,7 @@ def chunked_prefill_paged_decode(
tmp_output = torch.empty(
size=(total_num_seq, num_query_heads, max_num_partitions,
head_size),
dtype=output.dtype,
dtype=query.dtype,
Comment thread
ProExpertProg marked this conversation as resolved.
device=output.device,
)
exp_sums = torch.empty(
Expand Down Expand Up @@ -324,6 +334,7 @@ def chunked_prefill_paged_decode(
kv_cache_dtype=kv_cache_dtype,
k_scale=k_scale,
v_scale=v_scale,
fp8_out_scale=output_scale,
)
else:
kernel_paged_attention_2d[(
Expand All @@ -340,6 +351,7 @@ def chunked_prefill_paged_decode(
scale=sm_scale,
k_scale=k_scale,
v_scale=v_scale,
out_scale=output_scale,
num_query_heads=num_query_heads,
num_queries_per_kv=num_queries_per_kv,
num_queries_per_kv_padded=num_queries_per_kv_padded,
Expand All @@ -365,4 +377,5 @@ def chunked_prefill_paged_decode(
stride_v_cache_3=value_cache.stride(3),
filter_by_query_len=True,
query_start_len_ptr=query_start_loc,
USE_FP8=output_scale is not None,
)
15 changes: 13 additions & 2 deletions vllm/attention/ops/prefix_prefill.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

# To check compatibility
IS_TURING = current_platform.get_device_capability() == (7, 5)
float8_info = torch.finfo(current_platform.fp8_dtype())


# Here's an example autotuner config for this kernel. This config does provide
Expand Down Expand Up @@ -42,6 +43,7 @@ def _fwd_kernel(Q,
sm_scale,
k_scale,
v_scale,
out_scale,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Same here

B_Start_Loc,
B_Seqlen,
x: tl.constexpr,
Expand Down Expand Up @@ -80,8 +82,11 @@ def _fwd_kernel(Q,
num_unroll_cache: tl.constexpr,
num_unroll_request: tl.constexpr,
SKIP_DECODE: tl.constexpr,
USE_FP8: tl.constexpr,
MAX_Q_LEN: tl.constexpr = 0,
MAX_CTX_LEN: tl.constexpr = 0):
MAX_CTX_LEN: tl.constexpr = 0,
FP8_MIN: tl.constexpr = float8_info.min,
FP8_MAX: tl.constexpr = float8_info.max):

cur_batch = tl.program_id(0)
cur_head = tl.program_id(1)
Expand Down Expand Up @@ -274,6 +279,9 @@ def _fwd_kernel(Q,
off_o = ((cur_batch_in_all_start_index + offs_m[:, None]) * stride_obs +
cur_head * stride_oh + offs_d[None, :] * stride_od)
out_ptrs = Out + off_o
if USE_FP8:
acc = acc / tl.load(out_scale)
Comment thread
ProExpertProg marked this conversation as resolved.
Outdated
acc = tl.clamp(acc, FP8_MIN, FP8_MAX)
tl.store(out_ptrs,
acc,
mask=dim_mask[None, :] & (offs_m[:, None] < cur_batch_query_len))
Expand Down Expand Up @@ -732,7 +740,8 @@ def context_attention_fwd(q,
alibi_slopes=None,
sliding_window=None,
sm_scale=None,
skip_decode=False):
skip_decode=False,
fp8_out_scale=None):

q_dtype_is_f32 = q.dtype is torch.float32

Expand Down Expand Up @@ -857,6 +866,7 @@ def context_attention_fwd(q,
sm_scale,
k_scale,
v_scale,
fp8_out_scale,
b_start_loc,
b_seq_len,
k_cache.shape[4],
Expand Down Expand Up @@ -892,6 +902,7 @@ def context_attention_fwd(q,
BLOCK_DMODEL_PADDED=Lk_padded,
SLIDING_WINDOW=sliding_window,
SKIP_DECODE=skip_decode,
USE_FP8=fp8_out_scale is not None,
BLOCK_M=128,
BLOCK_N=64,
num_unroll_cache=4,
Expand Down
22 changes: 22 additions & 0 deletions vllm/attention/ops/triton_unified_attention.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
import triton.language as tl

from vllm.logger import init_logger
from vllm.platforms import current_platform

logger = init_logger(__name__)
float8_info = torch.finfo(current_platform.fp8_dtype())


@triton.jit
Expand Down Expand Up @@ -59,6 +61,7 @@ def kernel_unified_attention_2d(
scale, # float32
k_scale, # float32
v_scale, # float32
out_scale, # float32
softcap, # float32
num_query_heads: tl.constexpr, # int
num_queries_per_kv: tl.constexpr, # int
Expand All @@ -85,6 +88,9 @@ def kernel_unified_attention_2d(
BLOCK_Q: tl.constexpr, # int
num_seqs: tl.int32,
BLOCK_M: tl.constexpr, # int
USE_FP8: tl.constexpr, # bool
FP8_MIN: tl.constexpr = float8_info.min,
FP8_MAX: tl.constexpr = float8_info.max,
):
q_block_global_idx = tl.program_id(0)
kv_head_idx = tl.program_id(1)
Expand Down Expand Up @@ -240,6 +246,9 @@ def kernel_unified_attention_2d(

# epilogue
acc = acc / L[:, None]
if USE_FP8:
acc = acc / tl.load(out_scale)
Comment thread
ProExpertProg marked this conversation as resolved.
Outdated
acc = tl.clamp(acc, FP8_MIN, FP8_MAX)

output_offset = (query_offset_0[:, None] * output_stride_0 +
query_offset_1[:, None] * output_stride_1 +
Expand Down Expand Up @@ -486,6 +495,7 @@ def reduce_segments(
seq_lens_ptr, # [num_seqs]
num_seqs, # int
num_query_heads: tl.constexpr, # int
out_scale, # float32
output_stride_0: tl.int64, # int
output_stride_1: tl.int64, # int, should be equal to head_size
block_table_stride: tl.int64, # int
Expand All @@ -495,6 +505,9 @@ def reduce_segments(
query_start_len_ptr, # [num_seqs+1]
BLOCK_Q: tl.constexpr, # int
NUM_SEGMENTS_PER_SEQ: tl.constexpr, # int
USE_FP8: tl.constexpr, # bool
FP8_MIN: tl.constexpr = float8_info.min,
FP8_MAX: tl.constexpr = float8_info.max,
):
query_token_idx = tl.program_id(0)
query_head_idx = tl.program_id(1)
Expand Down Expand Up @@ -550,6 +563,10 @@ def reduce_segments(
# safely divide by overall_expsum, returning 0.0 if overall_expsum is 0
acc = tl.where(overall_expsum == 0.0, 0.0, acc_sum / overall_expsum)

if USE_FP8:
acc = acc / tl.load(out_scale)
Comment thread
ProExpertProg marked this conversation as resolved.
Outdated
acc = tl.clamp(acc, FP8_MIN, FP8_MAX)

# write result
output_offset = (query_token_idx * output_stride_0 +
query_head_idx * output_stride_1 +
Expand All @@ -575,6 +592,7 @@ def unified_attention(
k_descale,
v_descale,
alibi_slopes=None,
output_scale=None,
):
assert causal, "Only causal attention is supported"
assert q_descale is None, "Q scales not supported"
Expand Down Expand Up @@ -622,6 +640,7 @@ def unified_attention(
scale=softmax_scale,
k_scale=k_descale,
v_scale=v_descale,
out_scale=output_scale,
softcap=softcap,
num_query_heads=num_query_heads,
num_queries_per_kv=num_queries_per_kv,
Expand All @@ -648,6 +667,7 @@ def unified_attention(
BLOCK_Q=BLOCK_Q,
num_seqs=num_seqs,
BLOCK_M=BLOCK_M,
USE_FP8=output_scale is not None,
)
else:
# for initial version, NUM_SEGMENTS = 16 is chosen as a default
Expand Down Expand Up @@ -726,6 +746,7 @@ def unified_attention(
seq_lens_ptr=seqused_k,
num_seqs=num_seqs,
num_query_heads=num_query_heads,
out_scale=output_scale,
output_stride_0=out.stride(0),
output_stride_1=out.stride(1),
block_table_stride=block_table.stride(0),
Expand All @@ -735,4 +756,5 @@ def unified_attention(
query_start_len_ptr=cu_seqlens_q,
BLOCK_Q=BLOCK_Q,
NUM_SEGMENTS_PER_SEQ=NUM_SEGMENTS,
USE_FP8=output_scale is not None,
)
14 changes: 7 additions & 7 deletions vllm/v1/attention/backends/triton_attn.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ def get_builder_cls() -> type["TritonAttentionMetadataBuilder"]:

class TritonAttentionImpl(AttentionImpl):

def fused_output_quant_supported(self, dtype: torch.dtype, static: bool,
group_shape: tuple[int, int]):
return True
Comment thread
ProExpertProg marked this conversation as resolved.
Outdated

def __init__(
self,
num_heads: int,
Expand Down Expand Up @@ -156,11 +160,6 @@ def forward(
"""
assert output is not None, "Output tensor must be provided."

if output_scale is not None:
raise NotImplementedError(
"fused output quantization is not yet supported"
" for TritonAttentionImpl")

if attn_metadata is None:
# Profiling run.
return output
Expand Down Expand Up @@ -262,7 +261,8 @@ def forward(
v_scale=layer._v_scale,
alibi_slopes=self.alibi_slopes,
sliding_window=self.sliding_window[0],
sm_scale=self.scale)
sm_scale=self.scale,
output_scale=output_scale)

else:
descale_shape = (cu_seqlens_q.shape[0] - 1, key.shape[1])
Expand All @@ -285,6 +285,6 @@ def forward(
q_descale=None, # Not supported
k_descale=layer._k_scale.expand(descale_shape),
v_descale=layer._v_scale.expand(descale_shape),
)
output_scale=output_scale)

return output
Loading