← Back to C-Kernel-Engine Docs Doxygen Source Documentation
 
Loading...
Searching...
No Matches
deepseek_kernels.c
Go to the documentation of this file.
1/**
2 * @file deepseek_kernels.c
3 * @brief Scalar reference kernels for DeepSeek-style research ops.
4 *
5 * These kernels intentionally prioritize explicit math contracts over speed.
6 * They are used to pin PyTorch parity before adding SIMD/threaded variants.
7 */
8
9#include <math.h>
10#include <float.h>
11#include <limits.h>
12#include <stddef.h>
13#include <stdint.h>
14#include <stdlib.h>
15#include <string.h>
16
17#include "bf16_utils.h"
18#include "ck_threadpool.h"
19
20static inline size_t ds_mhc_idx(int t, int s, int d, int n_streams, int dim)
21{
22 return ((size_t)t * (size_t)n_streams + (size_t)s) * (size_t)dim + (size_t)d;
23}
24
25static inline size_t ds_mix_idx(int t, int out_s, int in_s, int n_streams)
26{
27 return ((size_t)t * (size_t)n_streams + (size_t)out_s) * (size_t)n_streams + (size_t)in_s;
28}
29
30void deepseek_mhc_mix_f32(const float *streams,
31 const float *mix,
32 float *out,
33 int tokens,
34 int n_streams,
35 int dim)
36{
37 if (!streams || !mix || !out || tokens <= 0 || n_streams <= 0 || dim <= 0) return;
38
39 for (int t = 0; t < tokens; ++t) {
40 for (int os = 0; os < n_streams; ++os) {
41 for (int d = 0; d < dim; ++d) {
42 float acc = 0.0f;
43 for (int is = 0; is < n_streams; ++is) {
44 acc += mix[ds_mix_idx(t, os, is, n_streams)] *
45 streams[ds_mhc_idx(t, is, d, n_streams, dim)];
46 }
47 out[ds_mhc_idx(t, os, d, n_streams, dim)] = acc;
48 }
49 }
50 }
51}
52
53void deepseek_mhc_mix_backward_f32(const float *d_out,
54 const float *streams,
55 const float *mix,
56 float *d_streams,
57 float *d_mix,
58 int tokens,
59 int n_streams,
60 int dim)
61{
62 if (!d_out || !streams || !mix || !d_streams || !d_mix ||
63 tokens <= 0 || n_streams <= 0 || dim <= 0) return;
64
65 const size_t stream_count = (size_t)tokens * (size_t)n_streams * (size_t)dim;
66 const size_t mix_count = (size_t)tokens * (size_t)n_streams * (size_t)n_streams;
67 for (size_t i = 0; i < stream_count; ++i) d_streams[i] = 0.0f;
68 for (size_t i = 0; i < mix_count; ++i) d_mix[i] = 0.0f;
69
70 for (int t = 0; t < tokens; ++t) {
71 for (int os = 0; os < n_streams; ++os) {
72 for (int is = 0; is < n_streams; ++is) {
73 float d_mix_acc = 0.0f;
74 const float m = mix[ds_mix_idx(t, os, is, n_streams)];
75 for (int d = 0; d < dim; ++d) {
76 const float go = d_out[ds_mhc_idx(t, os, d, n_streams, dim)];
77 d_streams[ds_mhc_idx(t, is, d, n_streams, dim)] += m * go;
78 d_mix_acc += go * streams[ds_mhc_idx(t, is, d, n_streams, dim)];
79 }
80 d_mix[ds_mix_idx(t, os, is, n_streams)] = d_mix_acc;
81 }
82 }
83 }
84}
85
86void deepseek_dsa_topk_softmax_f32(const float *scores,
87 int *indices,
88 float *weights,
89 int tokens,
90 int heads,
91 int key_count,
92 int top_k)
93{
94 if (!scores || !indices || !weights || tokens <= 0 || heads <= 0 ||
95 key_count <= 0 || top_k <= 0) return;
96
97 if (top_k > key_count) top_k = key_count;
98
99 for (int t = 0; t < tokens; ++t) {
100 for (int h = 0; h < heads; ++h) {
101 const float *row = scores + ((size_t)t * (size_t)heads + (size_t)h) * (size_t)key_count;
102 int *idx = indices + ((size_t)t * (size_t)heads + (size_t)h) * (size_t)top_k;
103 float *w = weights + ((size_t)t * (size_t)heads + (size_t)h) * (size_t)top_k;
104
105 for (int k = 0; k < top_k; ++k) {
106 idx[k] = -1;
107 w[k] = -FLT_MAX;
108 }
109
110 for (int j = 0; j < key_count; ++j) {
111 const float v = row[j];
112 int pos = -1;
113 for (int k = 0; k < top_k; ++k) {
114 if (idx[k] < 0 || v > w[k] || (v == w[k] && j < idx[k])) {
115 pos = k;
116 break;
117 }
118 }
119 if (pos >= 0) {
120 for (int k = top_k - 1; k > pos; --k) {
121 idx[k] = idx[k - 1];
122 w[k] = w[k - 1];
123 }
124 idx[pos] = j;
125 w[pos] = v;
126 }
127 }
128
129 float max_v = w[0];
130 for (int k = 1; k < top_k; ++k) if (w[k] > max_v) max_v = w[k];
131 float sum = 0.0f;
132 for (int k = 0; k < top_k; ++k) {
133 w[k] = expf(w[k] - max_v);
134 sum += w[k];
135 }
136 if (sum > 0.0f) {
137 const float inv = 1.0f / sum;
138 for (int k = 0; k < top_k; ++k) w[k] *= inv;
139 }
140 }
141 }
142}
143
144
145extern void topk_softmax_backward_f32(const int *indices,
146 const float *weights,
147 const float *d_weights,
148 float *d_scores,
149 int num_tokens,
150 int n_experts_or_keys,
151 int k);
152
154 const float *weights,
155 const float *d_weights,
156 float *d_scores,
157 int tokens,
158 int heads,
159 int key_count,
160 int top_k)
161{
162 if (!indices || !weights || !d_weights || !d_scores ||
163 tokens <= 0 || heads <= 0 || key_count <= 0 || top_k <= 0) return;
164
166 weights,
167 d_weights,
168 d_scores,
169 tokens * heads,
170 key_count,
171 top_k);
172}
173
174
175static inline size_t ds_mla_tok_idx(int t, int d, int dim)
176{
177 return (size_t)t * (size_t)dim + (size_t)d;
178}
179
180static inline size_t ds_mla_thd_idx(int t, int h, int d, int heads, int dim)
181{
182 return ((size_t)t * (size_t)heads + (size_t)h) * (size_t)dim + (size_t)d;
183}
184
185void deepseek_mla_kv_decompress_f32(const float *compressed_kv,
186 const float *kv_b_proj,
187 float *k_nope,
188 float *value,
189 int tokens,
190 int heads,
191 int kv_lora_rank,
192 int qk_nope_dim,
193 int v_dim)
194{
195 if (!compressed_kv || !kv_b_proj || !k_nope || !value ||
196 tokens <= 0 || heads <= 0 || kv_lora_rank <= 0 || qk_nope_dim <= 0 || v_dim <= 0) {
197 return;
198 }
199
200 const int out_per_head = qk_nope_dim + v_dim;
201 for (int t = 0; t < tokens; ++t) {
202 for (int h = 0; h < heads; ++h) {
203 for (int d = 0; d < qk_nope_dim; ++d) {
204 const int out_col = h * out_per_head + d;
205 float acc = 0.0f;
206 for (int r = 0; r < kv_lora_rank; ++r) {
207 acc += kv_b_proj[(size_t)out_col * (size_t)kv_lora_rank + (size_t)r] *
208 compressed_kv[ds_mla_tok_idx(t, r, kv_lora_rank)];
209 }
210 k_nope[ds_mla_thd_idx(t, h, d, heads, qk_nope_dim)] = acc;
211 }
212 for (int d = 0; d < v_dim; ++d) {
213 const int out_col = h * out_per_head + qk_nope_dim + d;
214 float acc = 0.0f;
215 for (int r = 0; r < kv_lora_rank; ++r) {
216 acc += kv_b_proj[(size_t)out_col * (size_t)kv_lora_rank + (size_t)r] *
217 compressed_kv[ds_mla_tok_idx(t, r, kv_lora_rank)];
218 }
219 value[ds_mla_thd_idx(t, h, d, heads, v_dim)] = acc;
220 }
221 }
222 }
223}
224
225void deepseek_mla_kv_decompress_bf16_token_range(const float *compressed_kv,
226 const uint16_t *kv_b_proj,
227 float *k_nope,
228 float *value,
229 int tokens,
230 int heads,
231 int kv_lora_rank,
232 int qk_nope_dim,
233 int v_dim,
234 int token_begin,
235 int token_end)
236{
237 if (!compressed_kv || !kv_b_proj || !k_nope || !value ||
238 tokens <= 0 || heads <= 0 || kv_lora_rank <= 0 || qk_nope_dim <= 0 || v_dim <= 0 ||
239 token_begin < 0 || token_begin >= token_end || token_end > tokens) {
240 return;
241 }
242
243 const int out_per_head = qk_nope_dim + v_dim;
244 for (int t = token_begin; t < token_end; ++t) {
245 for (int h = 0; h < heads; ++h) {
246 for (int d = 0; d < qk_nope_dim; ++d) {
247 const int out_col = h * out_per_head + d;
248 float acc = 0.0f;
249 for (int r = 0; r < kv_lora_rank; ++r) {
250 acc += bf16_to_float(kv_b_proj[(size_t)out_col * (size_t)kv_lora_rank + (size_t)r]) *
251 compressed_kv[ds_mla_tok_idx(t, r, kv_lora_rank)];
252 }
253 k_nope[ds_mla_thd_idx(t, h, d, heads, qk_nope_dim)] =
255 }
256 for (int d = 0; d < v_dim; ++d) {
257 const int out_col = h * out_per_head + qk_nope_dim + d;
258 float acc = 0.0f;
259 for (int r = 0; r < kv_lora_rank; ++r) {
260 acc += bf16_to_float(kv_b_proj[(size_t)out_col * (size_t)kv_lora_rank + (size_t)r]) *
261 compressed_kv[ds_mla_tok_idx(t, r, kv_lora_rank)];
262 }
263 value[ds_mla_thd_idx(t, h, d, heads, v_dim)] =
265 }
266 }
267 }
268}
269
270void deepseek_mla_kv_decompress_bf16(const float *compressed_kv,
271 const uint16_t *kv_b_proj,
272 float *k_nope,
273 float *value,
274 int tokens,
275 int heads,
276 int kv_lora_rank,
277 int qk_nope_dim,
278 int v_dim)
279{
280 if (tokens <= 0) return;
282 compressed_kv, kv_b_proj, k_nope, value, tokens, heads,
283 kv_lora_rank, qk_nope_dim, v_dim, 0, tokens);
284}
285
286typedef struct {
287 const float *compressed_kv;
288 const uint16_t *kv_b_proj;
289 float *k_nope;
290 float *value;
291 int tokens;
292 int heads;
293 int kv_lora_rank;
294 int qk_nope_dim;
295 int v_dim;
296} ds_mla_kv_decompress_bf16_args_t;
297
298static void ds_mla_kv_decompress_bf16_rows(int begin, int end, void *opaque)
299{
300 const ds_mla_kv_decompress_bf16_args_t *args =
301 (const ds_mla_kv_decompress_bf16_args_t *)opaque;
303 args->compressed_kv, args->kv_b_proj, args->k_nope, args->value,
304 args->tokens, args->heads, args->kv_lora_rank, args->qk_nope_dim,
305 args->v_dim, begin, end);
306}
307
309 const float *compressed_kv,
310 const uint16_t *kv_b_proj,
311 float *k_nope,
312 float *value,
313 int tokens,
314 int heads,
315 int kv_lora_rank,
316 int qk_nope_dim,
317 int v_dim)
318{
319 ck_threadpool_t *pool = ck_threadpool_global();
320 const char *disabled = getenv("CK_DISABLE_MLA_PARALLEL_PREFILL");
321 if ((disabled && disabled[0] && strcmp(disabled, "0") != 0) ||
322 !pool || ck_threadpool_n_threads(pool) <= 1 || tokens < 2) {
324 compressed_kv, kv_b_proj, k_nope, value, tokens, heads,
325 kv_lora_rank, qk_nope_dim, v_dim);
326 return;
327 }
328 ds_mla_kv_decompress_bf16_args_t args = {
329 .compressed_kv = compressed_kv,
330 .kv_b_proj = kv_b_proj,
331 .k_nope = k_nope,
332 .value = value,
333 .tokens = tokens,
334 .heads = heads,
335 .kv_lora_rank = kv_lora_rank,
336 .qk_nope_dim = qk_nope_dim,
337 .v_dim = v_dim,
338 };
339 int active = ck_threadpool_n_threads(pool);
340 if (active > tokens) active = tokens;
341 int grain = tokens / (active * 4);
342 if (grain < 1) grain = 1;
344 pool, active, 0, tokens, grain, ds_mla_kv_decompress_bf16_rows, &args);
345}
346
347/* Model-agnostic implementation of the DeepSeek-V3 interleaved MLA rotary
348 * layout. Kimi and Instella reuse this exact tensor transform; the ds_ prefix
349 * records its origin, not a model-selection restriction. */
350static void ds_mla_apply_kimi_rope(const float *src,
351 float *dst,
352 const float *cos_row,
353 const float *sin_row,
354 int dim)
355{
356 const int half = dim / 2;
357 for (int i = 0; i < half; ++i) {
358 const float x_first = src[2 * i];
359 const float x_second = src[2 * i + 1];
360 const float c = cos_row[i];
361 const float s = sin_row[i];
362 dst[i] = x_first * c - x_second * s;
363 dst[half + i] = x_second * c + x_first * s;
364 }
365}
366
368 const float *q_pe,
369 const float *k_nope,
370 const float *k_pe,
371 const float *cos,
372 const float *sin,
373 float *query,
374 float *key,
375 int tokens,
376 int heads,
377 int qk_nope_dim,
378 int qk_rope_dim)
379{
380 if (!q_nope || !q_pe || !k_nope || !k_pe || !cos || !sin || !query || !key ||
381 tokens <= 0 || heads <= 0 || qk_nope_dim <= 0 || qk_rope_dim <= 0 || (qk_rope_dim % 2) != 0) {
382 return;
383 }
384
385 const int q_head_dim = qk_nope_dim + qk_rope_dim;
386 for (int t = 0; t < tokens; ++t) {
387 const float *cos_row = cos + (size_t)t * (size_t)(qk_rope_dim / 2);
388 const float *sin_row = sin + (size_t)t * (size_t)(qk_rope_dim / 2);
389 for (int h = 0; h < heads; ++h) {
390 float *q_out = query + ds_mla_thd_idx(t, h, 0, heads, q_head_dim);
391 float *k_out = key + ds_mla_thd_idx(t, h, 0, heads, q_head_dim);
392 const float *qn = q_nope + ds_mla_thd_idx(t, h, 0, heads, qk_nope_dim);
393 const float *qp = q_pe + ds_mla_thd_idx(t, h, 0, heads, qk_rope_dim);
394 const float *kn = k_nope + ds_mla_thd_idx(t, h, 0, heads, qk_nope_dim);
395 const float *kp = k_pe + ds_mla_tok_idx(t, 0, qk_rope_dim);
396 for (int d = 0; d < qk_nope_dim; ++d) {
397 q_out[d] = qn[d];
398 k_out[d] = kn[d];
399 }
400 ds_mla_apply_kimi_rope(qp, q_out + qk_nope_dim, cos_row, sin_row, qk_rope_dim);
401 ds_mla_apply_kimi_rope(kp, k_out + qk_nope_dim, cos_row, sin_row, qk_rope_dim);
402 }
403 }
404}
405
407 const float *k_nope,
408 const float *kv_a_packed,
409 const float *cos,
410 const float *sin,
411 float *query,
412 float *key,
413 int tokens,
414 int heads,
415 int kv_lora_rank,
416 int qk_nope_dim,
417 int qk_rope_dim)
418{
419 if (!q_packed || !k_nope || !kv_a_packed || !cos || !sin || !query || !key ||
420 tokens <= 0 || heads <= 0 || kv_lora_rank <= 0 || qk_nope_dim <= 0 ||
421 qk_rope_dim <= 0 || qk_rope_dim > 256 || (qk_rope_dim % 2) != 0) {
422 return;
423 }
424
425 const int q_head_dim = qk_nope_dim + qk_rope_dim;
426 const int kv_a_dim = kv_lora_rank + qk_rope_dim;
427 const int half = qk_rope_dim / 2;
428 if (qk_rope_dim > 256) {
429 return;
430 }
431 for (int t = 0; t < tokens; ++t) {
432 const float *cos_row = cos + (size_t)t * (size_t)half;
433 const float *sin_row = sin + (size_t)t * (size_t)half;
434 const float *kp = kv_a_packed + (size_t)t * (size_t)kv_a_dim + (size_t)kv_lora_rank;
435 for (int h = 0; h < heads; ++h) {
436 const float *q_in = q_packed + ds_mla_thd_idx(t, h, 0, heads, q_head_dim);
437 const float *kn = k_nope + ds_mla_thd_idx(t, h, 0, heads, qk_nope_dim);
438 float *q_out = query + ds_mla_thd_idx(t, h, 0, heads, q_head_dim);
439 float *k_out = key + ds_mla_thd_idx(t, h, 0, heads, q_head_dim);
440
441 for (int d = 0; d < qk_nope_dim; ++d) {
442 q_out[d] = q_in[d];
443 k_out[d] = kn[d];
444 }
445
446 const float *qp = q_in + qk_nope_dim;
447 float q_pe_tmp[256];
448 if (qk_rope_dim > (int)(sizeof(q_pe_tmp) / sizeof(q_pe_tmp[0]))) {
449 return;
450 }
451 for (int i = 0; i < qk_rope_dim; ++i) q_pe_tmp[i] = qp[i];
452 for (int i = 0; i < half; ++i) {
453 const float q_first = q_pe_tmp[2 * i];
454 const float q_second = q_pe_tmp[2 * i + 1];
455 const float k_first = kp[2 * i];
456 const float k_second = kp[2 * i + 1];
457 const float c = cos_row[i];
458 const float ss = sin_row[i];
459 q_out[qk_nope_dim + i] = q_first * c - q_second * ss;
460 q_out[qk_nope_dim + half + i] = q_second * c + q_first * ss;
461 k_out[qk_nope_dim + i] = k_first * c - k_second * ss;
462 k_out[qk_nope_dim + half + i] = k_second * c + k_first * ss;
463 }
464 }
465 }
466}
467
468static inline float ds_mla_bf16_round(float value)
469{
470 return bf16_to_float(float_to_bf16(value));
471}
472
474 const float *q_packed,
475 const float *k_nope,
476 const float *kv_a_packed,
477 const float *cos,
478 const float *sin,
479 float *query,
480 float *key,
481 int tokens,
482 int heads,
483 int kv_lora_rank,
484 int qk_nope_dim,
485 int qk_rope_dim)
486{
487 if (!q_packed || !k_nope || !kv_a_packed || !cos || !sin || !query || !key ||
488 tokens <= 0 || heads <= 0 || kv_lora_rank <= 0 || qk_nope_dim <= 0 ||
489 qk_rope_dim <= 0 || (qk_rope_dim % 2) != 0) {
490 return;
491 }
492
493 const int q_head_dim = qk_nope_dim + qk_rope_dim;
494 const int kv_a_dim = kv_lora_rank + qk_rope_dim;
495 const int half = qk_rope_dim / 2;
496 for (int t = 0; t < tokens; ++t) {
497 const float *cos_row = cos + (size_t)t * (size_t)half;
498 const float *sin_row = sin + (size_t)t * (size_t)half;
499 const float *kp = kv_a_packed + (size_t)t * (size_t)kv_a_dim + (size_t)kv_lora_rank;
500 for (int h = 0; h < heads; ++h) {
501 const float *q_in = q_packed + ds_mla_thd_idx(t, h, 0, heads, q_head_dim);
502 const float *kn = k_nope + ds_mla_thd_idx(t, h, 0, heads, qk_nope_dim);
503 float *q_out = query + ds_mla_thd_idx(t, h, 0, heads, q_head_dim);
504 float *k_out = key + ds_mla_thd_idx(t, h, 0, heads, q_head_dim);
505
506 for (int d = 0; d < qk_nope_dim; ++d) {
507 q_out[d] = ds_mla_bf16_round(q_in[d]);
508 k_out[d] = ds_mla_bf16_round(kn[d]);
509 }
510
511 float q_pe_tmp[256];
512 for (int i = 0; i < qk_rope_dim; ++i) {
513 q_pe_tmp[i] = ds_mla_bf16_round(q_in[qk_nope_dim + i]);
514 }
515 for (int i = 0; i < half; ++i) {
516 const float q_first = q_pe_tmp[2 * i];
517 const float q_second = q_pe_tmp[2 * i + 1];
518 const float k_first = ds_mla_bf16_round(kp[2 * i]);
519 const float k_second = ds_mla_bf16_round(kp[2 * i + 1]);
520 const float c = ds_mla_bf16_round(cos_row[i]);
521 const float s = ds_mla_bf16_round(sin_row[i]);
522
523 const float q_first_cos = ds_mla_bf16_round(q_first * c);
524 const float q_second_sin = ds_mla_bf16_round(q_second * s);
525 const float q_second_cos = ds_mla_bf16_round(q_second * c);
526 const float q_first_sin = ds_mla_bf16_round(q_first * s);
527 const float k_first_cos = ds_mla_bf16_round(k_first * c);
528 const float k_second_sin = ds_mla_bf16_round(k_second * s);
529 const float k_second_cos = ds_mla_bf16_round(k_second * c);
530 const float k_first_sin = ds_mla_bf16_round(k_first * s);
531
532 q_out[qk_nope_dim + i] = ds_mla_bf16_round(q_first_cos - q_second_sin);
533 q_out[qk_nope_dim + half + i] = ds_mla_bf16_round(q_second_cos + q_first_sin);
534 k_out[qk_nope_dim + i] = ds_mla_bf16_round(k_first_cos - k_second_sin);
535 k_out[qk_nope_dim + half + i] = ds_mla_bf16_round(k_second_cos + k_first_sin);
536 }
537 }
538 }
539}
540
541static inline size_t ds_qkv_idx(int token, int head, int d, int heads, int dim)
542{
543 return ((size_t)token * (size_t)heads + (size_t)head) * (size_t)dim + (size_t)d;
544}
545
546static void ds_softmax(float *x, int n)
547{
548 if (n <= 0) return;
549 float max_v = x[0];
550 for (int i = 1; i < n; ++i) if (x[i] > max_v) max_v = x[i];
551 float sum = 0.0f;
552 for (int i = 0; i < n; ++i) {
553 x[i] = expf(x[i] - max_v);
554 sum += x[i];
555 }
556 if (sum > 0.0f) {
557 const float inv = 1.0f / sum;
558 for (int i = 0; i < n; ++i) x[i] *= inv;
559 }
560}
561
562void deepseek_csa_attention_f32(const float *q,
563 const float *k,
564 const float *v,
565 const int *indices,
566 float *out,
567 float *attn,
568 int query_tokens,
569 int key_tokens,
570 int heads,
571 int dim,
572 int top_k,
573 float scale)
574{
575 if (!q || !k || !v || !indices || !out || query_tokens <= 0 || key_tokens <= 0 ||
576 heads <= 0 || dim <= 0 || top_k <= 0) return;
577
578 for (int tq = 0; tq < query_tokens; ++tq) {
579 for (int h = 0; h < heads; ++h) {
580 float local_scores[top_k];
581 int valid = 0;
582 for (int j = 0; j < top_k; ++j) {
583 const int tk = indices[((size_t)tq * (size_t)heads + (size_t)h) * (size_t)top_k + (size_t)j];
584 if (tk < 0 || tk >= key_tokens) {
585 local_scores[j] = -FLT_MAX;
586 continue;
587 }
588 float dot = 0.0f;
589 for (int d = 0; d < dim; ++d) {
590 dot += q[ds_qkv_idx(tq, h, d, heads, dim)] * k[ds_qkv_idx(tk, h, d, heads, dim)];
591 }
592 local_scores[j] = dot * scale;
593 valid++;
594 }
595
596 float *out_row = out + ds_qkv_idx(tq, h, 0, heads, dim);
597 for (int d = 0; d < dim; ++d) out_row[d] = 0.0f;
598 if (valid == 0) {
599 if (attn) {
600 for (int j = 0; j < top_k; ++j) {
601 attn[((size_t)tq * (size_t)heads + (size_t)h) * (size_t)top_k + (size_t)j] = 0.0f;
602 }
603 }
604 continue;
605 }
606
607 ds_softmax(local_scores, top_k);
608 for (int j = 0; j < top_k; ++j) {
609 const int tk = indices[((size_t)tq * (size_t)heads + (size_t)h) * (size_t)top_k + (size_t)j];
610 const float a = (tk >= 0 && tk < key_tokens) ? local_scores[j] : 0.0f;
611 if (attn) attn[((size_t)tq * (size_t)heads + (size_t)h) * (size_t)top_k + (size_t)j] = a;
612 if (a == 0.0f) continue;
613 for (int d = 0; d < dim; ++d) {
614 out_row[d] += a * v[ds_qkv_idx(tk, h, d, heads, dim)];
615 }
616 }
617 }
618 }
619}
620
622 const float *q,
623 const float *k,
624 const float *v,
625 const int *indices,
626 const float *attn,
627 float *d_q,
628 float *d_k,
629 float *d_v,
630 int query_tokens,
631 int key_tokens,
632 int heads,
633 int dim,
634 int top_k,
635 float scale)
636{
637 if (!d_out || !q || !k || !v || !indices || !attn || !d_q || !d_k || !d_v ||
638 query_tokens <= 0 || key_tokens <= 0 || heads <= 0 || dim <= 0 || top_k <= 0) return;
639
640 const size_t q_count = (size_t)query_tokens * (size_t)heads * (size_t)dim;
641 const size_t kv_count = (size_t)key_tokens * (size_t)heads * (size_t)dim;
642 for (size_t i = 0; i < q_count; ++i) d_q[i] = 0.0f;
643 for (size_t i = 0; i < kv_count; ++i) {
644 d_k[i] = 0.0f;
645 d_v[i] = 0.0f;
646 }
647
648 for (int tq = 0; tq < query_tokens; ++tq) {
649 for (int h = 0; h < heads; ++h) {
650 float d_attn[top_k];
651 float attn_dot = 0.0f;
652 for (int j = 0; j < top_k; ++j) {
653 const int tk = indices[((size_t)tq * (size_t)heads + (size_t)h) * (size_t)top_k + (size_t)j];
654 float da = 0.0f;
655 if (tk >= 0 && tk < key_tokens) {
656 const float a = attn[((size_t)tq * (size_t)heads + (size_t)h) * (size_t)top_k + (size_t)j];
657 for (int d = 0; d < dim; ++d) {
658 const float go = d_out[ds_qkv_idx(tq, h, d, heads, dim)];
659 da += go * v[ds_qkv_idx(tk, h, d, heads, dim)];
660 d_v[ds_qkv_idx(tk, h, d, heads, dim)] += a * go;
661 }
662 attn_dot += a * da;
663 }
664 d_attn[j] = da;
665 }
666
667 for (int j = 0; j < top_k; ++j) {
668 const int tk = indices[((size_t)tq * (size_t)heads + (size_t)h) * (size_t)top_k + (size_t)j];
669 if (tk < 0 || tk >= key_tokens) continue;
670 const float a = attn[((size_t)tq * (size_t)heads + (size_t)h) * (size_t)top_k + (size_t)j];
671 const float d_score = a * (d_attn[j] - attn_dot);
672 for (int d = 0; d < dim; ++d) {
673 const float qv = q[ds_qkv_idx(tq, h, d, heads, dim)];
674 const float kv = k[ds_qkv_idx(tk, h, d, heads, dim)];
675 d_q[ds_qkv_idx(tq, h, d, heads, dim)] += scale * d_score * kv;
676 d_k[ds_qkv_idx(tk, h, d, heads, dim)] += scale * d_score * qv;
677 }
678 }
679 }
680 }
681}
682
684 const float *k,
685 const float *v,
686 const int *indices,
687 float *out,
688 float *attn,
689 int query_tokens,
690 int key_tokens,
691 int heads,
692 int dim,
693 int top_k,
694 float scale,
695 int mode)
696{
697 if (mode != 0) {
698 deepseek_csa_attention_f32(q, k, v, indices, out, attn,
699 query_tokens, key_tokens, heads, dim, top_k, scale);
700 return;
701 }
702
703 int dense_indices[query_tokens * heads * key_tokens];
704 for (int tq = 0; tq < query_tokens; ++tq) {
705 for (int h = 0; h < heads; ++h) {
706 for (int tk = 0; tk < key_tokens; ++tk) {
707 dense_indices[((size_t)tq * (size_t)heads + (size_t)h) * (size_t)key_tokens + (size_t)tk] = tk;
708 }
709 }
710 }
711 deepseek_csa_attention_f32(q, k, v, dense_indices, out, attn,
712 query_tokens, key_tokens, heads, dim, key_tokens, scale);
713}
714
715
716static void ds_mla_attention_f32_query_range(const float *q,
717 const float *k,
718 const float *v,
719 float *output,
720 int num_heads,
721 int num_kv_heads,
722 int num_tokens,
723 int qk_head_dim,
724 int v_head_dim,
725 float scale,
726 float *scores,
727 int query_begin,
728 int query_end,
729 int query_step,
730 int bf16_phases)
731{
732 for (int query = query_begin; query < query_end; query += query_step) {
733 const int t = query / num_heads;
734 const int h = query - t * num_heads;
735 const int kv_h = (int)((long long)h * (long long)num_kv_heads / (long long)num_heads);
736 const float *q_vec = q + ds_mla_thd_idx(t, h, 0, num_heads, qk_head_dim);
737
738 float max_score = -FLT_MAX;
739 for (int j = 0; j <= t; ++j) {
740 const float *k_vec = k + ds_mla_thd_idx(j, kv_h, 0, num_kv_heads, qk_head_dim);
741 float dot = 0.0f;
742 for (int d = 0; d < qk_head_dim; ++d) {
743 dot += bf16_phases
744 ? ds_mla_bf16_round(q_vec[d]) * ds_mla_bf16_round(k_vec[d])
745 : q_vec[d] * k_vec[d];
746 }
747 /* Eager BF16 attention stores the QK matmul result before scaling,
748 * then stores the scaled score. Keep the FP32 provider unchanged. */
749 const float score = bf16_phases
751 : dot * scale;
752 scores[j] = score;
753 if (score > max_score) max_score = score;
754 }
755
756 float sum = 0.0f;
757 for (int j = 0; j <= t; ++j) {
758 const float e = expf(scores[j] - max_score);
759 scores[j] = e;
760 sum += e;
761 }
762 const float inv_sum = sum > 0.0f ? (1.0f / sum) : 0.0f;
763 float *out = output + ((size_t)t * (size_t)num_heads + (size_t)h) * (size_t)v_head_dim;
764 for (int d = 0; d < v_head_dim; ++d) out[d] = 0.0f;
765 for (int j = 0; j <= t; ++j) {
766 const float weight = bf16_phases
767 ? ds_mla_bf16_round(scores[j] * inv_sum)
768 : scores[j] * inv_sum;
769 const float *v_vec = v + ds_mla_thd_idx(j, kv_h, 0, num_kv_heads, v_head_dim);
770 for (int d = 0; d < v_head_dim; ++d) {
771 out[d] += weight * (bf16_phases
772 ? ds_mla_bf16_round(v_vec[d]) : v_vec[d]);
773 }
774 }
775 if (bf16_phases) {
776 for (int d = 0; d < v_head_dim; ++d) {
777 out[d] = ds_mla_bf16_round(out[d]);
778 }
779 }
780 }
781}
782
783static int ds_mla_prefill_valid(const float *q, const float *k,
784 const float *v, float *output,
785 int num_heads, int num_kv_heads,
786 int num_tokens, int qk_head_dim,
787 int v_head_dim, float scale,
788 float *scores, size_t scores_bytes)
789{
790 return q && k && v && output && scores && num_heads > 0 &&
791 num_kv_heads > 0 && num_heads >= num_kv_heads &&
792 num_heads % num_kv_heads == 0 && num_tokens > 0 &&
793 qk_head_dim > 0 && v_head_dim > 0 &&
794 num_tokens <= INT_MAX / num_heads &&
795 (size_t)num_tokens <= SIZE_MAX / sizeof(float) &&
796 scores_bytes >= (size_t)num_tokens * sizeof(float) &&
797 isfinite(scale) && scale > 0.0f;
798}
799
801 const float *k,
802 const float *v,
803 float *output,
804 int num_heads,
805 int num_kv_heads,
806 int num_tokens,
807 int qk_head_dim,
808 int v_head_dim,
809 float scale,
810 float *scores,
811 size_t scores_bytes)
812{
813 if (!ds_mla_prefill_valid(q, k, v, output, num_heads, num_kv_heads,
814 num_tokens, qk_head_dim, v_head_dim, scale, scores,
815 scores_bytes)) return;
816
818 q, k, v, output, num_heads, num_kv_heads, num_tokens,
819 qk_head_dim, v_head_dim, scale, scores,
820 0, num_tokens * num_heads, 1, 0);
821}
822
824 const float *q, const float *k, const float *v, float *output,
825 int num_heads, int num_kv_heads, int num_tokens,
826 int qk_head_dim, int v_head_dim, float scale,
827 float *scores, size_t scores_bytes)
828{
829 if (!ds_mla_prefill_valid(q, k, v, output, num_heads, num_kv_heads,
830 num_tokens, qk_head_dim, v_head_dim, scale, scores,
831 scores_bytes)) return;
833 q, k, v, output, num_heads, num_kv_heads, num_tokens,
834 qk_head_dim, v_head_dim, scale, scores,
835 0, num_tokens * num_heads, 1, 1);
836}
837
838typedef struct {
839 const float *q;
840 const float *k;
841 const float *v;
842 float *output;
843 int num_heads;
844 int num_kv_heads;
845 int num_tokens;
846 int qk_head_dim;
847 int v_head_dim;
848 float scale;
849 float *scores;
850 int bf16_phases;
851 _Alignas(CK_CACHE_LINE) atomic_int next_token;
852} ds_mla_attention_f32_args_t;
853
854static void ds_mla_attention_f32_work(int ith, int nth, void *opaque)
855{
856 ds_mla_attention_f32_args_t *args =
857 (ds_mla_attention_f32_args_t *)opaque;
858 float *thread_scores = args->scores + (size_t)ith * (size_t)args->num_tokens;
859 (void)nth;
860 /* One token row contains every query head and costs O(t). Dynamic claims
861 * keep asymmetric cores busy without sharing score scratch. Query rows are
862 * independent, and every row retains its original reduction order. */
863 for (;;) {
864 const int token = atomic_fetch_add_explicit(
865 &args->next_token,
866 1,
867 memory_order_relaxed);
868 if (token >= args->num_tokens) break;
870 args->q, args->k, args->v, args->output,
871 args->num_heads, args->num_kv_heads, args->num_tokens,
872 args->qk_head_dim, args->v_head_dim, args->scale,
873 thread_scores,
874 token * args->num_heads,
875 (token + 1) * args->num_heads,
876 1, args->bf16_phases);
877 }
878}
879
881 const float *q,
882 const float *k,
883 const float *v,
884 float *output,
885 int num_heads,
886 int num_kv_heads,
887 int num_tokens,
888 int qk_head_dim,
889 int v_head_dim,
890 float scale,
891 float *scores,
892 size_t scores_bytes,
893 int bf16_phases)
894{
895 if (!ds_mla_prefill_valid(q, k, v, output, num_heads, num_kv_heads,
896 num_tokens, qk_head_dim, v_head_dim, scale, scores,
897 scores_bytes)) return;
898 ck_threadpool_t *pool = ck_threadpool_global();
899 const char *disabled = getenv("CK_DISABLE_MLA_PARALLEL_PREFILL");
900 int active = pool ? ck_threadpool_n_threads(pool) : 1;
901 if (active > num_heads) active = num_heads;
902 const size_t score_row_bytes =
903 num_tokens > 0 ? (size_t)num_tokens * sizeof(float) : 0;
904 if ((disabled && disabled[0] && strcmp(disabled, "0") != 0) ||
905 !pool || active <= 1 || num_tokens <= 0 || num_heads <= 0 ||
906 num_tokens > INT_MAX / num_heads ||
907 score_row_bytes == 0 || (size_t)active > SIZE_MAX / score_row_bytes ||
908 scores_bytes < (size_t)active * score_row_bytes) {
909 if (bf16_phases) {
911 q, k, v, output, num_heads, num_kv_heads, num_tokens,
912 qk_head_dim, v_head_dim, scale, scores, scores_bytes);
913 } else {
915 q, k, v, output, num_heads, num_kv_heads, num_tokens,
916 qk_head_dim, v_head_dim, scale, scores, scores_bytes);
917 }
918 return;
919 }
920 ds_mla_attention_f32_args_t args = {
921 .q = q, .k = k, .v = v, .output = output,
922 .num_heads = num_heads, .num_kv_heads = num_kv_heads,
923 .num_tokens = num_tokens, .qk_head_dim = qk_head_dim,
924 .v_head_dim = v_head_dim, .scale = scale, .scores = scores,
925 .bf16_phases = bf16_phases,
926 };
927 atomic_init(&args.next_token, 0);
929}
930
932 const float *q, const float *k, const float *v, float *output,
933 int num_heads, int num_kv_heads, int num_tokens,
934 int qk_head_dim, int v_head_dim, float scale,
935 float *scores, size_t scores_bytes)
936{
937 ds_mla_attention_parallel_dispatch(q, k, v, output, num_heads,
938 num_kv_heads, num_tokens, qk_head_dim, v_head_dim,
939 scale, scores, scores_bytes, 0);
940}
941
943 const float *q, const float *k, const float *v, float *output,
944 int num_heads, int num_kv_heads, int num_tokens,
945 int qk_head_dim, int v_head_dim, float scale,
946 float *scores, size_t scores_bytes)
947{
948 ds_mla_attention_parallel_dispatch(q, k, v, output, num_heads,
949 num_kv_heads, num_tokens, qk_head_dim, v_head_dim,
950 scale, scores, scores_bytes, 1);
951}
952
953void deepseek_mla_attention_f32(const float *q,
954 const float *k,
955 const float *v,
956 float *output,
957 int num_heads,
958 int num_kv_heads,
959 int num_tokens,
960 int qk_head_dim,
961 int v_head_dim)
962{
963 if (num_tokens <= 0 || (size_t)num_tokens > SIZE_MAX / sizeof(float)) return;
964 const size_t scores_bytes = (size_t)num_tokens * sizeof(float);
965 float *scores = (float *)malloc(scores_bytes);
966 if (!scores) return;
968 q, k, v, output, num_heads, num_kv_heads, num_tokens,
969 qk_head_dim, v_head_dim, 1.0f / sqrtf((float)qk_head_dim),
970 scores, scores_bytes);
971 free(scores);
972}
973
975 float *v_cache,
976 const float *k,
977 const float *v,
978 int num_tokens,
979 int num_kv_heads,
980 int qk_head_dim,
981 int v_head_dim,
982 int max_seq_len,
983 int cache_stride)
984{
985 if (!k_cache || !v_cache || !k || !v || num_tokens <= 0 ||
986 num_kv_heads <= 0 || qk_head_dim <= 0 || v_head_dim <= 0 ||
987 max_seq_len <= 0 || cache_stride <= 0) {
988 return;
989 }
990 if (qk_head_dim > cache_stride || v_head_dim > cache_stride) {
991 return;
992 }
993 if (num_tokens > max_seq_len) {
994 num_tokens = max_seq_len;
995 }
996
997 for (int t = 0; t < num_tokens; ++t) {
998 for (int h = 0; h < num_kv_heads; ++h) {
999 const float *k_src = k + ((size_t)t * (size_t)num_kv_heads + (size_t)h) * (size_t)qk_head_dim;
1000 const float *v_src = v + ((size_t)t * (size_t)num_kv_heads + (size_t)h) * (size_t)v_head_dim;
1001 float *k_dst = k_cache + ((size_t)h * (size_t)max_seq_len + (size_t)t) * (size_t)cache_stride;
1002 float *v_dst = v_cache + ((size_t)h * (size_t)max_seq_len + (size_t)t) * (size_t)cache_stride;
1003 for (int d = 0; d < qk_head_dim; ++d) k_dst[d] = k_src[d];
1004 for (int d = qk_head_dim; d < cache_stride; ++d) k_dst[d] = 0.0f;
1005 for (int d = 0; d < v_head_dim; ++d) v_dst[d] = v_src[d];
1006 for (int d = v_head_dim; d < cache_stride; ++d) v_dst[d] = 0.0f;
1007 }
1008 }
1009}
1010
1012 float *v_cache,
1013 const float *k,
1014 const float *v,
1015 int pos,
1016 int num_kv_heads,
1017 int qk_head_dim,
1018 int v_head_dim,
1019 int max_seq_len,
1020 int cache_stride)
1021{
1022 if (!k_cache || !v_cache || !k || !v || pos < 0 ||
1023 num_kv_heads <= 0 || qk_head_dim <= 0 || v_head_dim <= 0 ||
1024 max_seq_len <= 0 || cache_stride <= 0) {
1025 return;
1026 }
1027 if (pos >= max_seq_len || qk_head_dim > cache_stride || v_head_dim > cache_stride) {
1028 return;
1029 }
1030
1031 for (int h = 0; h < num_kv_heads; ++h) {
1032 const float *k_src = k + ((size_t)h * (size_t)qk_head_dim);
1033 const float *v_src = v + ((size_t)h * (size_t)v_head_dim);
1034 float *k_dst = k_cache + ((size_t)h * (size_t)max_seq_len + (size_t)pos) * (size_t)cache_stride;
1035 float *v_dst = v_cache + ((size_t)h * (size_t)max_seq_len + (size_t)pos) * (size_t)cache_stride;
1036
1037 for (int d = 0; d < qk_head_dim; ++d) {
1038 k_dst[d] = k_src[d];
1039 }
1040 for (int d = qk_head_dim; d < cache_stride; ++d) {
1041 k_dst[d] = 0.0f;
1042 }
1043 for (int d = 0; d < v_head_dim; ++d) {
1044 v_dst[d] = v_src[d];
1045 }
1046 for (int d = v_head_dim; d < cache_stride; ++d) {
1047 v_dst[d] = 0.0f;
1048 }
1049 }
1050}
1051
1052static void ds_mla_attention_decode_workspace(const float *q,
1053 const float *k_cache,
1054 const float *v_cache,
1055 float *output,
1056 int num_heads,
1057 int num_kv_heads,
1058 int cache_len,
1059 int qk_head_dim,
1060 int v_head_dim,
1061 int max_seq_len,
1062 int cache_stride,
1063 float scale,
1064 float *scores,
1065 size_t scores_bytes,
1066 int bf16_phases)
1067{
1068 if (!q || !k_cache || !v_cache || !output || num_heads <= 0 ||
1069 num_kv_heads <= 0 || num_heads < num_kv_heads ||
1070 num_heads % num_kv_heads != 0 || cache_len <= 0 ||
1071 cache_len > max_seq_len || qk_head_dim <= 0 ||
1072 v_head_dim <= 0 || max_seq_len <= 0 || cache_stride <= 0 ||
1073 !isfinite(scale) || scale <= 0.0f) {
1074 return;
1075 }
1076 if (qk_head_dim > cache_stride || v_head_dim > cache_stride) {
1077 return;
1078 }
1079 if ((size_t)cache_len > SIZE_MAX / sizeof(float) || !scores ||
1080 scores_bytes < (size_t)cache_len * sizeof(float)) {
1081 return;
1082 }
1083
1084 for (int h = 0; h < num_heads; ++h) {
1085 const int kv_h = (int)((long long)h * (long long)num_kv_heads / (long long)num_heads);
1086 const float *q_vec = q + (size_t)h * (size_t)qk_head_dim;
1087
1088 float max_score = -FLT_MAX;
1089 for (int j = 0; j < cache_len; ++j) {
1090 const float *k_vec = k_cache + ((size_t)kv_h * (size_t)max_seq_len + (size_t)j) * (size_t)cache_stride;
1091 float dot = 0.0f;
1092 for (int d = 0; d < qk_head_dim; ++d) {
1093 dot += bf16_phases
1094 ? ds_mla_bf16_round(q_vec[d]) * ds_mla_bf16_round(k_vec[d])
1095 : q_vec[d] * k_vec[d];
1096 }
1097 const float score = bf16_phases
1098 ? ds_mla_bf16_round(ds_mla_bf16_round(dot) * scale)
1099 : dot * scale;
1100 scores[j] = score;
1101 if (score > max_score) max_score = score;
1102 }
1103
1104 float sum = 0.0f;
1105 for (int j = 0; j < cache_len; ++j) {
1106 const float e = expf(scores[j] - max_score);
1107 scores[j] = e;
1108 sum += e;
1109 }
1110
1111 const float inv_sum = sum > 0.0f ? (1.0f / sum) : 0.0f;
1112 float *out = output + (size_t)h * (size_t)v_head_dim;
1113 for (int d = 0; d < v_head_dim; ++d) out[d] = 0.0f;
1114 for (int j = 0; j < cache_len; ++j) {
1115 const float w = bf16_phases
1116 ? ds_mla_bf16_round(scores[j] * inv_sum)
1117 : scores[j] * inv_sum;
1118 const float *v_vec = v_cache + ((size_t)kv_h * (size_t)max_seq_len + (size_t)j) * (size_t)cache_stride;
1119 for (int d = 0; d < v_head_dim; ++d) {
1120 out[d] += w * (bf16_phases
1121 ? ds_mla_bf16_round(v_vec[d]) : v_vec[d]);
1122 }
1123 }
1124 if (bf16_phases) {
1125 for (int d = 0; d < v_head_dim; ++d) {
1126 out[d] = ds_mla_bf16_round(out[d]);
1127 }
1128 }
1129 }
1130
1131}
1132
1134 const float *q, const float *k_cache, const float *v_cache,
1135 float *output, int num_heads, int num_kv_heads, int cache_len,
1136 int qk_head_dim, int v_head_dim, int max_seq_len, int cache_stride,
1137 float scale, float *scores, size_t scores_bytes)
1138{
1139 ds_mla_attention_decode_workspace(q, k_cache, v_cache, output,
1140 num_heads, num_kv_heads, cache_len, qk_head_dim, v_head_dim,
1141 max_seq_len, cache_stride, scale, scores, scores_bytes, 0);
1142}
1143
1145 const float *q, const float *k_cache, const float *v_cache,
1146 float *output, int num_heads, int num_kv_heads, int cache_len,
1147 int qk_head_dim, int v_head_dim, int max_seq_len, int cache_stride,
1148 float scale, float *scores, size_t scores_bytes)
1149{
1150 ds_mla_attention_decode_workspace(q, k_cache, v_cache, output,
1151 num_heads, num_kv_heads, cache_len, qk_head_dim, v_head_dim,
1152 max_seq_len, cache_stride, scale, scores, scores_bytes, 1);
1153}
1154
1156 const float *k_cache,
1157 const float *v_cache,
1158 float *output,
1159 int num_heads,
1160 int num_kv_heads,
1161 int cache_len,
1162 int qk_head_dim,
1163 int v_head_dim,
1164 int max_seq_len,
1165 int cache_stride)
1166{
1167 if (cache_len <= 0 || (size_t)cache_len > SIZE_MAX / sizeof(float)) return;
1168 const size_t scores_bytes = (size_t)cache_len * sizeof(float);
1169 float *scores = (float *)malloc(scores_bytes);
1170 if (!scores) return;
1172 q, k_cache, v_cache, output, num_heads, num_kv_heads, cache_len,
1173 qk_head_dim, v_head_dim, max_seq_len, cache_stride,
1174 1.0f / sqrtf((float)qk_head_dim), scores, scores_bytes);
1175 free(scores);
1176}
static uint16_t float_to_bf16(float f)
Definition bf16_utils.h:90
static float bf16_to_float(uint16_t v)
Definition bf16_utils.h:38
Persistent pthread thread pool for CK-Engine inference.
void ck_threadpool_parallel_for_n(ck_threadpool_t *pool, int active_threads, int begin, int end, int grain_size, ck_range_fn_t fn, void *args)
#define CK_CACHE_LINE
void ck_threadpool_dispatch_n(ck_threadpool_t *pool, int active_threads, ck_work_fn_t fn, void *args)
ck_threadpool_t * ck_threadpool_global(void)
int ck_threadpool_n_threads(const ck_threadpool_t *pool)
static size_t ds_mix_idx(int t, int out_s, int in_s, int n_streams)
void deepseek_mla_partial_rope_concat_f32(const float *q_nope, const float *q_pe, const float *k_nope, const float *k_pe, const float *cos, const float *sin, float *query, float *key, int tokens, int heads, int qk_nope_dim, int qk_rope_dim)
static void ds_mla_attention_f32_work(int ith, int nth, void *opaque)
void deepseek_mla_attention_f32_workspace(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int qk_head_dim, int v_head_dim, float scale, float *scores, size_t scores_bytes)
static size_t ds_mhc_idx(int t, int s, int d, int n_streams, int dim)
static void ds_mla_attention_decode_workspace(const float *q, const float *k_cache, const float *v_cache, float *output, int num_heads, int num_kv_heads, int cache_len, int qk_head_dim, int v_head_dim, int max_seq_len, int cache_stride, float scale, float *scores, size_t scores_bytes, int bf16_phases)
void deepseek_csa_attention_f32(const float *q, const float *k, const float *v, const int *indices, float *out, float *attn, int query_tokens, int key_tokens, int heads, int dim, int top_k, float scale)
void topk_softmax_backward_f32(const int *indices, const float *weights, const float *d_weights, float *d_scores, int num_tokens, int n_experts_or_keys, int k)
Backward for hard top-k followed by softmax over selected values.
static int ds_mla_prefill_valid(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int qk_head_dim, int v_head_dim, float scale, float *scores, size_t scores_bytes)
void deepseek_mla_attention_bf16_phases_parallel_dispatch(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int qk_head_dim, int v_head_dim, float scale, float *scores, size_t scores_bytes)
void deepseek_mla_attention_decode_f32_workspace(const float *q, const float *k_cache, const float *v_cache, float *output, int num_heads, int num_kv_heads, int cache_len, int qk_head_dim, int v_head_dim, int max_seq_len, int cache_stride, float scale, float *scores, size_t scores_bytes)
void deepseek_mhc_mix_f32(const float *streams, const float *mix, float *out, int tokens, int n_streams, int dim)
void deepseek_mla_kv_decompress_bf16(const float *compressed_kv, const uint16_t *kv_b_proj, float *k_nope, float *value, int tokens, int heads, int kv_lora_rank, int qk_nope_dim, int v_dim)
void deepseek_mla_kv_decompress_f32(const float *compressed_kv, const float *kv_b_proj, float *k_nope, float *value, int tokens, int heads, int kv_lora_rank, int qk_nope_dim, int v_dim)
static float ds_mla_bf16_round(float value)
void deepseek_mla_kv_decompress_bf16_token_range(const float *compressed_kv, const uint16_t *kv_b_proj, float *k_nope, float *value, int tokens, int heads, int kv_lora_rank, int qk_nope_dim, int v_dim, int token_begin, int token_end)
static size_t ds_qkv_idx(int token, int head, int d, int heads, int dim)
static size_t ds_mla_thd_idx(int t, int h, int d, int heads, int dim)
static void ds_mla_attention_f32_query_range(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int qk_head_dim, int v_head_dim, float scale, float *scores, int query_begin, int query_end, int query_step, int bf16_phases)
void deepseek_mla_attention_f32_parallel_dispatch(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int qk_head_dim, int v_head_dim, float scale, float *scores, size_t scores_bytes)
static void ds_mla_kv_decompress_bf16_rows(int begin, int end, void *opaque)
void deepseek_csa_attention_backward_f32(const float *d_out, const float *q, const float *k, const float *v, const int *indices, const float *attn, float *d_q, float *d_k, float *d_v, int query_tokens, int key_tokens, int heads, int dim, int top_k, float scale)
void deepseek_mla_kv_cache_batch_store_f32(float *k_cache, float *v_cache, const float *k, const float *v, int num_tokens, int num_kv_heads, int qk_head_dim, int v_head_dim, int max_seq_len, int cache_stride)
void deepseek_mla_attention_bf16_phases_workspace(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int qk_head_dim, int v_head_dim, float scale, float *scores, size_t scores_bytes)
static void ds_softmax(float *x, int n)
static size_t ds_mla_tok_idx(int t, int d, int dim)
void deepseek_mla_attention_f32(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int qk_head_dim, int v_head_dim)
void deepseek_mhc_mix_backward_f32(const float *d_out, const float *streams, const float *mix, float *d_streams, float *d_mix, int tokens, int n_streams, int dim)
void deepseek_dsa_topk_softmax_f32(const float *scores, int *indices, float *weights, int tokens, int heads, int key_count, int top_k)
void deepseek_dsa_topk_softmax_backward_f32(const int *indices, const float *weights, const float *d_weights, float *d_scores, int tokens, int heads, int key_count, int top_k)
void deepseek_mla_kv_decompress_bf16_parallel_dispatch(const float *compressed_kv, const uint16_t *kv_b_proj, float *k_nope, float *value, int tokens, int heads, int kv_lora_rank, int qk_nope_dim, int v_dim)
void deepseek_mla_partial_rope_concat_packed_f32(const float *q_packed, const float *k_nope, const float *kv_a_packed, const float *cos, const float *sin, float *query, float *key, int tokens, int heads, int kv_lora_rank, int qk_nope_dim, int qk_rope_dim)
void deepseek_mla_attention_decode_bf16_phases_workspace(const float *q, const float *k_cache, const float *v_cache, float *output, int num_heads, int num_kv_heads, int cache_len, int qk_head_dim, int v_head_dim, int max_seq_len, int cache_stride, float scale, float *scores, size_t scores_bytes)
void deepseek_mla_attention_decode_f32(const float *q, const float *k_cache, const float *v_cache, float *output, int num_heads, int num_kv_heads, int cache_len, int qk_head_dim, int v_head_dim, int max_seq_len, int cache_stride)
void deepseek_hybrid_attention_f32(const float *q, const float *k, const float *v, const int *indices, float *out, float *attn, int query_tokens, int key_tokens, int heads, int dim, int top_k, float scale, int mode)
void deepseek_mla_kv_cache_store_f32(float *k_cache, float *v_cache, const float *k, const float *v, int pos, int num_kv_heads, int qk_head_dim, int v_head_dim, int max_seq_len, int cache_stride)
void deepseek_mla_partial_rope_concat_packed_bf16_storage(const float *q_packed, const float *k_nope, const float *kv_a_packed, const float *cos, const float *sin, float *query, float *key, int tokens, int heads, int kv_lora_rank, int qk_nope_dim, int qk_rope_dim)
static void ds_mla_attention_parallel_dispatch(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int qk_head_dim, int v_head_dim, float scale, float *scores, size_t scores_bytes, int bf16_phases)
static void ds_mla_apply_kimi_rope(const float *src, float *dst, const float *cos_row, const float *sin_row, int dim)
const char * token
Definition tokenizer.h:307
int32_t float * score
Definition tokenizer.h:328
uint32_t end
Definition utf8.c:215