← Back to C-Kernel-Engine Docs Doxygen Source Documentation
 
Loading...
Searching...
No Matches
gemma4_per_layer_embed.c
Go to the documentation of this file.
1#include <math.h>
2#include <stdint.h>
3#include <stddef.h>
4#include <stdlib.h>
5#include <string.h>
6#if defined(__AVX2__)
7#include <immintrin.h>
8#endif
9
10#include "ck_threadpool.h"
11#include "ckernel_quant.h"
12#include "bf16_utils.h"
13
15 const float *A, const float *B, const float *bias, float *C,
16 int M, int N, int K, int output_begin, int output_end);
18 const float *input, const float *gamma, float *output, float *rstd_cache,
19 int tokens, int d_model, int aligned_embed_dim, float eps);
20
21typedef struct {
22 ck_half d;
23 ck_half dmin;
24 uint8_t scales[K_SCALE_SIZE];
25 uint8_t qh[QK_K / 8];
26 uint8_t qs[QK_K / 2];
27} ck_gemma4_block_q5_K;
28
29#define CK_GEMMA4_MAX_EMBED_DIM 16384
30
31static inline float ck_bf16_to_f32(uint16_t v)
32{
33 uint32_t bits = ((uint32_t)v) << 16;
34 float out;
35 memcpy(&out, &bits, sizeof(out));
36 return out;
37}
38
39static float ck_gemma4_bf16_dot(const uint16_t *x, const uint16_t *y, int n)
40{
41 int i = 0;
42 double sum = 0.0;
43#if defined(__AVX2__)
44 // Match ggml-cpu's BF16 AVX2 reduction for this selected numerical contract.
45 __m256 c1 = _mm256_setzero_ps();
46 __m256 c2 = _mm256_setzero_ps();
47 __m256 c3 = _mm256_setzero_ps();
48 __m256 c4 = _mm256_setzero_ps();
49#define CK_GEMMA4_LOAD_BF16(p) _mm256_castsi256_ps(_mm256_slli_epi32( \
50 _mm256_cvtepu16_epi32(_mm_loadu_si128((const __m128i *)(p))), 16))
51 for (; i + 32 <= n; i += 32) {
52 c1 = _mm256_add_ps(_mm256_mul_ps(CK_GEMMA4_LOAD_BF16(x + i),
53 CK_GEMMA4_LOAD_BF16(y + i)), c1);
54 c2 = _mm256_add_ps(_mm256_mul_ps(CK_GEMMA4_LOAD_BF16(x + i + 8),
55 CK_GEMMA4_LOAD_BF16(y + i + 8)), c2);
56 c3 = _mm256_add_ps(_mm256_mul_ps(CK_GEMMA4_LOAD_BF16(x + i + 16),
57 CK_GEMMA4_LOAD_BF16(y + i + 16)), c3);
58 c4 = _mm256_add_ps(_mm256_mul_ps(CK_GEMMA4_LOAD_BF16(x + i + 24),
59 CK_GEMMA4_LOAD_BF16(y + i + 24)), c4);
60 }
61#undef CK_GEMMA4_LOAD_BF16
62 c1 = _mm256_add_ps(_mm256_add_ps(c1, c3), _mm256_add_ps(c2, c4));
63 __m128 g = _mm_add_ps(_mm256_extractf128_ps(c1, 1), _mm256_castps256_ps128(c1));
64 g = _mm_add_ps(g, _mm_movehl_ps(g, g));
65 g = _mm_add_ss(g, _mm_movehdup_ps(g));
66 sum = (double)_mm_cvtss_f32(g);
67#endif
68 for (; i < n; ++i) {
69 sum += (double)(ck_bf16_to_f32(x[i]) * ck_bf16_to_f32(y[i]));
70 }
71 return (float)sum;
72}
73
74static inline float ck_gemma4_gelu(float x)
75{
76 if (x <= -10.0f) return 0.0f;
77 if (x >= 10.0f) return x;
79 const float c0 = 0.7978845608028654f;
80 const float c1 = 0.044715f;
81 const float y = 0.5f * x * (1.0f + tanhf(c0 * x * (1.0f + c1 * x * x)));
83}
84
85static inline void ck_gemma4_unpack_q5_k_scales(const uint8_t *scales, uint8_t *sc, uint8_t *m)
86{
87 sc[0] = scales[0] & 0x3F;
88 sc[1] = scales[1] & 0x3F;
89 sc[2] = scales[2] & 0x3F;
90 sc[3] = scales[3] & 0x3F;
91
92 m[0] = scales[4] & 0x3F;
93 m[1] = scales[5] & 0x3F;
94 m[2] = scales[6] & 0x3F;
95 m[3] = scales[7] & 0x3F;
96
97 sc[4] = (scales[8] & 0x0F) | ((scales[0] >> 6) << 4);
98 sc[5] = (scales[9] & 0x0F) | ((scales[1] >> 6) << 4);
99 sc[6] = (scales[10] & 0x0F) | ((scales[2] >> 6) << 4);
100 sc[7] = (scales[11] & 0x0F) | ((scales[3] >> 6) << 4);
101
102 m[4] = (scales[8] >> 4) | ((scales[4] >> 6) << 4);
103 m[5] = (scales[9] >> 4) | ((scales[5] >> 6) << 4);
104 m[6] = (scales[10] >> 4) | ((scales[6] >> 6) << 4);
105 m[7] = (scales[11] >> 4) | ((scales[7] >> 6) << 4);
106}
107
108static inline uint8_t ck_gemma4_q5_k_value(const ck_gemma4_block_q5_K *block, int subblock, int i)
109{
110 const uint8_t *ql = block->qs + (subblock / 2) * 32;
111 const uint8_t low = (subblock & 1) ? (uint8_t)(ql[i] >> 4) : (uint8_t)(ql[i] & 0x0F);
112 const uint8_t high = (block->qh[i] & (uint8_t)(1u << subblock)) ? 16u : 0u;
113 return (uint8_t)(low | high);
114}
115
116static void ck_gemma4_dequant_q5_k_block(const ck_gemma4_block_q5_K *block, float *out)
117{
118 uint8_t sc[8];
119 uint8_t m[8];
120 ck_gemma4_unpack_q5_k_scales(block->scales, sc, m);
121 const float d = CK_FP16_TO_FP32(block->d);
122 const float dmin = CK_FP16_TO_FP32(block->dmin);
123 for (int s = 0; s < 8; ++s) {
124 const float scale = d * (float)sc[s];
125 const float minv = dmin * (float)m[s];
126 for (int i = 0; i < 32; ++i) {
127 out[s * 32 + i] = scale * (float)ck_gemma4_q5_k_value(block, s, i) - minv;
128 }
129 }
130}
131
132static void ck_gemma4_rmsnorm_tmp(const float *x, const float *gamma, float *out, int n, float eps)
133{
134 double ss = 0.0;
135 for (int i = 0; i < n; ++i) {
136 ss += (double)x[i] * (double)x[i];
137 }
138 const float scale = 1.0f / sqrtf((float)(ss / (double)n) + eps);
139 for (int i = 0; i < n; ++i) {
140 out[i] = x[i] * scale * gamma[i];
141 }
142}
143
144typedef struct {
145 float *per_layer_input;
146 const float *hidden;
147 const int32_t *token_ids;
148 const void *per_layer_token_emb;
149 const uint16_t *per_layer_model_proj;
150 const float *per_layer_proj_norm;
151 int num_layers;
152 int embed_dim;
153 int per_layer_dim;
154 int vocab_size;
155 float eps;
156} ck_gemma4_prepare_args_t;
157
158static void ck_gemma4_prepare_q5_range(int begin, int end, void *opaque)
159{
160 const ck_gemma4_prepare_args_t *args =
161 (const ck_gemma4_prepare_args_t *)opaque;
162 const ck_gemma4_block_q5_K *token_blocks =
163 (const ck_gemma4_block_q5_K *)args->per_layer_token_emb;
164 const size_t token_blocks_per_row = (size_t)args->num_layers;
165 const float token_scale = sqrtf((float)args->per_layer_dim);
166 const float model_scale = 1.0f / sqrtf((float)args->embed_dim);
167 const float mix_scale = 0.7071067811865475f;
168 float token_vec[QK_K];
169 float proj_vec[QK_K];
170 float proj_normed[QK_K];
171
172 for (int t = begin; t < end; ++t) {
173 const int token = args->token_ids[t];
174 if (token < 0 || token >= args->vocab_size) continue;
175 const float *h = args->hidden + (size_t)t * (size_t)args->embed_dim;
176 uint16_t rounded_hidden[args->embed_dim];
177 for (int j = 0; j < args->embed_dim; ++j) {
178 rounded_hidden[j] = float_to_bf16(h[j]);
179 }
180 for (int layer = 0; layer < args->num_layers; ++layer) {
181 float *dst = args->per_layer_input +
182 ((size_t)t * (size_t)args->num_layers + (size_t)layer) *
183 (size_t)args->per_layer_dim;
184 const ck_gemma4_block_q5_K *tok_block = token_blocks +
185 (size_t)token * token_blocks_per_row + (size_t)layer;
186 ck_gemma4_dequant_q5_k_block(tok_block, token_vec);
187 for (int i = 0; i < args->per_layer_dim; ++i) {
188 token_vec[i] *= token_scale;
189 }
190
191 const uint16_t *model_proj_base = args->per_layer_model_proj +
192 (size_t)layer * (size_t)args->per_layer_dim *
193 (size_t)args->embed_dim;
194 for (int i = 0; i < args->per_layer_dim; ++i) {
195 const uint16_t *row = model_proj_base +
196 (size_t)i * (size_t)args->embed_dim;
197 const float acc = ck_gemma4_bf16_dot(row, rounded_hidden, args->embed_dim);
198 proj_vec[i] = acc * model_scale;
199 }
201 proj_vec, args->per_layer_proj_norm, proj_normed,
202 args->per_layer_dim, args->eps);
203 for (int i = 0; i < args->per_layer_dim; ++i) {
204 dst[i] = (token_vec[i] + proj_normed[i]) * mix_scale;
205 }
206 }
207 }
208}
209
210static void ck_gemma4_prepare_bf16_range(int begin, int end, void *opaque)
211{
212 const ck_gemma4_prepare_args_t *args =
213 (const ck_gemma4_prepare_args_t *)opaque;
214 const uint16_t *token_embeddings =
215 (const uint16_t *)args->per_layer_token_emb;
216 const float token_scale = sqrtf((float)args->per_layer_dim);
217 const float model_scale = 1.0f / sqrtf((float)args->embed_dim);
218 const float mix_scale = 0.7071067811865475f;
219 float token_vec[QK_K];
220 float proj_vec[QK_K];
221 float proj_normed[QK_K];
222
223 for (int t = begin; t < end; ++t) {
224 const int token = args->token_ids[t];
225 if (token < 0 || token >= args->vocab_size) continue;
226 const float *h = args->hidden + (size_t)t * (size_t)args->embed_dim;
227 uint16_t rounded_hidden[args->embed_dim];
228 for (int j = 0; j < args->embed_dim; ++j) {
229 rounded_hidden[j] = float_to_bf16(h[j]);
230 }
231 for (int layer = 0; layer < args->num_layers; ++layer) {
232 float *dst = args->per_layer_input +
233 ((size_t)t * (size_t)args->num_layers + (size_t)layer) *
234 (size_t)args->per_layer_dim;
235 const uint16_t *tok_row = token_embeddings +
236 ((size_t)token * (size_t)args->num_layers + (size_t)layer) *
237 (size_t)args->per_layer_dim;
238 for (int i = 0; i < args->per_layer_dim; ++i) {
239 token_vec[i] = ck_bf16_to_f32(tok_row[i]) * token_scale;
240 }
241
242 const uint16_t *model_proj_base = args->per_layer_model_proj +
243 (size_t)layer * (size_t)args->per_layer_dim *
244 (size_t)args->embed_dim;
245 for (int i = 0; i < args->per_layer_dim; ++i) {
246 const uint16_t *row = model_proj_base +
247 (size_t)i * (size_t)args->embed_dim;
248 const float acc = ck_gemma4_bf16_dot(row, rounded_hidden, args->embed_dim);
249 proj_vec[i] = acc * model_scale;
250 }
252 proj_vec, args->per_layer_proj_norm, proj_normed,
253 args->per_layer_dim, args->eps);
254 for (int i = 0; i < args->per_layer_dim; ++i) {
255 dst[i] = (token_vec[i] + proj_normed[i]) * mix_scale;
256 }
257 }
258 }
259}
260
262 int tokens, ck_range_fn_t fn, ck_gemma4_prepare_args_t *args)
263{
264 ck_threadpool_t *pool = ck_threadpool_global();
265 int active = pool ? ck_threadpool_n_threads(pool) : 1;
266 const char *disabled = getenv("CK_DISABLE_GEMMA4_PREPARE_PARALLEL");
267 if (disabled && disabled[0] && strcmp(disabled, "0") != 0) active = 1;
268 if (active > tokens) active = tokens;
269 ck_threadpool_parallel_for_n(pool, active, 0, tokens, 1, fn, args);
270}
271
272void gemma4_per_layer_prepare_forward(float *per_layer_input,
273 const float *hidden,
274 const int32_t *token_ids,
275 const void *per_layer_token_emb,
276 const uint16_t *per_layer_model_proj,
277 const float *per_layer_proj_norm,
278 int tokens,
279 int num_layers,
280 int embed_dim,
281 int per_layer_dim,
282 int vocab_size,
283 float eps)
284{
285 if (!per_layer_input || !hidden || !token_ids || !per_layer_token_emb ||
286 !per_layer_model_proj || !per_layer_proj_norm || tokens <= 0 ||
287 num_layers <= 0 || embed_dim <= 0 || embed_dim > CK_GEMMA4_MAX_EMBED_DIM ||
288 per_layer_dim != QK_K || vocab_size <= 0) {
289 return;
290 }
291
292 ck_gemma4_prepare_args_t args = {
293 .per_layer_input = per_layer_input,
294 .hidden = hidden,
295 .token_ids = token_ids,
296 .per_layer_token_emb = per_layer_token_emb,
297 .per_layer_model_proj = per_layer_model_proj,
298 .per_layer_proj_norm = per_layer_proj_norm,
299 .num_layers = num_layers,
300 .embed_dim = embed_dim,
301 .per_layer_dim = per_layer_dim,
302 .vocab_size = vocab_size,
303 .eps = eps,
304 };
306}
307
308
309void gemma4_per_layer_prepare_bf16_forward(float *per_layer_input,
310 const float *hidden,
311 const int32_t *token_ids,
312 const uint16_t *per_layer_token_emb,
313 const uint16_t *per_layer_model_proj,
314 const float *per_layer_proj_norm,
315 int tokens,
316 int num_layers,
317 int embed_dim,
318 int per_layer_dim,
319 int vocab_size,
320 float eps)
321{
322 if (!per_layer_input || !hidden || !token_ids || !per_layer_token_emb ||
323 !per_layer_model_proj || !per_layer_proj_norm || tokens <= 0 ||
324 num_layers <= 0 || embed_dim <= 0 || embed_dim > CK_GEMMA4_MAX_EMBED_DIM ||
325 per_layer_dim <= 0 || vocab_size <= 0) {
326 return;
327 }
328
329 if (per_layer_dim > QK_K) {
330 return;
331 }
332 ck_gemma4_prepare_args_t args = {
333 .per_layer_input = per_layer_input,
334 .hidden = hidden,
335 .token_ids = token_ids,
336 .per_layer_token_emb = per_layer_token_emb,
337 .per_layer_model_proj = per_layer_model_proj,
338 .per_layer_proj_norm = per_layer_proj_norm,
339 .num_layers = num_layers,
340 .embed_dim = embed_dim,
341 .per_layer_dim = per_layer_dim,
342 .vocab_size = vocab_size,
343 .eps = eps,
344 };
346}
347
348typedef struct {
349 float *hidden;
350 const float *per_layer_input;
351 const float *inp_gate;
352 const float *proj;
353 const float *post_norm;
354 const float *out_scale;
355 int layer;
356 int num_layers;
357 int embed_dim;
358 int per_layer_dim;
359 int tokens;
360 float eps;
361 const int *segment_lengths;
362 int num_segments;
363 int singleton_tail;
364} ck_gemma4_embed_args_t;
365
366static int ck_gemma4_embed_row_group(const ck_gemma4_embed_args_t *args, int token, int tokens)
367{
368 if (!args->segment_lengths) return tokens > 1 ? 2 : 1;
369 int start = 0;
370 for (int segment = 0; segment < args->num_segments; ++segment) {
371 const int length = args->segment_lengths[segment];
372 if (token < start + length) {
373 if (length == 1 || (args->singleton_tail && segment == args->num_segments - 1)) {
374 return 1;
375 }
376 return 2;
377 }
378 start += length;
379 }
380 return 1;
381}
382
383static void ck_gemma4_embed_range(int begin, int end, void *opaque)
384{
385 const ck_gemma4_embed_args_t *args =
386 (const ck_gemma4_embed_args_t *)opaque;
387 float gate_vec[QK_K];
388 float branch[4096];
389 float branch_normed[4096];
390 for (int t = begin; t < end; ++t) {
391 float *h = args->hidden + (size_t)t * (size_t)args->embed_dim;
392 const float *inp_vec = args->per_layer_input +
393 ((size_t)t * (size_t)args->num_layers + (size_t)args->layer) *
394 (size_t)args->per_layer_dim;
395
396 const int row_group = ck_gemma4_embed_row_group(args, t, args->tokens);
398 h, args->inp_gate, NULL, gate_vec, row_group,
399 args->per_layer_dim, args->embed_dim, 0, args->per_layer_dim);
400 for (int i = 0; i < args->per_layer_dim; ++i) {
401 gate_vec[i] = ck_gemma4_gelu(gate_vec[i]) * inp_vec[i];
402 }
403
405 gate_vec, args->proj, NULL, branch, row_group,
406 args->embed_dim, args->per_layer_dim, 0, args->embed_dim);
408 branch, args->post_norm, branch_normed, NULL,
409 1, args->embed_dim, args->embed_dim, args->eps);
410 const float layer_scale = args->out_scale ? args->out_scale[0] : 1.0f;
411 for (int j = 0; j < args->embed_dim; ++j) {
412 h[j] = (h[j] + branch_normed[j]) * layer_scale;
413 }
414 }
415}
416
418 const float *per_layer_input,
419 const float *inp_gate,
420 const float *proj,
421 const float *post_norm,
422 const float *out_scale,
423 int tokens,
424 int layer,
425 int num_layers,
426 int embed_dim,
427 int per_layer_dim,
428 float eps,
429 const int *segment_lengths,
430 int num_segments,
431 int singleton_tail)
432{
433 if (!hidden || !per_layer_input || !inp_gate || !proj || !post_norm ||
434 tokens <= 0 || layer < 0 || layer >= num_layers || embed_dim <= 0 ||
435 per_layer_dim != QK_K || embed_dim > 4096 ||
436 (segment_lengths == NULL) != (num_segments == 0) ||
437 (singleton_tail != 0 && singleton_tail != 1)) {
438 return;
439 }
440 if (segment_lengths) {
441 int remaining = tokens;
442 for (int i = 0; i < num_segments; ++i) {
443 if (segment_lengths[i] < 0 || segment_lengths[i] > remaining) return;
444 remaining -= segment_lengths[i];
445 }
446 if (remaining != 0) return;
447 }
448
449 ck_gemma4_embed_args_t args = {
450 .hidden = hidden,
451 .per_layer_input = per_layer_input,
452 .inp_gate = inp_gate,
453 .proj = proj,
454 .post_norm = post_norm,
455 .out_scale = out_scale,
456 .layer = layer,
457 .num_layers = num_layers,
458 .embed_dim = embed_dim,
459 .per_layer_dim = per_layer_dim,
460 .tokens = tokens,
461 .eps = eps,
462 .segment_lengths = segment_lengths,
463 .num_segments = num_segments,
464 .singleton_tail = singleton_tail,
465 };
466 ck_threadpool_t *pool = ck_threadpool_global();
467 int active = pool ? ck_threadpool_n_threads(pool) : 1;
468 const char *disabled = getenv("CK_DISABLE_GEMMA4_EMBED_PARALLEL");
469 if (disabled && disabled[0] && strcmp(disabled, "0") != 0) active = 1;
470 if (active > tokens) active = tokens;
472 pool, active, 0, tokens, 1, ck_gemma4_embed_range, &args);
473}
474
476 const float *scale,
477 int tokens,
478 int embed_dim)
479{
480 if (!hidden || !scale || tokens <= 0 || embed_dim <= 0) {
481 return;
482 }
483
484 const float s = scale[0];
485 const size_t n = (size_t)tokens * (size_t)embed_dim;
486 for (size_t i = 0; i < n; ++i) {
487 hidden[i] *= s;
488 }
489}
490
492 int tokens,
493 int vocab_size,
494 float cap)
495{
496 if (!logits || tokens <= 0 || vocab_size <= 0 || cap <= 0.0f) {
497 return;
498 }
499 const float inv_cap = 1.0f / cap;
500 const size_t total = (size_t)tokens * (size_t)vocab_size;
501 for (size_t i = 0; i < total; ++i) {
502 logits[i] = tanhf(logits[i] * inv_cap) * cap;
503 }
504}
static uint16_t float_to_bf16(float f)
Definition bf16_utils.h:90
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)
ck_threadpool_t * ck_threadpool_global(void)
void(* ck_range_fn_t)(int begin, int end, void *args)
int ck_threadpool_n_threads(const ck_threadpool_t *pool)
Quantization block structures for weight-only quantization.
#define K_SCALE_SIZE
uint16_t ck_half
#define CK_FP16_TO_FP32(x)
#define CK_FP32_TO_FP16(x)
#define QK_K
void gemma4_per_layer_prepare_forward(float *per_layer_input, const float *hidden, const int32_t *token_ids, const void *per_layer_token_emb, const uint16_t *per_layer_model_proj, const float *per_layer_proj_norm, int tokens, int num_layers, int embed_dim, int per_layer_dim, int vocab_size, float eps)
#define CK_GEMMA4_MAX_EMBED_DIM
void rmsnorm_forward_llama_production(const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps)
void gemm_nt_f32_llama_production_output_range(const float *A, const float *B, const float *bias, float *C, int M, int N, int K, int output_begin, int output_end)
static void ck_gemma4_dequant_q5_k_block(const ck_gemma4_block_q5_K *block, float *out)
static int ck_gemma4_embed_row_group(const ck_gemma4_embed_args_t *args, int token, int tokens)
static void ck_gemma4_prepare_parallel(int tokens, ck_range_fn_t fn, ck_gemma4_prepare_args_t *args)
static void ck_gemma4_embed_range(int begin, int end, void *opaque)
void gemma4_per_layer_embed_forward(float *hidden, const float *per_layer_input, const float *inp_gate, const float *proj, const float *post_norm, const float *out_scale, int tokens, int layer, int num_layers, int embed_dim, int per_layer_dim, float eps, const int *segment_lengths, int num_segments, int singleton_tail)
static void ck_gemma4_unpack_q5_k_scales(const uint8_t *scales, uint8_t *sc, uint8_t *m)
static float ck_bf16_to_f32(uint16_t v)
static float ck_gemma4_gelu(float x)
void assistant_layer_scale_forward(float *hidden, const float *scale, int tokens, int embed_dim)
static float ck_gemma4_bf16_dot(const uint16_t *x, const uint16_t *y, int n)
void gemma4_per_layer_prepare_bf16_forward(float *per_layer_input, const float *hidden, const int32_t *token_ids, const uint16_t *per_layer_token_emb, const uint16_t *per_layer_model_proj, const float *per_layer_proj_norm, int tokens, int num_layers, int embed_dim, int per_layer_dim, int vocab_size, float eps)
void gemma4_final_logit_softcap_forward(float *logits, int tokens, int vocab_size, float cap)
static void ck_gemma4_prepare_bf16_range(int begin, int end, void *opaque)
static void ck_gemma4_prepare_q5_range(int begin, int end, void *opaque)
static void ck_gemma4_rmsnorm_tmp(const float *x, const float *gamma, float *out, int n, float eps)
static uint8_t ck_gemma4_q5_k_value(const ck_gemma4_block_q5_K *block, int subblock, int i)
#define C(color)
Definition show_config.c:39
const char * token
Definition tokenizer.h:307
int vocab_size
Definition true_bpe.h:197
uint32_t end
Definition utf8.c:215
uint32_t start
Definition utf8.c:214