Skip to content

Commit b77d646

Browse files
zqlcoderoot
andauthored
model: Add support for Nanbeige4.2 (ggml-org#25994)
* support nanbeige4.2 model * fix * fix flake8 Lint check * fix loop bound check and drop redundant head_dim --------- Co-authored-by: root <lizongqiang@kanzhun.com>
1 parent 0324696 commit b77d646

10 files changed

Lines changed: 265 additions & 1 deletion

File tree

conversion/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@
167167
"ModernBertForMaskedLM": "bert",
168168
"ModernBertForSequenceClassification": "bert",
169169
"ModernBertModel": "bert",
170+
"NanbeigeForCausalLM": "nanbeige",
170171
"NemotronForCausalLM": "nemotron",
171172
"NemotronHForCausalLM": "nemotron",
172173
"NeoBERT": "bert",

conversion/nanbeige.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
from __future__ import annotations
2+
3+
from .base import ModelBase, gguf, logger
4+
from .llama import LlamaModel
5+
6+
7+
@ModelBase.register("NanbeigeForCausalLM")
8+
class NanbeigeModel(LlamaModel):
9+
model_arch = gguf.MODEL_ARCH.NANBEIGE
10+
undo_permute = True
11+
12+
def set_gguf_parameters(self):
13+
super().set_gguf_parameters()
14+
hparams = self.hparams
15+
16+
n_loops = int(hparams.get("num_loops", 1) or 1)
17+
if n_loops < 1:
18+
n_loops = 1
19+
self.gguf_writer.add_num_loops(n_loops)
20+
logger.info(f"gguf: num_loops = {n_loops}")
21+
22+
skip_loop_final_norm = bool(hparams.get("skip_loop_final_norm", False))
23+
self.gguf_writer.add_skip_loop_final_norm(skip_loop_final_norm)
24+
logger.info(f"gguf: skip_loop_final_norm = {skip_loop_final_norm}")

gguf-py/gguf/constants.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@ class LLM:
145145
TOKEN_SHIFT_COUNT = "{arch}.token_shift_count"
146146
INTERLEAVE_MOE_LAYER_STEP = "{arch}.interleave_moe_layer_step"
147147
FULL_ATTENTION_INTERVAL = "{arch}.full_attention_interval"
148+
NUM_LOOPS = "{arch}.num_loops"
149+
SKIP_LOOP_FINAL_NORM = "{arch}.skip_loop_final_norm"
148150
HASH_LAYER_COUNT = "{arch}.hash_layer_count"
149151
ACTIVATION_SPARSITY_SCALE = "{arch}.activation_sparsity_scale"
150152
ALTUP_ACTIVE_IDX = "{arch}.altup.active_idx"
@@ -545,6 +547,7 @@ class MODEL_ARCH(IntEnum):
545547
KIMI_LINEAR = auto()
546548
TALKIE = auto()
547549
MELLUM = auto()
550+
NANBEIGE = auto()
548551

549552

550553
class VISION_PROJECTOR_TYPE(IntEnum):
@@ -1134,6 +1137,7 @@ class MODEL_TENSOR(IntEnum):
11341137
MODEL_ARCH.KIMI_LINEAR: "kimi-linear",
11351138
MODEL_ARCH.TALKIE: "talkie",
11361139
MODEL_ARCH.MELLUM: "mellum",
1140+
MODEL_ARCH.NANBEIGE: "nanbeige",
11371141
}
11381142

11391143
VISION_PROJECTOR_TYPE_NAMES: dict[VISION_PROJECTOR_TYPE, str] = {
@@ -4505,7 +4509,22 @@ class MODEL_TENSOR(IntEnum):
45054509
MODEL_TENSOR.FFN_DOWN_EXP,
45064510
MODEL_TENSOR.FFN_UP_EXP,
45074511
],
4508-
# TODO
4512+
MODEL_ARCH.NANBEIGE: [
4513+
MODEL_TENSOR.TOKEN_EMBD,
4514+
MODEL_TENSOR.OUTPUT_NORM,
4515+
MODEL_TENSOR.OUTPUT,
4516+
MODEL_TENSOR.ROPE_FREQS,
4517+
MODEL_TENSOR.ATTN_NORM,
4518+
MODEL_TENSOR.ATTN_Q,
4519+
MODEL_TENSOR.ATTN_K,
4520+
MODEL_TENSOR.ATTN_V,
4521+
MODEL_TENSOR.ATTN_OUT,
4522+
MODEL_TENSOR.ATTN_ROT_EMBD,
4523+
MODEL_TENSOR.FFN_NORM,
4524+
MODEL_TENSOR.FFN_GATE,
4525+
MODEL_TENSOR.FFN_DOWN,
4526+
MODEL_TENSOR.FFN_UP,
4527+
],
45094528
}
45104529

