enricollen commited on
Commit
6bd0ed7
·
verified ·
1 Parent(s): 30dfb4e

Add new ColBERT model

Browse files
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ banner.jpg filter=lfs diff=lfs merge=lfs -text
1_Dense/config.json ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ {
2
+ "in_features": 768,
3
+ "out_features": 128,
4
+ "bias": false,
5
+ "activation_function": "torch.nn.modules.linear.Identity",
6
+ "use_residual": false
7
+ }
1_Dense/model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:71027f8d3555a15591f7067c157616966ace757b17f8641c74044fa3e5ead669
3
+ size 393304
README.md ADDED
@@ -0,0 +1,390 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ language:
3
+ - it
4
+ library_name: pylate
5
+ tags:
6
+ - colbert
7
+ - late-interaction
8
+ - sentence-transformers
9
+ - italian
10
+ - retrieval
11
+ - information-retrieval
12
+ - rag
13
+ - multi-vector
14
+ pipeline_tag: sentence-similarity
15
+ license: apache-2.0
16
+ base_model: nickprock/Italian-ModernBERT-base-embed-mmarco-mnrl
17
+ ---
18
+
19
+ # ItColBERT
20
+
21
+ ![ItColBERT banner](banner.jpg)
22
+
23
+ **A monolingual Italian late-interaction retriever.** Built with
24
+ [PyLate](https://github.com/lightonai/pylate) on top of an Italian ModernBERT
25
+ backbone, for semantic search and RAG over Italian text.
26
+
27
+ *Built and maintained by Enrico Nello. Training code, evaluation harness, and
28
+ full development history: [github.com/enricollen/it-colbert](https://github.com/enricollen/it-colbert).*
29
+
30
+ ## TL;DR
31
+
32
+ - **What:** ColBERT-style multi-vector retriever, specialized on Italian.
33
+ - **Why it exists:** as far as I could find, there was no *Italian-only*
34
+ late-interaction retriever — see "Why I built this" below.
35
+ - **Size:** ModernBERT-base backbone (~150M parameters), 128-dim token vectors.
36
+ - **Best at:** short-to-medium Italian passages (search, RAG chunks, FAQ
37
+ retrieval). Weakest at long documents unless you use the chunking recipe
38
+ below.
39
+ - **Not:** multilingual, and not the strongest late-interaction model overall
40
+ — see [How it compares](#how-it-compares).
41
+
42
+ ## Why I built this
43
+
44
+ Before starting, I looked for an Italian late-interaction model and mostly
45
+ found two things: multilingual late-interaction models that *include* Italian
46
+ among many languages ([`jina-colbert-v2`](https://huggingface.co/jinaai/jina-colbert-v2),
47
+ [`mLateOn`](https://huggingface.co/lightonai/mLateOn), [`ColBERT-XM`](https://huggingface.co/antoinelouis/colbertxm),
48
+ [`SauerkrautLM-Multi-ModernColBERT`](https://huggingface.co/VAGOsolutions/SauerkrautLM-Multi-ModernColBERT)),
49
+ and strong Italian dense embedding models that give up ColBERT's token-level
50
+ matching for a single vector per passage. Nothing I found combined the two:
51
+ an Italian-specialized model that keeps late interaction. That gap is what
52
+ made me want to try building one — not "the first Italian ColBERT" (it
53
+ isn't, the models above already cover Italian), but the first one that's
54
+ *specialized* on it rather than one language among many.
55
+
56
+ ## What is late interaction, in plain terms?
57
+
58
+ Most retrieval embedding models compress a whole passage into a single
59
+ vector, so a search is one comparison per document. ColBERT-style models
60
+ instead keep one small vector **per token**, and score a document by finding
61
+ the best-matching document token for every query token (MaxSim), summing the
62
+ result. That keeps fine-grained lexical detail — rare names, specific
63
+ numbers, exact phrasing — that gets blurred away when everything is squeezed
64
+ into one vector. It costs more storage (many vectors instead of one) in
65
+ exchange for that precision.
66
+
67
+ ## What this is for
68
+
69
+ - Building a RAG retrieval stage over Italian documents.
70
+ - Semantic search over Italian text where exact wording/entities matter, not
71
+ just topic similarity.
72
+ - Reranking a first-stage retriever's candidates.
73
+
74
+ **Not** intended for: cross-lingual retrieval (query in one language,
75
+ documents in another — this model wasn't trained for it), or as a drop-in
76
+ replacement for large multilingual dense embedders when Italian isn't the
77
+ only language in your corpus.
78
+
79
+ ## Quickstart
80
+
81
+ ```bash
82
+ pip install -U pylate
83
+ ```
84
+
85
+ ### Reranking a short candidate list
86
+
87
+ The simplest usage — no index needed, good for reranking a first-stage
88
+ retriever's top results:
89
+
90
+ ```python
91
+ from pylate import rank, models
92
+
93
+ model = models.ColBERT(model_name_or_path="enricollen/ItColBERT")
94
+
95
+ queries = ["Qual è la capitale d'Italia?"]
96
+ documents = [[
97
+ "Roma è la capitale d'Italia.",
98
+ "Milano è la capitale economica del Paese.",
99
+ "Napoli è una città del sud Italia.",
100
+ ]]
101
+ documents_ids = [[1, 2, 3]]
102
+
103
+ queries_embeddings = model.encode(queries, is_query=True)
104
+ documents_embeddings = model.encode(documents, is_query=False)
105
+
106
+ reranked = rank.rerank(
107
+ documents_ids=documents_ids,
108
+ queries_embeddings=queries_embeddings,
109
+ documents_embeddings=documents_embeddings,
110
+ )
111
+ print(reranked)
112
+ # [[{'id': 1, 'score': 31.682}, {'id': 2, 'score': 31.552}, {'id': 3, 'score': 31.454}]]
113
+ # one list per query, sorted highest score first — "Roma" wins, as expected.
114
+ ```
115
+
116
+ ### Indexing a larger corpus
117
+
118
+ For anything beyond a handful of documents per query, build a persistent
119
+ index instead of reranking in memory every time:
120
+
121
+ ```python
122
+ from pylate import indexes, models, retrieve
123
+
124
+ model = models.ColBERT(model_name_or_path="enricollen/ItColBERT")
125
+
126
+ index = indexes.PLAID(
127
+ index_folder="pylate-index",
128
+ index_name="index",
129
+ override=True,
130
+ )
131
+
132
+ documents_ids = ["1", "2", "3"]
133
+ documents = ["document 1 text", "document 2 text", "document 3 text"]
134
+
135
+ documents_embeddings = model.encode(
136
+ documents, batch_size=32, is_query=False, show_progress_bar=True,
137
+ )
138
+ index.add_documents(documents_ids=documents_ids, documents_embeddings=documents_embeddings)
139
+
140
+ retriever = retrieve.ColBERT(index=index)
141
+ queries_embeddings = model.encode(
142
+ ["a query"], batch_size=32, is_query=True, show_progress_bar=True,
143
+ )
144
+ results = retriever.retrieve(queries_embeddings=queries_embeddings, k=10)
145
+ print(results)
146
+ # [[{'id': '1', 'score': 30.81}, {'id': '2', 'score': 30.80}, {'id': '3', 'score': 30.78}]]
147
+ # same shape as reranking above — list per query, sorted by score — but drawn
148
+ # from a persistent index instead of the in-memory documents you pass in.
149
+ ```
150
+
151
+ Reload an existing index later without re-encoding anything:
152
+
153
+ ```python
154
+ index = indexes.PLAID(index_folder="pylate-index", index_name="index")
155
+ ```
156
+
157
+ **Documents longer than 512 tokens are truncated at index time.** If your
158
+ corpus has long documents (articles, reports, legal text), split them into
159
+ ~2,000-character overlapping chunks, index each chunk separately, and take
160
+ the max score per source document — see [Evaluation](#evaluation) for why
161
+ this matters and how much it recovers.
162
+
163
+ ## Model details
164
+
165
+ | | |
166
+ |---|---|
167
+ | Base model | [`nickprock/Italian-ModernBERT-base-embed-mmarco-mnrl`](https://huggingface.co/nickprock/Italian-ModernBERT-base-embed-mmarco-mnrl) |
168
+ | Architecture | ModernBERT backbone (~150M params) → dense projection → 128-dim token vectors |
169
+ | Similarity | MaxSim (late interaction) |
170
+ | Query length | 32 tokens |
171
+ | Document length | 512 tokens (see the chunking note above for longer documents) |
172
+ | Language | Italian only |
173
+ | License | Apache 2.0 |
174
+ | Trained on | One RTX 3090 (24GB), Intel Core i7-14700K, 32GB RAM (27GB usable under WSL2) — no cluster |
175
+
176
+ ```
177
+ ColBERT(
178
+ (0): Transformer({'max_seq_length': 31, 'architecture': 'ModernBertModel'})
179
+ (1): Dense({'in_features': 768, 'out_features': 128, 'bias': False})
180
+ )
181
+ ```
182
+
183
+ ## Training recipe
184
+
185
+ Two stages, following the [ColBERT-Zero](https://huggingface.co/blog/lightonai/colbert-zero)
186
+ result that starting from a retrieval-capable checkpoint and running
187
+ supervised contrastive + distillation reaches ~99% of full multi-vector
188
+ pretraining at roughly a tenth of the cost — which is why this doesn't start
189
+ from a raw language model.
190
+
191
+ **1. Supervised contrastive** (`CachedContrastive`, temperature 0.02), on:
192
+
193
+ - [`unicamp-dl/mmarco`](https://huggingface.co/datasets/unicamp-dl/mmarco) — Italian triples
194
+ - [`hotchpotch/mmarco-hard-negatives-reranker-filtered`](https://huggingface.co/datasets/hotchpotch/mmarco-hard-negatives-reranker-filtered) — reranker-mined hard negatives
195
+ - [`nickprock/it-wiki-retrieval-synthetic-hn`](https://huggingface.co/datasets/nickprock/it-wiki-retrieval-synthetic-hn)
196
+ - [`yuri-no/miracl-ita-argos`](https://huggingface.co/datasets/yuri-no/miracl-ita-argos) and [`yuri-no/squad-ita`](https://huggingface.co/datasets/yuri-no/squad-ita) — community machine translations, added to widen the mix past machine-translated mMARCO
197
+
198
+ **2. Knowledge distillation** (`Distillation`, KL) from a single cross-encoder
199
+ teacher — [`lightonai/embeddings-fine-tuning-filtered-it`](https://huggingface.co/datasets/lightonai/embeddings-fine-tuning-filtered-it)
200
+ (`mxbai-rerank-large-v2` scores) — sample budget spread proportionally across
201
+ all 8 splits.
202
+
203
+ Checkpoints were selected on pooled MLDR-it nDCG@10 and mMARCO-it MRR@10, not
204
+ on hold-out KD KL divergence — that metric measures how closely the student
205
+ copies the teacher's opinion on the teacher's own data, not whether retrieval
206
+ actually improved, and in an earlier run it kept climbing while real
207
+ retrieval quality fell.
208
+
209
+ Everything here — training, benchmarking, significance testing — ran on a
210
+ single consumer GPU, no cluster. That budget shaped some choices directly:
211
+ batch/mini-batch sizes, and the fact that chunked long-document evaluation
212
+ (~26GB host RAM) runs right at this machine's ceiling.
213
+
214
+ ## How I got here
215
+
216
+ The short version of the road to this checkpoint, including the parts that
217
+ didn't work — because a model card that only shows the winning run isn't
218
+ telling the whole story:
219
+
220
+ 1. **Start from a model that already retrieves**, rather than a raw language
221
+ model — the ColBERT-Zero efficiency result above.
222
+ 2. **Broaden the training data, then distil.** The starting checkpoint only
223
+ knew machine-translated mMARCO. I added more varied Italian data and
224
+ applied a second distillation stage. This produced the model in this
225
+ repository — the strongest Italian-specialized late-interaction model I
226
+ could benchmark it against, except on long documents, which was its
227
+ weakest result.
228
+ 3. **The long-document weakness turned out to be mostly mechanical.** My
229
+ hardest benchmark's documents run a few thousand words each, and were
230
+ being cut off at 512 tokens during indexing — discarding roughly 80% of
231
+ the average document before the model ever saw it. Splitting documents
232
+ into overlapping chunks at query time, with **no retraining at all**,
233
+ recovered most of that gap (see the two MLDR-it rows below).
234
+ 4. **Two follow-up training attempts, both tested, neither beat that free
235
+ fix.** I mined harder training examples from the model's own predictions
236
+ — no improvement, and a small real drop in generalization. I then trained
237
+ a second version to read twice as much text per document instead of
238
+ relying on chunking — statistically no better than chunking a normally
239
+ -trained model, once compared fairly on held-out data.
240
+ 5. **What shipped.** Since neither training attempt beat "train normally,
241
+ then chunk long documents at query time," that's what's in this repo:
242
+ this model, plus the chunking recipe for anything longer than 512 tokens.
243
+
244
+ ## Evaluation
245
+
246
+ Four Italian retrieval benchmarks. 95% confidence intervals in brackets —
247
+ treat any gap smaller than the interval width as noise, not a real
248
+ difference.
249
+
250
+ | Benchmark | Metric | Score (95% CI) | In-domain? |
251
+ |---|---|---|---|
252
+ | MLDR-it (test, ~10k docs) | nDCG@10 | 0.4008 [0.3404, 0.4589] | No — the clean out-of-domain test |
253
+ | MLDR-it, **chunked at query time** | nDCG@10 | 0.4610 [0.4002, 0.5212] | No |
254
+ | mMARCO-it (dev, pooled 100k) | MRR@10 (rank only) | 0.7196 [0.7104, 0.7291] | Partially — mMARCO is in the training mix |
255
+ | MIRACL-ita (dev, pooled) | nDCG@10 | 0.7194 [0.6984, 0.7375] | Partially — different split of a training source |
256
+ | SQuAD-ita (test, pooled) | nDCG@10 | 0.9026 [0.8974, 0.9075] | Partially — different split of a training source |
257
+
258
+ **MLDR-it is the only clean out-of-domain benchmark, so weigh it most.** Its
259
+ documents run a median ~2,700 tokens against this model's 512-token index —
260
+ almost all of it is truncated by default. Splitting each document into
261
+ 2,000-character overlapping chunks and max-pooling scores at query time (no
262
+ retraining, ~7× the indexing cost) recovers most of the gap. Use the
263
+ truncated number if index size/latency is the constraint, the chunked number
264
+ if document coverage matters more.
265
+
266
+ ### How it compares
267
+
268
+ Same protocol, real numbers, paired-bootstrap significance tested against
269
+ this model. A **†** marks a score that is *not* statistically distinguishable
270
+ from ItColBERT (p > .05) — read those as ties, not losses or wins, regardless
271
+ of which number is higher.
272
+
273
+ | Model | MLDR-it (nDCG@10) | mMARCO-it (MRR@10) | MIRACL-ita (nDCG@10) | SQuAD-ita (nDCG@10) |
274
+ |---|---|---|---|---|
275
+ | **ItColBERT (this model)** | **0.4008** (0.4610 chunked) | **0.7196** | **0.7194** | **0.9026** |
276
+ | mLateOn | 0.4623 | 0.8207 | 0.7880 | 0.9480 |
277
+ | jina-colbert-v2 | 0.3858 † | 0.8389 | 0.7755 | 0.8849 |
278
+ | bge-m3 (dense) | 0.4531 | 0.7812 | 0.7566 | 0.8247 |
279
+ | multilingual-e5-large (dense) | 0.4310 † | 0.8239 | 0.7653 | 0.8513 |
280
+ | SauerkrautLM-Multi-ModernColBERT | 0.3122 | 0.5342 | 0.5996 | 0.8338 |
281
+ | ColBERT-XM | 0.2734 | 0.6654 | 0.6260 | 0.8558 |
282
+ | BM25 | 0.4850 (vs. ItColBERT's 0.4610 chunked: † ) | 0.5715 | 0.5516 | 0.8262 |
283
+
284
+ Reading the MLDR-it column: against BM25's 0.4850, ItColBERT's plain
285
+ 512-token number (0.4008) loses significantly — but that's comparing unequal
286
+ document access, since BM25 reads the whole document and ItColBERT reads the
287
+ first 512 tokens of it. Once ItColBERT is allowed to read the same amount of
288
+ each document (the 0.4610 chunked number), the two are a statistical tie.
289
+
290
+ In plain terms: this is the strongest **Italian-specialized**
291
+ late-interaction model I could find and benchmark against, and it beats most
292
+ general-purpose late-interaction alternatives outright. It doesn't beat the
293
+ single strongest multilingual late-interaction model I tested (mLateOn), and
294
+ it doesn't beat large multilingual dense embedders on most benchmarks —
295
+ matching those was never the goal; they're a different, much larger model
296
+ class.
297
+
298
+ **Protocol notes that matter for these numbers:**
299
+
300
+ - All late-interaction models above are indexed at the same document length
301
+ unless a row is marked "chunked".
302
+ - Pooled corpora inflate absolute scores; use them for relative ranking, not
303
+ as numbers comparable to published full-corpus results.
304
+ - MLDR-it has 200 queries — differences under ~0.03 nDCG@10 are inside the
305
+ noise. Don't read a ranking claim as established without a significance
306
+ test behind it.
307
+ - MIRACL-ita and SQuAD-ita are **community machine translations**, not
308
+ official resources, and both overlap this model's training data source
309
+ (different splits, checked for direct query leakage — none found).
310
+
311
+ ## Limitations
312
+
313
+ - Italian only. Cross-lingual retrieval isn't the goal here.
314
+ - Much of the training data derives from machine-translated mMARCO, and it
315
+ shows: short-passage retrieval is the strongest result, long-document
316
+ retrieval the weakest, even after the chunking fix.
317
+ - Documents longer than 512 tokens truncate at index time unless you chunk
318
+ and max-pool (see Quickstart and Evaluation above).
319
+ - Multi-vector indexes are larger than single-vector dense indexes, and
320
+ chunking multiplies that further — budget accordingly for large corpora.
321
+ - Behind the strongest multilingual late-interaction model I tested
322
+ (mLateOn) on every benchmark, and behind large multilingual dense
323
+ embedders on most — see "How it compares".
324
+ - Not evaluated for bias or harmful content. Usual caveats apply for a model
325
+ trained substantially on machine-translated web and QA data.
326
+
327
+ ## What's next
328
+
329
+ Not done yet, in rough priority order:
330
+
331
+ - Fusing this model's rankings with BM25 (rank fusion) — cheap, and the
332
+ chunked MLDR-it numbers above suggest it should help, since the two
333
+ disagree on individual queries while scoring about the same overall.
334
+ - Re-running the comparison table above with every model chunked, not just
335
+ this one, for a fully apples-to-apples long-document comparison.
336
+ - A smaller 64-dimension variant, for when index size matters more than the
337
+ last points of quality — planned, not trained yet.
338
+ - An MTEB-Italian-style community benchmark check, if/when suitable
339
+ multi-vector support exists in that harness.
340
+
341
+ ## Citation
342
+
343
+ If you use this model, please cite it, plus ColBERT/ColBERTv2, PyLate,
344
+ mMARCO, and MLDR below.
345
+
346
+ ```bibtex
347
+ @misc{nello2026itcolbert,
348
+ author = {Nello, Enrico},
349
+ title = {ItColBERT: A Monolingual Italian Late-Interaction Retriever},
350
+ year = {2026},
351
+ publisher = {Hugging Face},
352
+ howpublished = {\url{https://huggingface.co/enricollen/ItColBERT}},
353
+ }
354
+ ```
355
+
356
+ ```bibtex
357
+ @inproceedings{DBLP:conf/cikm/ChaffinS25,
358
+ author = {Antoine Chaffin and Rapha{\"{e}}l Sourty},
359
+ title = {PyLate: Flexible Training and Retrieval for Late Interaction Models},
360
+ booktitle = {Proceedings of the 34th {ACM} International Conference on Information
361
+ and Knowledge Management, {CIKM} 2025, Seoul, Republic of Korea, November
362
+ 10-14, 2025},
363
+ pages = {6334--6339},
364
+ publisher = {{ACM}},
365
+ year = {2025},
366
+ url = {https://github.com/lightonai/pylate},
367
+ doi = {10.1145/3746252.3761608},
368
+ }
369
+ ```
370
+
371
+ Further reading: [ColBERTv2](https://arxiv.org/abs/2112.01488),
372
+ [mMARCO](https://arxiv.org/abs/2108.13897),
373
+ [MLDR / BGE-M3](https://arxiv.org/abs/2402.03216).
374
+
375
+ ## Acknowledgments
376
+
377
+ Built on [`nickprock/Italian-ModernBERT-base-embed-mmarco-mnrl`](https://huggingface.co/nickprock/Italian-ModernBERT-base-embed-mmarco-mnrl)
378
+ and [PyLate](https://github.com/lightonai/pylate) (LightOn). Benchmarked
379
+ against [`SauerkrautLM-Multi-ModernColBERT`](https://huggingface.co/VAGOsolutions/SauerkrautLM-Multi-ModernColBERT),
380
+ [`jina-colbert-v2`](https://huggingface.co/jinaai/jina-colbert-v2),
381
+ [`mLateOn`](https://huggingface.co/lightonai/mLateOn), and
382
+ [`ColBERT-XM`](https://huggingface.co/antoinelouis/colbertxm) — thank you to
383
+ everyone building and sharing these, Italian NLP is a small enough space that
384
+ every open checkpoint helps.
385
+
386
+ ### Framework versions
387
+
388
+ Python 3.11.15 · Sentence Transformers 5.3.0 · PyLate 1.5.0 · Transformers
389
+ 5.3.0 · PyTorch 2.6.0+cu124 · Accelerate 1.14.0 · Datasets 5.0.1 · Tokenizers
390
+ 0.22.2
banner.jpg ADDED

Git LFS Details

  • SHA256: eeb6c72b770085f9109461b31fa75521cea91fdcd4b7c4738919cad8b56795d9
  • Pointer size: 131 Bytes
  • Size of remote file: 451 kB
config.json ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "ModernBertModel"
4
+ ],
5
+ "attention_bias": false,
6
+ "attention_dropout": 0.0,
7
+ "bos_token_id": 2,
8
+ "classifier_activation": "gelu",
9
+ "classifier_bias": false,
10
+ "classifier_dropout": 0.0,
11
+ "classifier_pooling": "mean",
12
+ "cls_token_id": 2,
13
+ "decoder_bias": true,
14
+ "deterministic_flash_attn": false,
15
+ "dtype": "float32",
16
+ "embedding_dropout": 0.0,
17
+ "eos_token_id": 3,
18
+ "global_attn_every_n_layers": 3,
19
+ "gradient_checkpointing": false,
20
+ "hidden_activation": "gelu",
21
+ "hidden_size": 768,
22
+ "initializer_cutoff_factor": 2.0,
23
+ "initializer_range": 0.02,
24
+ "intermediate_size": 1152,
25
+ "layer_norm_eps": 1e-05,
26
+ "layer_types": [
27
+ "full_attention",
28
+ "sliding_attention",
29
+ "sliding_attention",
30
+ "full_attention",
31
+ "sliding_attention",
32
+ "sliding_attention",
33
+ "full_attention",
34
+ "sliding_attention",
35
+ "sliding_attention",
36
+ "full_attention",
37
+ "sliding_attention",
38
+ "sliding_attention",
39
+ "full_attention",
40
+ "sliding_attention",
41
+ "sliding_attention",
42
+ "full_attention",
43
+ "sliding_attention",
44
+ "sliding_attention",
45
+ "full_attention",
46
+ "sliding_attention",
47
+ "sliding_attention",
48
+ "full_attention"
49
+ ],
50
+ "local_attention": 128,
51
+ "mask_token_id": 4,
52
+ "max_position_embeddings": 8192,
53
+ "mlp_bias": false,
54
+ "mlp_dropout": 0.0,
55
+ "model_type": "modernbert",
56
+ "norm_bias": false,
57
+ "norm_eps": 1e-05,
58
+ "num_attention_heads": 12,
59
+ "num_hidden_layers": 22,
60
+ "pad_token_id": 1,
61
+ "position_embedding_type": "absolute",
62
+ "repad_logits_with_grad": false,
63
+ "rope_parameters": {
64
+ "full_attention": {
65
+ "rope_theta": 160000.0,
66
+ "rope_type": "default"
67
+ },
68
+ "sliding_attention": {
69
+ "rope_theta": 10000.0,
70
+ "rope_type": "default"
71
+ }
72
+ },
73
+ "sep_token_id": 3,
74
+ "sparse_pred_ignore_index": -100,
75
+ "sparse_prediction": false,
76
+ "tie_word_embeddings": true,
77
+ "transformers_version": "5.3.0",
78
+ "unk_token_id": 0,
79
+ "vocab_size": 32002
80
+ }
config_sentence_transformers.json ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "__version__": {
3
+ "sentence_transformers": "5.3.0",
4
+ "transformers": "5.3.0",
5
+ "pytorch": "2.6.0+cu124"
6
+ },
7
+ "prompts": {
8
+ "query": "",
9
+ "document": ""
10
+ },
11
+ "default_prompt_name": null,
12
+ "similarity_fn_name": "MaxSim",
13
+ "query_prefix": "[Q] ",
14
+ "document_prefix": "[D] ",
15
+ "query_length": 32,
16
+ "document_length": 512,
17
+ "attend_to_expansion_tokens": false,
18
+ "skiplist_words": [
19
+ "!",
20
+ "\"",
21
+ "#",
22
+ "$",
23
+ "%",
24
+ "&",
25
+ "'",
26
+ "(",
27
+ ")",
28
+ "*",
29
+ "+",
30
+ ",",
31
+ "-",
32
+ ".",
33
+ "/",
34
+ ":",
35
+ ";",
36
+ "<",
37
+ "=",
38
+ ">",
39
+ "?",
40
+ "@",
41
+ "[",
42
+ "\\",
43
+ "]",
44
+ "^",
45
+ "_",
46
+ "`",
47
+ "{",
48
+ "|",
49
+ "}",
50
+ "~"
51
+ ],
52
+ "do_query_expansion": true
53
+ }
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:27d4cd409f50488bbb572ca7d31a9a5043c18b26719938f983e5b22696105059
3
+ size 539649784
modules.json ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "idx": 0,
4
+ "name": "0",
5
+ "path": "",
6
+ "type": "sentence_transformers.models.Transformer"
7
+ },
8
+ {
9
+ "idx": 1,
10
+ "name": "1",
11
+ "path": "1_Dense",
12
+ "type": "pylate.models.Dense.Dense"
13
+ }
14
+ ]
sentence_bert_config.json ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ {
2
+ "max_seq_length": 31,
3
+ "do_lower_case": false
4
+ }
tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer_config.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "backend": "tokenizers",
3
+ "clean_up_tokenization_spaces": true,
4
+ "cls_token": "[CLS]",
5
+ "is_local": true,
6
+ "mask_token": "[MASK]",
7
+ "max_length": 8192,
8
+ "model_input_names": [
9
+ "input_ids",
10
+ "attention_mask"
11
+ ],
12
+ "model_max_length": 511,
13
+ "pad_to_multiple_of": null,
14
+ "pad_token": "[MASK]",
15
+ "pad_token_type_id": 0,
16
+ "padding_side": "right",
17
+ "sep_token": "[SEP]",
18
+ "special_tokens": {
19
+ "cls_token": "[CLS]",
20
+ "mask_token": "[MASK]",
21
+ "pad_token": "[PAD]",
22
+ "sep_token": "[SEP]",
23
+ "unk_token": "[UNK]"
24
+ },
25
+ "stride": 0,
26
+ "tokenizer_class": "TokenizersBackend",
27
+ "truncation_side": "right",
28
+ "truncation_strategy": "longest_first",
29
+ "unk_token": "[UNK]"
30
+ }