@@ -387,6 +387,181 @@ static ggml_tensor * gemma4_view_2d_slice(ggml_context * ctx, ggml_tensor * x, i
387387 (size_t )idx * x->ne [0 ] * x->ne [1 ] * ggml_element_size (x));
388388}
389389
390+ static ggml_tensor * build_gemma4_per_layer_input (
391+ ggml_context * ctx,
392+ const Gemma4Weights & w,
393+ ggml_tensor * embed,
394+ ggml_tensor * token_ids,
395+ int n_tokens,
396+ int layer_idx) {
397+ if (!token_ids || !w.per_layer_tok_embd || !w.per_layer_model_proj ||
398+ !w.per_layer_proj_norm || w.n_embd_per_layer <= 0 ) {
399+ return nullptr ;
400+ }
401+ const int D = w.n_embd_per_layer ;
402+ const size_t elt_tok = ggml_element_size (w.per_layer_tok_embd );
403+ const size_t elt_norm = ggml_element_size (w.per_layer_proj_norm );
404+
405+ ggml_tensor * tok_embd_layer = ggml_view_2d (
406+ ctx, w.per_layer_tok_embd , D, w.n_vocab ,
407+ w.per_layer_tok_embd ->nb [1 ], (size_t )layer_idx * D * elt_tok);
408+ ggml_tensor * inp_pl = ggml_get_rows (ctx, tok_embd_layer, token_ids);
409+ inp_pl = ggml_scale (ctx, inp_pl, std::sqrt ((float )D));
410+
411+ ggml_tensor * proj_w_layer = ggml_view_2d (
412+ ctx, w.per_layer_model_proj , w.n_embd , D,
413+ w.per_layer_model_proj ->nb [1 ],
414+ (size_t )layer_idx * D * w.per_layer_model_proj ->nb [1 ]);
415+ ggml_tensor * proj = ggml_mul_mat (ctx, proj_w_layer, embed);
416+ proj = ggml_scale (ctx, proj, 1 .0f / std::sqrt ((float )w.n_embd ));
417+ proj = ggml_rms_norm (ctx, proj, w.norm_eps );
418+ ggml_tensor * norm_w = ggml_view_1d (
419+ ctx, w.per_layer_proj_norm , D, (size_t )layer_idx * D * elt_norm);
420+ proj = ggml_mul (ctx, proj, norm_w);
421+
422+ ggml_tensor * per_layer = ggml_add (ctx, proj, inp_pl);
423+ return ggml_scale (ctx, per_layer, 1 .0f / std::sqrt (2 .0f ));
424+ }
425+
426+ void gemma4_layer_step_graph_free (Gemma4LayerStepGraph & sg) {
427+ if (sg.ctx ) {
428+ ggml_free (sg.ctx );
429+ sg.ctx = nullptr ;
430+ }
431+ sg.gf = nullptr ;
432+ sg.positions = nullptr ;
433+ sg.token_ids = nullptr ;
434+ sg.attn_mask_full = nullptr ;
435+ sg.attn_mask_swa = nullptr ;
436+ }
437+
438+ void gemma4_layer_step_graph_destroy (Gemma4LayerStepGraph & sg) {
439+ if (sg.alloc ) {
440+ ggml_gallocr_free (sg.alloc );
441+ sg.alloc = nullptr ;
442+ }
443+ gemma4_layer_step_graph_free (sg);
444+ }
445+
446+ bool build_gemma4_layer_step (
447+ Gemma4LayerStepGraph & sg,
448+ const Gemma4Weights & w,
449+ Gemma4Cache & cache,
450+ ggml_backend_t backend,
451+ int layer_idx,
452+ ggml_tensor * act_in,
453+ ggml_tensor * orig_embed,
454+ ggml_tensor * act_out,
455+ int chunk_start,
456+ int n_tokens,
457+ int kv_start) {
458+ gemma4_layer_step_graph_free (sg);
459+ if (layer_idx < 0 || layer_idx >= w.n_layer ) return false ;
460+
461+ ggml_init_params ip{};
462+ ip.mem_size = ggml_tensor_overhead () * 16384 + ggml_graph_overhead () + 16 * 1024 * 1024 ;
463+ ip.no_alloc = true ;
464+ sg.ctx = ggml_init (ip);
465+ if (!sg.ctx ) return false ;
466+ sg.gf = ggml_new_graph_custom (sg.ctx , 16384 , false );
467+
468+ ggml_tensor * inp = ggml_view_2d (
469+ sg.ctx , act_in, w.n_embd , n_tokens,
470+ act_in->nb [1 ], (size_t )chunk_start * act_in->nb [1 ]);
471+ ggml_set_input (inp);
472+
473+ ggml_tensor * embed = ggml_view_2d (
474+ sg.ctx , orig_embed, w.n_embd , n_tokens,
475+ orig_embed->nb [1 ], (size_t )chunk_start * orig_embed->nb [1 ]);
476+ ggml_set_input (embed);
477+
478+ sg.positions = ggml_new_tensor_1d (sg.ctx , GGML_TYPE_I32 , n_tokens);
479+ ggml_set_input (sg.positions );
480+
481+ sg.token_ids = ggml_new_tensor_1d (sg.ctx , GGML_TYPE_I32 , n_tokens);
482+ ggml_set_input (sg.token_ids );
483+
484+ const int kv_len_raw = kv_start + n_tokens;
485+ const int kv_len_padded = (kv_len_raw + 255 ) & ~255 ;
486+ sg.attn_mask_full = ggml_new_tensor_4d (
487+ sg.ctx , GGML_TYPE_F32 , kv_len_padded, n_tokens, 1 , 1 );
488+ ggml_set_input (sg.attn_mask_full );
489+ ggml_tensor * mask_full_f16 = ggml_cast (sg.ctx , sg.attn_mask_full , GGML_TYPE_F16 );
490+
491+ const int swa_size = cache.swa_size ;
492+ if (swa_size <= 0 ) return false ;
493+ const int swa_len_raw = std::min (kv_start + n_tokens, swa_size);
494+ const int swa_len_padded = (swa_len_raw + 255 ) & ~255 ;
495+ sg.attn_mask_swa = ggml_new_tensor_4d (
496+ sg.ctx , GGML_TYPE_F32 , swa_len_padded, n_tokens, 1 , 1 );
497+ ggml_set_input (sg.attn_mask_swa );
498+ ggml_tensor * mask_swa_f16 = ggml_cast (sg.ctx , sg.attn_mask_swa , GGML_TYPE_F16 );
499+
500+ ggml_tensor * pl_input = build_gemma4_per_layer_input (
501+ sg.ctx , w, embed, sg.token_ids , n_tokens, layer_idx);
502+ ggml_tensor * layer_out = build_gemma4_layer (
503+ sg.ctx , sg.gf , w, cache, layer_idx, inp, sg.positions ,
504+ mask_full_f16, mask_swa_f16, pl_input, kv_start, n_tokens);
505+ if (!layer_out) return false ;
506+
507+ ggml_tensor * out_view = ggml_view_2d (
508+ sg.ctx , act_out, w.n_embd , n_tokens,
509+ act_out->nb [1 ], (size_t )chunk_start * act_out->nb [1 ]);
510+ ggml_build_forward_expand (sg.gf , ggml_cpy (sg.ctx , layer_out, out_view));
511+
512+ if (!sg.alloc ) {
513+ sg.alloc = ggml_gallocr_new (ggml_backend_get_default_buffer_type (backend));
514+ }
515+ return ggml_gallocr_alloc_graph (sg.alloc , sg.gf );
516+ }
517+
518+ bool compute_gemma4_split_argmax (
519+ ggml_backend_t backend,
520+ const Gemma4Weights & w,
521+ ggml_tensor * act,
522+ int token_offset,
523+ int n_tokens,
524+ std::vector<int32_t > & out_argmax) {
525+ ggml_init_params ip{};
526+ ip.mem_size = ggml_tensor_overhead () * 64 + ggml_graph_overhead () + 1024 * 1024 ;
527+ ip.no_alloc = true ;
528+ ggml_context * ctx = ggml_init (ip);
529+ if (!ctx) return false ;
530+ ggml_cgraph * gf = ggml_new_graph (ctx);
531+
532+ ggml_tensor * act_view = ggml_view_2d (
533+ ctx, act, w.n_embd , n_tokens, act->nb [1 ],
534+ (size_t )token_offset * act->nb [1 ]);
535+ ggml_tensor * cur = gemma4_rms_norm_mul (ctx, act_view, w.out_norm , w.norm_eps );
536+ cur = ggml_mul_mat (ctx, w.output , cur);
537+ if (w.final_logit_softcap > 0 .0f ) {
538+ cur = ggml_scale (ctx, cur, 1 .0f / w.final_logit_softcap );
539+ cur = ggml_tanh (ctx, cur);
540+ cur = ggml_scale (ctx, cur, w.final_logit_softcap );
541+ }
542+ cur = ggml_argmax (ctx, cur);
543+ ggml_set_output (cur);
544+ ggml_build_forward_expand (gf, cur);
545+
546+ ggml_gallocr_t alloc = ggml_gallocr_new (ggml_backend_get_default_buffer_type (backend));
547+ if (!alloc || !ggml_gallocr_alloc_graph (alloc, gf)) {
548+ if (alloc) ggml_gallocr_free (alloc);
549+ ggml_free (ctx);
550+ return false ;
551+ }
552+ if (ggml_backend_graph_compute (backend, gf) != GGML_STATUS_SUCCESS ) {
553+ ggml_gallocr_free (alloc);
554+ ggml_free (ctx);
555+ return false ;
556+ }
557+ out_argmax.resize ((size_t )n_tokens);
558+ ggml_backend_tensor_get (cur, out_argmax.data (), 0 ,
559+ sizeof (int32_t ) * (size_t )n_tokens);
560+ ggml_gallocr_free (alloc);
561+ ggml_free (ctx);
562+ return true ;
563+ }
564+
390565bool gemma4_step (
391566 ggml_backend_t backend,
392567 const Gemma4Weights & w,
0 commit comments