Skip to content

Commit 816bdef

Browse files
model : add Jina Embeddings v5 Nano (partial EuroBERT) support (ggml-org#19826)
* WIP: Add EuroBERT support with autoformatting changes This commit includes: - EuroBERT model implementation for GGUF conversion - C++ backend support for EuroBERT architecture - Unintended autoformatting changes to Python files Saving before reverting formatting-only changes. * feat: add back eos assert when not last token pooling * feat: removed duplicated code and cleanup * feat: removed not working architectures and unnecessary check * fix: typo * fix: dynamic pooling config * feat: added an example model for eurobert * feat: proper llama-vocab implementation for jina-v5 * fix: removed unnecessary comments
1 parent c0b29a9 commit 816bdef

12 files changed

Lines changed: 214 additions & 4 deletions

convert_hf_to_gguf.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,6 +1148,9 @@ def get_vocab_base_pre(self, tokenizer) -> str:
11481148
if chkhsh == "27949a2493fc4a9f53f5b9b029c82689cfbe5d3a1929bb25e043089e28466de6":
11491149
# ref: https://huggingface.co/jinaai/jina-embeddings-v2-base-de
11501150
res = "jina-v2-de"
1151+
if chkhsh == "a023e9fdc5a11f034d3ef515b92350e56fb2af1f66c6b6811a4444ea9bf8763d":
1152+
# ref: https://huggingface.co/jinaai/jina-embeddings-v5-text-nano
1153+
res = "jina-v5-nano"
11511154
if chkhsh == "c136ed14d01c2745d4f60a9596ae66800e2b61fa45643e72436041855ad4089d":
11521155
# ref: https://huggingface.co/abacusai/Smaug-Llama-3-70B-Instruct
11531156
res = "smaug-bpe"
@@ -6125,6 +6128,32 @@ def modify_tensors(self, data_torch, name, bid):
61256128
yield from super().modify_tensors(data_torch, name, bid)
61266129

61276130

6131+
@ModelBase.register("EuroBertModel", "JinaEmbeddingsV5Model")
6132+
class EuroBertModel(TextModel):
6133+
model_arch = gguf.MODEL_ARCH.EUROBERT
6134+
6135+
def set_vocab(self):
6136+
self.gguf_writer.add_add_bos_token(False)
6137+
self._set_vocab_gpt2()
6138+
6139+
def set_gguf_parameters(self):
6140+
super().set_gguf_parameters()
6141+
6142+
# EuroBert is bidirectional (encoder)
6143+
self.gguf_writer.add_causal_attention(False)
6144+
6145+
self.gguf_writer.add_rope_scaling_type(gguf.RopeScalingType.NONE)
6146+
6147+
self._try_set_pooling_type()
6148+
6149+
def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iterable[tuple[str, Tensor]]:
6150+
# Strip "model." prefix from tensor names
6151+
if name.startswith("model."):
6152+
name = name[6:]
6153+
6154+
yield from super().modify_tensors(data_torch, name, bid)
6155+
6156+
61286157
@ModelBase.register("XLMRobertaModel", "XLMRobertaForSequenceClassification")
61296158
class XLMRobertaModel(BertModel):
61306159
model_arch = gguf.MODEL_ARCH.BERT

convert_hf_to_gguf_update.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ class TOKENIZER_TYPE(IntEnum):
107107
{"name": "jina-v2-en", "tokt": TOKENIZER_TYPE.WPM, "repo": "https://huggingface.co/jinaai/jina-embeddings-v2-base-en", }, # WPM!
108108
{"name": "jina-v2-es", "tokt": TOKENIZER_TYPE.BPE, "repo": "https://huggingface.co/jinaai/jina-embeddings-v2-base-es", },
109109
{"name": "jina-v2-de", "tokt": TOKENIZER_TYPE.BPE, "repo": "https://huggingface.co/jinaai/jina-embeddings-v2-base-de", },
110+
{"name": "jina-v5-nano", "tokt": TOKENIZER_TYPE.BPE, "repo": "https://huggingface.co/jinaai/jina-embeddings-v5-text-nano", },
110111
{"name": "smaug-bpe", "tokt": TOKENIZER_TYPE.BPE, "repo": "https://huggingface.co/abacusai/Smaug-Llama-3-70B-Instruct", },
111112
{"name": "poro-chat", "tokt": TOKENIZER_TYPE.BPE, "repo": "https://huggingface.co/LumiOpen/Poro-34B-chat", },
112113
{"name": "jina-v2-code", "tokt": TOKENIZER_TYPE.BPE, "repo": "https://huggingface.co/jinaai/jina-embeddings-v2-base-code", },

gguf-py/gguf/constants.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@ class MODEL_ARCH(IntEnum):
379379
NEO_BERT = auto()
380380
JINA_BERT_V2 = auto()
381381
JINA_BERT_V3 = auto()
382+
EUROBERT = auto()
382383
BLOOM = auto()
383384
STABLELM = auto()
384385
QWEN = auto()
@@ -820,6 +821,7 @@ class MODEL_TENSOR(IntEnum):
820821
MODEL_ARCH.NEO_BERT: "neo-bert",
821822
MODEL_ARCH.JINA_BERT_V2: "jina-bert-v2",
822823
MODEL_ARCH.JINA_BERT_V3: "jina-bert-v3",
824+
MODEL_ARCH.EUROBERT: "eurobert",
823825
MODEL_ARCH.BLOOM: "bloom",
824826
MODEL_ARCH.STABLELM: "stablelm",
825827
MODEL_ARCH.QWEN: "qwen",
@@ -1587,6 +1589,19 @@ class MODEL_TENSOR(IntEnum):
15871589
MODEL_TENSOR.FFN_UP,
15881590
MODEL_TENSOR.LAYER_OUT_NORM,
15891591
],
1592+
MODEL_ARCH.EUROBERT: [
1593+
MODEL_TENSOR.TOKEN_EMBD,
1594+
MODEL_TENSOR.OUTPUT_NORM,
1595+
MODEL_TENSOR.ATTN_NORM,
1596+
MODEL_TENSOR.ATTN_Q,
1597+
MODEL_TENSOR.ATTN_K,
1598+
MODEL_TENSOR.ATTN_V,
1599+
MODEL_TENSOR.ATTN_OUT,
1600+
MODEL_TENSOR.FFN_NORM,
1601+
MODEL_TENSOR.FFN_GATE,
1602+
MODEL_TENSOR.FFN_UP,
1603+
MODEL_TENSOR.FFN_DOWN,
1604+
],
15901605
MODEL_ARCH.MPT: [
15911606
MODEL_TENSOR.TOKEN_EMBD,
15921607
MODEL_TENSOR.OUTPUT_NORM,

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ add_library(llama
6262
models/dream.cpp
6363
models/ernie4-5-moe.cpp
6464
models/ernie4-5.cpp
65+
models/eurobert.cpp
6566
models/exaone-moe.cpp
6667
models/exaone.cpp
6768
models/exaone4.cpp

src/llama-arch.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ static const std::map<llm_arch, const char *> LLM_ARCH_NAMES = {
2626
{ LLM_ARCH_NEO_BERT, "neo-bert" },
2727
{ LLM_ARCH_JINA_BERT_V2, "jina-bert-v2" },
2828
{ LLM_ARCH_JINA_BERT_V3, "jina-bert-v3" },
29+
{ LLM_ARCH_EUROBERT, "eurobert" },
2930
{ LLM_ARCH_BLOOM, "bloom" },
3031
{ LLM_ARCH_STABLELM, "stablelm" },
3132
{ LLM_ARCH_QWEN, "qwen" },
@@ -819,6 +820,20 @@ static std::set<llm_tensor> llm_get_tensor_names(llm_arch arch) {
819820
LLM_TENSOR_CLS,
820821
LLM_TENSOR_CLS_OUT,
821822
};
823+
case LLM_ARCH_EUROBERT:
824+
return {
825+
LLM_TENSOR_TOKEN_EMBD,
826+
LLM_TENSOR_OUTPUT_NORM,
827+
LLM_TENSOR_ATTN_NORM,
828+
LLM_TENSOR_ATTN_Q,
829+
LLM_TENSOR_ATTN_K,
830+
LLM_TENSOR_ATTN_V,
831+
LLM_TENSOR_ATTN_OUT,
832+
LLM_TENSOR_FFN_NORM,
833+
LLM_TENSOR_FFN_GATE,
834+
LLM_TENSOR_FFN_UP,
835+
LLM_TENSOR_FFN_DOWN,
836+
};
822837
case LLM_ARCH_MODERN_BERT:
823838
return {
824839
LLM_TENSOR_TOKEN_EMBD,

src/llama-arch.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ enum llm_arch {
3030
LLM_ARCH_NEO_BERT,
3131
LLM_ARCH_JINA_BERT_V2,
3232
LLM_ARCH_JINA_BERT_V3,
33+
LLM_ARCH_EUROBERT,
3334
LLM_ARCH_BLOOM,
3435
LLM_ARCH_STABLELM,
3536
LLM_ARCH_QWEN,

src/llama-model.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -979,6 +979,16 @@ void llama_model::load_hparams(llama_model_loader & ml) {
979979
type = LLM_TYPE_250M;
980980
}
981981
} break;
982+
case LLM_ARCH_EUROBERT:
983+
{
984+
ml.get_key(LLM_KV_ATTENTION_LAYERNORM_RMS_EPS, hparams.f_norm_rms_eps);
985+
ml.get_key(LLM_KV_ATTENTION_CAUSAL, hparams.causal_attn);
986+
ml.get_key(LLM_KV_POOLING_TYPE, hparams.pooling_type);
987+
988+
if (hparams.n_layer == 12) {
989+
type = LLM_TYPE_SMALL; // 0.2B
990+
}
991+
} break;
982992
case LLM_ARCH_BLOOM:
983993
{
984994
ml.get_key(LLM_KV_ATTENTION_LAYERNORM_EPS, hparams.f_norm_eps);
@@ -3570,6 +3580,29 @@ bool llama_model::load_tensors(llama_model_loader & ml) {
35703580
layer.ffn_down = create_tensor(tn(LLM_TENSOR_FFN_DOWN, "weight", i), {n_ff, n_embd}, 0);
35713581
}
35723582
} break;
3583+
case LLM_ARCH_EUROBERT:
3584+
{
3585+
tok_embd = create_tensor(tn(LLM_TENSOR_TOKEN_EMBD, "weight"), {n_embd, n_vocab}, 0);
3586+
3587+
output_norm = create_tensor(tn(LLM_TENSOR_OUTPUT_NORM, "weight"), {n_embd}, 0);
3588+
3589+
for (int i = 0; i < n_layer; ++i) {
3590+
auto & layer = layers[i];
3591+
3592+
layer.attn_norm = create_tensor(tn(LLM_TENSOR_ATTN_NORM, "weight", i), {n_embd}, 0);
3593+
3594+
layer.wq = create_tensor(tn(LLM_TENSOR_ATTN_Q, "weight", i), {n_embd, n_embd}, 0);
3595+
layer.wk = create_tensor(tn(LLM_TENSOR_ATTN_K, "weight", i), {n_embd, n_embd_gqa}, 0);
3596+
layer.wv = create_tensor(tn(LLM_TENSOR_ATTN_V, "weight", i), {n_embd, n_embd_gqa}, 0);
3597+
layer.wo = create_tensor(tn(LLM_TENSOR_ATTN_OUT, "weight", i), {n_embd, n_embd}, 0);
3598+
3599+
layer.ffn_norm = create_tensor(tn(LLM_TENSOR_FFN_NORM, "weight", i), {n_embd}, 0);
3600+
3601+
layer.ffn_gate = create_tensor(tn(LLM_TENSOR_FFN_GATE, "weight", i), {n_embd, n_ff}, 0);
3602+
layer.ffn_up = create_tensor(tn(LLM_TENSOR_FFN_UP, "weight", i), {n_embd, n_ff}, 0);
3603+
layer.ffn_down = create_tensor(tn(LLM_TENSOR_FFN_DOWN, "weight", i), {n_ff, n_embd}, 0);
3604+
}
3605+
} break;
35733606
case LLM_ARCH_JINA_BERT_V2:
35743607
{
35753608
tok_embd = create_tensor(tn(LLM_TENSOR_TOKEN_EMBD, "weight"), {n_embd, n_vocab}, 0); // word_embeddings
@@ -8181,6 +8214,7 @@ llama_memory_i * llama_model::create_memory(const llama_memory_params & params,
81818214
case LLM_ARCH_NOMIC_BERT:
81828215
case LLM_ARCH_NOMIC_BERT_MOE:
81838216
case LLM_ARCH_NEO_BERT:
8217+
case LLM_ARCH_EUROBERT:
81848218
case LLM_ARCH_WAVTOKENIZER_DEC:
81858219
case LLM_ARCH_MODERN_BERT:
81868220
case LLM_ARCH_GEMMA_EMBEDDING:
@@ -8378,6 +8412,10 @@ ggml_cgraph * llama_model::build_graph(const llm_graph_params & params) const {
83788412
{
83798413
llm = std::make_unique<llm_build_neo_bert>(*this, params);
83808414
} break;
8415+
case LLM_ARCH_EUROBERT:
8416+
{
8417+
llm = std::make_unique<llm_build_eurobert>(*this, params);
8418+
} break;
83818419
case LLM_ARCH_BLOOM:
83828420
{
83838421
llm = std::make_unique<llm_build_bloom>(*this, params);
@@ -9004,6 +9042,7 @@ llama_rope_type llama_model_rope_type(const llama_model * model) {
90049042
case LLM_ARCH_MODERN_BERT:
90059043
case LLM_ARCH_NOMIC_BERT:
90069044
case LLM_ARCH_NOMIC_BERT_MOE:
9045+
case LLM_ARCH_EUROBERT:
90079046
case LLM_ARCH_STABLELM:
90089047
case LLM_ARCH_BITNET:
90099048
case LLM_ARCH_QWEN:

src/llama-vocab.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1890,7 +1890,8 @@ void llama_vocab::impl::load(llama_model_loader & ml, const LLM_KV & kv) {
18901890
tokenizer_pre == "falcon-h1" ||
18911891
tokenizer_pre == "pixtral" ||
18921892
tokenizer_pre == "midm-2.0" ||
1893-
tokenizer_pre == "lfm2") {
1893+
tokenizer_pre == "lfm2" ||
1894+
tokenizer_pre == "jina-v5-nano") {
18941895
pre_type = LLAMA_VOCAB_PRE_TYPE_LLAMA3;
18951896
ignore_merges = true;
18961897
add_bos = true;

src/models/eurobert.cpp

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
#include "models.h"
2+
3+
llm_build_eurobert::llm_build_eurobert(const llama_model & model, const llm_graph_params & params) : llm_graph_context(params) {
4+
const int64_t n_embd_head = hparams.n_embd_head_v;
5+
6+
GGML_ASSERT(n_embd_head == hparams.n_embd_head_k);
7+
8+
ggml_tensor * cur;
9+
ggml_tensor * inpL;
10+
ggml_tensor * inp_pos = build_inp_pos();
11+
12+
inpL = build_inp_embd(model.tok_embd);
13+
cb(inpL, "inp_embd", -1);
14+
15+
auto * inp_attn = build_attn_inp_no_cache();
16+
17+
ggml_tensor * inp_out_ids = build_inp_out_ids();
18+
19+
for (int il = 0; il < n_layer; ++il) {
20+
ggml_tensor * cur = inpL;
21+
22+
cur = build_norm(inpL,
23+
model.layers[il].attn_norm, NULL,
24+
LLM_NORM_RMS, il);
25+
26+
{
27+
ggml_tensor * Qcur;
28+
ggml_tensor * Kcur;
29+
ggml_tensor * Vcur;
30+
31+
Qcur = build_lora_mm(model.layers[il].wq, cur);
32+
Kcur = build_lora_mm(model.layers[il].wk, cur);
33+
Vcur = build_lora_mm(model.layers[il].wv, cur);
34+
35+
Qcur = ggml_reshape_3d(ctx0, Qcur, n_embd_head, n_head, n_tokens);
36+
Kcur = ggml_reshape_3d(ctx0, Kcur, n_embd_head, n_head_kv, n_tokens);
37+
Vcur = ggml_reshape_3d(ctx0, Vcur, n_embd_head, n_head_kv, n_tokens);
38+
39+
Qcur = ggml_rope_ext(
40+
ctx0, Qcur, inp_pos, nullptr,
41+
n_rot, rope_type, n_ctx_orig, freq_base, freq_scale,
42+
ext_factor, attn_factor, beta_fast, beta_slow
43+
);
44+
45+
Kcur = ggml_rope_ext(
46+
ctx0, Kcur, inp_pos, nullptr,
47+
n_rot, rope_type, n_ctx_orig, freq_base, freq_scale,
48+
ext_factor, attn_factor, beta_fast, beta_slow
49+
);
50+
51+
cb(Qcur, "Qcur", il);
52+
cb(Kcur, "Kcur", il);
53+
cb(Vcur, "Vcur", il);
54+
55+
cur = build_attn(inp_attn,
56+
model.layers[il].wo, nullptr,
57+
Qcur, Kcur, Vcur, nullptr, nullptr, nullptr, 1.0f/sqrtf(float(n_embd_head)), il);
58+
cb(cur, "kqv_out", il);
59+
}
60+
61+
if (il == n_layer - 1 && inp_out_ids) {
62+
cur = ggml_get_rows(ctx0, cur, inp_out_ids);
63+
inpL = ggml_get_rows(ctx0, inpL, inp_out_ids);
64+
}
65+
66+
cur = ggml_add(ctx0, cur, inpL);
67+
68+
ggml_tensor * ffn_inp = cur;
69+
cb(ffn_inp, "ffn_inp", il);
70+
71+
cur = build_norm(ffn_inp,
72+
model.layers[il].ffn_norm, NULL,
73+
LLM_NORM_RMS, il);
74+
cb(cur, "ffn_norm", il);
75+
76+
cur = build_ffn(cur,
77+
model.layers[il].ffn_up, NULL, NULL,
78+
model.layers[il].ffn_gate, NULL, NULL,
79+
model.layers[il].ffn_down, NULL, NULL,
80+
NULL, LLM_FFN_SILU, LLM_FFN_PAR, il);
81+
cb(cur, "ffn_out", il);
82+
83+
cur = ggml_add(ctx0, cur, ffn_inp);
84+
85+
inpL = cur;
86+
}
87+
cur = inpL;
88+
89+
cur = build_norm(cur,
90+
model.output_norm, NULL,
91+
LLM_NORM_RMS, -1);
92+
93+
cb(cur, "result_embd", -1);
94+
res->t_embd = cur;
95+
96+
ggml_build_forward_expand(gf, cur);
97+
}

src/models/models.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,10 @@ struct llm_build_neo_bert : public llm_graph_context {
424424
llm_build_neo_bert(const llama_model & model, const llm_graph_params & params);
425425
};
426426

427+
struct llm_build_eurobert : public llm_graph_context {
428+
llm_build_eurobert(const llama_model & model, const llm_graph_params & params);
429+
};
430+
427431
template <bool iswa>
428432
struct llm_build_olmo2 : public llm_graph_context {
429433
llm_build_olmo2(const llama_model & model, const llm_graph_params & params);

0 commit comments

Comments
 (0)