char-fork/llama.cpp

git clone https://git.t4t.associates/char-fork/llama.cpp

Titaniumtownsycl: fuse the gated-delta-net state writeback cpy (#26643)3d9388535

char/aliceai-t5-moe
16.0 KiB366 linesraw
1#include <sycl/sycl.hpp>
2#include "dpct/helper.hpp"
3#include "common.hpp"
4#include "ggml.h"
5#include "gated_delta_net.hpp"
6#include <cmath>
7
8
9template <int S_v, bool KDA, bool keep_rs_t>
10void gated_delta_net_sycl(const float *     q,
11                          const float *     k,
12                          const float *     v,
13                          const float *     g,
14                          const float *     beta,
15                          const float *     curr_state,
16                          float *           dst,
17                          float *           state,
18                          int64_t           H,
19                          int64_t           n_tokens,
20                          int64_t           sq1,
21                          int64_t           sq2,
22                          int64_t           sq3,
23                          int64_t           sv1,
24                          int64_t           sv2,
25                          int64_t           sv3,
26                          int64_t           sb1,
27                          int64_t           sb2,
28                          int64_t           sb3,
29                          const sycl::uint3 neqk1_magic,
30                          const sycl::uint3 rq3_magic,
31                          float             scale,
32                          int64_t           state_slot_stride,
33                          int               K) {
34    auto           item_ct1 = sycl::ext::oneapi::this_work_item::get_nd_item<3>();
35    const uint32_t h_idx    = item_ct1.get_group(2);
36    const uint32_t sequence = item_ct1.get_group(1);
37    // each warp owns one column, using warp-level primitives to reduce across rows
38    const int      lane     = item_ct1.get_local_id(2);
39    const int      col      = item_ct1.get_group(0) * item_ct1.get_local_range(1) + item_ct1.get_local_id(1);
40
41    const uint32_t iq1 = fastmodulo(h_idx, neqk1_magic);
42    const uint32_t iq3 = fastdiv(sequence, rq3_magic);
43
44    float *       attn_data        = dst;
45
46    // input state holds s0 only [S_v, S_v, H, n_seqs] — seq stride is D = H * S_v * S_v.
47    // output state layout (per-slot D * n_seqs) — same per-(seq,head) offset as before.
48    const int64_t state_in_offset      = sequence * H * S_v * S_v + h_idx * S_v * S_v;
49    const int64_t state_out_offset     = (sequence * H + h_idx) * S_v * S_v;
50    state += state_out_offset;
51    curr_state += state_in_offset + col * S_v;
52    attn_data += (sequence * n_tokens * H + h_idx) * S_v;
53
54    constexpr int warp_size = ggml_sycl_get_physical_warp_size() < S_v ? ggml_sycl_get_physical_warp_size() : S_v;
55    static_assert(S_v % warp_size == 0, "S_v must be a multiple of warp_size");
56    constexpr int rows_per_lane = (S_v + warp_size - 1) / warp_size;
57    float         s_shard[rows_per_lane];
58#pragma unroll
59    for (int r = 0; r < rows_per_lane; r++) {
60        const int i = r * warp_size + lane;
61        s_shard[r]  = curr_state[i];
62    }
63
64    // snapshot slot mapping: slot 0 = most recent state, slot s = s tokens back.
65    // When n_tokens < K only slots 0..n_tokens-1 are written; older slots are caller-owned.
66
67    for (int t = 0; t < n_tokens; t++) {
68        const float * q_t = q + iq3 * sq3 + t * sq2 + iq1 * sq1;
69        const float * k_t = k + iq3 * sq3 + t * sq2 + iq1 * sq1;
70        const float * v_t = v + sequence * sv3 + t * sv2 + h_idx * sv1;
71
72        const int64_t gb_offset = sequence * sb3 + t * sb2 + h_idx * sb1;
73        const float * beta_t = beta + gb_offset;
74        const float * g_t    = g    + gb_offset * (KDA ? S_v : 1);
75
76        const float beta_val = *beta_t;
77
78        if constexpr (!KDA) {
79            const float g_val = sycl::native::exp(*g_t);
80
81            // kv[col] = (S^T @ k)[col] = sum_i S[i][col] * k[i]
82            float kv_shard = 0.0f;
83#pragma unroll
84            for (int r = 0; r < rows_per_lane; r++) {
85                const int i = r * warp_size + lane;
86                kv_shard += s_shard[r] * k_t[i];
87            }
88            float kv_col = warp_reduce_sum<warp_size>(kv_shard);
89
90            // delta[col] = (v[col] - g * kv[col]) * beta
91            float delta_col = (v_t[col] - g_val * kv_col) * beta_val;
92
93            // fused: S[i][col] = g * S[i][col] + k[i] * delta[col]
94            // attn[col] = (S^T @ q)[col] = sum_i S[i][col] * q[i]
95            float attn_partial = 0.0f;
96#pragma unroll
97            for (int r = 0; r < rows_per_lane; r++) {
98                const int i = r * warp_size + lane;
99                s_shard[r]  = g_val * s_shard[r] + k_t[i] * delta_col;
100                attn_partial += s_shard[r] * q_t[i];
101            }
102
103            float attn_col = warp_reduce_sum<warp_size>(attn_partial);
104
105            if (lane == 0) {
106                attn_data[col] = attn_col * scale;
107            }
108        } else {
109            // kv[col] = sum_i g[i] * S[i][col] * k[i]
110            float kv_shard = 0.0f;
111#pragma unroll
112            for (int r = 0; r < rows_per_lane; r++) {
113                const int i = r * warp_size + lane;
114                kv_shard += sycl::native::exp(g_t[i]) * s_shard[r] * k_t[i];
115            }
116
117            float kv_col = warp_reduce_sum<warp_size>(kv_shard);
118
119            // delta[col] = (v[col] - kv[col]) * beta
120            float delta_col = (v_t[col] - kv_col) * beta_val;
121
122            // fused: S[i][col] = g[i] * S[i][col] + k[i] * delta[col]
123            // attn[col] = (S^T @ q)[col] = sum_i S[i][col] * q[i]
124            float attn_partial = 0.0f;
125#pragma unroll
126            for (int r = 0; r < rows_per_lane; r++) {
127                const int i = r * warp_size + lane;
128                s_shard[r]  = sycl::native::exp(g_t[i]) * s_shard[r] + k_t[i] * delta_col;
129                attn_partial += s_shard[r] * q_t[i];
130            }
131
132            float attn_col = warp_reduce_sum<warp_size>(attn_partial);
133
134            if (lane == 0) {
135                attn_data[col] = attn_col * scale;
136            }
137        }
138
139        attn_data += S_v * H;
140
141
142    // Write state back to global memory
143        if constexpr (keep_rs_t) {
144            const int target_slot = (int) n_tokens - 1 - t;
145            if (target_slot >= 0 && target_slot < K) {
146                float * curr_state = state + target_slot * state_slot_stride;
147#pragma unroll
148                for (int r = 0; r < rows_per_lane; r++) {
149                    const int i = r * warp_size + lane;
150                    curr_state[col * S_v + i] = s_shard[r];
151                }
152            }
153        }
154    }
155
156    if constexpr (!keep_rs_t) {
157#pragma unroll
158        for (int r = 0; r < rows_per_lane; r++) {
159            const int i          = r * warp_size + lane;
160            state[col * S_v + i] = s_shard[r];
161        }
162    }
163}
164
165template <bool KDA, bool keep_rs_t>
166static void launch_gated_delta_net(const float *   q_d,
167                                   const float *   k_d,
168                                   const float *   v_d,
169                                   const float *   g_d,
170                                   const float *   b_d,
171                                   const float *   s_d,
172                                   float *         dst_d,
173                                   float *         state_d,
174                                   int64_t         S_v,
175                                   int64_t         H,
176                                   int64_t         n_tokens,
177                                   int64_t         n_seqs,
178                                   int64_t         sq1,
179                                   int64_t         sq2,
180                                   int64_t         sq3,
181                                   int64_t         sv1,
182                                   int64_t         sv2,
183                                   int64_t         sv3,
184                                   int64_t         sb1,
185                                   int64_t         sb2,
186                                   int64_t         sb3,
187                                   int64_t         neqk1,
188                                   int64_t         rq3,
189                                   float           scale,
190                                   int64_t         state_slot_stride,
191                                   int             K,
192                                   dpct::queue_ptr stream) {
193    //TODO: Add chunked kernel for even faster pre-fill
194    const int warp_size = ggml_sycl_info().devices[ggml_sycl_get_device()].warp_size;
195
196    const int num_warps = 4;
197    dpct::dim3 grid_dims(H, n_seqs, (S_v + num_warps - 1) / num_warps);
198    dpct::dim3 block_dims(warp_size <= S_v ? warp_size : S_v, num_warps, 1);
199
200    const sycl::uint3 neqk1_magic = init_fastdiv_values(neqk1);
201    const sycl::uint3 rq3_magic   = init_fastdiv_values(rq3);
202
203    switch (S_v) {
204        case 16:
205            {
206                constexpr int sv = 16;
207                stream->parallel_for(sycl::nd_range<3>(grid_dims * block_dims, block_dims),
208                                     [=](sycl::nd_item<3> /*item_ct1*/) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
209                                         gated_delta_net_sycl<sv, KDA, keep_rs_t>(q_d, k_d, v_d, g_d, b_d, s_d, dst_d, state_d, H, n_tokens,
210                                                                       sq1, sq2, sq3, sv1, sv2, sv3, sb1, sb2,
211                                                                       sb3, neqk1_magic, rq3_magic, scale, state_slot_stride, K);
212                                     });
213            }
214            break;
215        case 32:
216            {
217                constexpr int sv = 32;
218                stream->parallel_for(sycl::nd_range<3>(grid_dims * block_dims, block_dims),
219                                     [=](sycl::nd_item<3> /*item_ct1*/) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
220                                         gated_delta_net_sycl<sv, KDA, keep_rs_t>(q_d, k_d, v_d, g_d, b_d, s_d, dst_d, state_d, H, n_tokens,
221                                                                       sq1, sq2, sq3, sv1, sv2, sv3, sb1, sb2,
222                                                                       sb3, neqk1_magic, rq3_magic, scale, state_slot_stride, K);
223                                     });
224            }
225            break;
226        case 64: {
227            {
228                constexpr int sv = 64;
229                stream->parallel_for(sycl::nd_range<3>(grid_dims * block_dims, block_dims),
230                                        [=](sycl::nd_item<3> /*item_ct1*/) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
231                                            gated_delta_net_sycl<sv, KDA, keep_rs_t>(
232                                                q_d, k_d, v_d, g_d, b_d, s_d, dst_d, state_d, H, n_tokens, sq1, sq2,
233                                                sq3, sv1, sv2, sv3, sb1, sb2, sb3, neqk1_magic, rq3_magic, scale, state_slot_stride, K);
234                                        });
235            }
236            break;
237        }
238        case 128: {
239            {
240                constexpr int sv = 128;
241                stream->parallel_for(sycl::nd_range<3>(grid_dims * block_dims, block_dims),
242                                        [=](sycl::nd_item<3> /*item_ct1*/) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
243                                            gated_delta_net_sycl<sv, KDA, keep_rs_t>(
244                                                q_d, k_d, v_d, g_d, b_d, s_d, dst_d, state_d, H, n_tokens, sq1, sq2,
245                                                sq3, sv1, sv2, sv3, sb1, sb2, sb3, neqk1_magic, rq3_magic, scale, state_slot_stride, K);
246                                        });
247            }
248            break;
249        }
250        default:
251            GGML_ABORT("fatal error");
252            break;
253    }
254}
255
256static void ggml_sycl_op_gated_delta_net_impl(ggml_backend_sycl_context & ctx, ggml_tensor * dst,
257                                              const ggml_sycl_gated_delta_net_fused_cache * cache) {
258    ggml_tensor * src_q     = dst->src[0];
259    ggml_tensor * src_k     = dst->src[1];
260    ggml_tensor * src_v     = dst->src[2];
261    ggml_tensor * src_g     = dst->src[3];
262    ggml_tensor * src_beta  = dst->src[4];
263    ggml_tensor * src_state = dst->src[5];
264
265    GGML_TENSOR_LOCALS(int64_t, neq, src_q, ne);
266    GGML_TENSOR_LOCALS(size_t , nbq, src_q, nb);
267    GGML_TENSOR_LOCALS(int64_t, nek, src_k, ne);
268    GGML_TENSOR_LOCALS(size_t , nbk, src_k, nb);
269    GGML_TENSOR_LOCALS(int64_t, nev, src_v, ne);
270    GGML_TENSOR_LOCALS(size_t,  nbv, src_v, nb);
271    GGML_TENSOR_LOCALS(size_t,  nbb, src_beta, nb);
272
273    const int64_t S_v      = nev0;
274    const int64_t H        = nev1;
275    const int64_t n_tokens = nev2;
276    const int64_t n_seqs   = nev3;
277
278    const bool kda = (src_g->ne[0] == S_v);
279
280    GGML_ASSERT(neq1 == nek1);
281    const int64_t neqk1 = neq1;
282
283    const int64_t rq3 = nev3 / neq3;
284
285    const float * q_d = (const float *) src_q->data;
286    const float * k_d = (const float *) src_k->data;
287    const float * v_d = (const float *) src_v->data;
288    const float * g_d = (const float *) src_g->data;
289    const float * b_d = (const float *) src_beta->data;
290
291    const float * s_d   = (const float *) src_state->data;
292    float *       dst_d = (float *) dst->data;
293
294    GGML_ASSERT(ggml_is_contiguous_rows(src_q));
295    GGML_ASSERT(ggml_is_contiguous_rows(src_k));
296    GGML_ASSERT(ggml_is_contiguous_rows(src_v));
297    GGML_ASSERT(ggml_are_same_stride(src_q, src_k));
298    GGML_ASSERT(src_g->ne[0] == 1 || kda);
299    GGML_ASSERT(ggml_is_contiguous(src_g));
300    GGML_ASSERT(ggml_is_contiguous(src_beta));
301    GGML_ASSERT(ggml_is_contiguous(src_state));
302
303    // strides in floats (beta strides used for both g and beta offset computation)
304    const int64_t sq1 = nbq1 / sizeof(float);
305    const int64_t sq2 = nbq2 / sizeof(float);
306    const int64_t sq3 = nbq3 / sizeof(float);
307    const int64_t sv1 = nbv1 / sizeof(float);
308    const int64_t sv2 = nbv2 / sizeof(float);
309    const int64_t sv3 = nbv3 / sizeof(float);
310    const int64_t sb1 = nbb1 / sizeof(float);
311    const int64_t sb2 = nbb2 / sizeof(float);
312    const int64_t sb3 = nbb3 / sizeof(float);
313
314    const float scale = 1.0f / sqrtf((float) S_v);
315
316    dpct::queue_ptr stream = ctx.stream();
317
318    // K (snapshot slot count) is an op param; state holds s0 only [S_v, S_v, H, n_seqs].
319    const int K = ggml_get_op_params_i32(dst, 0);
320    const bool keep_rs = K > 1;
321
322    // recurrent state -> dst tail (after attention scores), or the cache when fusing
323    float * state_d           = dst_d + S_v * H * n_tokens * n_seqs;
324    int64_t state_slot_stride = S_v * S_v * H * n_seqs;
325    if (cache != nullptr) {
326        state_d           = cache->data;
327        state_slot_stride = cache->slot_stride;
328    }
329
330    if (kda) {
331        if (keep_rs) {
332            launch_gated_delta_net<true, true>(q_d, k_d, v_d, g_d, b_d, s_d, dst_d, state_d,
333                S_v, H, n_tokens, n_seqs, sq1, sq2, sq3, sv1, sv2, sv3,
334                sb1, sb2, sb3, neqk1, rq3, scale, state_slot_stride, K, stream);
335        } else {
336            launch_gated_delta_net<true, false>(q_d, k_d, v_d, g_d, b_d, s_d, dst_d, state_d,
337                S_v, H, n_tokens, n_seqs, sq1, sq2, sq3, sv1, sv2, sv3,
338                sb1, sb2, sb3, neqk1, rq3, scale, state_slot_stride, K, stream);
339        }
340    } else {
341        if (keep_rs) {
342            launch_gated_delta_net<false, true>(q_d, k_d, v_d, g_d, b_d, s_d, dst_d, state_d,
343                S_v, H, n_tokens, n_seqs, sq1, sq2, sq3, sv1, sv2, sv3,
344                sb1, sb2, sb3, neqk1, rq3, scale, state_slot_stride, K, stream);
345        } else {
346            launch_gated_delta_net<false, false>(q_d, k_d, v_d, g_d, b_d, s_d, dst_d, state_d,
347                S_v, H, n_tokens, n_seqs, sq1, sq2, sq3, sv1, sv2, sv3,
348                sb1, sb2, sb3, neqk1, rq3, scale, state_slot_stride, K, stream);
349        }
350    }
351}
352
353void ggml_sycl_op_gated_delta_net(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
354    ggml_sycl_op_gated_delta_net_impl(ctx, dst, nullptr);
355}
356
357void ggml_sycl_gated_delta_net(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
358    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/6);
359    ggml_sycl_op_gated_delta_net(ctx, dst);
360}
361
362void ggml_sycl_op_gated_delta_net_fused_cache(ggml_backend_sycl_context & ctx, ggml_tensor * dst,
363                                              ggml_sycl_gated_delta_net_fused_cache cache) {
364    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/6);
365    ggml_sycl_op_gated_delta_net_impl(ctx, dst, &cache);
366}