Ripple-65B-Preview-GGUF / patches /llama.cpp-ricursive.patch
prometheusAIR's picture
Add patches/llama.cpp-ricursive.patch
ee1454d verified
Raw History Blame Contribute Delete
23.1 kB
diff --git a/conversion/__init__.py b/conversion/__init__.py
index 0c6204b87..5bd957bd1 100644
--- a/conversion/__init__.py
+++ b/conversion/__init__.py
@@ -19,6 +19,7 @@ __all__ = [
TEXT_MODEL_MAP: dict[str, str] = {
"NEOChatModel": "sensenova_u1",
"AfmoeForCausalLM": "afmoe",
+ "RicursiveForCausalLM": "ricursive",
"LagunaForCausalLM": "laguna",
"FlintForCausalLM": "flint",
"ApertusForCausalLM": "llama",
diff --git a/conversion/ricursive.py b/conversion/ricursive.py
new file mode 100644
index 000000000..e4ab321c0
--- /dev/null
+++ b/conversion/ricursive.py
@@ -0,0 +1,63 @@
+from __future__ import annotations
+
+from typing import Iterable, TYPE_CHECKING
+
+if TYPE_CHECKING:
+ from torch import Tensor
+
+from .base import ModelBase, TextModel, gguf
+
+
+@ModelBase.register("RicursiveForCausalLM")
+class RicursiveModel(TextModel):
+ model_arch = gguf.MODEL_ARCH.RICURSIVE
+
+ def set_vocab(self):
+ tokens, toktypes, tokpre = self.get_vocab_base()
+ self.gguf_writer.add_tokenizer_model("gpt2")
+ self.gguf_writer.add_tokenizer_pre(tokpre)
+ self.gguf_writer.add_token_list(tokens)
+ self.gguf_writer.add_token_types(toktypes)
+
+ special_vocab = gguf.SpecialVocab(self.dir_model, load_merges=True)
+ # tokenizer_config.json carries a plain ChatML stub; the vendor serves the tools-aware
+ # repo-root chat_template.jinja, which SpecialVocab would otherwise lose to the stub
+ if (template := self.dir_model / "chat_template.jinja").is_file():
+ special_vocab.chat_template = template.read_text(encoding="utf-8")
+ special_vocab.add_to_gguf(self.gguf_writer)
+
+ # tokenizer.json has no post_processor: the HF tokenizer never prepends <|endoftext|>
+ self.gguf_writer.add_add_bos_token(False)
+
+ def set_gguf_parameters(self):
+ super().set_gguf_parameters()
+ hparams = self.hparams
+
+ head_dim = hparams["head_dim"] # 128, while hidden_size / num_attention_heads is 64
+ self.gguf_writer.add_key_length(head_dim)
+ self.gguf_writer.add_value_length(head_dim)
+ self.gguf_writer.add_rope_dimension_count(head_dim)
+
+ # sliding_attention layers use RoPE, full_attention layers use no positional encoding
+ self.gguf_writer.add_sliding_window(hparams["sliding_window"])
+ self.gguf_writer.add_sliding_window_pattern([t == "sliding_attention" for t in hparams["layer_types"]])
+
+ if (embed_scale := hparams.get("embed_scale")) is not None:
+ self.gguf_writer.add_embedding_scale(embed_scale)
+ if (clamp := hparams.get("ffn_clamp_threshold")) is not None:
+ self.gguf_writer.add_swiglu_clamp(clamp)
+
+ assert hparams.get("use_gated_attention", True), "only gated-attention checkpoints are supported"
+ assert hparams.get("use_valres", False), "only value-residual checkpoints are supported"
+
+ def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iterable[tuple[str, Tensor]]:
+ if name.endswith("self_attn.value_res_lambda"):
+ assert bid is not None
+ yield (self.format_tensor_name(gguf.MODEL_TENSOR.ATTN_VALUE_RES, bid), data_torch)
+ return
+ if name.endswith("self_attn.g_proj.weight"):
+ assert bid is not None
+ yield (self.format_tensor_name(gguf.MODEL_TENSOR.ATTN_GATE, bid), data_torch)
+ return
+
+ yield from super().modify_tensors(data_torch, name, bid)
diff --git a/gguf-py/gguf/constants.py b/gguf-py/gguf/constants.py
index 930714f30..bc18372eb 100644
--- a/gguf-py/gguf/constants.py
+++ b/gguf-py/gguf/constants.py
@@ -162,6 +162,7 @@ class Keys:
EMBD_LENGTH_PER_LAYER_INP = "{arch}.embedding_length_per_layer_input"
SWIGLU_CLAMP_EXP = "{arch}.swiglu_clamp_exp"
SWIGLU_CLAMP_SHEXP = "{arch}.swiglu_clamp_shexp"
+ SWIGLU_CLAMP = "{arch}.swiglu_clamp"
HIDDEN_ACT = "{arch}.hidden_activation"
DENSE_FEAT_IN_SIZE = "{arch}.{dense}_feat_in"
DENSE_FEAT_OUT_SIZE = "{arch}.{dense}_feat_out"
@@ -708,6 +709,7 @@ class MODEL_ARCH(IntEnum):
DOTS3NOTE = auto()
ARCEE = auto()
AFMOE = auto()
+ RICURSIVE = auto()
LAGUNA = auto()
ERNIE4_5 = auto()
ERNIE4_5_MOE = auto()
@@ -807,6 +809,7 @@ class MODEL_TENSOR(IntEnum):
ATTN_SINKS = auto()
ATTN_SSMAX = auto()
ATTN_GATE = auto()
+ ATTN_VALUE_RES = auto() # ricursive: per-layer value-residual mix logit
ATTN_RESID_ALPHA = auto()
ATTN_RESID_BETA = auto()
FFN_GATE_INP = auto()
@@ -1621,6 +1624,7 @@ MODEL_ARCH_NAMES: dict[MODEL_ARCH, str] = {
MODEL_ARCH.DOTS3NOTE: "dots3note",
MODEL_ARCH.ARCEE: "arcee",
MODEL_ARCH.AFMOE: "afmoe",
+ MODEL_ARCH.RICURSIVE: "ricursive",
MODEL_ARCH.LAGUNA: "laguna",
MODEL_ARCH.ERNIE4_5: "ernie4_5",
MODEL_ARCH.ERNIE4_5_MOE: "ernie4_5-moe",
@@ -1717,6 +1721,7 @@ TENSOR_NAMES: dict[MODEL_TENSOR, str] = {
MODEL_TENSOR.ATTN_SINKS: "blk.{bid}.attn_sinks",
MODEL_TENSOR.ATTN_SSMAX: "blk.{bid}.attn_ssmax",
MODEL_TENSOR.ATTN_GATE: "blk.{bid}.attn_gate",
+ MODEL_TENSOR.ATTN_VALUE_RES: "blk.{bid}.attn_value_res",
MODEL_TENSOR.ATTN_RESID_ALPHA: "blk.{bid}.attn_resid_alpha",
MODEL_TENSOR.ATTN_RESID_BETA: "blk.{bid}.attn_resid_beta",
MODEL_TENSOR.ATTN_Q_NORM: "blk.{bid}.attn_q_norm",
@@ -5505,6 +5510,26 @@ MODEL_TENSORS: dict[MODEL_ARCH, list[MODEL_TENSOR]] = {
MODEL_TENSOR.FFN_DOWN,
MODEL_TENSOR.FFN_UP,
],
+ MODEL_ARCH.RICURSIVE: [
+ MODEL_TENSOR.TOKEN_EMBD,
+ MODEL_TENSOR.OUTPUT_NORM,
+ MODEL_TENSOR.OUTPUT,
+ MODEL_TENSOR.ATTN_NORM,
+ MODEL_TENSOR.ATTN_POST_NORM,
+ MODEL_TENSOR.ATTN_Q,
+ MODEL_TENSOR.ATTN_K,
+ MODEL_TENSOR.ATTN_V,
+ MODEL_TENSOR.ATTN_OUT,
+ MODEL_TENSOR.ATTN_Q_NORM,
+ MODEL_TENSOR.ATTN_K_NORM,
+ MODEL_TENSOR.ATTN_GATE,
+ MODEL_TENSOR.ATTN_VALUE_RES,
+ MODEL_TENSOR.FFN_PRE_NORM,
+ MODEL_TENSOR.FFN_POST_NORM,
+ MODEL_TENSOR.FFN_GATE,
+ MODEL_TENSOR.FFN_DOWN,
+ MODEL_TENSOR.FFN_UP,
+ ],
MODEL_ARCH.AFMOE: [
MODEL_TENSOR.TOKEN_EMBD,
MODEL_TENSOR.OUTPUT_NORM,
diff --git a/gguf-py/gguf/gguf_writer.py b/gguf-py/gguf/gguf_writer.py
index 0e7aa5012..a2e646c84 100644
--- a/gguf-py/gguf/gguf_writer.py
+++ b/gguf-py/gguf/gguf_writer.py
@@ -915,6 +915,9 @@ class GGUFWriter:
def add_swiglu_clamp_shexp(self, values: Sequence[float]) -> None:
self.add_array(Keys.LLM.SWIGLU_CLAMP_SHEXP.format(arch=self.arch), values)
+ def add_swiglu_clamp(self, value: float) -> None:
+ self.add_float32(Keys.LLM.SWIGLU_CLAMP.format(arch=self.arch), value)
+
def add_hidden_act(self, value: str) -> None:
self.add_string(Keys.LLM.HIDDEN_ACT.format(arch=self.arch), value)
diff --git a/src/llama-arch.cpp b/src/llama-arch.cpp
index 92a13e985..3b53ec39a 100644
--- a/src/llama-arch.cpp
+++ b/src/llama-arch.cpp
@@ -125,6 +125,7 @@ static const std::map<llm_arch, const char *> LLM_ARCH_NAMES = {
{ LLM_ARCH_DOTS3NOTE, "dots3note" },
{ LLM_ARCH_ARCEE, "arcee" },
{ LLM_ARCH_AFMOE, "afmoe" },
+ { LLM_ARCH_RICURSIVE, "ricursive" },
{ LLM_ARCH_LAGUNA, "laguna" },
{ LLM_ARCH_ERNIE4_5, "ernie4_5" },
{ LLM_ARCH_ERNIE4_5_MOE, "ernie4_5-moe" },
@@ -225,6 +226,7 @@ static const std::map<llm_kv, const char *> LLM_KV_NAMES = {
{ LLM_KV_EXPERT_CHUNK_FEED_FORWARD_LENGTH, "%s.expert_chunk_feed_forward_length" },
{ LLM_KV_SWIGLU_CLAMP_EXP, "%s.swiglu_clamp_exp" },
{ LLM_KV_SWIGLU_CLAMP_SHEXP, "%s.swiglu_clamp_shexp" },
+ { LLM_KV_SWIGLU_CLAMP, "%s.swiglu_clamp" },
{ LLM_KV_USE_PARALLEL_RESIDUAL, "%s.use_parallel_residual" },
{ LLM_KV_TENSOR_DATA_LAYOUT, "%s.tensor_data_layout" },
{ LLM_KV_EXPERT_COUNT, "%s.expert_count" },
@@ -540,6 +542,7 @@ static const std::map<llm_tensor, const char *> LLM_TENSOR_NAMES = {
{ LLM_TENSOR_ATTN_Q_NORM, "blk.%d.attn_q_norm" },
{ LLM_TENSOR_ATTN_K_NORM, "blk.%d.attn_k_norm" },
{ LLM_TENSOR_ATTN_GATE, "blk.%d.attn_gate" },
+ { LLM_TENSOR_ATTN_VALUE_RES, "blk.%d.attn_value_res" },
{ LLM_TENSOR_ATTN_RESID_ALPHA, "blk.%d.attn_resid_alpha" },
{ LLM_TENSOR_ATTN_RESID_BETA, "blk.%d.attn_resid_beta" },
{ LLM_TENSOR_FFN_POST_NORM, "blk.%d.post_ffw_norm" },
@@ -934,6 +937,7 @@ static const std::map<llm_tensor, llm_tensor_info> LLM_TENSOR_INFOS = {
{LLM_TENSOR_ATTN_QKV, {LLM_TENSOR_LAYER_REPEATING, GGML_OP_MUL_MAT}},
{LLM_TENSOR_ATTN_OUT, {LLM_TENSOR_LAYER_REPEATING, GGML_OP_MUL_MAT}},
{LLM_TENSOR_ATTN_GATE, {LLM_TENSOR_LAYER_REPEATING, GGML_OP_MUL_MAT}},
+ {LLM_TENSOR_ATTN_VALUE_RES, {LLM_TENSOR_LAYER_REPEATING, GGML_OP_MUL}},
{LLM_TENSOR_ATTN_RESID_ALPHA, {LLM_TENSOR_LAYER_REPEATING, GGML_OP_MUL}},
{LLM_TENSOR_ATTN_RESID_BETA, {LLM_TENSOR_LAYER_REPEATING, GGML_OP_MUL}},
{LLM_TENSOR_FFN_GATE, {LLM_TENSOR_LAYER_REPEATING, GGML_OP_MUL_MAT}},
diff --git a/src/llama-arch.h b/src/llama-arch.h
index f811607b6..5a2d8272d 100644
--- a/src/llama-arch.h
+++ b/src/llama-arch.h
@@ -129,6 +129,7 @@ enum llm_arch {
LLM_ARCH_DOTS3NOTE,
LLM_ARCH_ARCEE,
LLM_ARCH_AFMOE,
+ LLM_ARCH_RICURSIVE,
LLM_ARCH_LAGUNA,
LLM_ARCH_ERNIE4_5,
LLM_ARCH_ERNIE4_5_MOE,
@@ -229,6 +230,7 @@ enum llm_kv {
LLM_KV_EXPERT_CHUNK_FEED_FORWARD_LENGTH,
LLM_KV_SWIGLU_CLAMP_EXP,
LLM_KV_SWIGLU_CLAMP_SHEXP,
+ LLM_KV_SWIGLU_CLAMP,
LLM_KV_USE_PARALLEL_RESIDUAL,
LLM_KV_TENSOR_DATA_LAYOUT,
LLM_KV_EXPERT_COUNT,
@@ -540,6 +542,7 @@ enum llm_tensor {
LLM_TENSOR_ATTN_SINKS,
LLM_TENSOR_ATTN_SSMAX,
LLM_TENSOR_ATTN_GATE,
+ LLM_TENSOR_ATTN_VALUE_RES,
LLM_TENSOR_ATTN_RESID_ALPHA,
LLM_TENSOR_ATTN_RESID_BETA,
LLM_TENSOR_FFN_GATE_INP,
diff --git a/src/llama-hparams.h b/src/llama-hparams.h
index 95daf482d..4a9a2cf75 100644
--- a/src/llama-hparams.h
+++ b/src/llama-hparams.h
@@ -254,6 +254,7 @@ struct llama_hparams {
// Additional scale factors (Granite/Granite MoE)
float f_residual_scale = 0.0f;
float f_embedding_scale = 0.0f;
+ float f_swiglu_clamp = 0.0f; // dense FFN: silu(min(gate, c)) * clamp(up, -c, c)
float f_attention_scale = 0.0f;
// grok-2
diff --git a/src/llama-model.cpp b/src/llama-model.cpp
index 3c4e598f1..ed395b0b2 100644
--- a/src/llama-model.cpp
+++ b/src/llama-model.cpp
@@ -290,6 +290,8 @@ static llama_model * llama_model_mapping(llm_arch arch, const llama_model_params
return new llama_model_arcee(params);
case LLM_ARCH_AFMOE:
return new llama_model_afmoe(params);
+ case LLM_ARCH_RICURSIVE:
+ return new llama_model_ricursive(params);
case LLM_ARCH_LAGUNA:
return new llama_model_laguna(params);
case LLM_ARCH_ERNIE4_5:
@@ -3753,6 +3755,7 @@ llama_rope_type llama_model_rope_type(const llama_model * model) {
case LLM_ARCH_COGVLM:
case LLM_ARCH_PANGU_EMBED:
case LLM_ARCH_AFMOE:
+ case LLM_ARCH_RICURSIVE:
case LLM_ARCH_LAGUNA:
case LLM_ARCH_QWEN3NEXT:
case LLM_ARCH_CLOVER_MOE:
diff --git a/src/llama-model.h b/src/llama-model.h
index 45d2b8666..2c3d6b15d 100644
--- a/src/llama-model.h
+++ b/src/llama-model.h
@@ -312,6 +312,7 @@ struct llama_layer {
struct ggml_tensor * wv_enc = nullptr;
struct ggml_tensor * wo_enc = nullptr;
struct ggml_tensor * wqkv_gate = nullptr;
+ struct ggml_tensor * attn_value_res = nullptr; // ricursive: value-residual mix logit, [1]
struct ggml_tensor * wqkv_gate_b = nullptr;
// K2 Horizon MoVA
struct ggml_tensor * attn_v_gate = nullptr;
diff --git a/src/models/models.h b/src/models/models.h
index dd3b7b1ed..449ac3c37 100644
--- a/src/models/models.h
+++ b/src/models/models.h
@@ -2238,6 +2238,19 @@ struct llama_model_afmoe : public llama_model_base {
};
+struct llama_model_ricursive : public llama_model_base {
+ llama_model_ricursive(const struct llama_model_params & params) : llama_model_base(params) {}
+ void load_arch_hparams(llama_model_loader & ml) override;
+ void load_arch_tensors(llama_model_loader & ml) override;
+
+ struct graph : public llm_graph_context {
+ graph(const llama_model & model, const llm_graph_params & params);
+ };
+
+ std::unique_ptr<llm_graph_context> build_arch_graph(const llm_graph_params & params) const override;
+};
+
+
struct llama_model_beam : public llama_model_base {
llama_model_beam(const struct llama_model_params & params) : llama_model_base(params) {}
void load_arch_hparams(llama_model_loader & ml) override;
diff --git a/src/models/ricursive.cpp b/src/models/ricursive.cpp
new file mode 100644
index 000000000..d11255d8f
--- /dev/null
+++ b/src/models/ricursive.cpp
@@ -0,0 +1,216 @@
+#include "models.h"
+
+void llama_model_ricursive::load_arch_hparams(llama_model_loader & ml) {
+ ml.get_key(LLM_KV_ATTENTION_LAYERNORM_RMS_EPS, hparams.f_norm_rms_eps);
+ ml.get_key(LLM_KV_EMBEDDING_SCALE, hparams.f_embedding_scale, false);
+ ml.get_key(LLM_KV_SWIGLU_CLAMP, hparams.f_swiglu_clamp, false);
+
+ // 4 sliding (RoPE) : 1 full (NoPE), the window includes the current token
+ ml.get_key(LLM_KV_ATTENTION_SLIDING_WINDOW, hparams.n_swa);
+ hparams.swa_type = LLAMA_SWA_TYPE_STANDARD;
+ load_swa_pattern(ml, 5);
+
+ hparams.rope_freq_base_train_swa = hparams.rope_freq_base_train;
+ hparams.rope_freq_scale_train_swa = hparams.rope_freq_scale_train;
+ ml.get_key(LLM_KV_ROPE_FREQ_BASE_SWA, hparams.rope_freq_base_train_swa, false);
+
+ switch (hparams.n_layer()) {
+ case 80: type = LLM_TYPE_65B; break;
+ default: type = LLM_TYPE_UNKNOWN;
+ }
+}
+
+void llama_model_ricursive::load_arch_tensors(llama_model_loader &) {
+ LLAMA_LOAD_LOCALS;
+
+ tok_embd = create_tensor(tn(LLM_TENSOR_TOKEN_EMBD, "weight"), {n_embd, n_vocab}, 0);
+
+ // output
+ output_norm = create_tensor(tn(LLM_TENSOR_OUTPUT_NORM, "weight"), {n_embd}, 0);
+ output = create_tensor(tn(LLM_TENSOR_OUTPUT, "weight"), {n_embd, n_vocab}, TENSOR_NOT_REQUIRED);
+
+ // if output is NULL, init from the input tok embed
+ if (output == NULL) {
+ output = create_tensor(tn(LLM_TENSOR_TOKEN_EMBD, "weight"), {n_embd, n_vocab}, TENSOR_DUPLICATED);
+ }
+
+ for (int i = 0; i < n_layer; ++i) {
+ auto & layer = layers[i];
+
+ // sandwich attention normalization
+ layer.attn_norm = create_tensor(tn(LLM_TENSOR_ATTN_NORM, "weight", i), {n_embd}, 0);
+ layer.attn_post_norm = create_tensor(tn(LLM_TENSOR_ATTN_POST_NORM, "weight", i), {n_embd}, 0);
+
+ create_tensor_qkv(layer, i, n_embd, n_embd_head_k * n_head, n_embd_k_gqa, n_embd_v_gqa, 0);
+ layer.wo = create_tensor(tn(LLM_TENSOR_ATTN_OUT, "weight", i), {n_embd_head_k * n_head, n_embd}, 0);
+
+ layer.attn_q_norm = create_tensor(tn(LLM_TENSOR_ATTN_Q_NORM, "weight", i), {n_embd_head_k}, 0);
+ layer.attn_k_norm = create_tensor(tn(LLM_TENSOR_ATTN_K_NORM, "weight", i), {n_embd_head_k}, 0);
+
+ // elementwise sigmoid gate on the attention output
+ layer.wqkv_gate = create_tensor(tn(LLM_TENSOR_ATTN_GATE, "weight", i), {n_embd, n_embd_head_k * n_head}, 0);
+
+ // value residual: v_proj sees lerp(scaled token embeddings, attn_norm output, sigmoid(lambda))
+ layer.attn_value_res = create_tensor(tn(LLM_TENSOR_ATTN_VALUE_RES, "weight", i), {1}, 0);
+
+ // sandwich ffn normalization
+ layer.ffn_norm = create_tensor(tn(LLM_TENSOR_FFN_NORM, "weight", i), {n_embd}, 0);
+ layer.ffn_post_norm = create_tensor(tn(LLM_TENSOR_FFN_POST_NORM, "weight", i), {n_embd}, 0);
+
+ layer.ffn_gate = create_tensor(tn(LLM_TENSOR_FFN_GATE, "weight", i), {n_embd, n_ff}, 0);
+ layer.ffn_down = create_tensor(tn(LLM_TENSOR_FFN_DOWN, "weight", i), {n_ff, n_embd}, 0);
+ layer.ffn_up = create_tensor(tn(LLM_TENSOR_FFN_UP, "weight", i), {n_embd, n_ff}, 0);
+ }
+}
+
+std::unique_ptr<llm_graph_context> llama_model_ricursive::build_arch_graph(const llm_graph_params & params) const {
+ return std::make_unique<graph>(*this, params);
+}
+
+llama_model_ricursive::graph::graph(const llama_model & model, const llm_graph_params & params) : llm_graph_context(params) {
+ const int64_t n_embd_head = hparams.n_embd_head_v();
+
+ GGML_ASSERT(n_embd_head == hparams.n_embd_head_k());
+ GGML_ASSERT(n_embd_head == n_rot);
+
+ ggml_tensor * cur;
+ ggml_tensor * inpL;
+
+ // build_inp_embd applies hparams.f_embedding_scale (sqrt(n_embd) here) itself
+ inpL = build_inp_embd(model.tok_embd);
+ cb(inpL, "inp_scaled", -1);
+
+ // the value-residual source for every layer, including layer 0
+ ggml_tensor * inp_embd = inpL;
+
+ // inp_pos - contains the positions
+ ggml_tensor * inp_pos = build_inp_pos();
+ auto * inp_attn = build_attn_inp_kv_iswa();
+ ggml_tensor * inp_out_ids = build_inp_out_ids();
+
+ const float kq_scale = 1.0f/sqrtf(float(n_embd_head));
+
+ for (int il = 0; il < n_layer; ++il) {
+ res->t_layer_inp[il] = inpL;
+
+ const auto & layer = model.layers[il];
+
+ const bool is_swa = hparams.is_swa(il);
+
+ ggml_tensor * inpSA = inpL;
+
+ cur = build_norm(inpL, layer.attn_norm, NULL, LLM_NORM_RMS, il);
+ cb(cur, "attn_norm", il);
+
+ // self-attention
+ {
+ ggml_tensor * attn_inp = cur;
+
+ ggml_tensor * Qcur = build_lora_mm(layer.wq, cur, layer.wq_s);
+ cb(Qcur, "Qcur", il);
+ ggml_tensor * Kcur = build_lora_mm(layer.wk, cur, layer.wk_s);
+ cb(Kcur, "Kcur", il);
+
+ ggml_tensor * mix = ggml_sigmoid(ctx0, layer.attn_value_res);
+ ggml_tensor * vinp = ggml_add(ctx0, inp_embd, ggml_mul(ctx0, ggml_sub(ctx0, cur, inp_embd), mix));
+ cb(vinp, "vres_inp", il);
+ ggml_tensor * Vcur = build_lora_mm(layer.wv, vinp, layer.wv_s);
+ cb(Vcur, "Vcur", il);
+
+ Qcur = ggml_reshape_3d(ctx0, Qcur, n_embd_head, n_head, n_tokens);
+ Kcur = ggml_reshape_3d(ctx0, Kcur, n_embd_head, n_head_kv, n_tokens);
+ Vcur = ggml_reshape_3d(ctx0, Vcur, n_embd_head, n_head_kv, n_tokens);
+
+ Qcur = build_norm(Qcur, layer.attn_q_norm, NULL, LLM_NORM_RMS, il);
+ Kcur = build_norm(Kcur, layer.attn_k_norm, NULL, LLM_NORM_RMS, il);
+ cb(Qcur, "Qcur_normed", il);
+ cb(Kcur, "Kcur_normed", il);
+
+ // full-attention layers carry no positional encoding
+ if (is_swa) {
+ const float freq_base_l = model.get_rope_freq_base (cparams, il);
+ const float freq_scale_l = model.get_rope_freq_scale(cparams, il);
+
+ Qcur = ggml_rope_ext(
+ ctx0, Qcur, inp_pos, nullptr,
+ n_rot, rope_type, n_ctx_orig, freq_base_l, freq_scale_l,
+ ext_factor, attn_factor, beta_fast, beta_slow);
+ Kcur = ggml_rope_ext(
+ ctx0, Kcur, inp_pos, nullptr,
+ n_rot, rope_type, n_ctx_orig, freq_base_l, freq_scale_l,
+ ext_factor, attn_factor, beta_fast, beta_slow);
+ cb(Qcur, "Qcur_rope", il);
+ cb(Kcur, "Kcur_rope", il);
+ }
+
+ cur = build_attn(inp_attn,
+ NULL, NULL, NULL, // wo is applied after gating
+ Qcur, Kcur, Vcur, nullptr, nullptr, nullptr, kq_scale, il);
+ cb(cur, "attn_out", il);
+
+ // attention gating: attn_out * sigmoid(g_proj(attn_norm)) BEFORE o_proj
+ ggml_tensor * gate = build_lora_mm(layer.wqkv_gate, attn_inp);
+ gate = ggml_sigmoid(ctx0, gate);
+ cb(gate, "attn_gate_sig", il);
+ cur = ggml_mul(ctx0, cur, gate);
+ cb(cur, "attn_gated", il);
+
+ cur = build_lora_mm(layer.wo, cur, layer.wo_s);
+ cb(cur, "attn_o_proj", il);
+ }
+
+ cur = build_norm(cur, layer.attn_post_norm, NULL, LLM_NORM_RMS, il);
+ cb(cur, "attn_post_norm", il);
+
+ if (il == n_layer - 1 && inp_out_ids) {
+ cur = ggml_get_rows(ctx0, cur, inp_out_ids);
+ inpSA = ggml_get_rows(ctx0, inpSA, inp_out_ids);
+ }
+
+ ggml_tensor * ffn_inp = ggml_add(ctx0, cur, inpSA);
+ cb(ffn_inp, "ffn_inp", il);
+
+ cur = build_norm(ffn_inp, layer.ffn_norm, NULL, LLM_NORM_RMS, il);
+ cb(cur, "ffn_norm", il);
+
+ // dense SwiGLU with pre-activation clamping
+ {
+ ggml_tensor * up = build_lora_mm(layer.ffn_up, cur, layer.ffn_up_s);
+ cb(up, "ffn_up", il);
+ ggml_tensor * gate = build_lora_mm(layer.ffn_gate, cur, layer.ffn_gate_s);
+ cb(gate, "ffn_gate", il);
+
+ if (hparams.f_swiglu_clamp > 0.0f) {
+ cur = ggml_swiglu_clamp(ctx0, gate, up, hparams.f_swiglu_clamp);
+ } else {
+ cur = ggml_swiglu_split(ctx0, gate, up);
+ }
+ cb(cur, "ffn_swiglu", il);
+
+ cur = build_lora_mm(layer.ffn_down, cur, layer.ffn_down_s);
+ cb(cur, "ffn_out", il);
+ }
+
+ cur = build_norm(cur, layer.ffn_post_norm, NULL, LLM_NORM_RMS, il);
+ cb(cur, "ffn_post_norm", il);
+
+ cur = ggml_add(ctx0, cur, ffn_inp);
+ cur = build_cvec(cur, il);
+ cb(cur, "l_out", il);
+
+ // input for next layer
+ inpL = cur;
+ }
+
+ cur = inpL;
+
+ cur = build_norm(cur, model.output_norm, NULL, LLM_NORM_RMS, -1);
+ cb(cur, "result_norm", -1);
+
+ res->t_embd = cur;
+
+ // lm_head
+ cur = build_lora_mm(model.output, cur, model.output_s);
+ cb(cur, "result_output", -1);
+ res->t_logits = cur;
+}