Skip to content

Commit 56c984f

Browse files
authored
[webgpu] Simplify the signature of CanApplyFlashAttention (microsoft#26926)
This pull request simplifies the logic for handling present key/value tensors in the WebGPU Flash Attention implementation. The main change is that the responsibility for creating internal present key/value tensors is moved from the caller to the `ApplyFlashAttention` function itself. This reduces code duplication and makes the API easier to use. Additionally, the `CanApplyFlashAttention` function is simplified to remove unnecessary checks for present key/value tensors.
1 parent 4a858a8 commit 56c984f

5 files changed

Lines changed: 22 additions & 15 deletions

File tree

onnxruntime/contrib_ops/webgpu/bert/attention.cc

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -726,16 +726,9 @@ Status Attention::ComputeInternal(onnxruntime::webgpu::ComputeContext& context)
726726
parameters.qkv_format_ = Q_K_V_BSNH;
727727

728728
// Check if we can use flash attention
729-
// For Attention operator, we need to create present_key and present_value tensors for flash attention
730-
// even though they are not exposed as outputs
731-
TensorShapeVector present_kv_shape({parameters.batch_size_, parameters.num_heads_,
732-
parameters.total_sequence_length_, parameters.head_size_});
733-
Tensor present_key = context.CreateGPUTensor(input->DataType(), present_kv_shape);
734-
Tensor present_value = context.CreateGPUTensor(input->DataType(), present_kv_shape);
735-
736-
if (CanApplyFlashAttention(nullptr, &present_key, &present_value, parameters, context)) {
729+
if (CanApplyFlashAttention(nullptr, parameters, context)) {
737730
// FlashAttention supports Q_K_V_BSNH format directly
738-
return ApplyFlashAttention(&Q_bsd, &K_bsd, &V_bsd, attention_bias, output, nullptr, &present_key, nullptr, &present_value,
731+
return ApplyFlashAttention(&Q_bsd, &K_bsd, &V_bsd, attention_bias, output, nullptr, nullptr, nullptr, nullptr,
739732
parameters, context, nullptr);
740733
}
741734

onnxruntime/contrib_ops/webgpu/bert/flash_attention.cc

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,22 @@ Status ApplyFlashAttention(const Tensor* Q, const Tensor* K, const Tensor* V, co
400400
const Tensor* cos_cache, const Tensor* sin_cache) {
401401
constexpr uint32_t tile_size = 64;
402402

403+
// Create present_key and present_value tensors if they are nullptr
404+
Tensor internal_present_key;
405+
Tensor internal_present_value;
406+
if (present_key == nullptr) {
407+
TensorShapeVector present_kv_shape({parameters.batch_size_, parameters.num_heads_,
408+
parameters.total_sequence_length_, parameters.head_size_});
409+
internal_present_key = context.CreateGPUTensor(Q->DataType(), TensorShape(present_kv_shape));
410+
present_key = &internal_present_key;
411+
}
412+
if (present_value == nullptr) {
413+
TensorShapeVector present_kv_shape({parameters.batch_size_, parameters.num_heads_,
414+
parameters.total_sequence_length_, parameters.head_size_});
415+
internal_present_value = context.CreateGPUTensor(Q->DataType(), TensorShape(present_kv_shape));
416+
present_value = &internal_present_value;
417+
}
418+
403419
// Extract present_sequence_length directly from present_key tensor shape:
404420
// (batch_size, num_heads, total_sequence_length/max_sequence_length, head_size)
405421
const uint32_t present_sequence_length = static_cast<uint32_t>(present_key->Shape()[2]);
@@ -532,14 +548,12 @@ Status ApplyFlashAttention(const Tensor* Q, const Tensor* K, const Tensor* V, co
532548
return Status::OK();
533549
}
534550

535-
bool CanApplyFlashAttention(const Tensor* bias, const Tensor* present_key, const Tensor* present_value,
551+
bool CanApplyFlashAttention(const Tensor* bias,
536552
const WebgpuAttentionParameters& parameters, onnxruntime::webgpu::ComputeContext& context) {
537553
return !parameters.is_packed_qkv_ &&
538554
parameters.head_size_ == parameters.v_head_size_ &&
539555
bias == nullptr &&
540556
context.HasFeature(wgpu::FeatureName::Subgroups) &&
541-
present_key != nullptr && present_value != nullptr && present_key->SizeInBytes() > 0 &&
542-
present_value->SizeInBytes() > 0 &&
543557
((context.AdapterInfo().vendor == std::string_view{"qualcomm"} && parameters.head_size_ % 8 == 0) || parameters.head_size_ % 4 == 0);
544558
}
545559

onnxruntime/contrib_ops/webgpu/bert/flash_attention.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ Status ApplyFlashAttention(const Tensor* Q, const Tensor* K, const Tensor* V, co
184184
const WebgpuAttentionParameters& parameters, onnxruntime::webgpu::ComputeContext& context, const Tensor* seqlen_k = nullptr,
185185
const Tensor* cos_cache = nullptr, const Tensor* sin_cache = nullptr);
186186

187-
bool CanApplyFlashAttention(const Tensor* bias, const Tensor* present_key, const Tensor* present_value,
187+
bool CanApplyFlashAttention(const Tensor* bias,
188188
const WebgpuAttentionParameters& parameters, onnxruntime::webgpu::ComputeContext& context);
189189

190190
// Split packed QKV with Q/K rotary embedding and copy KV cache fusion

onnxruntime/contrib_ops/webgpu/bert/group_query_attention.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ Status GroupQueryAttention::ComputeInternal(onnxruntime::webgpu::ComputeContext&
252252
// Create a temporary parameters copy with is_packed_qkv_ set to false to check if flash attention can be applied after unpacking
253253
WebgpuAttentionParameters temp_params = parameters;
254254
temp_params.is_packed_qkv_ = false;
255-
will_use_flash_attention = CanApplyFlashAttention(nullptr, present_key, present_value, temp_params, context);
255+
will_use_flash_attention = CanApplyFlashAttention(nullptr, temp_params, context);
256256
}
257257

258258
if (parameters.is_packed_qkv_ && do_rotary_) {

onnxruntime/contrib_ops/webgpu/bert/multihead_attention.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ Status MultiHeadAttention::ComputeInternal(onnxruntime::webgpu::ComputeContext&
104104
Tensor* output_qk = context.Output(3, output_qk_shape);
105105

106106
if (output_qk == nullptr && // Flash attention does not output QK scores
107-
CanApplyFlashAttention(bias, present_key, present_value, parameters, context)) {
107+
CanApplyFlashAttention(bias, parameters, context)) {
108108
return ApplyFlashAttention(query, key, value, attention_bias, output, past_key, present_key, past_value,
109109
present_value, parameters, context);
110110
}

0 commit comments

Comments
 (0)