model: add dots3-note (#27060)
* text: conversion * init impl * address review comments * fix rope * move to a new llama_kv_cache_dsa_iswa
This commit is contained in:
@@ -64,6 +64,9 @@ TEXT_MODEL_MAP: dict[str, str] = {
|
|||||||
"DistilBertForSequenceClassification": "bert",
|
"DistilBertForSequenceClassification": "bert",
|
||||||
"DistilBertModel": "bert",
|
"DistilBertModel": "bert",
|
||||||
"Dots1ForCausalLM": "dots1",
|
"Dots1ForCausalLM": "dots1",
|
||||||
|
"Dots3NoteForCausalLM": "dots3",
|
||||||
|
"Dots3NoteForConditionalGeneration": "dots3",
|
||||||
|
"Dots3NoteTextForCausalLM": "dots3",
|
||||||
"DotsOCRForCausalLM": "qwen",
|
"DotsOCRForCausalLM": "qwen",
|
||||||
"DreamModel": "dream",
|
"DreamModel": "dream",
|
||||||
"Ernie4_5ForCausalLM": "ernie",
|
"Ernie4_5ForCausalLM": "ernie",
|
||||||
|
|||||||
@@ -0,0 +1,195 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import math
|
||||||
|
import re
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING, Callable, Iterable
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from torch import Tensor
|
||||||
|
|
||||||
|
from .base import ModelBase, gguf
|
||||||
|
|
||||||
|
from .deepseek import DeepseekV2Model
|
||||||
|
|
||||||
|
|
||||||
|
@ModelBase.register("Dots3NoteForCausalLM", "Dots3NoteForConditionalGeneration", "Dots3NoteTextForCausalLM")
|
||||||
|
class Dots3NoteModel(DeepseekV2Model):
|
||||||
|
model_arch = gguf.MODEL_ARCH.DOTS3NOTE
|
||||||
|
skip_mtp = False
|
||||||
|
supports_mtp_export = True
|
||||||
|
|
||||||
|
# trunk layer count, stashed before indexing for filter_tensors (mirrors DeepseekV32Model)
|
||||||
|
_n_main_layers: int | None = None
|
||||||
|
|
||||||
|
def index_tensors(self, remote_hf_model_id: str | None = None):
|
||||||
|
type(self)._n_main_layers = self.hparams["num_hidden_layers"]
|
||||||
|
return super().index_tensors(remote_hf_model_id=remote_hf_model_id)
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
hparams = self.hparams
|
||||||
|
|
||||||
|
# config file doesn't specify MTP block, detect it from model weight
|
||||||
|
self.n_nextn = 1 if "model.mtp.embed_tokens.weight" in self.model_tensors else 0
|
||||||
|
if self.n_nextn:
|
||||||
|
self.block_count += self.n_nextn
|
||||||
|
self.tensor_map = gguf.get_tensor_name_map(self.model_arch, self.block_count)
|
||||||
|
|
||||||
|
self.layer_types = hparams["layer_types"]
|
||||||
|
if len(self.layer_types) < hparams["num_hidden_layers"]:
|
||||||
|
raise ValueError("layer_types is shorter than num_hidden_layers")
|
||||||
|
|
||||||
|
if hparams.get("use_dsa", True) is not True:
|
||||||
|
raise ValueError("dots3-note conversion requires use_dsa=true")
|
||||||
|
if hparams.get("normalization", "RMSNorm") != "RMSNorm" or hparams.get("final_norm", "RMSNorm") != "RMSNorm":
|
||||||
|
raise ValueError("dots3-note conversion only supports RMSNorm")
|
||||||
|
if hparams.get("k_rope_only_layernorm", True) is not True:
|
||||||
|
raise ValueError("dots3-note conversion requires k_rope_only_layernorm=true")
|
||||||
|
if hparams.get("topk_method", "noaux_tc") != "noaux_tc" or hparams.get("scoring_func") != "sigmoid":
|
||||||
|
raise ValueError("dots3-note conversion only supports noaux_tc/sigmoid expert gating")
|
||||||
|
if hparams.get("n_group", 1) != 1 or hparams.get("topk_group", 1) != 1:
|
||||||
|
raise ValueError("dots3-note conversion does not support grouped expert routing")
|
||||||
|
if hparams.get("use_dynamic_rsf", False) or hparams.get("moe_gating_fp32", False):
|
||||||
|
raise ValueError("dots3-note conversion does not support use_dynamic_rsf/moe_gating_fp32")
|
||||||
|
for key in ("attention_gate_type", "swa_attention_gate_type"):
|
||||||
|
if hparams.get(key, "headwise") != "headwise":
|
||||||
|
raise ValueError(f"dots3-note conversion only supports headwise attention gate, got {key}={hparams.get(key)!r}")
|
||||||
|
if hparams["swa_qk_nope_head_dim"] + hparams["swa_qk_rope_head_dim"] != hparams.get("swa_head_dim", 256):
|
||||||
|
raise ValueError("swa_head_dim must equal swa_qk_nope_head_dim + swa_qk_rope_head_dim")
|
||||||
|
if hparams["swa_qk_rope_head_dim"] != hparams["qk_rope_head_dim"]:
|
||||||
|
# both layer kinds share a single rope_dimension_count
|
||||||
|
raise ValueError("swa_qk_rope_head_dim must match qk_rope_head_dim")
|
||||||
|
|
||||||
|
self.apply_lora_rescale = hparams.get("apply_mla_qkv_lora_rescale", False)
|
||||||
|
|
||||||
|
def _is_swa_layer(self, bid: int) -> bool:
|
||||||
|
if bid >= self.hparams["num_hidden_layers"]:
|
||||||
|
# note: the NextN/MTP block uses the sliding-attention MLA
|
||||||
|
return True
|
||||||
|
return self.layer_types[bid] == "sliding_attention"
|
||||||
|
|
||||||
|
def set_vocab(self):
|
||||||
|
from transformers import AutoTokenizer
|
||||||
|
tokenizer = AutoTokenizer.from_pretrained(self.dir_model)
|
||||||
|
special_vocab = gguf.SpecialVocab(self.dir_model, load_merges=True)
|
||||||
|
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._set_special_token("eot", tokenizer.get_added_vocab()["<|endofassistant|>"]) # ty: ignore[unresolved-attribute]
|
||||||
|
special_vocab.add_to_gguf(self.gguf_writer)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def filter_tensors(cls, item: tuple[str, Callable[[], Tensor]]) -> tuple[str, Callable[[], Tensor]] | None:
|
||||||
|
if (titem := super().filter_tensors(item)) is None:
|
||||||
|
return None
|
||||||
|
name, gen = titem
|
||||||
|
if name.startswith(("vision_encoder.", "audio_encoder.")):
|
||||||
|
return None
|
||||||
|
|
||||||
|
assert cls._n_main_layers is not None
|
||||||
|
is_mtp = name.startswith("model.mtp.") or \
|
||||||
|
((m := re.match(r"model\.layers\.(\d+)\.", name)) is not None and int(m.group(1)) >= cls._n_main_layers)
|
||||||
|
|
||||||
|
# --no-mtp: drop the NextN/MTP block; --mtp: keep only that block plus the shared embeddings/norm/lm_head
|
||||||
|
if is_mtp and cls.no_mtp:
|
||||||
|
return None
|
||||||
|
if cls.mtp_only and not is_mtp and name not in (
|
||||||
|
"model.embed_tokens.weight", "model.norm.weight", "lm_head.weight",
|
||||||
|
):
|
||||||
|
return None
|
||||||
|
|
||||||
|
return name, gen
|
||||||
|
|
||||||
|
def set_gguf_parameters(self):
|
||||||
|
hparams = self.hparams
|
||||||
|
|
||||||
|
# head_count is a per-layer array because the two layer kinds have different head counts
|
||||||
|
n_layer = hparams["num_hidden_layers"]
|
||||||
|
hparams["num_attention_heads"] = [
|
||||||
|
hparams["swa_num_attention_heads"] if self._is_swa_layer(il) else hparams["num_attention_heads"]
|
||||||
|
for il in range(self.block_count)
|
||||||
|
]
|
||||||
|
|
||||||
|
# prevent the base class from emitting key/value_length from the unused head_dim
|
||||||
|
hparams.pop("head_dim", None)
|
||||||
|
|
||||||
|
super().set_gguf_parameters()
|
||||||
|
|
||||||
|
# MLA geometry of the sliding-window layers (rope.freq_base_swa is emitted by the base class)
|
||||||
|
swa_kv_lora_rank = hparams["swa_kv_lora_rank"]
|
||||||
|
self.gguf_writer.add_sliding_window(hparams["sliding_window_size"])
|
||||||
|
self.gguf_writer.add_sliding_window_pattern([self._is_swa_layer(il) for il in range(n_layer)])
|
||||||
|
self.gguf_writer.add_kv_lora_rank_swa(swa_kv_lora_rank)
|
||||||
|
self.gguf_writer.add_key_length_swa(swa_kv_lora_rank + hparams["swa_qk_rope_head_dim"])
|
||||||
|
self.gguf_writer.add_value_length_swa(swa_kv_lora_rank)
|
||||||
|
self.gguf_writer.add_key_length_mla_swa(hparams["swa_qk_nope_head_dim"] + hparams["swa_qk_rope_head_dim"])
|
||||||
|
self.gguf_writer.add_value_length_mla_swa(hparams["swa_v_head_dim"])
|
||||||
|
if hparams["swa_q_lora_rank"] != hparams["q_lora_rank"]:
|
||||||
|
raise ValueError("dots3-note conversion assumes a shared q_lora_rank for both layer kinds")
|
||||||
|
|
||||||
|
if self.n_nextn:
|
||||||
|
self.gguf_writer.add_nextn_predict_layers(self.n_nextn)
|
||||||
|
|
||||||
|
# DSA indexer (full-attention layers only)
|
||||||
|
self.gguf_writer.add_indexer_head_count(hparams["index_n_heads"])
|
||||||
|
self.gguf_writer.add_indexer_key_length(hparams["index_head_dim"])
|
||||||
|
self.gguf_writer.add_indexer_top_k(hparams["index_topk"])
|
||||||
|
self.gguf_writer.add_indexer_types([not self._is_swa_layer(il) for il in range(n_layer)])
|
||||||
|
|
||||||
|
def prepare_metadata(self, vocab_only: bool):
|
||||||
|
from_dir = self.fname_out.is_dir()
|
||||||
|
super().prepare_metadata(vocab_only=vocab_only)
|
||||||
|
|
||||||
|
if not self.mtp_only or not from_dir:
|
||||||
|
return
|
||||||
|
|
||||||
|
output_type: str = self.ftype.name.partition("_")[2]
|
||||||
|
fname_default: str = gguf.naming_convention(
|
||||||
|
self.metadata.name, self.metadata.basename, self.metadata.finetune,
|
||||||
|
self.metadata.version, size_label=None, output_type=output_type, model_type=None)
|
||||||
|
self.fname_out = self.fname_out.parent / f"mtp-{fname_default}.gguf"
|
||||||
|
|
||||||
|
def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iterable[tuple[str, Tensor]]:
|
||||||
|
# move the MTP token embedding into the NextN block so the standard nextn mapping picks it up
|
||||||
|
if name == "model.mtp.embed_tokens.weight":
|
||||||
|
name = f"model.layers.{self.hparams['num_hidden_layers']}.embed_tokens.weight"
|
||||||
|
bid = self.hparams["num_hidden_layers"]
|
||||||
|
|
||||||
|
# fold the activation rescale sqrt(n_embd/lora_rank) into the preceding RMSNorm weight
|
||||||
|
# this also covers the indexer wq_b, which reads the same rescaled q_lora activation
|
||||||
|
if self.apply_lora_rescale and bid is not None:
|
||||||
|
if name.endswith("q_a_layernorm.weight"):
|
||||||
|
data_torch = data_torch * math.sqrt(self.hparams["hidden_size"] / self.hparams["q_lora_rank"])
|
||||||
|
elif name.endswith("kv_a_layernorm.weight"):
|
||||||
|
rank = self.hparams["swa_kv_lora_rank"] if self._is_swa_layer(bid) else self.hparams["kv_lora_rank"]
|
||||||
|
data_torch = data_torch * math.sqrt(self.hparams["hidden_size"] / rank)
|
||||||
|
|
||||||
|
# MLA absorption: split kv_b_proj into k_b (transposed) and v_b, per-layer-kind geometry
|
||||||
|
if name.endswith("kv_b_proj.weight"):
|
||||||
|
assert bid is not None
|
||||||
|
if self._is_swa_layer(bid):
|
||||||
|
n_head = self.hparams["swa_num_attention_heads"]
|
||||||
|
qk_nope_head_dim = self.hparams["swa_qk_nope_head_dim"]
|
||||||
|
v_head_dim = self.hparams["swa_v_head_dim"]
|
||||||
|
else:
|
||||||
|
n_head = self.hparams["num_attention_heads"]
|
||||||
|
qk_nope_head_dim = self.hparams["qk_nope_head_dim"]
|
||||||
|
v_head_dim = self.hparams["v_head_dim"]
|
||||||
|
if isinstance(n_head, list): # set_gguf_parameters turns this into a per-layer array
|
||||||
|
n_head = n_head[bid]
|
||||||
|
|
||||||
|
assert data_torch.shape[0] == n_head * (qk_nope_head_dim + v_head_dim)
|
||||||
|
|
||||||
|
kv_b = data_torch.view(n_head, qk_nope_head_dim + v_head_dim, data_torch.shape[-1])
|
||||||
|
k_b, v_b = kv_b.split([qk_nope_head_dim, v_head_dim], dim=1)
|
||||||
|
k_b = k_b.transpose(1, 2)
|
||||||
|
|
||||||
|
yield from ModelBase.modify_tensors(self, k_b, name.replace("kv_b_proj", "k_b_proj"), bid)
|
||||||
|
yield from ModelBase.modify_tensors(self, v_b, name.replace("kv_b_proj", "v_b_proj"), bid)
|
||||||
|
return
|
||||||
|
|
||||||
|
yield from super().modify_tensors(data_torch, name, bid)
|
||||||
@@ -205,6 +205,9 @@ class Keys:
|
|||||||
VALUE_LENGTH_MLA = "{arch}.attention.value_length_mla"
|
VALUE_LENGTH_MLA = "{arch}.attention.value_length_mla"
|
||||||
KEY_LENGTH_SWA = "{arch}.attention.key_length_swa"
|
KEY_LENGTH_SWA = "{arch}.attention.key_length_swa"
|
||||||
VALUE_LENGTH_SWA = "{arch}.attention.value_length_swa"
|
VALUE_LENGTH_SWA = "{arch}.attention.value_length_swa"
|
||||||
|
KEY_LENGTH_MLA_SWA = "{arch}.attention.key_length_mla_swa"
|
||||||
|
VALUE_LENGTH_MLA_SWA = "{arch}.attention.value_length_mla_swa"
|
||||||
|
KV_LORA_RANK_SWA = "{arch}.attention.kv_lora_rank_swa"
|
||||||
SHARED_KV_LAYERS = "{arch}.attention.shared_kv_layers"
|
SHARED_KV_LAYERS = "{arch}.attention.shared_kv_layers"
|
||||||
SLIDING_WINDOW_PATTERN = "{arch}.attention.sliding_window_pattern"
|
SLIDING_WINDOW_PATTERN = "{arch}.attention.sliding_window_pattern"
|
||||||
TEMPERATURE_SCALE = "{arch}.attention.temperature_scale"
|
TEMPERATURE_SCALE = "{arch}.attention.temperature_scale"
|
||||||
@@ -558,6 +561,7 @@ class MODEL_ARCH(IntEnum):
|
|||||||
BAILINGMOE2 = auto()
|
BAILINGMOE2 = auto()
|
||||||
BAILINGMOE3 = auto()
|
BAILINGMOE3 = auto()
|
||||||
DOTS1 = auto()
|
DOTS1 = auto()
|
||||||
|
DOTS3NOTE = auto()
|
||||||
ARCEE = auto()
|
ARCEE = auto()
|
||||||
AFMOE = auto()
|
AFMOE = auto()
|
||||||
LAGUNA = auto()
|
LAGUNA = auto()
|
||||||
@@ -1275,6 +1279,7 @@ MODEL_ARCH_NAMES: dict[MODEL_ARCH, str] = {
|
|||||||
MODEL_ARCH.BAILINGMOE2: "bailingmoe2",
|
MODEL_ARCH.BAILINGMOE2: "bailingmoe2",
|
||||||
MODEL_ARCH.BAILINGMOE3: "bailingmoe3",
|
MODEL_ARCH.BAILINGMOE3: "bailingmoe3",
|
||||||
MODEL_ARCH.DOTS1: "dots1",
|
MODEL_ARCH.DOTS1: "dots1",
|
||||||
|
MODEL_ARCH.DOTS3NOTE: "dots3note",
|
||||||
MODEL_ARCH.ARCEE: "arcee",
|
MODEL_ARCH.ARCEE: "arcee",
|
||||||
MODEL_ARCH.AFMOE: "afmoe",
|
MODEL_ARCH.AFMOE: "afmoe",
|
||||||
MODEL_ARCH.LAGUNA: "laguna",
|
MODEL_ARCH.LAGUNA: "laguna",
|
||||||
@@ -4334,6 +4339,44 @@ MODEL_TENSORS: dict[MODEL_ARCH, list[MODEL_TENSOR]] = {
|
|||||||
MODEL_TENSOR.FFN_UP_EXP,
|
MODEL_TENSOR.FFN_UP_EXP,
|
||||||
MODEL_TENSOR.FFN_UP_SHEXP,
|
MODEL_TENSOR.FFN_UP_SHEXP,
|
||||||
],
|
],
|
||||||
|
MODEL_ARCH.DOTS3NOTE: [
|
||||||
|
MODEL_TENSOR.TOKEN_EMBD,
|
||||||
|
MODEL_TENSOR.OUTPUT_NORM,
|
||||||
|
MODEL_TENSOR.OUTPUT,
|
||||||
|
MODEL_TENSOR.ATTN_NORM,
|
||||||
|
MODEL_TENSOR.ATTN_Q_A,
|
||||||
|
MODEL_TENSOR.ATTN_Q_B,
|
||||||
|
MODEL_TENSOR.ATTN_KV_A_MQA,
|
||||||
|
MODEL_TENSOR.ATTN_K_B,
|
||||||
|
MODEL_TENSOR.ATTN_V_B,
|
||||||
|
MODEL_TENSOR.ATTN_Q_A_NORM,
|
||||||
|
MODEL_TENSOR.ATTN_KV_A_NORM,
|
||||||
|
MODEL_TENSOR.ATTN_K_NORM,
|
||||||
|
MODEL_TENSOR.ATTN_GATE,
|
||||||
|
MODEL_TENSOR.ATTN_OUT,
|
||||||
|
MODEL_TENSOR.FFN_NORM,
|
||||||
|
MODEL_TENSOR.FFN_GATE,
|
||||||
|
MODEL_TENSOR.FFN_DOWN,
|
||||||
|
MODEL_TENSOR.FFN_UP,
|
||||||
|
MODEL_TENSOR.FFN_GATE_INP,
|
||||||
|
MODEL_TENSOR.FFN_EXP_PROBS_B,
|
||||||
|
MODEL_TENSOR.FFN_GATE_EXP,
|
||||||
|
MODEL_TENSOR.FFN_DOWN_EXP,
|
||||||
|
MODEL_TENSOR.FFN_UP_EXP,
|
||||||
|
MODEL_TENSOR.FFN_GATE_SHEXP,
|
||||||
|
MODEL_TENSOR.FFN_DOWN_SHEXP,
|
||||||
|
MODEL_TENSOR.FFN_UP_SHEXP,
|
||||||
|
MODEL_TENSOR.INDEXER_K_NORM,
|
||||||
|
MODEL_TENSOR.INDEXER_PROJ,
|
||||||
|
MODEL_TENSOR.INDEXER_ATTN_K,
|
||||||
|
MODEL_TENSOR.INDEXER_ATTN_Q_B,
|
||||||
|
# NextN/MTP tensors - preserved but unused
|
||||||
|
MODEL_TENSOR.NEXTN_EH_PROJ,
|
||||||
|
MODEL_TENSOR.NEXTN_EMBED_TOKENS,
|
||||||
|
MODEL_TENSOR.NEXTN_ENORM,
|
||||||
|
MODEL_TENSOR.NEXTN_HNORM,
|
||||||
|
MODEL_TENSOR.NEXTN_SHARED_HEAD_NORM,
|
||||||
|
],
|
||||||
MODEL_ARCH.ARCEE: [
|
MODEL_ARCH.ARCEE: [
|
||||||
MODEL_TENSOR.TOKEN_EMBD,
|
MODEL_TENSOR.TOKEN_EMBD,
|
||||||
MODEL_TENSOR.OUTPUT_NORM,
|
MODEL_TENSOR.OUTPUT_NORM,
|
||||||
|
|||||||
@@ -785,6 +785,15 @@ class GGUFWriter:
|
|||||||
def add_key_length_swa(self, length: int) -> None:
|
def add_key_length_swa(self, length: int) -> None:
|
||||||
self.add_uint32(Keys.Attention.KEY_LENGTH_SWA.format(arch=self.arch), length)
|
self.add_uint32(Keys.Attention.KEY_LENGTH_SWA.format(arch=self.arch), length)
|
||||||
|
|
||||||
|
def add_key_length_mla_swa(self, length: int) -> None:
|
||||||
|
self.add_uint32(Keys.Attention.KEY_LENGTH_MLA_SWA.format(arch=self.arch), length)
|
||||||
|
|
||||||
|
def add_value_length_mla_swa(self, length: int) -> None:
|
||||||
|
self.add_uint32(Keys.Attention.VALUE_LENGTH_MLA_SWA.format(arch=self.arch), length)
|
||||||
|
|
||||||
|
def add_kv_lora_rank_swa(self, length: int) -> None:
|
||||||
|
self.add_uint32(Keys.Attention.KV_LORA_RANK_SWA.format(arch=self.arch), length)
|
||||||
|
|
||||||
def add_value_length_swa(self, length: int) -> None:
|
def add_value_length_swa(self, length: int) -> None:
|
||||||
self.add_uint32(Keys.Attention.VALUE_LENGTH_SWA.format(arch=self.arch), length)
|
self.add_uint32(Keys.Attention.VALUE_LENGTH_SWA.format(arch=self.arch), length)
|
||||||
|
|
||||||
|
|||||||
@@ -723,6 +723,7 @@ class TensorNameMap:
|
|||||||
"model.layers.layers.{bid}.mixer.k", # plamo2
|
"model.layers.layers.{bid}.mixer.k", # plamo2
|
||||||
"model.layers.layers.{bid}.mixer.k_norm", # plamo3
|
"model.layers.layers.{bid}.mixer.k_norm", # plamo3
|
||||||
"layers.{bid}.self_attn.k_norm", # qwen3-embedding
|
"layers.{bid}.self_attn.k_norm", # qwen3-embedding
|
||||||
|
"model.layers.{bid}.self_attn.k_rope_only_layernorm", # dots3note
|
||||||
"model.layers.{bid}.attention.key_layernorm", # apertus
|
"model.layers.{bid}.attention.key_layernorm", # apertus
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ add_library(llama
|
|||||||
llama-kv-cache.cpp
|
llama-kv-cache.cpp
|
||||||
llama-kv-cache-iswa.cpp
|
llama-kv-cache-iswa.cpp
|
||||||
llama-kv-cache-dsa.cpp
|
llama-kv-cache-dsa.cpp
|
||||||
|
llama-kv-cache-dsa-iswa.cpp
|
||||||
llama-kv-cache-msa.cpp
|
llama-kv-cache-msa.cpp
|
||||||
llama-kv-cache-dsv4.cpp
|
llama-kv-cache-dsv4.cpp
|
||||||
llama-memory.cpp
|
llama-memory.cpp
|
||||||
|
|||||||
@@ -110,6 +110,7 @@ static const std::map<llm_arch, const char *> LLM_ARCH_NAMES = {
|
|||||||
{ LLM_ARCH_BAILINGMOE2, "bailingmoe2" },
|
{ LLM_ARCH_BAILINGMOE2, "bailingmoe2" },
|
||||||
{ LLM_ARCH_BAILINGMOE3, "bailingmoe3" },
|
{ LLM_ARCH_BAILINGMOE3, "bailingmoe3" },
|
||||||
{ LLM_ARCH_DOTS1, "dots1" },
|
{ LLM_ARCH_DOTS1, "dots1" },
|
||||||
|
{ LLM_ARCH_DOTS3NOTE, "dots3note" },
|
||||||
{ LLM_ARCH_ARCEE, "arcee" },
|
{ LLM_ARCH_ARCEE, "arcee" },
|
||||||
{ LLM_ARCH_AFMOE, "afmoe" },
|
{ LLM_ARCH_AFMOE, "afmoe" },
|
||||||
{ LLM_ARCH_LAGUNA, "laguna" },
|
{ LLM_ARCH_LAGUNA, "laguna" },
|
||||||
@@ -273,6 +274,9 @@ static const std::map<llm_kv, const char *> LLM_KV_NAMES = {
|
|||||||
{ LLM_KV_ATTENTION_VALUE_LENGTH_MLA, "%s.attention.value_length_mla" },
|
{ LLM_KV_ATTENTION_VALUE_LENGTH_MLA, "%s.attention.value_length_mla" },
|
||||||
{ LLM_KV_ATTENTION_KEY_LENGTH_SWA, "%s.attention.key_length_swa" },
|
{ LLM_KV_ATTENTION_KEY_LENGTH_SWA, "%s.attention.key_length_swa" },
|
||||||
{ LLM_KV_ATTENTION_VALUE_LENGTH_SWA, "%s.attention.value_length_swa" },
|
{ LLM_KV_ATTENTION_VALUE_LENGTH_SWA, "%s.attention.value_length_swa" },
|
||||||
|
{ LLM_KV_ATTENTION_KEY_LENGTH_MLA_SWA, "%s.attention.key_length_mla_swa" },
|
||||||
|
{ LLM_KV_ATTENTION_VALUE_LENGTH_MLA_SWA, "%s.attention.value_length_mla_swa" },
|
||||||
|
{ LLM_KV_ATTENTION_KV_LORA_RANK_SWA, "%s.attention.kv_lora_rank_swa" },
|
||||||
{ LLM_KV_ATTENTION_INDEXER_HEAD_COUNT, "%s.attention.indexer.head_count" },
|
{ LLM_KV_ATTENTION_INDEXER_HEAD_COUNT, "%s.attention.indexer.head_count" },
|
||||||
{ LLM_KV_ATTENTION_INDEXER_KEY_LENGTH, "%s.attention.indexer.key_length" },
|
{ LLM_KV_ATTENTION_INDEXER_KEY_LENGTH, "%s.attention.indexer.key_length" },
|
||||||
{ LLM_KV_ATTENTION_INDEXER_TOP_K, "%s.attention.indexer.top_k" },
|
{ LLM_KV_ATTENTION_INDEXER_TOP_K, "%s.attention.indexer.top_k" },
|
||||||
@@ -1056,6 +1060,7 @@ bool llm_arch_supports_sm_tensor(const llm_arch & arch) {
|
|||||||
case LLM_ARCH_DEEPSEEK2:
|
case LLM_ARCH_DEEPSEEK2:
|
||||||
case LLM_ARCH_DEEPSEEK32:
|
case LLM_ARCH_DEEPSEEK32:
|
||||||
case LLM_ARCH_DEEPSEEK4:
|
case LLM_ARCH_DEEPSEEK4:
|
||||||
|
case LLM_ARCH_DOTS3NOTE:
|
||||||
case LLM_ARCH_GLM_DSA:
|
case LLM_ARCH_GLM_DSA:
|
||||||
case LLM_ARCH_BITNET:
|
case LLM_ARCH_BITNET:
|
||||||
case LLM_ARCH_T5:
|
case LLM_ARCH_T5:
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ enum llm_arch {
|
|||||||
LLM_ARCH_BAILINGMOE2,
|
LLM_ARCH_BAILINGMOE2,
|
||||||
LLM_ARCH_BAILINGMOE3,
|
LLM_ARCH_BAILINGMOE3,
|
||||||
LLM_ARCH_DOTS1,
|
LLM_ARCH_DOTS1,
|
||||||
|
LLM_ARCH_DOTS3NOTE,
|
||||||
LLM_ARCH_ARCEE,
|
LLM_ARCH_ARCEE,
|
||||||
LLM_ARCH_AFMOE,
|
LLM_ARCH_AFMOE,
|
||||||
LLM_ARCH_LAGUNA,
|
LLM_ARCH_LAGUNA,
|
||||||
@@ -278,6 +279,9 @@ enum llm_kv {
|
|||||||
LLM_KV_ATTENTION_VALUE_LENGTH_MLA,
|
LLM_KV_ATTENTION_VALUE_LENGTH_MLA,
|
||||||
LLM_KV_ATTENTION_KEY_LENGTH_SWA,
|
LLM_KV_ATTENTION_KEY_LENGTH_SWA,
|
||||||
LLM_KV_ATTENTION_VALUE_LENGTH_SWA,
|
LLM_KV_ATTENTION_VALUE_LENGTH_SWA,
|
||||||
|
LLM_KV_ATTENTION_KEY_LENGTH_MLA_SWA,
|
||||||
|
LLM_KV_ATTENTION_VALUE_LENGTH_MLA_SWA,
|
||||||
|
LLM_KV_ATTENTION_KV_LORA_RANK_SWA,
|
||||||
LLM_KV_ATTENTION_INDEXER_HEAD_COUNT,
|
LLM_KV_ATTENTION_INDEXER_HEAD_COUNT,
|
||||||
LLM_KV_ATTENTION_INDEXER_KEY_LENGTH,
|
LLM_KV_ATTENTION_INDEXER_KEY_LENGTH,
|
||||||
LLM_KV_ATTENTION_INDEXER_TOP_K,
|
LLM_KV_ATTENTION_INDEXER_TOP_K,
|
||||||
|
|||||||
+60
-6
@@ -9,6 +9,7 @@
|
|||||||
#include "llama-kv-cache.h"
|
#include "llama-kv-cache.h"
|
||||||
#include "llama-kv-cache-iswa.h"
|
#include "llama-kv-cache-iswa.h"
|
||||||
#include "llama-kv-cache-dsa.h"
|
#include "llama-kv-cache-dsa.h"
|
||||||
|
#include "llama-kv-cache-dsa-iswa.h"
|
||||||
#include "llama-kv-cache-msa.h"
|
#include "llama-kv-cache-msa.h"
|
||||||
#include "llama-kv-cache-dsv4.h"
|
#include "llama-kv-cache-dsv4.h"
|
||||||
#include "llama-memory-hybrid.h"
|
#include "llama-memory-hybrid.h"
|
||||||
@@ -507,10 +508,12 @@ void llm_graph_input_attn_k::set_input(const llama_ubatch * ubatch) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool llm_graph_input_attn_k::can_reuse(const llm_graph_params & params) {
|
bool llm_graph_input_attn_k::can_reuse(const llm_graph_params & params) {
|
||||||
const auto * mctx = static_cast<const llama_kv_cache_context *>(params.mctx);
|
mctx = static_cast<const llama_kv_cache_context *>(params.mctx);
|
||||||
|
|
||||||
this->mctx = mctx;
|
return can_reuse_impl(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool llm_graph_input_attn_k::can_reuse_impl(const llm_graph_params & params) {
|
||||||
bool res = true;
|
bool res = true;
|
||||||
|
|
||||||
res &= self_k_idxs->ne[0] == params.ubatch.n_tokens;
|
res &= self_k_idxs->ne[0] == params.ubatch.n_tokens;
|
||||||
@@ -567,10 +570,12 @@ void llm_graph_input_attn_k_dsa::set_input(const llama_ubatch * ubatch) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool llm_graph_input_attn_k_dsa::can_reuse(const llm_graph_params & params) {
|
bool llm_graph_input_attn_k_dsa::can_reuse(const llm_graph_params & params) {
|
||||||
const auto * mctx = static_cast<const llama_kv_cache_dsa_context *>(params.mctx);
|
mctx = static_cast<const llama_kv_cache_dsa_context *>(params.mctx);
|
||||||
|
|
||||||
this->mctx = mctx;
|
return can_reuse_impl(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool llm_graph_input_attn_k_dsa::can_reuse_impl(const llm_graph_params & params) {
|
||||||
bool res = true;
|
bool res = true;
|
||||||
|
|
||||||
res &= self_k_idxs_mla->ne[0] == params.ubatch.n_tokens;
|
res &= self_k_idxs_mla->ne[0] == params.ubatch.n_tokens;
|
||||||
@@ -582,6 +587,25 @@ bool llm_graph_input_attn_k_dsa::can_reuse(const llm_graph_params & params) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void llm_graph_input_attn_k_dsa_iswa::set_input(const llama_ubatch * ubatch) {
|
||||||
|
inp_dsa->set_input(ubatch);
|
||||||
|
inp_swa->set_input(ubatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool llm_graph_input_attn_k_dsa_iswa::can_reuse(const llm_graph_params & params) {
|
||||||
|
mctx = static_cast<const llama_kv_cache_dsa_iswa_context *>(params.mctx);
|
||||||
|
|
||||||
|
inp_dsa->mctx = mctx->get_dsa();
|
||||||
|
inp_swa->mctx = mctx->get_swa();
|
||||||
|
|
||||||
|
bool res = true;
|
||||||
|
|
||||||
|
res &= inp_dsa->can_reuse_impl(params);
|
||||||
|
res &= inp_swa->can_reuse_impl(params);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
void llm_graph_input_attn_kv_iswa::set_input(const llama_ubatch * ubatch) {
|
void llm_graph_input_attn_kv_iswa::set_input(const llama_ubatch * ubatch) {
|
||||||
// base tensors may not be allocated if there are no non-SWA attention layers
|
// base tensors may not be allocated if there are no non-SWA attention layers
|
||||||
if (self_k_idxs && self_k_idxs->buffer) {
|
if (self_k_idxs && self_k_idxs->buffer) {
|
||||||
@@ -3210,8 +3234,12 @@ ggml_tensor * llm_graph_context::build_attn(
|
|||||||
return cur;
|
return cur;
|
||||||
}
|
}
|
||||||
|
|
||||||
llm_graph_input_attn_k_dsa * llm_graph_context::build_attn_inp_k_dsa() const {
|
static std::unique_ptr<llm_graph_input_attn_k_dsa> build_attn_inp_k_dsa_impl(
|
||||||
const auto * mctx_cur = static_cast<const llama_kv_cache_dsa_context *>(mctx);
|
ggml_context * ctx0,
|
||||||
|
const llama_ubatch & ubatch,
|
||||||
|
const llama_hparams & hparams,
|
||||||
|
const llama_cparams & cparams,
|
||||||
|
const llama_kv_cache_dsa_context * mctx_cur) {
|
||||||
|
|
||||||
auto inp = std::make_unique<llm_graph_input_attn_k_dsa>(hparams, cparams, mctx_cur);
|
auto inp = std::make_unique<llm_graph_input_attn_k_dsa>(hparams, cparams, mctx_cur);
|
||||||
|
|
||||||
@@ -3235,9 +3263,35 @@ llm_graph_input_attn_k_dsa * llm_graph_context::build_attn_inp_k_dsa() const {
|
|||||||
inp->self_k_rot_lid = mctx_cur->get_lid()->build_input_k_rot(ctx0);
|
inp->self_k_rot_lid = mctx_cur->get_lid()->build_input_k_rot(ctx0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return inp;
|
||||||
|
}
|
||||||
|
|
||||||
|
llm_graph_input_attn_k_dsa * llm_graph_context::build_attn_inp_k_dsa() const {
|
||||||
|
const auto * mctx_cur = static_cast<const llama_kv_cache_dsa_context *>(mctx);
|
||||||
|
|
||||||
|
auto inp = build_attn_inp_k_dsa_impl(ctx0, ubatch, hparams, cparams, mctx_cur);
|
||||||
|
|
||||||
return (llm_graph_input_attn_k_dsa *) res->add_input(std::move(inp));
|
return (llm_graph_input_attn_k_dsa *) res->add_input(std::move(inp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
llm_graph_input_attn_k_dsa_iswa * llm_graph_context::build_attn_inp_k_dsa_iswa() const {
|
||||||
|
const auto * mctx_cur = static_cast<const llama_kv_cache_dsa_iswa_context *>(mctx);
|
||||||
|
|
||||||
|
auto inp_dsa = build_attn_inp_k_dsa_impl(ctx0, ubatch, hparams, cparams, mctx_cur->get_dsa());
|
||||||
|
|
||||||
|
// build_attn_inp_k_impl rejects SWA caches, so construct the input directly
|
||||||
|
auto inp_swa = std::make_unique<llm_graph_input_attn_k>(hparams, cparams, mctx_cur->get_swa());
|
||||||
|
|
||||||
|
inp_swa->self_k_idxs = mctx_cur->get_swa()->build_input_k_idxs(ctx0, ubatch);
|
||||||
|
|
||||||
|
inp_swa->self_kq_mask = build_attn_inp_kq_mask(ctx0, mctx_cur->get_swa(), ubatch, cparams);
|
||||||
|
inp_swa->self_kq_mask_cnv = inp_swa->self_kq_mask;
|
||||||
|
|
||||||
|
auto inp = std::make_unique<llm_graph_input_attn_k_dsa_iswa>(std::move(inp_dsa), std::move(inp_swa), mctx_cur);
|
||||||
|
|
||||||
|
return (llm_graph_input_attn_k_dsa_iswa *) res->add_input(std::move(inp));
|
||||||
|
}
|
||||||
|
|
||||||
llm_graph_input_attn_kv_msa * llm_graph_context::build_attn_inp_kv_msa(bool msa_enabled) const {
|
llm_graph_input_attn_kv_msa * llm_graph_context::build_attn_inp_kv_msa(bool msa_enabled) const {
|
||||||
const auto * mctx_cur = static_cast<const llama_kv_cache_msa_context *>(mctx);
|
const auto * mctx_cur = static_cast<const llama_kv_cache_msa_context *>(mctx);
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ struct llama_memory_context_i;
|
|||||||
|
|
||||||
class llama_kv_cache_context;
|
class llama_kv_cache_context;
|
||||||
class llama_kv_cache_dsa_context;
|
class llama_kv_cache_dsa_context;
|
||||||
|
class llama_kv_cache_dsa_iswa_context;
|
||||||
class llama_kv_cache_msa_context;
|
class llama_kv_cache_msa_context;
|
||||||
class llama_kv_cache_dsv4_raw_context;
|
class llama_kv_cache_dsv4_raw_context;
|
||||||
class llama_kv_cache_dsv4_context;
|
class llama_kv_cache_dsv4_context;
|
||||||
@@ -374,6 +375,9 @@ public:
|
|||||||
|
|
||||||
bool can_reuse(const llm_graph_params & params) override;
|
bool can_reuse(const llm_graph_params & params) override;
|
||||||
|
|
||||||
|
// like can_reuse, but does not re-bind mctx
|
||||||
|
bool can_reuse_impl(const llm_graph_params & params);
|
||||||
|
|
||||||
ggml_tensor * get_k_idxs() const { return self_k_idxs; }
|
ggml_tensor * get_k_idxs() const { return self_k_idxs; }
|
||||||
|
|
||||||
ggml_tensor * get_kq_mask() const { return self_kq_mask_cnv; }
|
ggml_tensor * get_kq_mask() const { return self_kq_mask_cnv; }
|
||||||
@@ -405,6 +409,9 @@ public:
|
|||||||
|
|
||||||
bool can_reuse(const llm_graph_params & params) override;
|
bool can_reuse(const llm_graph_params & params) override;
|
||||||
|
|
||||||
|
// like can_reuse, but does not re-bind mctx
|
||||||
|
bool can_reuse_impl(const llm_graph_params & params);
|
||||||
|
|
||||||
ggml_tensor * get_k_idxs_mla() const { return self_k_idxs_mla; }
|
ggml_tensor * get_k_idxs_mla() const { return self_k_idxs_mla; }
|
||||||
ggml_tensor * get_k_idxs_lid() const { return self_k_idxs_lid; }
|
ggml_tensor * get_k_idxs_lid() const { return self_k_idxs_lid; }
|
||||||
|
|
||||||
@@ -427,6 +434,32 @@ public:
|
|||||||
const llama_kv_cache_dsa_context * mctx;
|
const llama_kv_cache_dsa_context * mctx;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// DSA input (full-attention layers + indexer) with K-only input for the SWA layers
|
||||||
|
class llm_graph_input_attn_k_dsa_iswa : public llm_graph_input_i {
|
||||||
|
public:
|
||||||
|
llm_graph_input_attn_k_dsa_iswa(
|
||||||
|
std::unique_ptr<llm_graph_input_attn_k_dsa> inp_dsa,
|
||||||
|
std::unique_ptr<llm_graph_input_attn_k> inp_swa,
|
||||||
|
const llama_kv_cache_dsa_iswa_context * mctx) :
|
||||||
|
inp_dsa(std::move(inp_dsa)),
|
||||||
|
inp_swa(std::move(inp_swa)),
|
||||||
|
mctx(mctx) {
|
||||||
|
}
|
||||||
|
~llm_graph_input_attn_k_dsa_iswa() = default;
|
||||||
|
|
||||||
|
void set_input(const llama_ubatch * ubatch) override;
|
||||||
|
|
||||||
|
bool can_reuse(const llm_graph_params & params) override;
|
||||||
|
|
||||||
|
llm_graph_input_attn_k_dsa * get_dsa() const { return inp_dsa.get(); }
|
||||||
|
llm_graph_input_attn_k * get_swa() const { return inp_swa.get(); }
|
||||||
|
|
||||||
|
std::unique_ptr<llm_graph_input_attn_k_dsa> inp_dsa;
|
||||||
|
std::unique_ptr<llm_graph_input_attn_k> inp_swa;
|
||||||
|
|
||||||
|
const llama_kv_cache_dsa_iswa_context * mctx;
|
||||||
|
};
|
||||||
|
|
||||||
// standard K/V attention input against the base cache, plus destination indices for the indexer key cache
|
// standard K/V attention input against the base cache, plus destination indices for the indexer key cache
|
||||||
class llm_graph_input_attn_kv_msa : public llm_graph_input_attn_kv {
|
class llm_graph_input_attn_kv_msa : public llm_graph_input_attn_kv {
|
||||||
public:
|
public:
|
||||||
@@ -1191,6 +1224,8 @@ struct llm_graph_context {
|
|||||||
|
|
||||||
llm_graph_input_attn_k_dsa * build_attn_inp_k_dsa() const;
|
llm_graph_input_attn_k_dsa * build_attn_inp_k_dsa() const;
|
||||||
|
|
||||||
|
llm_graph_input_attn_k_dsa_iswa * build_attn_inp_k_dsa_iswa() const;
|
||||||
|
|
||||||
llm_graph_input_attn_kv_msa * build_attn_inp_kv_msa(bool msa_enabled) const;
|
llm_graph_input_attn_kv_msa * build_attn_inp_kv_msa(bool msa_enabled) const;
|
||||||
|
|
||||||
ggml_tensor * build_attn(
|
ggml_tensor * build_attn(
|
||||||
|
|||||||
@@ -101,6 +101,11 @@ struct llama_hparams {
|
|||||||
uint32_t n_group_used = 0;
|
uint32_t n_group_used = 0;
|
||||||
uint32_t n_group_experts = 0;
|
uint32_t n_group_experts = 0;
|
||||||
|
|
||||||
|
// MLA + SWA (i.e. dots3note)
|
||||||
|
uint32_t n_lora_kv_swa = 0;
|
||||||
|
uint32_t n_embd_head_k_mla_swa = 0;
|
||||||
|
uint32_t n_embd_head_v_mla_swa = 0;
|
||||||
|
|
||||||
float expert_group_scale = 0.05f;
|
float expert_group_scale = 0.05f;
|
||||||
float expert_weights_scale = 0.0f;
|
float expert_weights_scale = 0.0f;
|
||||||
bool expert_weights_norm = false;
|
bool expert_weights_norm = false;
|
||||||
|
|||||||
@@ -0,0 +1,341 @@
|
|||||||
|
#include "llama-kv-cache-dsa-iswa.h"
|
||||||
|
|
||||||
|
#include "llama-impl.h"
|
||||||
|
#include "llama-batch.h"
|
||||||
|
#include "llama-model.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
//
|
||||||
|
// llama_kv_cache_dsa_iswa
|
||||||
|
//
|
||||||
|
|
||||||
|
llama_kv_cache_dsa_iswa::llama_kv_cache_dsa_iswa(
|
||||||
|
const llama_model & model,
|
||||||
|
ggml_type type_k,
|
||||||
|
ggml_type type_v,
|
||||||
|
bool v_trans,
|
||||||
|
bool offload,
|
||||||
|
bool swa_full,
|
||||||
|
bool unified,
|
||||||
|
uint32_t kv_size,
|
||||||
|
uint32_t n_seq_max,
|
||||||
|
uint32_t n_ubatch,
|
||||||
|
uint32_t n_pad,
|
||||||
|
const layer_filter_cb & filter_mla,
|
||||||
|
const layer_filter_cb & filter_lid,
|
||||||
|
const layer_reuse_cb & reuse) : unified(unified) {
|
||||||
|
|
||||||
|
const auto & hparams = model.hparams;
|
||||||
|
|
||||||
|
// chain filters
|
||||||
|
const layer_filter_cb filter_dsa = [&](int32_t il) {
|
||||||
|
if (filter_mla && !filter_mla(il)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !hparams.is_swa(il);
|
||||||
|
};
|
||||||
|
|
||||||
|
const layer_filter_cb filter_swa = [&](int32_t il) {
|
||||||
|
if (filter_mla && !filter_mla(il)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hparams.is_swa(il);
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint32_t size_dsa = kv_size;
|
||||||
|
|
||||||
|
// note: the SWA cache is always padded to 256 for performance
|
||||||
|
// https://github.com/ggml-org/llama.cpp/issues/17037
|
||||||
|
uint32_t size_swa = GGML_PAD(std::min(size_dsa, hparams.n_swa*(unified ? n_seq_max : 1) + n_ubatch), 256);
|
||||||
|
|
||||||
|
// when using full-size SWA cache, we set the SWA cache size to be equal to the base cache size
|
||||||
|
if (swa_full) {
|
||||||
|
LLAMA_LOG_WARN("%s: using full-size SWA cache (ref: %s)\n",
|
||||||
|
__func__, "https://github.com/ggml-org/llama.cpp/pull/13194#issuecomment-2868343055");
|
||||||
|
|
||||||
|
size_swa = size_dsa;
|
||||||
|
}
|
||||||
|
|
||||||
|
LLAMA_LOG_INFO("%s: creating DSA KV cache, size = %u cells\n", __func__, size_dsa);
|
||||||
|
|
||||||
|
kv_dsa = std::make_unique<llama_kv_cache_dsa>(
|
||||||
|
model, type_k, type_v,
|
||||||
|
v_trans, offload, unified, size_dsa, n_seq_max, n_pad,
|
||||||
|
0, LLAMA_SWA_TYPE_NONE, filter_dsa, filter_lid, reuse);
|
||||||
|
|
||||||
|
LLAMA_LOG_INFO("%s: creating SWA KV cache, size = %u cells\n", __func__, size_swa);
|
||||||
|
|
||||||
|
kv_swa = std::make_unique<llama_kv_cache>(
|
||||||
|
model, hparams, type_k, type_v,
|
||||||
|
v_trans, offload, unified, size_swa, n_seq_max, n_pad,
|
||||||
|
hparams.n_swa, hparams.swa_type, nullptr, filter_swa, reuse, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void llama_kv_cache_dsa_iswa::clear(bool data) {
|
||||||
|
kv_dsa->clear(data);
|
||||||
|
kv_swa->clear(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool llama_kv_cache_dsa_iswa::seq_rm(llama_seq_id seq_id, llama_pos p0, llama_pos p1) {
|
||||||
|
bool res = true;
|
||||||
|
|
||||||
|
res = res & kv_dsa->seq_rm(seq_id, p0, p1);
|
||||||
|
res = res & kv_swa->seq_rm(seq_id, p0, p1);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void llama_kv_cache_dsa_iswa::seq_cp(llama_seq_id seq_id_src, llama_seq_id seq_id_dst, llama_pos p0, llama_pos p1) {
|
||||||
|
kv_dsa->seq_cp(seq_id_src, seq_id_dst, p0, p1);
|
||||||
|
kv_swa->seq_cp(seq_id_src, seq_id_dst, p0, p1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void llama_kv_cache_dsa_iswa::seq_keep(llama_seq_id seq_id) {
|
||||||
|
kv_dsa->seq_keep(seq_id);
|
||||||
|
kv_swa->seq_keep(seq_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void llama_kv_cache_dsa_iswa::seq_add(llama_seq_id seq_id, llama_pos p0, llama_pos p1, llama_pos shift) {
|
||||||
|
kv_dsa->seq_add(seq_id, p0, p1, shift);
|
||||||
|
kv_swa->seq_add(seq_id, p0, p1, shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
void llama_kv_cache_dsa_iswa::seq_div(llama_seq_id seq_id, llama_pos p0, llama_pos p1, int d) {
|
||||||
|
kv_dsa->seq_div(seq_id, p0, p1, d);
|
||||||
|
kv_swa->seq_div(seq_id, p0, p1, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
llama_pos llama_kv_cache_dsa_iswa::seq_pos_min(llama_seq_id seq_id) const {
|
||||||
|
// the DSA cache is a superset of the SWA cache, so we can just check the SWA cache
|
||||||
|
return kv_swa->seq_pos_min(seq_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
llama_pos llama_kv_cache_dsa_iswa::seq_pos_max(llama_seq_id seq_id) const {
|
||||||
|
return kv_swa->seq_pos_max(seq_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<ggml_backend_buffer_type_t, size_t> llama_kv_cache_dsa_iswa::memory_breakdown() const {
|
||||||
|
std::map<ggml_backend_buffer_type_t, size_t> mb = kv_dsa->memory_breakdown();
|
||||||
|
for (const auto & buft_size : kv_swa->memory_breakdown()) {
|
||||||
|
mb[buft_size.first] += buft_size.second;
|
||||||
|
}
|
||||||
|
return mb;
|
||||||
|
}
|
||||||
|
|
||||||
|
llama_memory_context_ptr llama_kv_cache_dsa_iswa::init_batch(llama_batch_allocr & balloc, uint32_t n_ubatch, bool embd_all) {
|
||||||
|
GGML_UNUSED(embd_all);
|
||||||
|
|
||||||
|
// first try simple split
|
||||||
|
do {
|
||||||
|
if (!unified) {
|
||||||
|
// requires equal splits, so we skip the simple split
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
balloc.split_reset();
|
||||||
|
|
||||||
|
std::vector<llama_ubatch> ubatches;
|
||||||
|
while (true) {
|
||||||
|
auto ubatch = balloc.split_simple(n_ubatch);
|
||||||
|
|
||||||
|
if (ubatch.n_tokens == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ubatches.push_back(std::move(ubatch)); // NOLINT
|
||||||
|
}
|
||||||
|
|
||||||
|
if (balloc.get_n_used() < balloc.get_n_tokens()) {
|
||||||
|
// failed to find a suitable split
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto sinfos_mla = kv_dsa->get_mla()->prepare(ubatches);
|
||||||
|
if (sinfos_mla.empty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto sinfos_lid = kv_dsa->get_lid()->prepare(ubatches);
|
||||||
|
if (sinfos_lid.empty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto sinfos_swa = kv_swa->prepare(ubatches);
|
||||||
|
if (sinfos_swa.empty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(sinfos_mla.size() == sinfos_swa.size());
|
||||||
|
|
||||||
|
return std::make_unique<llama_kv_cache_dsa_iswa_context>(
|
||||||
|
this, std::move(sinfos_mla), std::move(sinfos_lid), std::move(sinfos_swa), std::move(ubatches));
|
||||||
|
} while (false);
|
||||||
|
|
||||||
|
// if it fails, try equal split
|
||||||
|
do {
|
||||||
|
balloc.split_reset();
|
||||||
|
|
||||||
|
std::vector<llama_ubatch> ubatches;
|
||||||
|
while (true) {
|
||||||
|
auto ubatch = balloc.split_equal(n_ubatch, !unified, 0);
|
||||||
|
|
||||||
|
if (ubatch.n_tokens == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ubatches.push_back(std::move(ubatch)); // NOLINT
|
||||||
|
}
|
||||||
|
|
||||||
|
if (balloc.get_n_used() < balloc.get_n_tokens()) {
|
||||||
|
// failed to find a suitable split
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto sinfos_mla = kv_dsa->get_mla()->prepare(ubatches);
|
||||||
|
if (sinfos_mla.empty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto sinfos_lid = kv_dsa->get_lid()->prepare(ubatches);
|
||||||
|
if (sinfos_lid.empty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto sinfos_swa = kv_swa->prepare(ubatches);
|
||||||
|
if (sinfos_swa.empty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(sinfos_mla.size() == sinfos_swa.size());
|
||||||
|
|
||||||
|
return std::make_unique<llama_kv_cache_dsa_iswa_context>(
|
||||||
|
this, std::move(sinfos_mla), std::move(sinfos_lid), std::move(sinfos_swa), std::move(ubatches));
|
||||||
|
} while (false);
|
||||||
|
|
||||||
|
return std::make_unique<llama_kv_cache_dsa_iswa_context>(LLAMA_MEMORY_STATUS_FAILED_PREPARE);
|
||||||
|
}
|
||||||
|
|
||||||
|
llama_memory_context_ptr llama_kv_cache_dsa_iswa::init_full() {
|
||||||
|
return std::make_unique<llama_kv_cache_dsa_iswa_context>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
llama_memory_context_ptr llama_kv_cache_dsa_iswa::init_update(llama_context * lctx, bool optimize) {
|
||||||
|
return std::make_unique<llama_kv_cache_dsa_iswa_context>(this, lctx, optimize);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool llama_kv_cache_dsa_iswa::get_can_shift() const {
|
||||||
|
return kv_dsa->get_can_shift() &&
|
||||||
|
kv_swa->get_can_shift() &&
|
||||||
|
kv_dsa->get_mla()->get_size() == kv_swa->get_size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void llama_kv_cache_dsa_iswa::state_write(llama_io_write_i & io, llama_seq_id seq_id, llama_state_seq_flags flags) const {
|
||||||
|
if ((flags & LLAMA_STATE_SEQ_FLAGS_PARTIAL_ONLY) == 0) {
|
||||||
|
kv_dsa->state_write(io, seq_id, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
kv_swa->state_write(io, seq_id, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
void llama_kv_cache_dsa_iswa::state_read(llama_io_read_i & io, llama_seq_id seq_id, llama_state_seq_flags flags) {
|
||||||
|
if ((flags & LLAMA_STATE_SEQ_FLAGS_PARTIAL_ONLY) == 0) {
|
||||||
|
kv_dsa->state_read(io, seq_id, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
kv_swa->state_read(io, seq_id, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
llama_kv_cache_dsa * llama_kv_cache_dsa_iswa::get_dsa() const {
|
||||||
|
return kv_dsa.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
llama_kv_cache * llama_kv_cache_dsa_iswa::get_swa() const {
|
||||||
|
return kv_swa.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// llama_kv_cache_dsa_iswa_context
|
||||||
|
//
|
||||||
|
|
||||||
|
llama_kv_cache_dsa_iswa_context::llama_kv_cache_dsa_iswa_context(llama_memory_status status) : status(status) {}
|
||||||
|
|
||||||
|
llama_kv_cache_dsa_iswa_context::llama_kv_cache_dsa_iswa_context(
|
||||||
|
llama_kv_cache_dsa_iswa * kv) :
|
||||||
|
ctx_dsa(kv->get_dsa()->init_full()),
|
||||||
|
ctx_swa(kv->get_swa()->init_full()),
|
||||||
|
status(llama_memory_status_combine(ctx_dsa->get_status(), ctx_swa->get_status())) {
|
||||||
|
}
|
||||||
|
|
||||||
|
llama_kv_cache_dsa_iswa_context::llama_kv_cache_dsa_iswa_context(
|
||||||
|
llama_kv_cache_dsa_iswa * kv,
|
||||||
|
llama_context * lctx,
|
||||||
|
bool optimize) :
|
||||||
|
ctx_dsa(kv->get_dsa()->init_update(lctx, optimize)),
|
||||||
|
ctx_swa(kv->get_swa()->init_update(lctx, optimize)),
|
||||||
|
status(llama_memory_status_combine(ctx_dsa->get_status(), ctx_swa->get_status())) {
|
||||||
|
}
|
||||||
|
|
||||||
|
llama_kv_cache_dsa_iswa_context::llama_kv_cache_dsa_iswa_context(
|
||||||
|
llama_kv_cache_dsa_iswa * kv,
|
||||||
|
slot_info_vec_t sinfos_mla,
|
||||||
|
slot_info_vec_t sinfos_lid,
|
||||||
|
slot_info_vec_t sinfos_swa,
|
||||||
|
std::vector<llama_ubatch> ubatches) :
|
||||||
|
ubatches(std::move(ubatches)),
|
||||||
|
// note: here we copy the ubatches. not sure if this is ideal
|
||||||
|
ctx_dsa(new llama_kv_cache_dsa_context(kv->get_dsa(), std::move(sinfos_mla), std::move(sinfos_lid), this->ubatches)),
|
||||||
|
ctx_swa(new llama_kv_cache_context(kv->get_swa(), std::move(sinfos_swa), this->ubatches)),
|
||||||
|
status(llama_memory_status_combine(ctx_dsa->get_status(), ctx_swa->get_status())) {
|
||||||
|
}
|
||||||
|
|
||||||
|
llama_kv_cache_dsa_iswa_context:: ~llama_kv_cache_dsa_iswa_context() = default;
|
||||||
|
|
||||||
|
bool llama_kv_cache_dsa_iswa_context::next() {
|
||||||
|
assert(status == LLAMA_MEMORY_STATUS_SUCCESS);
|
||||||
|
|
||||||
|
ctx_dsa->next();
|
||||||
|
ctx_swa->next();
|
||||||
|
|
||||||
|
if (++i_next >= ubatches.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool llama_kv_cache_dsa_iswa_context::apply() {
|
||||||
|
assert(!llama_memory_status_is_fail(status));
|
||||||
|
|
||||||
|
bool res = true;
|
||||||
|
|
||||||
|
res = res & ctx_dsa->apply();
|
||||||
|
res = res & ctx_swa->apply();
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
llama_memory_status llama_kv_cache_dsa_iswa_context::get_status() const {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
const llama_ubatch & llama_kv_cache_dsa_iswa_context::get_ubatch() const {
|
||||||
|
assert(status == LLAMA_MEMORY_STATUS_SUCCESS);
|
||||||
|
|
||||||
|
return ubatches[i_next];
|
||||||
|
}
|
||||||
|
|
||||||
|
const llama_kv_cache_dsa_context * llama_kv_cache_dsa_iswa_context::get_dsa() const {
|
||||||
|
assert(status == LLAMA_MEMORY_STATUS_SUCCESS);
|
||||||
|
|
||||||
|
return static_cast<const llama_kv_cache_dsa_context *>(ctx_dsa.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
const llama_kv_cache_context * llama_kv_cache_dsa_iswa_context::get_swa() const {
|
||||||
|
assert(status == LLAMA_MEMORY_STATUS_SUCCESS);
|
||||||
|
|
||||||
|
return static_cast<const llama_kv_cache_context *>(ctx_swa.get());
|
||||||
|
}
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "llama-kv-cache-dsa.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
//
|
||||||
|
// llama_kv_cache_dsa_iswa
|
||||||
|
//
|
||||||
|
|
||||||
|
// utilizes two child memories: llama_kv_cache_dsa for the full-attention (DSA) layers and llama_kv_cache for the SWA layers
|
||||||
|
|
||||||
|
class llama_kv_cache_dsa_iswa : public llama_memory_i {
|
||||||
|
public:
|
||||||
|
llama_kv_cache_dsa_iswa(
|
||||||
|
const llama_model & model,
|
||||||
|
ggml_type type_k,
|
||||||
|
ggml_type type_v,
|
||||||
|
bool v_trans,
|
||||||
|
bool offload,
|
||||||
|
bool swa_full,
|
||||||
|
bool unified,
|
||||||
|
uint32_t kv_size,
|
||||||
|
uint32_t n_seq_max,
|
||||||
|
uint32_t n_ubatch,
|
||||||
|
uint32_t n_pad,
|
||||||
|
const layer_filter_cb & filter_mla,
|
||||||
|
const layer_filter_cb & filter_lid,
|
||||||
|
const layer_reuse_cb & reuse);
|
||||||
|
|
||||||
|
~llama_kv_cache_dsa_iswa() = default;
|
||||||
|
|
||||||
|
//
|
||||||
|
// llama_memory_i
|
||||||
|
//
|
||||||
|
|
||||||
|
llama_memory_context_ptr init_batch(
|
||||||
|
llama_batch_allocr & balloc,
|
||||||
|
uint32_t n_ubatch,
|
||||||
|
bool embd_all) override;
|
||||||
|
|
||||||
|
llama_memory_context_ptr init_full() override;
|
||||||
|
|
||||||
|
llama_memory_context_ptr init_update(llama_context * lctx, bool optimize) override;
|
||||||
|
|
||||||
|
bool get_can_shift() const override;
|
||||||
|
|
||||||
|
void clear(bool data) override;
|
||||||
|
|
||||||
|
bool seq_rm (llama_seq_id seq_id, llama_pos p0, llama_pos p1) override;
|
||||||
|
void seq_cp (llama_seq_id seq_id_src, llama_seq_id seq_id_dst, llama_pos p0, llama_pos p1) override;
|
||||||
|
void seq_keep(llama_seq_id seq_id) override;
|
||||||
|
void seq_add (llama_seq_id seq_id, llama_pos p0, llama_pos p1, llama_pos shift) override;
|
||||||
|
void seq_div (llama_seq_id seq_id, llama_pos p0, llama_pos p1, int d) override;
|
||||||
|
|
||||||
|
llama_pos seq_pos_min(llama_seq_id seq_id) const override;
|
||||||
|
llama_pos seq_pos_max(llama_seq_id seq_id) const override;
|
||||||
|
|
||||||
|
std::map<ggml_backend_buffer_type_t, size_t> memory_breakdown() const override;
|
||||||
|
|
||||||
|
// state write/load
|
||||||
|
|
||||||
|
void state_write(llama_io_write_i & io, llama_seq_id seq_id = -1, llama_state_seq_flags flags = 0) const override;
|
||||||
|
void state_read (llama_io_read_i & io, llama_seq_id seq_id = -1, llama_state_seq_flags flags = 0) override;
|
||||||
|
|
||||||
|
//
|
||||||
|
// llama_kv_cache_dsa_iswa specific API
|
||||||
|
//
|
||||||
|
|
||||||
|
llama_kv_cache_dsa * get_dsa() const;
|
||||||
|
llama_kv_cache * get_swa() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const bool unified;
|
||||||
|
|
||||||
|
std::unique_ptr<llama_kv_cache_dsa> kv_dsa;
|
||||||
|
std::unique_ptr<llama_kv_cache> kv_swa;
|
||||||
|
};
|
||||||
|
|
||||||
|
class llama_kv_cache_dsa_iswa_context : public llama_memory_context_i {
|
||||||
|
public:
|
||||||
|
using slot_info_vec_t = llama_kv_cache::slot_info_vec_t;
|
||||||
|
|
||||||
|
// used for errors
|
||||||
|
llama_kv_cache_dsa_iswa_context(llama_memory_status status);
|
||||||
|
|
||||||
|
// used to create a full-cache context
|
||||||
|
llama_kv_cache_dsa_iswa_context(
|
||||||
|
llama_kv_cache_dsa_iswa * kv);
|
||||||
|
|
||||||
|
// used to create an update context
|
||||||
|
llama_kv_cache_dsa_iswa_context(
|
||||||
|
llama_kv_cache_dsa_iswa * kv,
|
||||||
|
llama_context * lctx,
|
||||||
|
bool optimize);
|
||||||
|
|
||||||
|
// used to create a batch processing context from a batch
|
||||||
|
llama_kv_cache_dsa_iswa_context(
|
||||||
|
llama_kv_cache_dsa_iswa * kv,
|
||||||
|
slot_info_vec_t sinfos_mla,
|
||||||
|
slot_info_vec_t sinfos_lid,
|
||||||
|
slot_info_vec_t sinfos_swa,
|
||||||
|
std::vector<llama_ubatch> ubatches);
|
||||||
|
|
||||||
|
virtual ~llama_kv_cache_dsa_iswa_context();
|
||||||
|
|
||||||
|
//
|
||||||
|
// llama_memory_context_i
|
||||||
|
//
|
||||||
|
|
||||||
|
bool next() override;
|
||||||
|
bool apply() override;
|
||||||
|
|
||||||
|
llama_memory_status get_status() const override;
|
||||||
|
const llama_ubatch & get_ubatch() const override;
|
||||||
|
|
||||||
|
//
|
||||||
|
// llama_kv_cache_dsa_iswa_context specific API
|
||||||
|
//
|
||||||
|
|
||||||
|
const llama_kv_cache_dsa_context * get_dsa() const;
|
||||||
|
const llama_kv_cache_context * get_swa() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// the index of the next ubatch to process
|
||||||
|
size_t i_next = 0;
|
||||||
|
|
||||||
|
std::vector<llama_ubatch> ubatches;
|
||||||
|
|
||||||
|
const llama_memory_context_ptr ctx_dsa;
|
||||||
|
const llama_memory_context_ptr ctx_swa;
|
||||||
|
|
||||||
|
const llama_memory_status status;
|
||||||
|
};
|
||||||
@@ -323,7 +323,8 @@ llama_kv_cache::llama_kv_cache(
|
|||||||
hparams.n_embd_head_k() % 64 == 0;
|
hparams.n_embd_head_k() % 64 == 0;
|
||||||
|
|
||||||
// always create Hadamard rotation tensors for DeepSeek lightning indexers
|
// always create Hadamard rotation tensors for DeepSeek lightning indexers
|
||||||
if ((model.arch == LLM_ARCH_DEEPSEEK32 || model.arch == LLM_ARCH_DEEPSEEK4 || model.arch == LLM_ARCH_GLM_DSA) &&
|
if ((model.arch == LLM_ARCH_DEEPSEEK32 || model.arch == LLM_ARCH_DEEPSEEK4 ||
|
||||||
|
model.arch == LLM_ARCH_GLM_DSA || model.arch == LLM_ARCH_DOTS3NOTE) &&
|
||||||
hparams.n_embd_head_k_full == hparams.indexer_head_size) {
|
hparams.n_embd_head_k_full == hparams.indexer_head_size) {
|
||||||
attn_rot_k = true;
|
attn_rot_k = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ bool llama_model_saver_supports_arch(llm_arch arch) {
|
|||||||
case LLM_ARCH_MELLUM:
|
case LLM_ARCH_MELLUM:
|
||||||
case LLM_ARCH_LAGUNA:
|
case LLM_ARCH_LAGUNA:
|
||||||
case LLM_ARCH_GRANITE_SWA:
|
case LLM_ARCH_GRANITE_SWA:
|
||||||
|
case LLM_ARCH_DOTS3NOTE: // TODO: need to handle SWA pattern and MLA+SWA config
|
||||||
return false;
|
return false;
|
||||||
default:
|
default:
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
+59
-1
@@ -11,6 +11,7 @@
|
|||||||
#include "llama-kv-cache.h"
|
#include "llama-kv-cache.h"
|
||||||
#include "llama-kv-cache-iswa.h"
|
#include "llama-kv-cache-iswa.h"
|
||||||
#include "llama-kv-cache-dsa.h"
|
#include "llama-kv-cache-dsa.h"
|
||||||
|
#include "llama-kv-cache-dsa-iswa.h"
|
||||||
#include "llama-kv-cache-msa.h"
|
#include "llama-kv-cache-msa.h"
|
||||||
#include "llama-kv-cache-dsv4.h"
|
#include "llama-kv-cache-dsv4.h"
|
||||||
#include "llama-memory-hybrid.h"
|
#include "llama-memory-hybrid.h"
|
||||||
@@ -194,6 +195,8 @@ static llama_model * llama_model_mapping(llm_arch arch, const llama_model_params
|
|||||||
return new llama_model_deepseek2ocr(params);
|
return new llama_model_deepseek2ocr(params);
|
||||||
case LLM_ARCH_DEEPSEEK32:
|
case LLM_ARCH_DEEPSEEK32:
|
||||||
return new llama_model_deepseek32(params);
|
return new llama_model_deepseek32(params);
|
||||||
|
case LLM_ARCH_DOTS3NOTE:
|
||||||
|
return new llama_model_dots3note(params);
|
||||||
case LLM_ARCH_DEEPSEEK4:
|
case LLM_ARCH_DEEPSEEK4:
|
||||||
return new llama_model_deepseek4(params);
|
return new llama_model_deepseek4(params);
|
||||||
case LLM_ARCH_GLM_DSA:
|
case LLM_ARCH_GLM_DSA:
|
||||||
@@ -851,6 +854,7 @@ const char * llm_type_name(llm_type type) {
|
|||||||
case LLM_TYPE_230B_A10B: return "230B.A10B";
|
case LLM_TYPE_230B_A10B: return "230B.A10B";
|
||||||
case LLM_TYPE_428B_A23B: return "428B.A23B";
|
case LLM_TYPE_428B_A23B: return "428B.A23B";
|
||||||
case LLM_TYPE_235B_A22B: return "235B.A22B";
|
case LLM_TYPE_235B_A22B: return "235B.A22B";
|
||||||
|
case LLM_TYPE_288B_A19B: return "288B.A19B";
|
||||||
case LLM_TYPE_300B_A47B: return "300B.A47B";
|
case LLM_TYPE_300B_A47B: return "300B.A47B";
|
||||||
case LLM_TYPE_310B_A15B: return "310B.A15B";
|
case LLM_TYPE_310B_A15B: return "310B.A15B";
|
||||||
case LLM_TYPE_355B_A32B: return "355B.A32B";
|
case LLM_TYPE_355B_A32B: return "355B.A32B";
|
||||||
@@ -1924,7 +1928,9 @@ void llama_model::print_info() const {
|
|||||||
LLAMA_LOG_INFO("%s: expert_weights_scale = %.1f\n", __func__, hparams.expert_weights_scale);
|
LLAMA_LOG_INFO("%s: expert_weights_scale = %.1f\n", __func__, hparams.expert_weights_scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arch == LLM_ARCH_DEEPSEEK2 || arch == LLM_ARCH_DEEPSEEK2OCR || arch == LLM_ARCH_DEEPSEEK32 || arch == LLM_ARCH_GLM_DSA || arch == LLM_ARCH_MISTRAL4) {
|
if (arch == LLM_ARCH_DEEPSEEK2 || arch == LLM_ARCH_DEEPSEEK2OCR ||
|
||||||
|
arch == LLM_ARCH_DEEPSEEK32 || arch == LLM_ARCH_GLM_DSA ||
|
||||||
|
arch == LLM_ARCH_DOTS3NOTE || arch == LLM_ARCH_MISTRAL4) {
|
||||||
LLAMA_LOG_INFO("%s: n_layer_dense_lead = %d\n", __func__, hparams.n_layer_dense_lead);
|
LLAMA_LOG_INFO("%s: n_layer_dense_lead = %d\n", __func__, hparams.n_layer_dense_lead);
|
||||||
LLAMA_LOG_INFO("%s: n_lora_q = %d\n", __func__, hparams.n_lora_q);
|
LLAMA_LOG_INFO("%s: n_lora_q = %d\n", __func__, hparams.n_lora_q);
|
||||||
LLAMA_LOG_INFO("%s: n_lora_kv = %d\n", __func__, hparams.n_lora_kv);
|
LLAMA_LOG_INFO("%s: n_lora_kv = %d\n", __func__, hparams.n_lora_kv);
|
||||||
@@ -2193,6 +2199,57 @@ llama_memory_i * llama_model::create_memory(const llama_memory_params & params,
|
|||||||
nullptr);
|
nullptr);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
case LLM_ARCH_DOTS3NOTE:
|
||||||
|
{
|
||||||
|
GGML_ASSERT(hparams.swa_type != LLAMA_SWA_TYPE_NONE);
|
||||||
|
|
||||||
|
if (params.ctx_type == LLAMA_CONTEXT_TYPE_MTP && hparams.n_layer_nextn > 0) {
|
||||||
|
// MTP draft context: plain attention KV cache holding only the nextn layer
|
||||||
|
llama_kv_cache::layer_filter_cb filter =
|
||||||
|
[&](uint32_t il) { return il >= hparams.n_layer(); };
|
||||||
|
|
||||||
|
res = new llama_kv_cache(
|
||||||
|
*this,
|
||||||
|
hparams,
|
||||||
|
params.type_k,
|
||||||
|
params.type_v,
|
||||||
|
!cparams.flash_attn,
|
||||||
|
cparams.offload_kqv,
|
||||||
|
cparams.kv_unified,
|
||||||
|
cparams.n_ctx_seq,
|
||||||
|
cparams.n_seq_max,
|
||||||
|
1,
|
||||||
|
hparams.n_swa,
|
||||||
|
hparams.swa_type,
|
||||||
|
nullptr,
|
||||||
|
filter,
|
||||||
|
nullptr,
|
||||||
|
nullptr);
|
||||||
|
} else {
|
||||||
|
// main context: DSA cache for the trunk full-attention layers plus a window-sized SWA cache
|
||||||
|
llama_kv_cache::layer_filter_cb filter_mla = nullptr;
|
||||||
|
if (hparams.n_layer_nextn > 0) {
|
||||||
|
filter_mla = [&](uint32_t il) { return il < hparams.n_layer(); };
|
||||||
|
}
|
||||||
|
llama_kv_cache::layer_filter_cb filter_lid = [&](uint32_t il) { return il < hparams.n_layer() && hparams.is_indexer_full(il); };
|
||||||
|
|
||||||
|
res = new llama_kv_cache_dsa_iswa(
|
||||||
|
*this,
|
||||||
|
params.type_k,
|
||||||
|
params.type_v,
|
||||||
|
!cparams.flash_attn,
|
||||||
|
cparams.offload_kqv,
|
||||||
|
params.swa_full,
|
||||||
|
cparams.kv_unified,
|
||||||
|
cparams.n_ctx_seq,
|
||||||
|
cparams.n_seq_max,
|
||||||
|
cparams.n_ubatch,
|
||||||
|
1,
|
||||||
|
filter_mla,
|
||||||
|
filter_lid,
|
||||||
|
nullptr);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
case LLM_ARCH_DEEPSEEK4:
|
case LLM_ARCH_DEEPSEEK4:
|
||||||
{
|
{
|
||||||
GGML_ASSERT(hparams.swa_type != LLAMA_SWA_TYPE_NONE);
|
GGML_ASSERT(hparams.swa_type != LLAMA_SWA_TYPE_NONE);
|
||||||
@@ -2661,6 +2718,7 @@ llama_rope_type llama_model_rope_type(const llama_model * model) {
|
|||||||
case LLM_ARCH_LLAMA_EMBED:
|
case LLM_ARCH_LLAMA_EMBED:
|
||||||
case LLM_ARCH_MAINCODER:
|
case LLM_ARCH_MAINCODER:
|
||||||
case LLM_ARCH_GLM_DSA:
|
case LLM_ARCH_GLM_DSA:
|
||||||
|
case LLM_ARCH_DOTS3NOTE:
|
||||||
case LLM_ARCH_NANBEIGE:
|
case LLM_ARCH_NANBEIGE:
|
||||||
case LLM_ARCH_POCKETTTS:
|
case LLM_ARCH_POCKETTTS:
|
||||||
return LLAMA_ROPE_TYPE_NORM;
|
return LLAMA_ROPE_TYPE_NORM;
|
||||||
|
|||||||
@@ -140,6 +140,7 @@ enum llm_type {
|
|||||||
LLM_TYPE_230B_A10B, // Minimax M2
|
LLM_TYPE_230B_A10B, // Minimax M2
|
||||||
LLM_TYPE_428B_A23B, // Minimax M3
|
LLM_TYPE_428B_A23B, // Minimax M3
|
||||||
LLM_TYPE_235B_A22B,
|
LLM_TYPE_235B_A22B,
|
||||||
|
LLM_TYPE_288B_A19B, // dots3-note
|
||||||
LLM_TYPE_300B_A47B, // Ernie MoE big
|
LLM_TYPE_300B_A47B, // Ernie MoE big
|
||||||
LLM_TYPE_310B_A15B, // /MiMo-V2-Flash
|
LLM_TYPE_310B_A15B, // /MiMo-V2-Flash
|
||||||
LLM_TYPE_355B_A32B, // GLM-4.5
|
LLM_TYPE_355B_A32B, // GLM-4.5
|
||||||
|
|||||||
@@ -0,0 +1,480 @@
|
|||||||
|
#include "models.h"
|
||||||
|
|
||||||
|
#include "llama-kv-cache.h"
|
||||||
|
#include "llama-kv-cache-dsa.h"
|
||||||
|
|
||||||
|
// note: code adapted from deepseek32.cpp (DSA indexer + absorbed MLA) and step35.cpp (head-wise output gate)
|
||||||
|
|
||||||
|
void llama_model_dots3note::load_arch_hparams(llama_model_loader & ml) {
|
||||||
|
ml.get_key(LLM_KV_ATTENTION_LAYERNORM_RMS_EPS, hparams.f_norm_rms_eps);
|
||||||
|
hparams.f_norm_eps = 1e-6; // eps for the indexer k_norm layer norm
|
||||||
|
|
||||||
|
// TODO: use MTP layer
|
||||||
|
ml.get_key(LLM_KV_NEXTN_PREDICT_LAYERS, hparams.n_layer_nextn, false);
|
||||||
|
GGML_ASSERT(hparams.n_layer_nextn < hparams.n_layer_all && "n_layer_nextn must be < n_layer_all");
|
||||||
|
|
||||||
|
// MoE parameters
|
||||||
|
ml.get_key(LLM_KV_EXPERT_SHARED_COUNT, hparams.n_expert_shared);
|
||||||
|
ml.get_key(LLM_KV_EXPERT_FEED_FORWARD_LENGTH, hparams.n_ff_exp);
|
||||||
|
ml.get_key(LLM_KV_LEADING_DENSE_BLOCK_COUNT, hparams.n_layer_dense_lead);
|
||||||
|
ml.get_key(LLM_KV_EXPERT_WEIGHTS_SCALE, hparams.expert_weights_scale, false);
|
||||||
|
ml.get_key(LLM_KV_EXPERT_WEIGHTS_NORM, hparams.expert_weights_norm, false);
|
||||||
|
ml.get_key(LLM_KV_EXPERT_GATING_FUNC, hparams.expert_gating_func);
|
||||||
|
|
||||||
|
// MLA parameters of the full-attention layers
|
||||||
|
ml.get_key(LLM_KV_ATTENTION_Q_LORA_RANK, hparams.n_lora_q);
|
||||||
|
ml.get_key(LLM_KV_ATTENTION_KV_LORA_RANK, hparams.n_lora_kv);
|
||||||
|
ml.get_key(LLM_KV_ATTENTION_KEY_LENGTH_MLA, hparams.n_embd_head_k_mla_impl);
|
||||||
|
ml.get_key(LLM_KV_ATTENTION_VALUE_LENGTH_MLA, hparams.n_embd_head_v_mla_impl);
|
||||||
|
|
||||||
|
// MLA parameters of the sliding-window layers
|
||||||
|
ml.get_key(LLM_KV_ATTENTION_KV_LORA_RANK_SWA, hparams.n_lora_kv_swa);
|
||||||
|
ml.get_key(LLM_KV_ATTENTION_KEY_LENGTH_MLA_SWA, hparams.n_embd_head_k_mla_swa);
|
||||||
|
ml.get_key(LLM_KV_ATTENTION_VALUE_LENGTH_MLA_SWA, hparams.n_embd_head_v_mla_swa);
|
||||||
|
|
||||||
|
hparams.swa_type = LLAMA_SWA_TYPE_STANDARD;
|
||||||
|
ml.get_key(LLM_KV_ATTENTION_SLIDING_WINDOW, hparams.n_swa);
|
||||||
|
ml.get_key(LLM_KV_ROPE_FREQ_BASE_SWA, hparams.rope_freq_base_train_swa);
|
||||||
|
ml.get_arr(LLM_KV_ATTENTION_SLIDING_WINDOW_PATTERN, hparams.is_swa_impl);
|
||||||
|
|
||||||
|
// DSA parameters
|
||||||
|
ml.get_key(LLM_KV_ATTENTION_INDEXER_HEAD_COUNT, hparams.indexer_n_head);
|
||||||
|
ml.get_key(LLM_KV_ATTENTION_INDEXER_KEY_LENGTH, hparams.indexer_head_size);
|
||||||
|
ml.get_key(LLM_KV_ATTENTION_INDEXER_TOP_K, hparams.indexer_top_k);
|
||||||
|
ml.get_arr(LLM_KV_ATTENTION_INDEXER_TYPES, hparams.is_indexer_full_impl);
|
||||||
|
|
||||||
|
switch (hparams.n_layer()) {
|
||||||
|
case 46: type = LLM_TYPE_288B_A19B; break;
|
||||||
|
default: type = LLM_TYPE_UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void llama_model_dots3note::load_arch_tensors(llama_model_loader & ml) {
|
||||||
|
LLAMA_LOAD_LOCALS;
|
||||||
|
GGML_UNUSED(ml);
|
||||||
|
|
||||||
|
if (!hparams.is_mla()) {
|
||||||
|
throw std::runtime_error("DOTS3NOTE architecture requires MLA");
|
||||||
|
}
|
||||||
|
|
||||||
|
const int64_t n_embd_head_qk_rope = hparams.n_rot();
|
||||||
|
|
||||||
|
const int64_t q_lora_rank = hparams.n_lora_q;
|
||||||
|
const int64_t n_ff_exp = hparams.n_ff_exp;
|
||||||
|
const int64_t n_expert_shared = hparams.n_expert_shared;
|
||||||
|
|
||||||
|
tok_embd = create_tensor(tn(LLM_TENSOR_TOKEN_EMBD, "weight"), {n_embd, n_vocab}, 0);
|
||||||
|
|
||||||
|
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) {
|
||||||
|
output = create_tensor(tn(LLM_TENSOR_TOKEN_EMBD, "weight"), {n_embd, n_vocab}, TENSOR_DUPLICATED);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < n_layer_all; ++i) {
|
||||||
|
auto & layer = layers[i];
|
||||||
|
|
||||||
|
const bool is_mtp = i >= n_layer;
|
||||||
|
// the NextN/MTP block uses the sliding-attention geometry
|
||||||
|
const bool is_swa = is_mtp || hparams.is_swa(i);
|
||||||
|
|
||||||
|
// MTP tensors are preserved in the GGUF but there is no MTP graph yet
|
||||||
|
const int flags = is_mtp ? TENSOR_SKIP | TENSOR_NOT_REQUIRED : 0;
|
||||||
|
|
||||||
|
const int64_t n_head_l = hparams.n_head(i);
|
||||||
|
|
||||||
|
const int64_t kv_lora_rank = is_swa ? hparams.n_lora_kv_swa : hparams.n_lora_kv;
|
||||||
|
const int64_t n_embd_head_k_mla = is_swa ? hparams.n_embd_head_k_mla_swa : hparams.n_embd_head_k_mla();
|
||||||
|
const int64_t n_embd_head_v_mla = is_swa ? hparams.n_embd_head_v_mla_swa : hparams.n_embd_head_v_mla();
|
||||||
|
const int64_t n_embd_head_qk_nope = n_embd_head_k_mla - n_embd_head_qk_rope;
|
||||||
|
|
||||||
|
layer.attn_norm = create_tensor(tn(LLM_TENSOR_ATTN_NORM, "weight", i), {n_embd}, flags);
|
||||||
|
layer.attn_q_a_norm = create_tensor(tn(LLM_TENSOR_ATTN_Q_A_NORM, "weight", i), {q_lora_rank}, flags);
|
||||||
|
layer.attn_kv_a_norm = create_tensor(tn(LLM_TENSOR_ATTN_KV_A_NORM, "weight", i), {kv_lora_rank}, flags);
|
||||||
|
// norm applied on the shared rope key before rope
|
||||||
|
layer.attn_k_norm = create_tensor(tn(LLM_TENSOR_ATTN_K_NORM, "weight", i), {n_embd_head_qk_rope}, flags);
|
||||||
|
|
||||||
|
layer.wq_a = create_tensor(tn(LLM_TENSOR_ATTN_Q_A, "weight", i), {n_embd, q_lora_rank}, flags);
|
||||||
|
layer.wq_b = create_tensor(tn(LLM_TENSOR_ATTN_Q_B, "weight", i), {q_lora_rank, n_head_l * n_embd_head_k_mla}, flags);
|
||||||
|
|
||||||
|
layer.wkv_a_mqa = create_tensor(tn(LLM_TENSOR_ATTN_KV_A_MQA, "weight", i), {n_embd, kv_lora_rank + n_embd_head_qk_rope}, flags);
|
||||||
|
|
||||||
|
layer.wk_b = create_tensor(tn(LLM_TENSOR_ATTN_K_B, "weight", i), {n_embd_head_qk_nope, kv_lora_rank, n_head_l}, flags);
|
||||||
|
layer.wv_b = create_tensor(tn(LLM_TENSOR_ATTN_V_B, "weight", i), {kv_lora_rank, n_embd_head_v_mla, n_head_l}, flags);
|
||||||
|
|
||||||
|
layer.wo = create_tensor(tn(LLM_TENSOR_ATTN_OUT, "weight", i), {n_head_l * n_embd_head_v_mla, n_embd}, flags);
|
||||||
|
|
||||||
|
// head-wise sigmoid output gate
|
||||||
|
layer.wqkv_gate = create_tensor(tn(LLM_TENSOR_ATTN_GATE, "weight", i), {n_embd, n_head_l}, flags);
|
||||||
|
|
||||||
|
layer.ffn_norm = create_tensor(tn(LLM_TENSOR_FFN_NORM, "weight", i), {n_embd}, flags);
|
||||||
|
|
||||||
|
// DSA indexer
|
||||||
|
if (!is_mtp && hparams.is_indexer_full(i)) {
|
||||||
|
layer.indexer_k_norm = create_tensor(tn(LLM_TENSOR_INDEXER_K_NORM, "weight", i), {hparams.indexer_head_size}, flags);
|
||||||
|
layer.indexer_k_norm_b = create_tensor(tn(LLM_TENSOR_INDEXER_K_NORM, "bias", i), {hparams.indexer_head_size}, flags);
|
||||||
|
layer.indexer_proj = create_tensor(tn(LLM_TENSOR_INDEXER_PROJ, "weight", i), {n_embd, hparams.indexer_n_head}, flags);
|
||||||
|
layer.indexer_attn_k = create_tensor(tn(LLM_TENSOR_INDEXER_ATTN_K, "weight", i), {n_embd, hparams.indexer_head_size}, flags);
|
||||||
|
layer.indexer_attn_q_b = create_tensor(tn(LLM_TENSOR_INDEXER_ATTN_Q_B, "weight", i), {q_lora_rank, hparams.indexer_n_head * hparams.indexer_head_size}, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_mtp || i < (int) hparams.n_layer_dense_lead) {
|
||||||
|
layer.ffn_gate = create_tensor(tn(LLM_TENSOR_FFN_GATE, "weight", i), {n_embd, n_ff}, flags);
|
||||||
|
layer.ffn_down = create_tensor(tn(LLM_TENSOR_FFN_DOWN, "weight", i), { n_ff, n_embd}, flags);
|
||||||
|
layer.ffn_up = create_tensor(tn(LLM_TENSOR_FFN_UP, "weight", i), {n_embd, n_ff}, flags);
|
||||||
|
} else {
|
||||||
|
if (n_expert == 0 || n_expert_used == 0) {
|
||||||
|
throw std::runtime_error("n_expert and n_expert_used must be > 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
layer.ffn_gate_inp = create_tensor(tn(LLM_TENSOR_FFN_GATE_INP, "weight", i), {n_embd, n_expert}, flags);
|
||||||
|
layer.ffn_exp_probs_b = create_tensor(tn(LLM_TENSOR_FFN_EXP_PROBS_B, "bias", i), {n_expert}, flags);
|
||||||
|
|
||||||
|
layer.ffn_gate_exps = create_tensor(tn(LLM_TENSOR_FFN_GATE_EXPS, "weight", i), { n_embd, n_ff_exp, n_expert}, flags);
|
||||||
|
layer.ffn_down_exps = create_tensor(tn(LLM_TENSOR_FFN_DOWN_EXPS, "weight", i), {n_ff_exp, n_embd, n_expert}, flags);
|
||||||
|
layer.ffn_up_exps = create_tensor(tn(LLM_TENSOR_FFN_UP_EXPS, "weight", i), { n_embd, n_ff_exp, n_expert}, flags);
|
||||||
|
|
||||||
|
layer.ffn_gate_shexp = create_tensor(tn(LLM_TENSOR_FFN_GATE_SHEXP, "weight", i), {n_embd, n_ff_exp * n_expert_shared}, flags);
|
||||||
|
layer.ffn_down_shexp = create_tensor(tn(LLM_TENSOR_FFN_DOWN_SHEXP, "weight", i), { n_ff_exp * n_expert_shared, n_embd}, flags);
|
||||||
|
layer.ffn_up_shexp = create_tensor(tn(LLM_TENSOR_FFN_UP_SHEXP, "weight", i), {n_embd, n_ff_exp * n_expert_shared}, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_mtp) {
|
||||||
|
layer.nextn.eh_proj = create_tensor(tn(LLM_TENSOR_NEXTN_EH_PROJ, "weight", i), { 2 * n_embd, n_embd }, flags);
|
||||||
|
layer.nextn.enorm = create_tensor(tn(LLM_TENSOR_NEXTN_ENORM, "weight", i), { n_embd }, flags);
|
||||||
|
layer.nextn.hnorm = create_tensor(tn(LLM_TENSOR_NEXTN_HNORM, "weight", i), { n_embd }, flags);
|
||||||
|
layer.nextn.embed_tokens = create_tensor(tn(LLM_TENSOR_NEXTN_EMBED_TOKENS, "weight", i), { n_embd, n_vocab }, flags);
|
||||||
|
layer.nextn.shared_head_norm = create_tensor(tn(LLM_TENSOR_NEXTN_SHARED_HEAD_NORM, "weight", i), { n_embd }, flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<llm_graph_context> llama_model_dots3note::build_arch_graph(const llm_graph_params & params) const {
|
||||||
|
return std::make_unique<graph>(*this, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
llama_model_dots3note::graph::graph(const llama_model & model, const llm_graph_params & params) :
|
||||||
|
llm_graph_context(params) {
|
||||||
|
GGML_ASSERT(hparams.is_mla());
|
||||||
|
|
||||||
|
const int64_t n_embd_head_qk_rope = hparams.n_rot();
|
||||||
|
|
||||||
|
const int64_t n_indexer_head = hparams.indexer_n_head;
|
||||||
|
const int64_t n_embd_indexer_head = hparams.indexer_head_size;
|
||||||
|
const uint32_t n_indexer_top_k = hparams.indexer_top_k;
|
||||||
|
|
||||||
|
// the indexer head layout is [rope | nope]
|
||||||
|
GGML_ASSERT(hparams.n_rot() <= n_embd_indexer_head);
|
||||||
|
|
||||||
|
ggml_tensor * cur;
|
||||||
|
ggml_tensor * inpL;
|
||||||
|
|
||||||
|
inpL = build_inp_embd(model.tok_embd);
|
||||||
|
|
||||||
|
ggml_tensor * inp_pos = build_inp_pos();
|
||||||
|
|
||||||
|
llm_graph_input_attn_k_dsa_iswa * inp_attn = build_attn_inp_k_dsa_iswa();
|
||||||
|
|
||||||
|
ggml_tensor * inp_out_ids = build_inp_out_ids();
|
||||||
|
|
||||||
|
for (int il = 0; il < n_layer; ++il) {
|
||||||
|
ggml_tensor * inpSA = inpL;
|
||||||
|
|
||||||
|
const bool is_swa = hparams.is_swa(il);
|
||||||
|
|
||||||
|
const int64_t n_head_l = hparams.n_head(il);
|
||||||
|
|
||||||
|
const int64_t kv_lora_rank = is_swa ? hparams.n_lora_kv_swa : hparams.n_lora_kv;
|
||||||
|
const int64_t n_embd_head_k_mla = is_swa ? hparams.n_embd_head_k_mla_swa : hparams.n_embd_head_k_mla();
|
||||||
|
const int64_t n_embd_head_v_mla = is_swa ? hparams.n_embd_head_v_mla_swa : hparams.n_embd_head_v_mla();
|
||||||
|
const int64_t n_embd_head_qk_nope = n_embd_head_k_mla - n_embd_head_qk_rope;
|
||||||
|
|
||||||
|
const float kq_scale = 1.0f/sqrtf(float(n_embd_head_k_mla));
|
||||||
|
const float freq_base_l = model.get_rope_freq_base(cparams, il);
|
||||||
|
|
||||||
|
// norm
|
||||||
|
cur = build_norm(inpL, model.layers[il].attn_norm, NULL, LLM_NORM_RMS, il);
|
||||||
|
cb(cur, "attn_norm", il);
|
||||||
|
|
||||||
|
// self_attention
|
||||||
|
{
|
||||||
|
ggml_tensor * attn_inp = cur;
|
||||||
|
|
||||||
|
ggml_tensor * qr = ggml_mul_mat(ctx0, model.layers[il].wq_a, cur);
|
||||||
|
cb(qr, "qr", il);
|
||||||
|
|
||||||
|
qr = build_norm(qr, model.layers[il].attn_q_a_norm, nullptr, LLM_NORM_RMS, il);
|
||||||
|
cb(qr, "qr", il);
|
||||||
|
|
||||||
|
ggml_tensor * top_k = nullptr;
|
||||||
|
|
||||||
|
// lightning indexer (full-attention layers only)
|
||||||
|
if (!is_swa) {
|
||||||
|
ggml_tensor * indexer_q = ggml_mul_mat(ctx0, model.layers[il].indexer_attn_q_b, qr);
|
||||||
|
cb(indexer_q, "indexer_q", il);
|
||||||
|
|
||||||
|
// {n_embd_indexer_head, n_indexer_head, n_tokens}
|
||||||
|
indexer_q = ggml_reshape_3d(ctx0, indexer_q, n_embd_indexer_head, n_indexer_head, n_tokens);
|
||||||
|
indexer_q = ggml_rope_ext(ctx0, indexer_q, inp_pos, nullptr, n_rot,
|
||||||
|
LLAMA_ROPE_TYPE_NEOX, n_ctx_orig, freq_base, freq_scale,
|
||||||
|
ext_factor, attn_factor, beta_fast, beta_slow);
|
||||||
|
cb(indexer_q, "indexer_q", il);
|
||||||
|
|
||||||
|
ggml_tensor * indexer_k = ggml_mul_mat(ctx0, model.layers[il].indexer_attn_k, cur);
|
||||||
|
cb(indexer_k, "indexer_k", il);
|
||||||
|
|
||||||
|
indexer_k = build_norm(indexer_k, model.layers[il].indexer_k_norm, model.layers[il].indexer_k_norm_b, LLM_NORM, il);
|
||||||
|
cb(indexer_k, "indexer_k", il);
|
||||||
|
|
||||||
|
// {n_embd_indexer_head, 1, n_tokens}
|
||||||
|
indexer_k = ggml_reshape_3d(ctx0, indexer_k, n_embd_indexer_head, 1, n_tokens);
|
||||||
|
indexer_k = ggml_rope_ext(ctx0, indexer_k, inp_pos, nullptr, n_rot,
|
||||||
|
LLAMA_ROPE_TYPE_NEOX, n_ctx_orig, freq_base, freq_scale,
|
||||||
|
ext_factor, attn_factor, beta_fast, beta_slow);
|
||||||
|
cb(indexer_k, "indexer_k", il);
|
||||||
|
|
||||||
|
// perform Hadamard transform on indexer q and k
|
||||||
|
indexer_q = ggml_mul_mat(ctx0, inp_attn->get_dsa()->self_k_rot_lid, indexer_q);
|
||||||
|
cb(indexer_q, "indexer_q", il);
|
||||||
|
indexer_k = ggml_mul_mat(ctx0, inp_attn->get_dsa()->self_k_rot_lid, indexer_k);
|
||||||
|
cb(indexer_k, "indexer_k", il);
|
||||||
|
|
||||||
|
// store indexer keys to KV cache
|
||||||
|
const auto * mctx_lid = inp_attn->get_dsa()->mctx->get_lid();
|
||||||
|
const auto & k_idxs_lid = inp_attn->get_dsa()->get_k_idxs_lid();
|
||||||
|
ggml_build_forward_expand(gf, mctx_lid->cpy_k(ctx0, indexer_k, k_idxs_lid, il));
|
||||||
|
|
||||||
|
ggml_tensor * indexer_weights = ggml_mul_mat(ctx0, model.layers[il].indexer_proj, cur);
|
||||||
|
cb(indexer_weights, "indexer_weights", il);
|
||||||
|
|
||||||
|
indexer_k = mctx_lid->get_k(ctx0, il);
|
||||||
|
|
||||||
|
// split the batch into streams if needed
|
||||||
|
const auto n_stream = indexer_k->ne[3];
|
||||||
|
indexer_q = ggml_view_4d(ctx0, indexer_q, indexer_q->ne[0], indexer_q->ne[1], indexer_q->ne[2]/n_stream, n_stream, indexer_q->nb[1], indexer_q->nb[2], indexer_q->nb[3]/n_stream, 0);
|
||||||
|
indexer_weights = ggml_view_4d(ctx0, indexer_weights, indexer_weights->ne[0], indexer_weights->ne[1]/n_stream, indexer_weights->ne[2], n_stream, indexer_weights->nb[1], indexer_weights->nb[2]/n_stream, indexer_weights->nb[3]/n_stream, 0);
|
||||||
|
|
||||||
|
// pre-scale weights to avoid scaling operations on huge indexer_score tensor
|
||||||
|
indexer_weights = ggml_scale(ctx0, indexer_weights, 1.0f / sqrtf(float(n_embd_indexer_head * n_indexer_head)));
|
||||||
|
cb(indexer_weights, "indexer_weights", il);
|
||||||
|
|
||||||
|
ggml_tensor * indexer_score = nullptr;
|
||||||
|
if (cparams.fused_lid) {
|
||||||
|
indexer_score = ggml_lightning_indexer(ctx0, indexer_q, indexer_k, indexer_weights, inp_attn->get_dsa()->get_kq_mask_lid());
|
||||||
|
cb(indexer_score, "indexer_score", il);
|
||||||
|
res->add_fused_node({LLM_FUSED_OP_LIGHTNING_INDEXER, indexer_score, il});
|
||||||
|
} else {
|
||||||
|
indexer_q = ggml_permute(ctx0, indexer_q, 0, 2, 1, 3);
|
||||||
|
cb(indexer_q, "indexer_q", il);
|
||||||
|
indexer_k = ggml_permute(ctx0, indexer_k, 0, 2, 1, 3);
|
||||||
|
cb(indexer_k, "indexer_k", il);
|
||||||
|
|
||||||
|
ggml_tensor * indexer_kq = ggml_mul_mat(ctx0, indexer_k, indexer_q);
|
||||||
|
cb(indexer_kq, "indexer_kq", il);
|
||||||
|
|
||||||
|
// ReLU requires contiguous tensors
|
||||||
|
indexer_kq = ggml_cont(ctx0, ggml_permute(ctx0, indexer_kq, 2, 1, 0, 3));
|
||||||
|
cb(indexer_kq, "indexer_kq", il);
|
||||||
|
|
||||||
|
indexer_score = ggml_relu(ctx0, indexer_kq);
|
||||||
|
cb(indexer_score, "indexer_score", il);
|
||||||
|
|
||||||
|
indexer_score = ggml_mul(ctx0, indexer_score, indexer_weights);
|
||||||
|
cb(indexer_score, "indexer_score", il);
|
||||||
|
|
||||||
|
// sum by q n_indexer_head dimension
|
||||||
|
indexer_score = ggml_sum_rows(ctx0, indexer_score);
|
||||||
|
cb(indexer_score, "indexer_score", il);
|
||||||
|
|
||||||
|
// permute result to match KQ mask
|
||||||
|
indexer_score = ggml_cont(ctx0, ggml_permute(ctx0, indexer_score, 2, 1, 0, 3));
|
||||||
|
cb(indexer_score, "indexer_score", il);
|
||||||
|
|
||||||
|
ggml_tensor * indexer_kq_mask = inp_attn->get_dsa()->get_kq_mask_lid();
|
||||||
|
indexer_score = ggml_add(ctx0, indexer_score, indexer_kq_mask);
|
||||||
|
cb(indexer_score, "indexer_score", il);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get indices of top k indexer scores
|
||||||
|
uint32_t n_top_k = indexer_score->ne[0] < n_indexer_top_k ? indexer_score->ne[0] : n_indexer_top_k;
|
||||||
|
top_k = ggml_cont(ctx0, ggml_top_k(ctx0, indexer_score, n_top_k));
|
||||||
|
cb(top_k, "top_k", il);
|
||||||
|
}
|
||||||
|
|
||||||
|
ggml_tensor * q = ggml_mul_mat(ctx0, model.layers[il].wq_b, qr);
|
||||||
|
cb(q, "q", il);
|
||||||
|
|
||||||
|
// split into {n_embd_head_qk_nope, n_head_l, n_tokens}
|
||||||
|
ggml_tensor * q_nope =
|
||||||
|
ggml_view_3d(ctx0, q, n_embd_head_qk_nope, n_head_l, n_tokens, ggml_row_size(q->type, n_embd_head_k_mla),
|
||||||
|
ggml_row_size(q->type, n_embd_head_k_mla) * n_head_l, 0);
|
||||||
|
cb(q_nope, "q_nope", il);
|
||||||
|
|
||||||
|
// and {n_embd_head_qk_rope, n_head_l, n_tokens}
|
||||||
|
ggml_tensor * q_pe = ggml_view_3d(
|
||||||
|
ctx0, q, n_embd_head_qk_rope, n_head_l, n_tokens, ggml_row_size(q->type, n_embd_head_k_mla),
|
||||||
|
ggml_row_size(q->type, n_embd_head_k_mla) * n_head_l, ggml_row_size(q->type, n_embd_head_qk_nope));
|
||||||
|
cb(q_pe, "q_pe", il);
|
||||||
|
|
||||||
|
ggml_tensor * kv_cmpr_pe = ggml_mul_mat(ctx0, model.layers[il].wkv_a_mqa, cur);
|
||||||
|
cb(kv_cmpr_pe, "kv_cmpr_pe", il);
|
||||||
|
|
||||||
|
// split into {kv_lora_rank, n_tokens}
|
||||||
|
ggml_tensor * kv_cmpr =
|
||||||
|
ggml_view_2d(ctx0, kv_cmpr_pe, kv_lora_rank, n_tokens,
|
||||||
|
ggml_row_size(kv_cmpr_pe->type, kv_lora_rank + n_embd_head_qk_rope), 0);
|
||||||
|
cb(kv_cmpr, "kv_cmpr", il);
|
||||||
|
|
||||||
|
// and {n_embd_head_qk_rope, 1, n_tokens}
|
||||||
|
ggml_tensor * k_pe = ggml_view_3d(ctx0, kv_cmpr_pe, n_embd_head_qk_rope, 1, n_tokens,
|
||||||
|
ggml_row_size(kv_cmpr_pe->type, kv_lora_rank + n_embd_head_qk_rope),
|
||||||
|
ggml_row_size(kv_cmpr_pe->type, kv_lora_rank + n_embd_head_qk_rope),
|
||||||
|
ggml_row_size(kv_cmpr_pe->type, kv_lora_rank));
|
||||||
|
cb(k_pe, "k_pe", il);
|
||||||
|
|
||||||
|
// norm on the shared rope key, applied before rope
|
||||||
|
k_pe = build_norm(k_pe, model.layers[il].attn_k_norm, nullptr, LLM_NORM_RMS, il);
|
||||||
|
cb(k_pe, "k_pe", il);
|
||||||
|
|
||||||
|
q_pe = ggml_rope_ext(ctx0, q_pe, inp_pos, nullptr, n_rot, rope_type, n_ctx_orig, freq_base_l, freq_scale,
|
||||||
|
ext_factor, attn_factor, beta_fast, beta_slow);
|
||||||
|
cb(q_pe, "q_pe", il);
|
||||||
|
|
||||||
|
k_pe = ggml_rope_ext(ctx0, k_pe, inp_pos, nullptr, n_rot, rope_type, n_ctx_orig, freq_base_l, freq_scale,
|
||||||
|
ext_factor, attn_factor, beta_fast, beta_slow);
|
||||||
|
cb(k_pe, "k_pe", il);
|
||||||
|
|
||||||
|
kv_cmpr = build_norm(kv_cmpr, model.layers[il].attn_kv_a_norm, nullptr, LLM_NORM_RMS, il);
|
||||||
|
cb(kv_cmpr, "kv_cmpr", il);
|
||||||
|
|
||||||
|
// MLA attention with the absorption optimization
|
||||||
|
{
|
||||||
|
// {n_embd_head_qk_nope, n_tokens, n_head_l}
|
||||||
|
q_nope = ggml_permute(ctx0, q_nope, 0, 2, 1, 3);
|
||||||
|
cb(q_nope, "q_nope_perm", il);
|
||||||
|
|
||||||
|
// {n_embd_head_qk_nope, kv_lora_rank, n_head_l} x {n_embd_head_qk_nope, n_tokens, n_head_l}
|
||||||
|
ggml_tensor * q_nope_absorbed = ggml_mul_mat(ctx0, model.layers[il].wk_b, q_nope);
|
||||||
|
cb(q_nope_absorbed, "q_nope_absorbed", il);
|
||||||
|
|
||||||
|
// {kv_lora_rank, n_head_l, n_tokens}
|
||||||
|
q_nope_absorbed = ggml_permute(ctx0, q_nope_absorbed, 0, 2, 1, 3);
|
||||||
|
cb(q_nope_absorbed, "q_nope_absorbed_perm", il);
|
||||||
|
|
||||||
|
// {n_embd_head_qk_rope + kv_lora_rank, n_head_l, n_tokens}
|
||||||
|
ggml_tensor * Qcur = ggml_concat(ctx0, q_nope_absorbed, q_pe, 0);
|
||||||
|
cb(Qcur, "Qcur", il);
|
||||||
|
|
||||||
|
kv_cmpr = ggml_reshape_3d(ctx0, kv_cmpr, kv_lora_rank, 1, n_tokens);
|
||||||
|
cb(kv_cmpr, "kv_cmpr_reshape", il);
|
||||||
|
|
||||||
|
// {n_embd_head_qk_rope + kv_lora_rank, 1, n_tokens}
|
||||||
|
ggml_tensor * Kcur = ggml_concat(ctx0, kv_cmpr, k_pe, 0);
|
||||||
|
cb(Kcur, "Kcur", il);
|
||||||
|
|
||||||
|
// {kv_lora_rank, 1, n_tokens}
|
||||||
|
ggml_tensor * Vcur = kv_cmpr;
|
||||||
|
cb(Vcur, "Vcur", il);
|
||||||
|
|
||||||
|
// apply the head-wise output gate before o_proj, so wo stays out of build_attn
|
||||||
|
if (is_swa) {
|
||||||
|
cur = build_attn(inp_attn->get_swa(),
|
||||||
|
nullptr, nullptr, nullptr,
|
||||||
|
Qcur, Kcur, Vcur, nullptr, nullptr, model.layers[il].wv_b, kq_scale, il);
|
||||||
|
} else {
|
||||||
|
cur = build_attn(inp_attn->get_dsa(),
|
||||||
|
nullptr, nullptr, nullptr,
|
||||||
|
Qcur, Kcur, Vcur, nullptr, nullptr, model.layers[il].wv_b, top_k, kq_scale, il);
|
||||||
|
}
|
||||||
|
cb(cur, "attn_out", il);
|
||||||
|
|
||||||
|
ggml_tensor * gate = build_lora_mm(model.layers[il].wqkv_gate, attn_inp);
|
||||||
|
cb(gate, "attn_gate", il);
|
||||||
|
|
||||||
|
gate = ggml_sigmoid(ctx0, gate);
|
||||||
|
cb(gate, "attn_gate_sigmoid", il);
|
||||||
|
|
||||||
|
// broadcast the per-head gate over the head dimension
|
||||||
|
ggml_tensor * attn_3d = ggml_reshape_3d(ctx0, cur, n_embd_head_v_mla, n_head_l, n_tokens);
|
||||||
|
ggml_tensor * gate_3d = ggml_reshape_3d(ctx0, gate, 1, n_head_l, n_tokens);
|
||||||
|
attn_3d = ggml_mul(ctx0, attn_3d, gate_3d);
|
||||||
|
cb(attn_3d, "attn_gated", il);
|
||||||
|
|
||||||
|
cur = ggml_reshape_2d(ctx0, attn_3d, n_embd_head_v_mla * n_head_l, n_tokens);
|
||||||
|
|
||||||
|
cur = build_lora_mm(model.layers[il].wo, cur, model.layers[il].wo_s);
|
||||||
|
cb(cur, "attn_output", 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, model.layers[il].ffn_norm, NULL, LLM_NORM_RMS, il);
|
||||||
|
cb(cur, "ffn_norm", il);
|
||||||
|
|
||||||
|
if ((uint32_t) il < hparams.n_layer_dense_lead) {
|
||||||
|
cur = build_ffn(cur,
|
||||||
|
model.layers[il].ffn_up, NULL, model.layers[il].ffn_up_s,
|
||||||
|
model.layers[il].ffn_gate, NULL, model.layers[il].ffn_gate_s,
|
||||||
|
model.layers[il].ffn_down, NULL, model.layers[il].ffn_down_s,
|
||||||
|
NULL, LLM_FFN_SILU, LLM_FFN_PAR, il);
|
||||||
|
cb(cur, "ffn_out", il);
|
||||||
|
} else {
|
||||||
|
ggml_tensor * moe_out = build_moe_ffn(cur,
|
||||||
|
model.layers[il].ffn_gate_inp,
|
||||||
|
model.layers[il].ffn_up_exps,
|
||||||
|
model.layers[il].ffn_gate_exps,
|
||||||
|
model.layers[il].ffn_down_exps,
|
||||||
|
model.layers[il].ffn_exp_probs_b,
|
||||||
|
n_expert, n_expert_used,
|
||||||
|
LLM_FFN_SILU, hparams.expert_weights_norm,
|
||||||
|
hparams.expert_weights_scale,
|
||||||
|
(llama_expert_gating_func_type) hparams.expert_gating_func,
|
||||||
|
il,
|
||||||
|
nullptr,
|
||||||
|
model.layers[il].ffn_gate_up_exps,
|
||||||
|
model.layers[il].ffn_up_exps_s,
|
||||||
|
model.layers[il].ffn_gate_exps_s,
|
||||||
|
model.layers[il].ffn_down_exps_s);
|
||||||
|
cb(moe_out, "ffn_moe_out", il);
|
||||||
|
|
||||||
|
ggml_tensor * ffn_shexp =
|
||||||
|
build_ffn(cur,
|
||||||
|
model.layers[il].ffn_up_shexp, NULL, model.layers[il].ffn_up_shexp_s,
|
||||||
|
model.layers[il].ffn_gate_shexp, NULL, model.layers[il].ffn_gate_shexp_s,
|
||||||
|
model.layers[il].ffn_down_shexp, NULL, model.layers[il].ffn_down_shexp_s,
|
||||||
|
NULL, LLM_FFN_SILU, LLM_FFN_PAR, il);
|
||||||
|
cb(ffn_shexp, "ffn_shexp", il);
|
||||||
|
|
||||||
|
cur = ggml_add(ctx0, moe_out, ffn_shexp);
|
||||||
|
cb(cur, "ffn_out", il);
|
||||||
|
}
|
||||||
|
|
||||||
|
cur = ggml_add(ctx0, cur, ffn_inp);
|
||||||
|
|
||||||
|
cur = build_cvec(cur, il);
|
||||||
|
cb(cur, "l_out", il);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
cur = ggml_mul_mat(ctx0, model.output, cur);
|
||||||
|
|
||||||
|
cb(cur, "result_output", -1);
|
||||||
|
res->t_logits = cur;
|
||||||
|
|
||||||
|
ggml_build_forward_expand(gf, cur);
|
||||||
|
}
|
||||||
@@ -1156,6 +1156,18 @@ struct llama_model_deepseek32 : public llama_model_base {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct llama_model_dots3note : public llama_model_base {
|
||||||
|
llama_model_dots3note(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_deepseek4 : public llama_model_base {
|
struct llama_model_deepseek4 : public llama_model_base {
|
||||||
llama_model_deepseek4(const struct llama_model_params & params) : llama_model_base(params) {}
|
llama_model_deepseek4(const struct llama_model_params & params) : llama_model_base(params) {}
|
||||||
void load_arch_hparams(llama_model_loader & ml) override;
|
void load_arch_hparams(llama_model_loader & ml) override;
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ static gguf_context_ptr get_gguf_ctx(const llm_arch arch, const bool moe) {
|
|||||||
} else if (arch == LLM_ARCH_DEEPSEEK2
|
} else if (arch == LLM_ARCH_DEEPSEEK2
|
||||||
|| arch == LLM_ARCH_DEEPSEEK32
|
|| arch == LLM_ARCH_DEEPSEEK32
|
||||||
|| arch == LLM_ARCH_GLM_DSA
|
|| arch == LLM_ARCH_GLM_DSA
|
||||||
|
|| arch == LLM_ARCH_DOTS3NOTE
|
||||||
|| arch == LLM_ARCH_KIMI_LINEAR
|
|| arch == LLM_ARCH_KIMI_LINEAR
|
||||||
|| arch == LLM_ARCH_BAILINGMOE3
|
|| arch == LLM_ARCH_BAILINGMOE3
|
||||||
|| arch == LLM_ARCH_KIMI_K3
|
|| arch == LLM_ARCH_KIMI_K3
|
||||||
@@ -166,6 +167,7 @@ static gguf_context_ptr get_gguf_ctx(const llm_arch arch, const bool moe) {
|
|||||||
if (arch == LLM_ARCH_DEEPSEEK2
|
if (arch == LLM_ARCH_DEEPSEEK2
|
||||||
|| arch == LLM_ARCH_DEEPSEEK32
|
|| arch == LLM_ARCH_DEEPSEEK32
|
||||||
|| arch == LLM_ARCH_GLM_DSA
|
|| arch == LLM_ARCH_GLM_DSA
|
||||||
|
|| arch == LLM_ARCH_DOTS3NOTE
|
||||||
|| arch == LLM_ARCH_KIMI_LINEAR
|
|| arch == LLM_ARCH_KIMI_LINEAR
|
||||||
|| arch == LLM_ARCH_BAILINGMOE3
|
|| arch == LLM_ARCH_BAILINGMOE3
|
||||||
|| arch == LLM_ARCH_KIMI_K3
|
|| arch == LLM_ARCH_KIMI_K3
|
||||||
@@ -175,6 +177,22 @@ static gguf_context_ptr get_gguf_ctx(const llm_arch arch, const bool moe) {
|
|||||||
ms.add_kv(LLM_KV_ROPE_DIMENSION_COUNT, uint32_t(64));
|
ms.add_kv(LLM_KV_ROPE_DIMENSION_COUNT, uint32_t(64));
|
||||||
ms.add_kv(LLM_KV_ATTENTION_KEY_LENGTH_MLA, uint32_t(192));
|
ms.add_kv(LLM_KV_ATTENTION_KEY_LENGTH_MLA, uint32_t(192));
|
||||||
ms.add_kv(LLM_KV_ATTENTION_VALUE_LENGTH_MLA, uint32_t(128));
|
ms.add_kv(LLM_KV_ATTENTION_VALUE_LENGTH_MLA, uint32_t(128));
|
||||||
|
if (arch == LLM_ARCH_DOTS3NOTE) {
|
||||||
|
// SWA layers reuse the same MLA geometry as the full layers in this fixture
|
||||||
|
ms.add_kv(LLM_KV_ATTENTION_KV_LORA_RANK_SWA, uint32_t(512));
|
||||||
|
ms.add_kv(LLM_KV_ATTENTION_KEY_LENGTH_SWA, uint32_t(576));
|
||||||
|
ms.add_kv(LLM_KV_ATTENTION_VALUE_LENGTH_SWA, uint32_t(512));
|
||||||
|
ms.add_kv(LLM_KV_ATTENTION_KEY_LENGTH_MLA_SWA, uint32_t(192));
|
||||||
|
ms.add_kv(LLM_KV_ATTENTION_VALUE_LENGTH_MLA_SWA, uint32_t(128));
|
||||||
|
ms.add_kv(LLM_KV_ROPE_FREQ_BASE_SWA, 10000.0f);
|
||||||
|
// indexer on the full-attention layers (inverse of the swa pattern)
|
||||||
|
std::vector<uint32_t> indexer_types;
|
||||||
|
indexer_types.reserve(n_layer);
|
||||||
|
for (uint32_t il = 0; il < n_layer; il++) {
|
||||||
|
indexer_types.push_back(il % 2 ? 0 : 1);
|
||||||
|
}
|
||||||
|
ms.add_kv(LLM_KV_ATTENTION_INDEXER_TYPES, indexer_types);
|
||||||
|
}
|
||||||
} else if (arch == LLM_ARCH_MINIMAX_M3) {
|
} else if (arch == LLM_ARCH_MINIMAX_M3) {
|
||||||
// partial rotary: n_rot must not exceed the indexer key length (64)
|
// partial rotary: n_rot must not exceed the indexer key length (64)
|
||||||
ms.add_kv(LLM_KV_ROPE_DIMENSION_COUNT, uint32_t(64));
|
ms.add_kv(LLM_KV_ROPE_DIMENSION_COUNT, uint32_t(64));
|
||||||
@@ -197,7 +215,8 @@ static gguf_context_ptr get_gguf_ctx(const llm_arch arch, const bool moe) {
|
|||||||
ms.add_kv(LLM_KV_ROPE_FREQ_BASE_SWA, 10000.0f);
|
ms.add_kv(LLM_KV_ROPE_FREQ_BASE_SWA, 10000.0f);
|
||||||
// SWA pattern: every 5th layer is full attention (matches E2B layer_types)
|
// SWA pattern: every 5th layer is full attention (matches E2B layer_types)
|
||||||
ms.add_kv(LLM_KV_ATTENTION_SLIDING_WINDOW_PATTERN, uint32_t(5));
|
ms.add_kv(LLM_KV_ATTENTION_SLIDING_WINDOW_PATTERN, uint32_t(5));
|
||||||
} else if (arch == LLM_ARCH_COHERE2MOE || arch == LLM_ARCH_MIMO2 || arch == LLM_ARCH_STEP35 || arch == LLM_ARCH_MUSE_GLIMMER || arch == LLM_ARCH_GRANITE_SWA) {
|
} else if (arch == LLM_ARCH_COHERE2MOE || arch == LLM_ARCH_MIMO2 || arch == LLM_ARCH_STEP35 ||
|
||||||
|
arch == LLM_ARCH_MUSE_GLIMMER || arch == LLM_ARCH_GRANITE_SWA || arch == LLM_ARCH_DOTS3NOTE) {
|
||||||
std::vector<uint32_t> pattern;
|
std::vector<uint32_t> pattern;
|
||||||
pattern.reserve(n_layer);
|
pattern.reserve(n_layer);
|
||||||
for (uint32_t il = 0; il < n_layer; il++) {
|
for (uint32_t il = 0; il < n_layer; il++) {
|
||||||
@@ -365,6 +384,7 @@ static bool moe_mandatory(const llm_arch arch) {
|
|||||||
case LLM_ARCH_DEEPSEEK:
|
case LLM_ARCH_DEEPSEEK:
|
||||||
case LLM_ARCH_DEEPSEEK2:
|
case LLM_ARCH_DEEPSEEK2:
|
||||||
case LLM_ARCH_DEEPSEEK32:
|
case LLM_ARCH_DEEPSEEK32:
|
||||||
|
case LLM_ARCH_DOTS3NOTE:
|
||||||
case LLM_ARCH_GLM4_MOE:
|
case LLM_ARCH_GLM4_MOE:
|
||||||
case LLM_ARCH_GLM_DSA:
|
case LLM_ARCH_GLM_DSA:
|
||||||
case LLM_ARCH_EXAONE_MOE:
|
case LLM_ARCH_EXAONE_MOE:
|
||||||
|
|||||||
Reference in New Issue
Block a user