45114530
# tensors that will not be serialized
@@ -4572,6 +4591,10 @@ class MODEL_TENSOR(IntEnum):
45724591
MODEL_TENSOR.ROPE_FREQS,
45734592
MODEL_TENSOR.ATTN_ROT_EMBD,
45744593
],
4594+
MODEL_ARCH.NANBEIGE: [
4595+
MODEL_TENSOR.ROPE_FREQS,
4596+
MODEL_TENSOR.ATTN_ROT_EMBD,
4597+
],
45754598
}
45764599

45774600
#

gguf-py/gguf/gguf_writer.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -908,6 +908,12 @@ def add_wkv_head_size(self, size: int) -> None:
908908
def add_token_shift_count(self, count: int) -> None:
909909
self.add_uint32(Keys.LLM.TOKEN_SHIFT_COUNT.format(arch=self.arch), count)
910910

911+
def add_num_loops(self, count: int) -> None:
912+
self.add_uint32(Keys.LLM.NUM_LOOPS.format(arch=self.arch), count)
913+
914+
def add_skip_loop_final_norm(self, value: bool) -> None:
915+
self.add_bool(Keys.LLM.SKIP_LOOP_FINAL_NORM.format(arch=self.arch), value)
916+
911917
def add_interleave_moe_layer_step(self, value: int) -> None:
912918
self.add_uint32(Keys.LLM.INTERLEAVE_MOE_LAYER_STEP.format(arch=self.arch), value)
913919

src/llama-arch.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ static const std::map<llm_arch, const char *> LLM_ARCH_NAMES = {
143143
{ LLM_ARCH_KIMI_LINEAR, "kimi-linear" },
144144
{ LLM_ARCH_TALKIE, "talkie" },
145145
{ LLM_ARCH_MELLUM, "mellum" },
146+
{ LLM_ARCH_NANBEIGE, "nanbeige" },
146147
{ LLM_ARCH_UNKNOWN, "(unknown)" },
147148
};
148149

