@@ -87,6 +87,7 @@ static __global__ void flash_attn_ext_f16(
8787 const half * V_h = (const half *) (V + nb13* sequence + nb12*(head / gqa_ratio)); // K and V have same shape
8888 const half * maskh = (const half *) (mask + nb33*(sequence % ne33) + nb31*ic0);
8989 const half2 * mask2 = (const half2 *) maskh;
90+ const float * sinksf = (const float *) sinks;
9091
9192 const int stride_Q = nb01 / sizeof (float );
9293 const int stride_KV = nb11 / sizeof (half);
@@ -381,6 +382,55 @@ static __global__ void flash_attn_ext_f16(
381382 __syncthreads ();
382383 }
383384
385+ // Apply attention sinks
386+ if (sinksf && blockIdx .y == 0 ) {
387+ const float sinkf = sinksf[head];
388+ const half sinkh = __float2half (sinkf);
389+
390+ #pragma unroll
391+ for (int j0 = 0 ; j0 < ncols; j0 += nwarps) {
392+ const int j = j0 + threadIdx .y ;
393+
394+ if (std::is_same<KQ_acc_t, float >::value) {
395+ float kqmax_new = fmaxf (KQ_max_f[j0/nwarps], sinkf);
396+ kqmax_new = warp_reduce_max<warp_size>(kqmax_new);
397+
398+ const float KQ_max_scale = expf (KQ_max_f[j0/nwarps] - kqmax_new);
399+ KQ_max_f[j0/nwarps] = kqmax_new;
400+
401+ KQ_rowsum_f[j0/nwarps] = KQ_rowsum_f[j0/nwarps] * KQ_max_scale + expf (sinkf - KQ_max_f[j0/nwarps]);
402+
403+ const half2 scale_h2 = make_half2 (KQ_max_scale, KQ_max_scale);
404+ #pragma unroll
405+ for (int i0 = 0 ; i0 < D/2 ; i0 += warp_size) {
406+ const int i = i0 + threadIdx .x ;
407+ if (i0 + warp_size > D/2 && i >= D/2 ) break ;
408+ VKQ2 [j*(D_padded/2 ) + i] *= scale_h2;
409+ }
410+ } else {
411+ half kqmax_old = __low2half (KQ_max_h2[j0/nwarps]);
412+ half kqmax_new = fmaxf (kqmax_old, sinkh);
413+ kqmax_new = warp_reduce_max<warp_size>(kqmax_new);
414+ KQ_max_h2[j0/nwarps] = __half2half2 (kqmax_new);
415+
416+ const half KQ_max_scale_h = hexp (kqmax_old - kqmax_new);
417+ const half2 KQ_max_scale = __half2half2 (KQ_max_scale_h);
418+
419+ KQ_rowsum_h2[j0/nwarps] = KQ_rowsum_h2[j0/nwarps] * KQ_max_scale;
420+ const half val = hexp (sinkh - kqmax_new);
421+ KQ_rowsum_h2[j0/nwarps].x = __hadd (KQ_rowsum_h2[j0/nwarps].x , val);
422+
423+ #pragma unroll
424+ for (int i0 = 0 ; i0 < D/2 ; i0 += warp_size) {
425+ const int i = i0 + threadIdx .x ;
426+ if (i0 + warp_size > D/2 && i >= D/2 ) break ;
427+ VKQ2 [j*(D_padded/2 ) + i] *= KQ_max_scale;
428+ }
429+ }
430+ }
431+
432+ __syncthreads ();
433+ }
384434#pragma unroll
385435 for (int j0 = 0 ; j0 < ncols; j0 += nwarps) {
386436 const int j_VKQ = j0 + threadIdx .y ;
0 commit comments