4343#include < aclnnop/aclnn_eq_tensor.h>
4444#include < aclnnop/aclnn_exp.h>
4545#include < aclnnop/aclnn_fill_scalar.h>
46- #include < aclnnop/aclnn_fused_infer_attention_score_v2 .h>
46+ #include < aclnnop/aclnn_fused_infer_attention_score_v5 .h>
4747#include < aclnnop/aclnn_ger.h>
4848#include < aclnnop/aclnn_group_norm.h>
4949#include < aclnnop/aclnn_gather_v2.h>
@@ -3860,6 +3860,7 @@ void ggml_cann_flash_attn_ext(ggml_backend_cann_context & ctx, ggml_tensor * dst
38603860 ggml_tensor * src1 = dst->src [1 ]; // k, fp16 | B, N, S, D (uncont) -> B, S, N, D (cont)
38613861 ggml_tensor * src2 = dst->src [2 ]; // v, fp16 | B, N, S, D (uncont) -> B, S, N, D (cont)
38623862 ggml_tensor * src3 = dst->src [3 ]; // mask, fp16
3863+ ggml_tensor * src4 = dst->src [4 ]; // sinks, f32 [n_heads]
38633864
38643865 // B, N, S, D (uncont) -> B, S, N, D (cont)
38653866 int64_t src0_bsnd_ne[GGML_MAX_DIMS ];
@@ -3932,22 +3933,28 @@ void ggml_cann_flash_attn_ext(ggml_backend_cann_context & ctx, ggml_tensor * dst
39323933 acl_k_tensor = ggml_cann_create_tensor (src1, src1_bsnd_ne, src1_bsnd_nb, GGML_MAX_DIMS );
39333934 acl_v_tensor = ggml_cann_create_tensor (src2, src2_bsnd_ne, src2_bsnd_nb, GGML_MAX_DIMS );
39343935
3935- // Step 2.5: Pad Q, K, V along head dimension if D is not a multiple of 16
3936- // (required by FusedInferAttentionScoreV2)
3937- const int64_t D = src0->ne [0 ];
3938- const int64_t D_padded = GGML_PAD (D, 16 );
3939- const bool needs_padding = (D != D_padded);
3936+ // Step 2.5: Pad Q, K, V along head dimension if D is not a multiples of 16
3937+ // (required by FusedInferAttentionScoreV5)
3938+ const int64_t DQ = src0->ne [0 ];
3939+ const int64_t DV = src2->ne [0 ];
3940+ const int64_t DQ_padded = GGML_PAD (DQ , 16 );
3941+ const int64_t DK_padded = GGML_PAD (src1->ne [0 ], 16 );
3942+ const int64_t DV_padded = GGML_PAD (DV , 16 );
3943+ const bool needs_padding = (DQ != DQ_padded) || (src1->ne [0 ] != DK_padded) || (DV != DV_padded);
39403944
39413945 ggml_cann_pool_alloc q_pad_allocator (ctx.pool ());
39423946 ggml_cann_pool_alloc k_pad_allocator (ctx.pool ());
39433947 ggml_cann_pool_alloc v_pad_allocator (ctx.pool ());
39443948
39453949 if (needs_padding) {
3946- int64_t paddings[] = { 0 , D_padded - D, 0 , 0 , 0 , 0 , 0 , 0 };
3947-
39483950 auto pad_fa_tensor = [&](acl_tensor_ptr & tensor, const int64_t * bsnd_ne,
3951+ int64_t D_orig, int64_t D_pad,
39493952 ggml_cann_pool_alloc & allocator) {
3950- int64_t pad_ne[GGML_MAX_DIMS ] = { D_padded, bsnd_ne[1 ], bsnd_ne[2 ], bsnd_ne[3 ] };
3953+ if (D_orig == D_pad) {
3954+ return ;
3955+ }
3956+ int64_t paddings[] = { 0 , D_pad - D_orig, 0 , 0 , 0 , 0 , 0 , 0 };
3957+ int64_t pad_ne[GGML_MAX_DIMS ] = { D_pad, bsnd_ne[1 ], bsnd_ne[2 ], bsnd_ne[3 ] };
39513958 size_t pad_nb[GGML_MAX_DIMS ];
39523959 pad_nb[0 ] = faElemSize;
39533960 for (int i = 1 ; i < GGML_MAX_DIMS ; ++i) {
@@ -3961,13 +3968,13 @@ void ggml_cann_flash_attn_ext(ggml_backend_cann_context & ctx, ggml_tensor * dst
39613968 tensor = std::move (padded);
39623969 };
39633970
3964- pad_fa_tensor (acl_q_tensor, src0_bsnd_ne, q_pad_allocator);
3965- pad_fa_tensor (acl_k_tensor, src1_bsnd_ne, k_pad_allocator);
3966- pad_fa_tensor (acl_v_tensor, src2_bsnd_ne, v_pad_allocator);
3971+ pad_fa_tensor (acl_q_tensor, src0_bsnd_ne, DQ , DQ_padded, q_pad_allocator);
3972+ pad_fa_tensor (acl_k_tensor, src1_bsnd_ne, src1-> ne [ 0 ], DK_padded, k_pad_allocator);
3973+ pad_fa_tensor (acl_v_tensor, src2_bsnd_ne, DV , DV_padded, v_pad_allocator);
39673974
3968- src0_bsnd_ne[0 ] = D_padded ;
3969- src1_bsnd_ne[0 ] = D_padded ;
3970- src2_bsnd_ne[0 ] = D_padded ;
3975+ src0_bsnd_ne[0 ] = DQ_padded ;
3976+ src1_bsnd_ne[0 ] = DK_padded ;
3977+ src2_bsnd_ne[0 ] = DV_padded ;
39713978 }
39723979
39733980 // Step 3: create the PSEShift tensor if needed
@@ -4039,30 +4046,66 @@ void ggml_cann_flash_attn_ext(ggml_backend_cann_context & ctx, ggml_tensor * dst
40394046 }
40404047 }
40414048
4042- // Step 4 : set the inputs for FusedInferAttention.
4049+ // Step 5 : set the inputs for FusedInferAttention.
40434050 acl_tensor_list_ptr acl_k_tensor_list = ggml_cann_create_tensor_list (acl_k_tensor);
40444051 acl_tensor_list_ptr acl_v_tensor_list = ggml_cann_create_tensor_list (acl_v_tensor);
40454052
40464053 int64_t numHeads = src0->ne [2 ]; // N
40474054 int64_t numKeyValueHeads = src1->ne [2 ];
4055+
4056+ // Step 5.5: create learnableSink tensor if src4 (sinks) is present
4057+ // V5 learnableSink: dtype must be F16, shape = (Q_N) 1D tensor
4058+ acl_tensor_ptr acl_learnable_sink_tensor;
4059+ ggml_cann_pool_alloc sink_f16_allocator (ctx.pool ());
4060+ if (src4 != nullptr ) {
4061+ // V5 requires learnableSink dtype to be BF16
4062+ const aclDataType sinkDataType = ACL_BF16 ;
4063+ const size_t sinkElemSize = sizeof (uint16_t );
4064+ void * sink_f16_buffer = sink_f16_allocator.alloc (numHeads * sinkElemSize);
4065+
4066+ // aclnn_cast requires matching shapes, so cast via a 4D tensor
4067+ // matching src4's shape, then create a 1D view for V5
4068+ int64_t sink_ne_4d[GGML_MAX_DIMS ] = { numHeads, 1 , 1 , 1 };
4069+ size_t sink_nb_4d[GGML_MAX_DIMS ];
4070+ sink_nb_4d[0 ] = sinkElemSize;
4071+ for (int i = 1 ; i < GGML_MAX_DIMS ; ++i) {
4072+ sink_nb_4d[i] = sink_nb_4d[i - 1 ] * sink_ne_4d[i - 1 ];
4073+ }
4074+ acl_tensor_ptr sink_bf16_4d =
4075+ ggml_cann_create_tensor (sink_f16_buffer, sinkDataType, sinkElemSize, sink_ne_4d, sink_nb_4d, GGML_MAX_DIMS );
4076+
4077+ acl_tensor_ptr acl_src4_f32_tensor = ggml_cann_create_tensor (src4);
4078+ aclnn_cast (ctx, acl_src4_f32_tensor.get (), sink_bf16_4d.get (), sinkDataType);
4079+
4080+ // create 1D view for V5 learnableSink (same buffer, 1D shape)
4081+ int64_t sink_ne_1d[1 ] = { numHeads };
4082+ size_t sink_nb_1d[1 ] = { sinkElemSize };
4083+ acl_learnable_sink_tensor =
4084+ ggml_cann_create_tensor (sink_f16_buffer, sinkDataType, sinkElemSize, sink_ne_1d, sink_nb_1d, 1 );
4085+ }
4086+
40484087 // double scaleValue = 1 / sqrt(src0->ne[0]); // 1/sqrt(d)
40494088 int64_t preTokens = 65535 ;
40504089 int64_t nextTokens = 65535 ;
40514090 char layout[5 ] = { ' B' , ' S' , ' N' , ' D' , 0 };
40524091 int64_t sparseMode = 0 ;
4053- int64_t innerPrecise = (src0->ne [1 ] == 1 ) ? 0 : 2 ;
4092+ // learnableSink requires innerPrecise = 0
4093+ int64_t innerPrecise = (src0->ne [1 ] == 1 || src4 != nullptr ) ? 0 : 2 ;
40544094 int64_t blockSize = 0 ;
40554095 int64_t antiquantMode = 0 ;
40564096 bool softmaxLseFlag = false ;
40574097 int64_t keyAntiquantMode = 0 ;
40584098 int64_t valueAntiquantMode = 0 ;
4099+ int64_t queryQuantMode = 0 ;
4100+ int64_t pseType = 0 ;
40594101
4060- GGML_ASSERT (dst->type == GGML_TYPE_F32 || dst->type == GGML_TYPE_F16 );
4102+ GGML_ASSERT (dst->type == GGML_TYPE_F32 || dst->type == GGML_TYPE_F16 || dst-> type == GGML_TYPE_BF16 );
40614103 acl_tensor_ptr fa_dst_tensor;
40624104 ggml_cann_pool_alloc out_f16_allocator (ctx.pool ());
4063- if (dst->type == GGML_TYPE_F32 || needs_padding) {
4064- int64_t * out_f16_ne = src0_bsnd_ne;
4065- size_t out_f16_nb[GGML_MAX_DIMS ];
4105+ if (dst->type != GGML_TYPE_F16 || needs_padding) {
4106+ // output shape: B, S, N, DV (V's head dim, not Q's)
4107+ int64_t out_f16_ne[GGML_MAX_DIMS ] = { src2_bsnd_ne[0 ], src0_bsnd_ne[1 ], src0_bsnd_ne[2 ], src0_bsnd_ne[3 ] };
4108+ size_t out_f16_nb[GGML_MAX_DIMS ];
40664109 out_f16_nb[0 ] = faElemSize;
40674110 for (int i = 1 ; i < GGML_MAX_DIMS ; ++i) {
40684111 out_f16_nb[i] = out_f16_nb[i - 1 ] * out_f16_ne[i - 1 ];
@@ -4076,7 +4119,7 @@ void ggml_cann_flash_attn_ext(ggml_backend_cann_context & ctx, ggml_tensor * dst
40764119 fa_dst_tensor = ggml_cann_create_tensor (dst);
40774120 }
40784121
4079- GGML_CANN_CALL_ACLNN_OP (ctx, FusedInferAttentionScoreV2 , acl_q_tensor.get (), acl_k_tensor_list.get (),
4122+ GGML_CANN_CALL_ACLNN_OP (ctx, FusedInferAttentionScoreV5 , acl_q_tensor.get (), acl_k_tensor_list.get (),
40804123 acl_v_tensor_list.get (), // q, k, v
40814124 bcast_pse_tensor.get (), nullptr , // pse, mask
40824125 nullptr , nullptr , // actSeqLen, actSeqLenkv
@@ -4088,6 +4131,9 @@ void ggml_cann_flash_attn_ext(ggml_backend_cann_context & ctx, ggml_tensor * dst
40884131 nullptr , nullptr , // kAntiquantScale, kAntiQuantOffset
40894132 nullptr , nullptr , // vAntiquantScale, vAntiQuantOffset
40904133 nullptr , nullptr , nullptr , // kSharedPrefix, vSharedPrefix, actSharedLen
4134+ nullptr , nullptr , nullptr , // queryRope, keyRope, keyRopeAntiquantScale
4135+ nullptr , acl_learnable_sink_tensor.get (), // dequantScaleQuery, learnableSink
4136+ nullptr , nullptr , // qStartIdx, kvStartIdx
40914137 numHeads, scaleValue, // heads, scaleValue
40924138 preTokens, nextTokens, // preTokens, nextTokens
40934139 layout, // inputLayout
@@ -4096,16 +4142,17 @@ void ggml_cann_flash_attn_ext(ggml_backend_cann_context & ctx, ggml_tensor * dst
40964142 blockSize, antiquantMode, // blockSize, antiquantMode
40974143 softmaxLseFlag, // softmaxLseFlag
40984144 keyAntiquantMode, valueAntiquantMode, // keyAntiqMode, valueAntiqMode
4145+ queryQuantMode, pseType, // queryQuantMode, pseType
40994146 fa_dst_tensor.get (), // attentionOut
41004147 nullptr // softmaxLse
41014148 );
41024149
4103- // Step 6: post-processing — slice padded output and/or cast to f32
4150+ // Step 6: post-processing — slice padded output and/or cast to dst type
41044151 if (needs_padding) {
41054152 ggml_cann_pool_alloc sliced_f16_allocator (ctx.pool ());
41064153
4107- if (dst->type == GGML_TYPE_F32 ) {
4108- int64_t sliced_ne[GGML_MAX_DIMS ] = { D , src0_bsnd_ne[1 ], src0_bsnd_ne[2 ], src0_bsnd_ne[3 ] };
4154+ if (dst->type != GGML_TYPE_F16 ) {
4155+ int64_t sliced_ne[GGML_MAX_DIMS ] = { DV , src0_bsnd_ne[1 ], src0_bsnd_ne[2 ], src0_bsnd_ne[3 ] };
41094156 size_t sliced_nb[GGML_MAX_DIMS ];
41104157 sliced_nb[0 ] = faElemSize;
41114158 for (int i = 1 ; i < GGML_MAX_DIMS ; ++i) {
@@ -4117,16 +4164,16 @@ void ggml_cann_flash_attn_ext(ggml_backend_cann_context & ctx, ggml_tensor * dst
41174164 sliced_ne, sliced_nb, GGML_MAX_DIMS );
41184165
41194166 GGML_CANN_CALL_ACLNN_OP (ctx, Slice, fa_dst_tensor.get (),
4120- (int64_t ) -1 , (int64_t ) 0 , D , (int64_t ) 1 , sliced_f16_tensor.get ());
4167+ (int64_t ) -1 , (int64_t ) 0 , DV , (int64_t ) 1 , sliced_f16_tensor.get ());
41214168
41224169 acl_tensor_ptr acl_dst_tensor = ggml_cann_create_tensor (dst);
41234170 aclnn_cast (ctx, sliced_f16_tensor.get (), acl_dst_tensor.get (), ggml_cann_type_mapping (dst->type ));
41244171 } else {
41254172 acl_tensor_ptr acl_dst_tensor = ggml_cann_create_tensor (dst);
41264173 GGML_CANN_CALL_ACLNN_OP (ctx, Slice, fa_dst_tensor.get (),
4127- (int64_t ) -1 , (int64_t ) 0 , D , (int64_t ) 1 , acl_dst_tensor.get ());
4174+ (int64_t ) -1 , (int64_t ) 0 , DV , (int64_t ) 1 , acl_dst_tensor.get ());
41284175 }
4129- } else if (dst->type == GGML_TYPE_F32 ) {
4176+ } else if (dst->type != GGML_TYPE_F16 ) {
41304177 acl_tensor_ptr acl_dst_tensor = ggml_cann_create_tensor (dst);
41314178 aclnn_cast (ctx, fa_dst_tensor.get (), acl_dst_tensor.get (), ggml_cann_type_mapping (dst->type ));
41324179 }
0 commit comments