/src/llama.cpp/src/models/gemma4.cpp
Line | Count | Source |
1 | | #include "models.h" |
2 | | |
3 | 0 | void llama_model_gemma4::load_arch_hparams(llama_model_loader & ml) { |
4 | 0 | hparams.swa_type = LLAMA_SWA_TYPE_STANDARD; |
5 | 0 | ml.get_key_or_arr(LLM_KV_ATTENTION_SLIDING_WINDOW_PATTERN, hparams.is_swa_impl, hparams.n_layer()); |
6 | |
|
7 | 0 | uint32_t n_kv_shared_layers = 0; |
8 | 0 | ml.get_key(LLM_KV_ATTENTION_SHARED_KV_LAYERS, n_kv_shared_layers, false); |
9 | |
|
10 | 0 | hparams.n_layer_kv_from_start = hparams.n_layer_all - (int32_t)n_kv_shared_layers; |
11 | 0 | hparams.f_attention_scale = 1.0f; // Gemma4 uses self.scaling = 1.0 (no pre-attn scaling) |
12 | |
|
13 | 0 | ml.get_key(LLM_KV_ROPE_FREQ_BASE_SWA, hparams.rope_freq_base_train_swa, false); |
14 | 0 | ml.get_key(LLM_KV_EXPERT_FEED_FORWARD_LENGTH, hparams.n_ff_exp, false); |
15 | 0 | ml.get_key(LLM_KV_ATTENTION_SLIDING_WINDOW, hparams.n_swa); |
16 | 0 | ml.get_key(LLM_KV_ATTENTION_LAYERNORM_RMS_EPS, hparams.f_norm_rms_eps); |
17 | 0 | ml.get_key(LLM_KV_EMBEDDING_LENGTH_PER_LAYER, hparams.n_embd_per_layer); |
18 | 0 | ml.get_key(LLM_KV_ATTENTION_KEY_LENGTH_SWA, hparams.n_embd_head_k_swa); |
19 | 0 | ml.get_key(LLM_KV_ATTENTION_VALUE_LENGTH_SWA, hparams.n_embd_head_v_swa); |
20 | 0 | ml.get_key(LLM_KV_FINAL_LOGIT_SOFTCAPPING, hparams.f_final_logit_softcapping, false); |
21 | |
|
22 | 0 | switch (hparams.n_layer()) { |
23 | 0 | case 30: type = LLM_TYPE_26B_A4B; break; |
24 | 0 | case 35: type = LLM_TYPE_E2B; break; |
25 | 0 | case 42: type = LLM_TYPE_E4B; break; |
26 | 0 | case 60: type = LLM_TYPE_31B; break; |
27 | 0 | default: type = LLM_TYPE_UNKNOWN; |
28 | 0 | } |
29 | 0 | } |
30 | | |
31 | 0 | void llama_model_gemma4::load_arch_tensors(llama_model_loader &) { |
32 | 0 | LLAMA_LOAD_LOCALS; |
33 | |
|
34 | 0 | const uint32_t n_embd_per_layer = hparams.n_embd_per_layer; |
35 | 0 | const int64_t n_ff_exp = hparams.n_ff_exp; |
36 | |
|
37 | 0 | if (n_embd_head_k != n_embd_head_v) { |
38 | 0 | throw std::runtime_error("Gemma 4 requires n_embd_head_k == n_embd_head_v"); |
39 | 0 | } |
40 | 0 | if (hparams.n_embd_head_k_swa != hparams.n_embd_head_v_swa) { |
41 | 0 | throw std::runtime_error("Gemma 4 requires n_embd_head_k_swa == n_embd_head_v_swa"); |
42 | 0 | } |
43 | | |
44 | 0 | output = create_tensor(tn(LLM_TENSOR_OUTPUT, "weight"), {n_embd, n_vocab}, TENSOR_NOT_REQUIRED); |
45 | | // if output is NULL, init from the input tok embed |
46 | 0 | if (output == NULL) { |
47 | 0 | output = create_tensor(tn(LLM_TENSOR_TOKEN_EMBD, "weight"), {n_embd, n_vocab}, TENSOR_DUPLICATED); |
48 | 0 | } |
49 | |
|
50 | 0 | tok_embd = create_tensor(tn(LLM_TENSOR_TOKEN_EMBD, "weight"), {n_embd, n_vocab}, 0); |
51 | |
|
52 | 0 | if (n_embd_per_layer > 0) { |
53 | 0 | per_layer_tok_embd = create_tensor(tn(LLM_TENSOR_PER_LAYER_TOKEN_EMBD, "weight"), {n_embd_per_layer * n_layer, n_vocab}, 0); |
54 | 0 | per_layer_model_proj = create_tensor(tn(LLM_TENSOR_PER_LAYER_MODEL_PROJ, "weight", 0), {n_embd, n_embd_per_layer * n_layer}, 0); |
55 | 0 | per_layer_proj_norm = create_tensor(tn(LLM_TENSOR_PER_LAYER_PROJ_NORM, "weight", 0), {n_embd_per_layer}, 0); |
56 | 0 | } |
57 | |
|
58 | 0 | output_norm = create_tensor(tn(LLM_TENSOR_OUTPUT_NORM, "weight"), {n_embd}, 0); |
59 | |
|
60 | 0 | int rope_freqs_flag = 0; |
61 | |
|
62 | 0 | for (int i = 0; i < n_layer; ++i) { |
63 | 0 | auto & layer = layers[i]; |
64 | 0 | const int64_t n_head = hparams.n_head(i); |
65 | 0 | const int64_t n_embd_head = hparams.n_embd_head_k(i); |
66 | 0 | const int64_t n_embd_k = hparams.n_embd_k_gqa(i); |
67 | 0 | const int64_t n_embd_v = hparams.n_embd_v_gqa(i); |
68 | 0 | const int kv_flags = hparams.has_kv(i) ? 0 : TENSOR_NOT_REQUIRED; |
69 | |
|
70 | 0 | layer.attn_norm = create_tensor(tn(LLM_TENSOR_ATTN_NORM, "weight", i), {n_embd}, 0); |
71 | | |
72 | | // note: use_alternative_attention (v_proj is optional, if it's not present, use k_proj) |
73 | 0 | layer.wq = create_tensor(tn(LLM_TENSOR_ATTN_Q, "weight", i), {n_embd, n_embd_head * n_head}, 0); |
74 | 0 | layer.wk = create_tensor(tn(LLM_TENSOR_ATTN_K, "weight", i), {n_embd, n_embd_k}, kv_flags); |
75 | 0 | layer.wv = create_tensor(tn(LLM_TENSOR_ATTN_V, "weight", i), {n_embd, n_embd_v}, TENSOR_NOT_REQUIRED); |
76 | 0 | layer.wo = create_tensor(tn(LLM_TENSOR_ATTN_OUT, "weight", i), {n_embd_head * n_head, n_embd}, 0); |
77 | |
|
78 | 0 | layer.attn_q_norm = create_tensor(tn(LLM_TENSOR_ATTN_Q_NORM, "weight", i), {n_embd_head}, 0); |
79 | 0 | layer.attn_k_norm = create_tensor(tn(LLM_TENSOR_ATTN_K_NORM, "weight", i), {n_embd_head}, kv_flags); |
80 | 0 | layer.attn_post_norm = create_tensor(tn(LLM_TENSOR_ATTN_POST_NORM, "weight", i), {n_embd}, 0); |
81 | |
|
82 | 0 | layer.out_scale = create_tensor(tn(LLM_TENSOR_LAYER_OUT_SCALE, "weight", i), {1u}, TENSOR_NOT_REQUIRED); |
83 | |
|
84 | 0 | if (!hparams.is_swa(i)) { |
85 | | // full_attention layers use rope_freqs for proportional rope |
86 | 0 | layer.rope_freqs = create_tensor(tn(LLM_TENSOR_ROPE_FREQS, "weight", i), {n_embd_head/2}, rope_freqs_flag); |
87 | 0 | rope_freqs_flag = TENSOR_DUPLICATED; |
88 | 0 | } |
89 | | |
90 | | // handle use_double_wide_mlp |
91 | 0 | int64_t n_ff_cur = hparams.n_ff(i); |
92 | | |
93 | | // for expert layers, we use normal FFN as shared expert (same as python code) |
94 | 0 | layer.ffn_norm = create_tensor(tn(LLM_TENSOR_FFN_NORM, "weight", i), {n_embd}, 0); |
95 | 0 | layer.ffn_gate = create_tensor(tn(LLM_TENSOR_FFN_GATE, "weight", i), {n_embd, n_ff_cur}, 0); |
96 | 0 | layer.ffn_up = create_tensor(tn(LLM_TENSOR_FFN_UP, "weight", i), {n_embd, n_ff_cur}, 0); |
97 | 0 | layer.ffn_down = create_tensor(tn(LLM_TENSOR_FFN_DOWN, "weight", i), {n_ff_cur, n_embd}, 0); |
98 | 0 | layer.ffn_post_norm = create_tensor(tn(LLM_TENSOR_FFN_POST_NORM, "weight", i), {n_embd}, 0); |
99 | | |
100 | | // MoE router |
101 | 0 | layer.ffn_gate_inp = create_tensor(tn(LLM_TENSOR_FFN_GATE_INP, "weight", i), {n_embd, n_expert}, TENSOR_NOT_REQUIRED); |
102 | 0 | bool has_expert = layer.ffn_gate_inp != nullptr; |
103 | | |
104 | | // norm |
105 | 0 | if (has_expert) { |
106 | 0 | layer.ffn_gate_inp_s = create_tensor(tn(LLM_TENSOR_FFN_GATE_INP, "scale", i), {n_embd}, 0); |
107 | |
|
108 | 0 | layer.ffn_pre_norm_2 = create_tensor(tn(LLM_TENSOR_FFN_PRE_NORM_2, "weight", i), {n_embd}, 0); |
109 | 0 | layer.ffn_post_norm_1 = create_tensor(tn(LLM_TENSOR_FFN_POST_NORM_1, "weight", i), {n_embd}, 0); |
110 | 0 | layer.ffn_post_norm_2 = create_tensor(tn(LLM_TENSOR_FFN_POST_NORM_2, "weight", i), {n_embd}, 0); |
111 | | |
112 | | // MoE FFN |
113 | 0 | layer.ffn_gate_up_exps = create_tensor(tn(LLM_TENSOR_FFN_GATE_UP_EXPS, "weight", i), {n_embd, n_ff_exp * 2, n_expert}, TENSOR_NOT_REQUIRED); |
114 | |
|
115 | 0 | if (layer.ffn_gate_up_exps == nullptr) { |
116 | 0 | layer.ffn_gate_exps = create_tensor(tn(LLM_TENSOR_FFN_GATE_EXPS, "weight", i), {n_embd, n_ff_exp, n_expert}, 0); |
117 | 0 | layer.ffn_up_exps = create_tensor(tn(LLM_TENSOR_FFN_UP_EXPS, "weight", i), {n_embd, n_ff_exp, n_expert}, 0); |
118 | 0 | } |
119 | |
|
120 | 0 | layer.ffn_down_exps = create_tensor(tn(LLM_TENSOR_FFN_DOWN_EXPS, "weight", i), {n_ff_exp, n_embd, n_expert}, 0); |
121 | | |
122 | | // per-expert scale will be loaded as down_exps_s at the end of the current switch case |
123 | 0 | } |
124 | | |
125 | | // per-layer embeddings |
126 | 0 | if (n_embd_per_layer > 0) { |
127 | 0 | layer.per_layer_inp_gate = create_tensor(tn(LLM_TENSOR_PER_LAYER_INP_GATE, "weight", i), {n_embd, n_embd_per_layer}, 0); |
128 | 0 | layer.per_layer_proj = create_tensor(tn(LLM_TENSOR_PER_LAYER_PROJ, "weight", i), {n_embd_per_layer, n_embd}, 0); |
129 | 0 | layer.per_layer_post_norm = create_tensor(tn(LLM_TENSOR_PER_LAYER_POST_NORM, "weight", i), {n_embd}, 0); |
130 | 0 | } |
131 | 0 | } |
132 | 0 | } |
133 | | |
134 | 0 | std::unique_ptr<llm_graph_context> llama_model_gemma4::build_arch_graph(const llm_graph_params & params) const { |
135 | 0 | return std::make_unique<graph>(*this, params); |
136 | 0 | } |
137 | | |
138 | | // get 2D slice view from a 3D tensor, the idx corresponds to the 3rd dim |
139 | 0 | static ggml_tensor * ggml_view_2d_slice(ggml_context * ctx0, ggml_tensor * x, int idx) { |
140 | 0 | GGML_ASSERT(idx < (int) x->ne[2]); |
141 | 0 | return ggml_view_2d(ctx0, x, x->ne[0], x->ne[1], ggml_row_size(x->type, x->ne[0]), |
142 | 0 | idx * x->ne[0] * x->ne[1] * ggml_element_size(x)); |
143 | 0 | } |
144 | | |
145 | | // TODO @ngxson : maybe improve this in the future |
146 | | class llm_graph_input_logits_bias : public llm_graph_input_i { |
147 | | public: |
148 | 0 | llm_graph_input_logits_bias(const llama_vocab & vocab) { |
149 | 0 | arr.resize(vocab.n_tokens(), 0.0f); |
150 | 0 | for (llama_token id : vocab.get_suppress_tokens()) { |
151 | 0 | if (0 <= id && id < (int32_t)vocab.n_tokens()) { |
152 | 0 | arr[id] = -INFINITY; |
153 | 0 | } |
154 | 0 | } |
155 | 0 | } |
156 | 0 | virtual ~llm_graph_input_logits_bias() = default; |
157 | | |
158 | 0 | void set_input(const llama_ubatch * /*ubatch*/) override { |
159 | 0 | const int64_t n_vocab = arr.size(); |
160 | 0 | ggml_backend_tensor_set(logits_bias, arr.data(), 0, n_vocab*ggml_element_size(logits_bias)); |
161 | 0 | } |
162 | | |
163 | 0 | bool can_reuse(const llm_graph_params & /*params*/) override { |
164 | 0 | return true; |
165 | 0 | } |
166 | | |
167 | | ggml_tensor * logits_bias = nullptr; // F32 [n_vocab] |
168 | | |
169 | | std::vector<float> arr; |
170 | | }; |
171 | | |
172 | | llama_model_gemma4::graph::graph(const llama_model & model, const llm_graph_params & params) : |
173 | 0 | llm_graph_context(params), |
174 | 0 | model(model), |
175 | 0 | n_embd_per_layer(model.hparams.n_embd_per_layer) { |
176 | 0 | ggml_tensor * cur; |
177 | 0 | ggml_tensor * inpL; |
178 | |
|
179 | 0 | inpL = build_inp_embd(model.tok_embd); |
180 | | |
181 | | // important: do not normalize weights for raw embeddings input (i.e. encoded image emdeddings) |
182 | 0 | inpL = ggml_scale(ctx0, inpL, ubatch.token ? sqrtf(n_embd) : 1.0f); |
183 | 0 | cb(inpL, "inp_scaled", -1); |
184 | | |
185 | | // inp_pos - contains the positions |
186 | 0 | ggml_tensor * inp_pos = build_inp_pos(); |
187 | | |
188 | | // TODO: is causal == true correct? might need some changes |
189 | 0 | auto * inp_attn = build_attn_inp_kv_iswa(); |
190 | |
|
191 | 0 | ggml_tensor * inp_out_ids = build_inp_out_ids(); |
192 | |
|
193 | 0 | ggml_tensor * inp_per_layer = nullptr; |
194 | 0 | if (model.per_layer_tok_embd) { |
195 | 0 | inp_per_layer = build_inp_per_layer(); |
196 | 0 | ggml_build_forward_expand(gf, inp_per_layer); |
197 | | |
198 | | // inp_per_layer shape: [n_embd_per_layer, n_tokens, n_layer] |
199 | 0 | inp_per_layer = project_per_layer_inputs(inpL, inp_per_layer); |
200 | 0 | } |
201 | |
|
202 | 0 | for (int il = 0; il < n_layer; ++il) { |
203 | 0 | const int64_t n_embd_head = hparams.n_embd_head_k(il); |
204 | 0 | GGML_ASSERT(n_embd_head == hparams.n_embd_head_v(il)); |
205 | |
|
206 | 0 | const int64_t n_head = hparams.n_head(il); |
207 | 0 | const int64_t n_head_kv = hparams.n_head_kv(il); |
208 | |
|
209 | 0 | const float freq_base_l = model.get_rope_freq_base(cparams, il); |
210 | 0 | const float freq_scale_l = model.get_rope_freq_scale(cparams, il); |
211 | 0 | const int n_rot_l = hparams.n_rot(il); |
212 | |
|
213 | 0 | res->t_layer_inp[il] = inpL; |
214 | | |
215 | | // norm |
216 | 0 | cur = build_norm(inpL, model.layers[il].attn_norm, nullptr, LLM_NORM_RMS, il); |
217 | 0 | cb(cur, "attn_norm", il); |
218 | |
|
219 | 0 | ggml_tensor * freq_factors = nullptr; |
220 | 0 | if (!hparams.is_swa(il)) { |
221 | | // full_attention layers use rope_freqs for proportional rope |
222 | 0 | freq_factors = model.layers[il].rope_freqs; |
223 | 0 | } |
224 | | |
225 | | // Q projection (shared for both non-KV and KV layers) |
226 | | // this is to mirror Gemma4Attention in pytorch code |
227 | 0 | ggml_tensor * Qcur; |
228 | 0 | { |
229 | 0 | Qcur = build_lora_mm(model.layers[il].wq, cur, model.layers[il].wq_s); |
230 | 0 | cb(Qcur, "Qcur", il); |
231 | |
|
232 | 0 | Qcur = ggml_reshape_3d(ctx0, Qcur, n_embd_head, n_head, n_tokens); |
233 | |
|
234 | 0 | Qcur = build_norm(Qcur, model.layers[il].attn_q_norm, nullptr, LLM_NORM_RMS, il); |
235 | 0 | cb(Qcur, "Qcur_normed", il); |
236 | |
|
237 | 0 | Qcur = ggml_rope_ext(ctx0, Qcur, inp_pos, freq_factors, n_rot_l, rope_type, n_ctx_orig, freq_base_l, freq_scale_l, |
238 | 0 | ext_factor, attn_factor, beta_fast, beta_slow); |
239 | 0 | cb(Qcur, "Qcur_pos", il); |
240 | 0 | } |
241 | | |
242 | | // self-attention |
243 | 0 | if (hparams.has_kv(il)) { |
244 | 0 | ggml_tensor * Kcur = build_lora_mm(model.layers[il].wk, cur, model.layers[il].wk_s); |
245 | 0 | cb(Kcur, "Kcur", il); |
246 | |
|
247 | 0 | ggml_tensor * Vcur = model.layers[il].wv |
248 | 0 | ? build_lora_mm(model.layers[il].wv, cur, model.layers[il].wv_s) |
249 | 0 | : Kcur; // if v_proj is not present, use Kcur as Vcur |
250 | 0 | cb(Vcur, "Vcur", il); |
251 | |
|
252 | 0 | Kcur = ggml_reshape_3d(ctx0, Kcur, n_embd_head, n_head_kv, n_tokens); |
253 | 0 | Vcur = ggml_reshape_3d(ctx0, Vcur, n_embd_head, n_head_kv, n_tokens); |
254 | |
|
255 | 0 | Kcur = build_norm(Kcur, model.layers[il].attn_k_norm, nullptr, LLM_NORM_RMS, il); |
256 | 0 | Vcur = ggml_rms_norm(ctx0, Vcur, hparams.f_norm_rms_eps); |
257 | |
|
258 | 0 | cb(Kcur, "Kcur_normed", il); |
259 | 0 | cb(Vcur, "Vcur_normed", il); |
260 | |
|
261 | 0 | Kcur = ggml_rope_ext(ctx0, Kcur, inp_pos, freq_factors, n_rot_l, rope_type, n_ctx_orig, freq_base_l, freq_scale_l, |
262 | 0 | ext_factor, attn_factor, beta_fast, beta_slow); |
263 | |
|
264 | 0 | cb(Kcur, "Kcur_pos", il); |
265 | |
|
266 | 0 | cur = build_attn(inp_attn, model.layers[il].wo, |
267 | 0 | nullptr, model.layers[il].wo_s, Qcur, Kcur, Vcur, nullptr, nullptr, nullptr, |
268 | 0 | hparams.f_attention_scale, il); |
269 | 0 | } else { |
270 | | // reuse KV cache of earlier layers |
271 | 0 | cur = build_attn(inp_attn, |
272 | 0 | model.layers[il].wo, nullptr, model.layers[il].wo_s, |
273 | 0 | Qcur, nullptr, nullptr, nullptr, nullptr, nullptr, hparams.f_attention_scale, il); |
274 | 0 | } |
275 | | |
276 | | // TODO @ngxson : strip unused token right after the last KV layer to speed up prompt processing |
277 | | // keep all rows when extracting unmasked nextn embeddings (MTP target needs the hidden state for every token) |
278 | 0 | if (il == n_layer - 1 && inp_out_ids && cparams.embeddings_nextn_masked) { |
279 | 0 | cur = ggml_get_rows(ctx0, cur, inp_out_ids); |
280 | 0 | inpL = ggml_get_rows(ctx0, inpL, inp_out_ids); |
281 | 0 | } |
282 | 0 | cur = build_norm(cur, |
283 | 0 | model.layers[il].attn_post_norm, nullptr, |
284 | 0 | LLM_NORM_RMS, il); |
285 | 0 | cb(cur, "attn_post_norm", il); |
286 | |
|
287 | 0 | ggml_tensor * attn_out = ggml_add(ctx0, cur, inpL); |
288 | 0 | cb(attn_out, "attn_out", il); |
289 | | |
290 | | // feed-forward network |
291 | 0 | const bool is_moe_layer = model.layers[il].ffn_gate_inp != nullptr; |
292 | 0 | if (is_moe_layer) { |
293 | | // MLP (shared exp) |
294 | 0 | ggml_tensor * cur_mlp = build_norm(attn_out, |
295 | 0 | model.layers[il].ffn_norm, nullptr, |
296 | 0 | LLM_NORM_RMS, il); |
297 | 0 | cb(cur_mlp, "ffn_norm_1", il); |
298 | |
|
299 | 0 | cur_mlp = build_ffn(cur_mlp, |
300 | 0 | model.layers[il].ffn_up, nullptr, model.layers[il].ffn_up_s, |
301 | 0 | model.layers[il].ffn_gate, nullptr, model.layers[il].ffn_gate_s, |
302 | 0 | model.layers[il].ffn_down, nullptr, model.layers[il].ffn_down_s, |
303 | 0 | nullptr, |
304 | 0 | LLM_FFN_GELU, LLM_FFN_PAR, il); |
305 | 0 | cur_mlp = build_norm(cur_mlp, |
306 | 0 | model.layers[il].ffn_post_norm_1, nullptr, |
307 | 0 | LLM_NORM_RMS, il); |
308 | 0 | cb(cur_mlp, "ffn_mlp", il); |
309 | | |
310 | | // Expert FFN |
311 | 0 | ggml_tensor * cur_moe = build_norm(attn_out, |
312 | 0 | model.layers[il].ffn_pre_norm_2, nullptr, |
313 | 0 | LLM_NORM_RMS, il); |
314 | 0 | cb(cur_moe, "ffn_norm_2", il); |
315 | | |
316 | | // custom MoE logits calculation (router operates on attn_out, not cur) |
317 | 0 | ggml_tensor * tmp = ggml_rms_norm(ctx0, attn_out, hparams.f_norm_rms_eps); |
318 | 0 | tmp = ggml_scale(ctx0, tmp, 1.0f / sqrtf((float) n_embd)); |
319 | 0 | tmp = ggml_mul(ctx0, tmp, model.layers[il].ffn_gate_inp_s); |
320 | 0 | ggml_tensor * logits = build_lora_mm(model.layers[il].ffn_gate_inp, tmp); // [n_expert, n_tokens] |
321 | 0 | cb(logits, "ffn_moe_logits", il); |
322 | |
|
323 | 0 | cur_moe = build_moe_ffn(cur_moe, |
324 | 0 | nullptr, // gate_inp |
325 | 0 | model.layers[il].ffn_up_exps, |
326 | 0 | model.layers[il].ffn_gate_exps, |
327 | 0 | model.layers[il].ffn_down_exps, |
328 | 0 | nullptr, // exp_probs_b (not used for gemma4) |
329 | 0 | n_expert, n_expert_used, |
330 | 0 | LLM_FFN_GELU, true, |
331 | 0 | 1.0f, |
332 | 0 | LLAMA_EXPERT_GATING_FUNC_TYPE_SOFTMAX, |
333 | 0 | il, logits, |
334 | 0 | model.layers[il].ffn_gate_up_exps, |
335 | 0 | model.layers[il].ffn_up_exps_s, |
336 | 0 | model.layers[il].ffn_gate_exps_s, |
337 | 0 | model.layers[il].ffn_down_exps_s); |
338 | 0 | cur_moe = build_norm(cur_moe, |
339 | 0 | model.layers[il].ffn_post_norm_2, nullptr, |
340 | 0 | LLM_NORM_RMS, il); |
341 | 0 | cb(cur_moe, "ffn_moe", il); |
342 | |
|
343 | 0 | cur = ggml_add(ctx0, cur_mlp, cur_moe); |
344 | 0 | cb(cur, "ffn_moe_combined", il); |
345 | 0 | } else { |
346 | 0 | cur = build_norm(attn_out, |
347 | 0 | model.layers[il].ffn_norm, nullptr, |
348 | 0 | LLM_NORM_RMS, il); |
349 | 0 | cb(cur, "ffn_norm", il); |
350 | |
|
351 | 0 | cur = build_ffn(cur, |
352 | 0 | model.layers[il].ffn_up, nullptr, model.layers[il].ffn_up_s, |
353 | 0 | model.layers[il].ffn_gate, nullptr, model.layers[il].ffn_gate_s, |
354 | 0 | model.layers[il].ffn_down, nullptr, model.layers[il].ffn_down_s, |
355 | 0 | nullptr, |
356 | 0 | LLM_FFN_GELU, LLM_FFN_PAR, il); |
357 | 0 | cb(cur, "ffn_out", il); |
358 | 0 | } |
359 | 0 | cur = build_norm(cur, |
360 | 0 | model.layers[il].ffn_post_norm, nullptr, |
361 | 0 | LLM_NORM_RMS, -1); |
362 | 0 | cb(cur, "ffn_post_norm", il); |
363 | | |
364 | | // residual connection |
365 | 0 | cur = ggml_add(ctx0, cur, attn_out); |
366 | | |
367 | | // per-layer embedding |
368 | 0 | if (inp_per_layer) { |
369 | 0 | ggml_tensor * pe_in = cur; |
370 | 0 | cb(cur, "pe_in", il); |
371 | |
|
372 | 0 | cur = build_lora_mm(model.layers[il].per_layer_inp_gate, cur); // [n_embd_per_layer, n_tokens] |
373 | 0 | cur = ggml_gelu(ctx0, cur); |
374 | |
|
375 | 0 | ggml_tensor * inp_this_layer = ggml_view_2d_slice(ctx0, inp_per_layer, il); // [n_embd_per_layer, n_tokens] |
376 | | |
377 | | // TODO @ngxson : improve this |
378 | 0 | if (il == n_layer - 1 && inp_out_ids && cparams.embeddings_nextn_masked) { |
379 | 0 | inp_this_layer = ggml_get_rows(ctx0, inp_this_layer, inp_out_ids); |
380 | 0 | } |
381 | |
|
382 | 0 | cur = ggml_mul(ctx0, cur, inp_this_layer); |
383 | 0 | cur = build_lora_mm(model.layers[il].per_layer_proj, cur); // [n_embd, n_tokens] |
384 | 0 | cur = build_norm(cur, model.layers[il].per_layer_post_norm, nullptr, LLM_NORM_RMS, il); |
385 | 0 | cb(cur, "per_layer_embd_out", il); |
386 | | |
387 | | // residual connection |
388 | 0 | cur = ggml_add(ctx0, pe_in, cur); |
389 | 0 | } |
390 | | |
391 | | // layer_scalar |
392 | 0 | if (model.layers[il].out_scale) { |
393 | 0 | cur = ggml_mul(ctx0, cur, model.layers[il].out_scale); |
394 | 0 | cb(cur, "out_scaled", il); |
395 | 0 | } |
396 | |
|
397 | 0 | cur = build_cvec(cur, il); |
398 | 0 | cb(cur, "l_out", il); |
399 | | |
400 | | // input for next layer |
401 | 0 | inpL = cur; |
402 | 0 | } |
403 | 0 | cur = inpL; |
404 | |
|
405 | 0 | cur = build_norm(cur, |
406 | 0 | model.output_norm, nullptr, |
407 | 0 | LLM_NORM_RMS, -1); |
408 | | |
409 | | // Expose the post-output-norm hidden state (the LM-head input feature) so that |
410 | | // MTP draft contexts can read it via llama_get_embeddings_nextn_ith() as the |
411 | | // recurrent h input. This matches the reference (transformers/vLLM/SGLang), |
412 | | // which feeds the drafter the target's post-final-norm hidden state. |
413 | 0 | cb(cur, "h_nextn", -1); |
414 | 0 | res->t_h_nextn = cur; |
415 | |
|
416 | 0 | if (!cparams.embeddings_nextn_masked && inp_out_ids) { |
417 | 0 | cur = ggml_get_rows(ctx0, cur, inp_out_ids); |
418 | 0 | } |
419 | |
|
420 | 0 | cb(cur, "result_norm", -1); |
421 | 0 | res->t_embd = cur; |
422 | | |
423 | | // lm_head |
424 | 0 | cur = build_lora_mm(model.output, cur, model.output_s); |
425 | |
|
426 | 0 | if (hparams.f_final_logit_softcapping) { |
427 | 0 | cur = ggml_scale(ctx0, cur, 1.0f / hparams.f_final_logit_softcapping); |
428 | 0 | cur = ggml_tanh(ctx0, cur); |
429 | 0 | cur = ggml_scale(ctx0, cur, hparams.f_final_logit_softcapping); |
430 | 0 | } |
431 | | |
432 | | // apply logits bias if needed (e.g. for gemma4_unified patch) |
433 | | // this is to mirror the suppress_tokens patch on transformers, to avoid model from outputing <image|> and <audio|> tokens (which is a known issue related to the checkpoint) |
434 | | // TODO: maybe handle this inside the sampling system in the future |
435 | 0 | if (!model.vocab.get_suppress_tokens().empty()) { |
436 | 0 | auto inp_bias = std::make_unique<llm_graph_input_logits_bias>(model.vocab); |
437 | 0 | inp_bias->logits_bias = ggml_new_tensor_1d(ctx0, GGML_TYPE_F32, inp_bias->arr.size()); |
438 | 0 | cur = ggml_add(ctx0, cur, inp_bias->logits_bias); |
439 | 0 | res->add_input(std::move(inp_bias)); |
440 | 0 | } |
441 | |
|
442 | 0 | cb(cur, "result_output", -1); |
443 | 0 | res->t_logits = cur; |
444 | |
|
445 | 0 | ggml_build_forward_expand(gf, cur); |
446 | 0 | } |
447 | | |
448 | | // equivalent to get_per_layer_inputs() in python code |
449 | | // output shape: [n_embd_per_layer, n_layer, n_tokens] |
450 | 0 | ggml_tensor * llama_model_gemma4::graph::build_inp_per_layer() { |
451 | 0 | auto inp = std::make_unique<llm_graph_input_embd>(n_embd); |
452 | |
|
453 | 0 | ggml_tensor * inp_per_layer; |
454 | 0 | float tok_embd_scale = sqrtf((float) n_embd_per_layer); |
455 | 0 | if (ubatch.token) { |
456 | 0 | inp->tokens = ggml_new_tensor_1d(ctx0, GGML_TYPE_I32, ubatch.n_tokens); |
457 | 0 | ggml_set_input(inp->tokens); |
458 | 0 | res->t_inp_tokens = inp->tokens; |
459 | |
|
460 | 0 | inp_per_layer = ggml_get_rows (ctx0, model.per_layer_tok_embd, inp->tokens); |
461 | 0 | inp_per_layer = ggml_reshape_3d(ctx0, inp_per_layer, n_embd_per_layer, n_layer, n_tokens); |
462 | 0 | inp_per_layer = ggml_scale (ctx0, inp_per_layer, tok_embd_scale); |
463 | 0 | cb(inp_per_layer, "inp_per_layer_selected", -1); |
464 | |
|
465 | 0 | res->add_input(std::move(inp)); |
466 | 0 | } else { |
467 | | // Multimodal embedding path: use padding token (ID=0) embedding |
468 | | // TODO: verify if this is the correct behavior in transformers implementation |
469 | 0 | const int64_t embd_size = model.per_layer_tok_embd->ne[0]; // n_embd_per_layer * n_layer |
470 | | |
471 | | // Extract and dequantize padding token embedding (row 0) |
472 | 0 | ggml_tensor * padding = ggml_view_1d(ctx0, model.per_layer_tok_embd, embd_size, 0); |
473 | 0 | inp_per_layer = ggml_cast (ctx0, padding, GGML_TYPE_F32); |
474 | 0 | inp_per_layer = ggml_scale(ctx0, inp_per_layer, tok_embd_scale); |
475 | | |
476 | | // Reshape to [n_embd_per_layer, n_layer, 1] |
477 | 0 | inp_per_layer = ggml_reshape_3d(ctx0, inp_per_layer, n_embd_per_layer, n_layer, 1); |
478 | 0 | cb(inp_per_layer, "inp_per_layer_multimodal", -1); |
479 | 0 | } |
480 | 0 | return inp_per_layer; |
481 | 0 | } |
482 | | |
483 | | // equivalent to project_per_layer_inputs() in python code |
484 | | // this calculates the per-layer inputs, so the final tensor shape will have n_layer as the last dim |
485 | | // inp_batch shape: [n_embd, n_tokens] |
486 | | // inp_per_layer shape: [n_embd_per_layer, n_layer, n_tokens] (from build_inp_per_layer) |
487 | | // output shape: [n_embd_per_layer, n_tokens, n_layer] |
488 | 0 | ggml_tensor * llama_model_gemma4::graph::project_per_layer_inputs(ggml_tensor * inp_batch, ggml_tensor * inp_per_layer) { |
489 | 0 | const float per_layer_projection_scale = 1.0f / sqrtf((float) n_embd); |
490 | 0 | const float per_layer_input_scale = 1.0f / sqrtf(2.0f); |
491 | | |
492 | | // note: this matrix multiplication will be performed in the input layer (i.e. on the CPU) |
493 | 0 | ggml_tensor * per_layer_proj; |
494 | 0 | per_layer_proj = ggml_mul_mat (ctx0, model.per_layer_model_proj, inp_batch); |
495 | 0 | per_layer_proj = ggml_scale (ctx0, per_layer_proj, per_layer_projection_scale); |
496 | 0 | per_layer_proj = ggml_reshape_3d(ctx0, per_layer_proj, n_embd_per_layer, n_layer, n_tokens); |
497 | |
|
498 | 0 | per_layer_proj = build_norm(per_layer_proj, model.per_layer_proj_norm, nullptr, LLM_NORM_RMS, -1); |
499 | 0 | cb(per_layer_proj, "per_layer_proj", -1); |
500 | |
|
501 | 0 | inp_per_layer = ggml_add (ctx0, per_layer_proj, inp_per_layer); |
502 | 0 | inp_per_layer = ggml_scale(ctx0, inp_per_layer, per_layer_input_scale); |
503 | 0 | cb(inp_per_layer, "inp_per_layer", -1); |
504 | | |
505 | | // permute to shape: [n_embd_per_layer, n_tokens, n_layer] |
506 | 0 | inp_per_layer = ggml_cont(ctx0, ggml_permute(ctx0, inp_per_layer, 0, 2, 1, 3)); |
507 | 0 | return inp_per_layer; |
508 | 0 | } |