@@ -221,6 +222,8 @@ static const std::map<llm_kv, const char *> LLM_KV_NAMES = {
221222
{ LLM_KV_TOKEN_SHIFT_COUNT, "%s.token_shift_count" },
222223
{ LLM_KV_INTERLEAVE_MOE_LAYER_STEP, "%s.interleave_moe_layer_step" },
223224
{ LLM_KV_FULL_ATTENTION_INTERVAL, "%s.full_attention_interval" },
225+
{ LLM_KV_NUM_LOOPS, "%s.num_loops" },
226+
{ LLM_KV_SKIP_LOOP_FINAL_NORM, "%s.skip_loop_final_norm" },
224227

225228
{ LLM_KV_ATTENTION_HEAD_COUNT, "%s.attention.head_count" },
226229
{ LLM_KV_ATTENTION_HEAD_COUNT_KV, "%s.attention.head_count_kv" },

src/llama-arch.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ enum llm_arch {
148148
LLM_ARCH_EAGLE3,
149149
LLM_ARCH_MINIMAX_M3,
150150
LLM_ARCH_DFLASH,
151+
LLM_ARCH_NANBEIGE,
151152
LLM_ARCH_UNKNOWN,
152153
};
153154

@@ -226,6 +227,8 @@ enum llm_kv {
226227
LLM_KV_TOKEN_SHIFT_COUNT,
227228
LLM_KV_INTERLEAVE_MOE_LAYER_STEP,
228229
LLM_KV_FULL_ATTENTION_INTERVAL,
230+
LLM_KV_NUM_LOOPS,
231+
LLM_KV_SKIP_LOOP_FINAL_NORM,
229232

230233
LLM_KV_ATTENTION_HEAD_COUNT,
231234
LLM_KV_ATTENTION_HEAD_COUNT_KV,

src/llama-context.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2339,6 +2339,7 @@ uint32_t llama_context::graph_max_nodes(uint32_t n_tokens) const {
23392339
model.arch == LLM_ARCH_QWEN35 ||
23402340
model.arch == LLM_ARCH_QWEN35MOE ||
23412341
model.arch == LLM_ARCH_DEEPSEEK4 ||
2342+
model.arch == LLM_ARCH_NANBEIGE ||
23422343
model.arch == LLM_ARCH_MINIMAX_M3) {
23432344
return std::max<uint32_t>(n_tokens * 40, 32u * model.n_tensors());
23442345
}

src/llama-model.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ static llama_model * llama_model_mapping(llm_arch arch, const llama_model_params
8585
return new llama_model_stablelm(params);
8686
case LLM_ARCH_MELLUM:
8787
return new llama_model_mellum(params);
88+
case LLM_ARCH_NANBEIGE:
89+
return new llama_model_nanbeige(params);
8890
case LLM_ARCH_QWEN:
8991
return new llama_model_qwen(params);
9092
case LLM_ARCH_QWEN2:
@@ -2491,6 +2493,7 @@ llama_rope_type llama_model_rope_type(const llama_model * model) {
24912493
case LLM_ARCH_LLAMA_EMBED:
24922494
case LLM_ARCH_MAINCODER:
24932495
case LLM_ARCH_GLM_DSA:
2496+
case LLM_ARCH_NANBEIGE:
24942497
return LLAMA_ROPE_TYPE_NORM;
24952498

24962499
// the pairs of head values are offset by n_rot/2

src/models/models.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,22 @@ struct llama_model_mellum : public llama_model_base {
424424
std::unique_ptr<llm_graph_context> build_arch_graph(const llm_graph_params & params) const override;
425425
};
426426

427+
struct llama_model_nanbeige : public llama_model_base {
428+
llama_model_nanbeige(const struct llama_model_params & params) : llama_model_base(params) {}
429+
void load_arch_hparams(llama_model_loader & ml) override;
430+
void load_arch_tensors(llama_model_loader & ml) override;
431+
432+
int n_loops = 1;
433+
int n_layer_phys = 0;
434+
bool skip_loop_final_norm = false;
435+
436+
struct graph : public llm_graph_context {
437+
graph(const llama_model & model, const llm_graph_params & params);
438+
};
439+
440+
std::unique_ptr<llm_graph_context> build_arch_graph(const llm_graph_params & params) const override;
441+
};
442+
427443
struct llama_model_qwen : public llama_model_base {
428444
llama_model_qwen(const struct llama_model_params & params) : llama_model_base(params) {}
429445
void load_arch_hparams(llama_model_loader & ml) override;

src/models/nanbeige.cpp

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
#include "models.h"
2+
3+
void llama_model_nanbeige::load_arch_hparams(llama_model_loader & ml) {
4+
ml.get_key(LLM_KV_ATTENTION_LAYERNORM_RMS_EPS, hparams.f_norm_rms_eps);
5+
6+
uint32_t n_loops_u = 1;
7+
ml.get_key(LLM_KV_NUM_LOOPS, n_loops_u, false);
8+
GGML_ASSERT(n_loops_u >= 1);
9+
10+
skip_loop_final_norm = false;
11+
ml.get_key(LLM_KV_SKIP_LOOP_FINAL_NORM, skip_loop_final_norm, false);
12+
13+
n_layer_phys = (int) hparams.n_layer();
14+
15+
// Bound-check before casting: signed int mul can overflow and bypass the guard.
16+
GGML_ASSERT((size_t) n_layer_phys * (size_t) n_loops_u <= (size_t) LLAMA_MAX_LAYERS);
17+
n_loops = (int) n_loops_u;
18+
19+
// Expand logical layer count before load_tensors() allocates layers / KV.
20+
if (n_loops > 1) {
21+
for (int j = 1; j < n_loops; ++j) {
22+
for (int i = 0; i < n_layer_phys; ++i) {
23+
const int dst = i + j * n_layer_phys;
24+
hparams.n_head_arr[dst] = hparams.n_head_arr[i];
25+
hparams.n_head_kv_arr[dst] = hparams.n_head_kv_arr[i];
26+
hparams.n_ff_arr[dst] = hparams.n_ff_arr[i];
27+
hparams.is_swa_impl[dst] = hparams.is_swa_impl[i];
28+
hparams.is_recr_impl[dst] = hparams.is_recr_impl[i];
29+
}
30+
}
31+
hparams.n_layer_all = (uint32_t) ((size_t) n_layer_phys * (size_t) n_loops);
32+
}
33+
34+
type = LLM_TYPE_UNKNOWN;
35+
}
36+
37+
void llama_model_nanbeige::load_arch_tensors(llama_model_loader &) {
38+
LLAMA_LOAD_LOCALS;
39+
40+
tok_embd = create_tensor(tn(LLM_TENSOR_TOKEN_EMBD, "weight"), {n_embd, n_vocab}, 0);
41+
42+
output_norm = create_tensor(tn(LLM_TENSOR_OUTPUT_NORM, "weight"), {n_embd}, 0);
43+
output = create_tensor(tn(LLM_TENSOR_OUTPUT, "weight"), {n_embd, n_vocab}, TENSOR_NOT_REQUIRED);
44+
if (output == NULL) {
45+
output = create_tensor(tn(LLM_TENSOR_TOKEN_EMBD, "weight"), {n_embd, n_vocab}, TENSOR_DUPLICATED);
46+
}
47+
48+
const int n_phys = n_layer_phys > 0 ? n_layer_phys : n_layer;
49+
for (int i = 0; i < n_phys; ++i) {
50+
auto & layer = layers[i];
51+
52+
layer.attn_norm = create_tensor(tn(LLM_TENSOR_ATTN_NORM, "weight", i), {n_embd}, 0);
53+
54+
create_tensor_qkv(layer, i, n_embd, n_embd_head_k * n_head, n_embd_k_gqa, n_embd_v_gqa, 0);
55+
layer.wo = create_tensor(tn(LLM_TENSOR_ATTN_OUT, "weight", i), {n_embd_head_k * n_head, n_embd}, 0);
56+
57+
layer.rope_freqs = create_tensor(tn(LLM_TENSOR_ROPE_FREQS, "weight", i), {n_rot/2},
58+
TENSOR_NOT_REQUIRED | (i != 0 ? TENSOR_DUPLICATED : 0));
59+
60+
layer.ffn_norm = create_tensor(tn(LLM_TENSOR_FFN_NORM, "weight", i), {n_embd}, 0);
61+
layer.ffn_gate = create_tensor(tn(LLM_TENSOR_FFN_GATE, "weight", i), {n_embd, n_ff}, 0);
62+
layer.ffn_down = create_tensor(tn(LLM_TENSOR_FFN_DOWN, "weight", i), { n_ff, n_embd}, 0);
63+
layer.ffn_up = create_tensor(tn(LLM_TENSOR_FFN_UP, "weight", i), {n_embd, n_ff}, 0);
64+
}
65+
66+
// Share physical weights across loops; each slot still has its own KV index.
67+
if (n_loops > 1) {
68+
for (int j = 1; j < n_loops; ++j) {
69+
for (int i = 0; i < n_phys; ++i) {
70+
layers[i + j * n_phys] = layers[i];
71+
}
72+
}
73+
}
74+
}
75+
76+
std::unique_ptr<llm_graph_context> llama_model_nanbeige::build_arch_graph(const llm_graph_params & params) const {
77+
return std::make_unique<graph>(*this, params);
78+
}
79+
80+
llama_model_nanbeige::graph::graph(const llama_model & model, const llm_graph_params & params) :
81+
llm_graph_context(params) {
82+
const auto & nb = static_cast<const llama_model_nanbeige &>(model);
83+
84+
const int64_t n_embd_head = hparams.n_embd_head_v();
85+
GGML_ASSERT(n_embd_head == hparams.n_embd_head_k());
86+
87+
const int n_phys = nb.n_layer_phys > 0 ? nb.n_layer_phys : (int) n_layer;
88+
const int n_loops = nb.n_loops > 0 ? nb.n_loops : 1;
89+
90+
ggml_tensor * cur;
91+
ggml_tensor * inpL;
92+
93+
inpL = build_inp_embd(model.tok_embd);
94+
95+
ggml_tensor * inp_pos = build_inp_pos();
96+
97+
auto * inp_attn = build_attn_inp_kv();
98+
99+
const float kq_scale = hparams.f_attention_scale == 0.0f
100+
? 1.0f / sqrtf(float(n_embd_head))
101+
: hparams.f_attention_scale;
102+
103+
ggml_tensor * inp_out_ids = build_inp_out_ids();
104+
105+
for (int il = 0; il < n_layer; ++il) {
106+
ggml_tensor * inpSA = inpL;
107+
108+
cur = build_norm(inpL, model.layers[il].attn_norm, NULL, LLM_NORM_RMS, il);
109+
cb(cur, "attn_norm", il);
110+
111+
{
112+
ggml_tensor * rope_factors = model.get_rope_factors(cparams, il);
113+
114+
auto [Qcur, Kcur, Vcur] = build_qkv(model.layers[il], cur,
115+
n_embd_head, n_head, n_head_kv, il);
116+
117+
Qcur = ggml_rope_ext(
118+
ctx0, Qcur, inp_pos, rope_factors,
119+
n_rot, rope_type, n_ctx_orig, freq_base, freq_scale,
120+
ext_factor, attn_factor, beta_fast, beta_slow);
121+
122+
Kcur = ggml_rope_ext(
123+
ctx0, Kcur, inp_pos, rope_factors,
124+
n_rot, rope_type, n_ctx_orig, freq_base, freq_scale,
125+
ext_factor, attn_factor, beta_fast, beta_slow);
126+
127+
cb(Qcur, "Qcur", il);
128+
cb(Kcur, "Kcur", il);
129+
cb(Vcur, "Vcur", il);
130+
131+
cur = build_attn(inp_attn,
132+
model.layers[il].wo, model.layers[il].wo_b, model.layers[il].wo_s,
133+
Qcur, Kcur, Vcur, nullptr, nullptr, nullptr, kq_scale, il);
134+
cb(cur, "attn_out", il);
135+
}
136+
137+
if (il == n_layer - 1 && inp_out_ids) {
138+
cur = ggml_get_rows(ctx0, cur, inp_out_ids);
139+
inpSA = ggml_get_rows(ctx0, inpSA, inp_out_ids);
140+
}
141+
142+
ggml_tensor * ffn_inp = ggml_add(ctx0, cur, inpSA);
143+
cb(ffn_inp, "ffn_inp", il);
144+
145+
cur = build_norm(ffn_inp, model.layers[il].ffn_norm, NULL, LLM_NORM_RMS, il);
146+
cb(cur, "ffn_norm", il);
147+
148+
cur = build_ffn(cur,
149+
model.layers[il].ffn_up, model.layers[il].ffn_up_b, model.layers[il].ffn_up_s,
150+
model.layers[il].ffn_gate, model.layers[il].ffn_gate_b, model.layers[il].ffn_gate_s,
151+
model.layers[il].ffn_down, model.layers[il].ffn_down_b, model.layers[il].ffn_down_s,
152+
NULL, LLM_FFN_SILU, LLM_FFN_PAR, il);
153+
cb(cur, "ffn_out", il);
154+
155+
cur = ggml_add(ctx0, cur, ffn_inp);
156+
cb(cur, "ffn_out", il);
157+
158+
cur = build_cvec(cur, il);
159+
cb(cur, "l_out", il);
160+
161+
inpL = cur;
162+
163+
if (n_loops > 1 &&
164+
((il + 1) % n_phys) == 0 &&
165+
(il + 1) < n_layer &&
166+
!nb.skip_loop_final_norm) {
167+
cur = build_norm(inpL, model.output_norm, NULL, LLM_NORM_RMS, il);
168+
cb(cur, "loop_norm", il);
169+
inpL = cur;
170+
}
171+
}
172+
173+
cur = inpL;
174+
175+
cur = build_norm(cur, model.output_norm, NULL, LLM_NORM_RMS, -1);
176+
cb(cur, "result_norm", -1);
177+
res->t_embd = cur;
178+
179+
cur = build_lora_mm(model.output, cur, model.output_s);
180+
cb(cur, "result_output", -1);
181+
res->t_logits = cur;
182+
183+
ggml_build_forward_expand(gf, cur);
184+
}

0 commit comments

Comments
 (0)