Feature Extraction
Transformers
Safetensors
modernbert
typed-decisions
decision-index
decision-model
cross-encoder
text-embeddings-inference
Instructions to use tasksource/tasksource-decider-nano with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use tasksource/tasksource-decider-nano with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("feature-extraction", model="tasksource/tasksource-decider-nano")# pip install -U transformers accelerate # Load model directly from transformers import AutoTokenizer, AutoModel tokenizer = AutoTokenizer.from_pretrained("tasksource/tasksource-decider-nano") model = AutoModel.from_pretrained("tasksource/tasksource-decider-nano", device_map="auto") - Notebooks
- Google Colab
- Kaggle
Model card: replace copied LateOn card with the actual decision-model card
Browse files
README.md
CHANGED
|
@@ -1,371 +1,92 @@
|
|
| 1 |
---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
tags:
|
|
|
|
|
|
|
| 3 |
- ColBERT
|
| 4 |
- multi-vector
|
| 5 |
- PyLate
|
| 6 |
- sentence-transformers
|
| 7 |
-
- sentence-similarity
|
| 8 |
-
- feature-extraction
|
| 9 |
-
pipeline_tag: decision-model
|
| 10 |
-
library_name: PyLate
|
| 11 |
-
license: apache-2.0
|
| 12 |
-
language:
|
| 13 |
-
- en
|
| 14 |
---
|
| 15 |
|
| 16 |
-
|
| 17 |
-
<img src="https://cdn-uploads.huggingface.co/production/uploads/609bbe2f4932693ca2009d6a/kbQOAarw0eaApow3M9HIl.png" alt="LightOn" width="512">
|
| 18 |
-
|
| 19 |
-
[](https://lighton.ai)
|
| 20 |
-
[](https://www.linkedin.com/company/lighton/)
|
| 21 |
-
[](https://x.com/LightOnIO)
|
| 22 |
-
|
| 23 |
-
📚 [Collection](https://huggingface.co/collections/lightonai/denseon-and-lateon) | 📝 [Blog](https://huggingface.co/blog/lightonai/denseon-lateon)
|
| 24 |
-
|
| 25 |
-
</div>
|
| 26 |
-
|
| 27 |
-
<h1 align="center">LateOn</h1>
|
| 28 |
-
|
| 29 |
-
<h3 align="center">State-of-the-Art ColBERT Retrieval Model by LightOn</h3>
|
| 30 |
-
|
| 31 |
-
<p align="center">
|
| 32 |
-
<a href="https://huggingface.co/lightonai/DenseOn">DenseOn</a> |
|
| 33 |
-
<a href="https://huggingface.co/lightonai/LateOn">LateOn</a> |
|
| 34 |
-
<a href="https://github.com/lightonai/pylate">PyLate</a> |
|
| 35 |
-
<a href="https://github.com/lightonai/fast-plaid">FastPLAID</a>
|
| 36 |
-
</p>
|
| 37 |
-
|
| 38 |
-
---
|
| 39 |
-
|
| 40 |
-
## About the LateOn / DenseOn Family
|
| 41 |
-
|
| 42 |
-
State-of-the-art retrieval is increasingly dominated by closed models, either hidden behind APIs or trained on undisclosed data. This blocks reproducibility, prevents study of possible data leakage, and gatekeeps progress to a handful of private labs. We thus decided to gather and curate a large amount of data and explore various mixtures. We release all the data used in our explorations:
|
| 43 |
-
- [Gathered pre-training data](https://huggingface.co/datasets/lightonai/embeddings-pre-training), 1.4B query-documents pairs alongside annotations used for non-destructive filtering (structural filtering, deduplication, cross-encoder pair relevancy)
|
| 44 |
-
- [Best pre-training mixture](https://huggingface.co/datasets/lightonai/embeddings-pre-training-curated) found with already applied filters
|
| 45 |
-
- [Fine-tuning datasets](https://huggingface.co/datasets/lightonai/embeddings-fine-tuning) with query, positive and 2048 mined documents alongside their scores for 1.88M samples.
|
| 46 |
-
|
| 47 |
-
Based on our findings, we trained LateOn (multi-vector/ColBERT) and DenseOn (single vector/dense) models on a proprietary Apache 2.0-compatible training dataset and release those models as well.
|
| 48 |
-
Both are built on the [ModernBERT](https://huggingface.co/answerdotai/ModernBERT-base) backbone at 149M parameters, a size we believe sits at the sweet spot: large enough to handle real-world queries and documents, small enough to serve at high throughput in latency-sensitive production systems.
|
| 49 |
-
For more information, please read our [blogpost](https://huggingface.co/blog/lightonai/denseon-lateon).
|
| 50 |
-
|
| 51 |
-
## LateOn
|
| 52 |
-
**LateOn** is a ColBERT (multi-vector) retrieval model built on ModernBERT (149M parameters), trained by [LightOn](https://lighton.ai) using [PyLate](https://github.com/lightonai/pylate). This is the supervised version, fine-tuned with hard-negative contrastive training. The unsupervised version can be found [here](https://huggingface.co/lightonai/LateOn-unsupervised)
|
| 53 |
-
|
| 54 |
-
Notably it:
|
| 55 |
|
| 56 |
-
|
| 57 |
-
- **Holds up under decontamination**: when training-overlap samples are stripped from the BEIR corpora, LateOn climbs to **60.36 nDCG@10** on the 12-dataset decontaminated split — first place overall.
|
| 58 |
-
- **Uses fully open data** for both pre-training and fine-tuning, with all signals released as metadata so you can rebuild, extend, or replace any filter.
|
| 59 |
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
LateOn achieves **57.22** average NDCG@10 on BEIR (15 datasets) and **60.36** on decontaminated BEIR (12 datasets), leading all ColBERT models. See our [blog post](https://huggingface.co/blog/lightonai/denseon-lateon) for full results and analysis.
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
Alongside LateOn, we also trained [DenseOn](https://huggingface.co/lightonai/DenseOn), a dense (single vector) variant, trained on the same setup. This variant is easier and cheaper to use, albeit with slightly weaker results (achieving a score of 56.20 on BEIR, it is still stronger than any dense base-sized model). It may also suffer from some limitations compared to LateOn, such as in terms of generalisation and long context.
|
| 66 |
-
|
| 67 |
-
## Results
|
| 68 |
-
|
| 69 |
-
### BEIR (15 datasets, NDCG@10)
|
| 70 |
-
|
| 71 |
-
| Model | Average | Size (M) | Embed dim | ArguAna | CQADupstackRetrieval | ClimateFEVER | DBPedia | FEVER | FiQA2018 | HotpotQA | MSMARCO | NFCorpus | NQ | QuoraRetrieval | SCIDOCS | SciFact | TRECCOVID | Touche2020 |
|
| 72 |
-
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
| 73 |
-
| [ColBERTv2](https://huggingface.co/colbert-ir/colbertv2.0) | 48.63 | 110 | 128 | 46.50 | *38.30* | 17.60 | 45.20 | 78.50 | 35.40 | 67.50 | *46.00* | 33.70 | 52.40 | 85.50 | 15.40 | 68.90 | 72.60 | 26.00 |
|
| 74 |
-
| [Jina-ColBERT-v2](https://huggingface.co/jinaai/jina-colbert-v2) | 51.85 | 600 | 128 | 36.60 | *40.80* | 23.90 | 47.10 | 80.50 | 40.80 | 76.60 | **46.90** | 34.60 | **64.00** | 88.70 | 18.60 | 67.80 | 83.40 | 27.40 |
|
| 75 |
-
| [ColBERT-small](https://huggingface.co/answerdotai/answerai-colbert-small-v1) | 53.79 | 33 | 96 | 50.09 | 38.75 | 33.07 | 45.58 | 90.96 | 41.15 | 76.11 | 43.50 | 37.30 | 59.10 | 87.72 | 18.42 | 74.77 | 84.59 | 25.69 |
|
| 76 |
-
| [GTE-ModernColBERT-v1](https://huggingface.co/lightonai/GTE-ModernColBERT-v1) | 54.75 | 149 | 128 | 47.52 | 41.08 | 31.33 | 47.56 | 87.67 | 45.25 | 77.48 | 45.60 | 37.83 | 61.62 | 86.71 | 19.22 | 76.33 | **84.84** | 31.25 |
|
| 77 |
-
| [ColBERT-Zero](https://huggingface.co/lightonai/ColBERT-Zero) | 55.39 | 149 | 128 | **52.82** | 41.41 | 35.90 | 47.43 | 90.52 | 42.50 | 79.45 | 45.95 | 37.21 | 61.82 | 85.19 | 19.84 | 76.33 | 78.27 | **36.24** |
|
| 78 |
-
| [LateOn-unsupervised](https://huggingface.co/lightonai/LateOn-unsupervised) | 50.11 | 149 | 128 | 43.12 | **47.71** | 18.76 | 43.36 | 65.74 | 51.94 | 68.17 | 37.51 | 37.15 | 58.41 | 89.48 | 21.13 | **76.89** | 69.81 | 22.53 |
|
| 79 |
-
| [LateOn](https://huggingface.co/lightonai/LateOn) | **57.22** | 149 | 128 | 50.52 | 47.36 | **39.67** | 45.99 | **92.02** | **53.12** | **79.98** | 45.67 | 37.79 | 63.91 | **89.67** | **21.90** | 76.61 | 83.60 | 30.52 |
|
| 80 |
-
|
| 81 |
-
LateOn achieves 57.22 average NDCG@10, becoming the first ColBERT (and sub 150M parameter) model to break the 57 mark on BEIR by surpassing the previous best ColBERT model (ColBERT-Zero at 55.32) by almost two points and exceeding GTE-ModernColBERT-v1 by two point and a half, despite sharing the same backbone.
|
| 82 |
-
It is worth noting that we achieve this performance only with contrastive data and without the use of the prompt (which has been shown to be beneficial in the ColBERT-Zero study but makes it harder and more expensive to use). This work was focused on an exploration of contrastive data, but we believe we can achieve much stronger results through a KD phase and the addition of prompts to serve as query expansion.
|
| 83 |
-
Given such strong performances, one fair concern would be overfitting to BEIR. As highlighted in the decontaminated BEIR experiments, our models stay very strong on benches curated from any possible data leakage, especially in the multi-vector case and contrary to some other models.
|
| 84 |
-
|
| 85 |
-
### Decontaminated BEIR (12 datasets, NDCG@10)
|
| 86 |
-
|
| 87 |
-
Standard benchmarks risk overestimating model quality when training data overlaps with evaluation corpora. This is a non-negligible risk in our case, as our mixture explorations are mostly built on BEIR evaluation. To quantify this and ensure that our model has not memorized possible leakage, we built decontaminated versions of the BEIR datasets by removing samples found in both the mGTE training dataset and in our internal training datasets.
|
| 88 |
-
Since many retrieval models draw from similar public sources (Wikipedia, MS MARCO, Common Crawl, academic corpora), we expect significant overlap across models and believe the decontaminated benchmarks provide a meaningful, if imperfect, stress test. The decontaminated datasets are publicly available on HuggingFace.
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
Despite being in the toughest position (as the decontamination is based on our data), LateOn and DenseOn stay consistent under decontamination.
|
| 92 |
-
LateOn keeps its #1 position and DenseOn stays in the top four (only falling behind our other strong multi-vector model, ColBERT-Zero). Neither model flinches, which is direct evidence of generalization rather than overfitting.
|
| 93 |
-
|
| 94 |
-
More broadly, ColBERT models seems to generalize better under decontamination: all three ColBERT models hold or improve their ranking, and they take 2 of the top 3 decontaminated positions. Although DenseOn holds strong, some dense models are hit harder, for example `GTE-ModernBERT`, dropping from 8th to last, which is particularly interesting considering our base mixture is derived from theirs. This highlights the strength of our curation methodology. While other models such as `Qwen3-Embedding-0.6B` also drop some ranks, hinting at an overlap with the BEIR evaluation, it is worth noting that newer models, such as the new `jina-embeddings-v5` and `pplx-embed-v1-0.6b` seems to exhibit stronger evidence of generalization rather than overfitting.
|
| 95 |
-
|
| 96 |
-
<div align="center">
|
| 97 |
-
<img src="https://cdn-uploads.huggingface.co/production/uploads/61dd91afdb45389905634d35/9kMmY66jIZsLxrQ6a7v3L.png" alt="LightOn" width="1024">
|
| 98 |
-
</div>
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
## Related Checkpoints
|
| 102 |
-
|
| 103 |
-
| Model | Stage | Link |
|
| 104 |
-
|:---|:---|:---|
|
| 105 |
-
| **LateOn** *(this card)* | Pre-training + fine-tuning *(recommended)* | [`lightonai/LateOn`](https://huggingface.co/lightonai/LateOn) |
|
| 106 |
-
| LateOn-unsupervised | Pre-training only | [`lightonai/LateOn-unsupervised`](https://huggingface.co/lightonai/LateOn-unsupervised) |
|
| 107 |
-
| DenseOn | Single-vector counterpart | [`lightonai/DenseOn`](https://huggingface.co/lightonai/DenseOn) |
|
| 108 |
-
| DenseOn-unsupervised | Single-vector, pre-training only | [`lightonai/DenseOn-unsupervised`](https://huggingface.co/lightonai/DenseOn-unsupervised) |
|
| 109 |
-
|
| 110 |
-
## Model Details
|
| 111 |
-
|
| 112 |
-
### Model Description
|
| 113 |
-
- **Model Type:** PyLate ColBERT model
|
| 114 |
-
- **Base model:** [LateOn-unsupervised](https://huggingface.co/lightonai/LateOn-unsupervised) (ModernBERT-base)
|
| 115 |
-
- **Document Length:** 300 tokens
|
| 116 |
-
- **Query Length:** 32 tokens
|
| 117 |
-
- **Output Dimensionality:** 128 tokens
|
| 118 |
-
- **Similarity Function:** MaxSim
|
| 119 |
-
- **Language:** English
|
| 120 |
-
- **License:** Apache 2.0
|
| 121 |
-
|
| 122 |
-
### Model Sources
|
| 123 |
-
|
| 124 |
-
- **Documentation:** [PyLate Documentation](https://lightonai.github.io/pylate/)
|
| 125 |
-
- **Repository:** [PyLate on GitHub](https://github.com/lightonai/pylate)
|
| 126 |
-
- **Hugging Face:** [PyLate models on Hugging Face](https://huggingface.co/models?library=PyLate)
|
| 127 |
-
|
| 128 |
-
### Full Model Architecture
|
| 129 |
|
| 130 |
```
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
(2): Dense({'in_features': 1536, 'out_features': 768, 'bias': False, 'activation_function': 'torch.nn.modules.linear.Identity', 'use_residual': True})
|
| 135 |
-
(3): Dense({'in_features': 768, 'out_features': 128, 'bias': False, 'activation_function': 'torch.nn.modules.linear.Identity', 'use_residual': False})
|
| 136 |
-
)
|
| 137 |
```
|
| 138 |
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
### Sentence Transformers
|
| 142 |
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
```bash
|
| 146 |
-
pip install "sentence-transformers>=6.0.0"
|
| 147 |
-
```
|
| 148 |
-
|
| 149 |
-
```python
|
| 150 |
-
from sentence_transformers import MultiVectorEncoder
|
| 151 |
-
|
| 152 |
-
model = MultiVectorEncoder("lightonai/LateOn")
|
| 153 |
-
|
| 154 |
-
query = "Which planet is known as the Red Planet?"
|
| 155 |
-
documents = [
|
| 156 |
-
"Venus is often called Earth's twin because of its similar size and proximity.",
|
| 157 |
-
"Mars, known for its reddish appearance, is often referred to as the Red Planet.",
|
| 158 |
-
"Jupiter, the largest planet in our solar system, has a prominent red spot.",
|
| 159 |
-
"Saturn, famous for its rings, is sometimes mistaken for the Red Planet.",
|
| 160 |
-
]
|
| 161 |
-
|
| 162 |
-
query_embeddings = model.encode_query(query)
|
| 163 |
-
document_embeddings = model.encode_document(documents)
|
| 164 |
-
print(query_embeddings.shape, document_embeddings[0].shape)
|
| 165 |
-
# (12, 128) (18, 128)
|
| 166 |
-
|
| 167 |
-
# MaxSim late-interaction scoring (higher is more relevant)
|
| 168 |
-
scores = model.similarity(query_embeddings, document_embeddings)
|
| 169 |
-
print(scores)
|
| 170 |
-
# tensor([[10.7942, 11.1104, 10.9743, 11.0811]])
|
| 171 |
-
```
|
| 172 |
-
|
| 173 |
-
### PyLate
|
| 174 |
-
|
| 175 |
-
First install the PyLate library:
|
| 176 |
-
|
| 177 |
-
```bash
|
| 178 |
-
pip install -U pylate
|
| 179 |
-
```
|
| 180 |
-
|
| 181 |
-
### Retrieval
|
| 182 |
-
|
| 183 |
-
Use this model with PyLate to index and retrieve documents. The index uses [FastPLAID](https://github.com/lightonai/fast-plaid) for efficient similarity search.
|
| 184 |
-
|
| 185 |
-
#### Indexing documents
|
| 186 |
-
|
| 187 |
-
Load the ColBERT model and initialize the PLAID index, then encode and index your documents:
|
| 188 |
-
|
| 189 |
-
```python
|
| 190 |
-
from pylate import indexes, models, retrieve
|
| 191 |
-
|
| 192 |
-
# Step 1: Load the ColBERT model
|
| 193 |
-
model = models.ColBERT(
|
| 194 |
-
model_name_or_path="lightonai/LateOn",
|
| 195 |
-
)
|
| 196 |
-
|
| 197 |
-
# Step 2: Initialize the PLAID index
|
| 198 |
-
index = indexes.PLAID(
|
| 199 |
-
index_folder="pylate-index",
|
| 200 |
-
index_name="index",
|
| 201 |
-
override=True, # This overwrites the existing index if any
|
| 202 |
-
)
|
| 203 |
-
|
| 204 |
-
# Step 3: Encode the documents
|
| 205 |
-
documents_ids = ["1", "2", "3"]
|
| 206 |
-
documents = ["document 1 text", "document 2 text", "document 3 text"]
|
| 207 |
-
|
| 208 |
-
documents_embeddings = model.encode(
|
| 209 |
-
documents,
|
| 210 |
-
batch_size=32,
|
| 211 |
-
is_query=False, # Ensure that it is set to False to indicate that these are documents, not queries
|
| 212 |
-
show_progress_bar=True,
|
| 213 |
-
)
|
| 214 |
-
|
| 215 |
-
# Step 4: Add document embeddings to the index by providing embeddings and corresponding ids
|
| 216 |
-
index.add_documents(
|
| 217 |
-
documents_ids=documents_ids,
|
| 218 |
-
documents_embeddings=documents_embeddings,
|
| 219 |
-
)
|
| 220 |
-
```
|
| 221 |
-
|
| 222 |
-
Note that you do not have to recreate the index and encode the documents every time. Once you have created an index and added the documents, you can re-use the index later by loading it:
|
| 223 |
-
|
| 224 |
-
```python
|
| 225 |
-
# To load an index, simply instantiate it with the correct folder/name and without overriding it
|
| 226 |
-
index = indexes.PLAID(
|
| 227 |
-
index_folder="pylate-index",
|
| 228 |
-
index_name="index",
|
| 229 |
-
)
|
| 230 |
-
```
|
| 231 |
-
|
| 232 |
-
#### Retrieving top-k documents for queries
|
| 233 |
-
|
| 234 |
-
Once the documents are indexed, you can retrieve the top-k most relevant documents for a given set of queries.
|
| 235 |
-
To do so, initialize the ColBERT retriever with the index you want to search in, encode the queries and then retrieve the top-k documents to get the top matches ids and relevance scores:
|
| 236 |
-
|
| 237 |
-
```python
|
| 238 |
-
# Step 1: Initialize the ColBERT retriever
|
| 239 |
-
retriever = retrieve.ColBERT(index=index)
|
| 240 |
-
|
| 241 |
-
# Step 2: Encode the queries
|
| 242 |
-
queries_embeddings = model.encode(
|
| 243 |
-
["query for document 3", "query for document 1"],
|
| 244 |
-
batch_size=32,
|
| 245 |
-
is_query=True, # Ensure that it is set to True to indicate that these are queries
|
| 246 |
-
show_progress_bar=True,
|
| 247 |
-
)
|
| 248 |
-
|
| 249 |
-
# Step 3: Retrieve top-k documents
|
| 250 |
-
scores = retriever.retrieve(
|
| 251 |
-
queries_embeddings=queries_embeddings,
|
| 252 |
-
k=10, # Retrieve the top 10 matches for each query
|
| 253 |
-
)
|
| 254 |
-
```
|
| 255 |
-
|
| 256 |
-
### Reranking
|
| 257 |
-
If you only want to use the ColBERT model to perform reranking on top of your first-stage retrieval pipeline without building an index, you can simply use rank function and pass the queries and documents to rerank:
|
| 258 |
|
| 259 |
```python
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
"query A",
|
| 264 |
-
"query B",
|
| 265 |
-
]
|
| 266 |
-
|
| 267 |
-
documents = [
|
| 268 |
-
["document A", "document B"],
|
| 269 |
-
["document 1", "document C", "document B"],
|
| 270 |
-
]
|
| 271 |
|
| 272 |
-
|
| 273 |
-
|
| 274 |
-
[1, 3, 2],
|
| 275 |
-
]
|
| 276 |
|
| 277 |
-
|
| 278 |
-
|
| 279 |
-
)
|
|
|
|
|
|
|
| 280 |
|
| 281 |
-
|
| 282 |
-
|
| 283 |
-
is_query=True,
|
| 284 |
-
)
|
| 285 |
-
|
| 286 |
-
documents_embeddings = model.encode(
|
| 287 |
-
documents,
|
| 288 |
-
is_query=False,
|
| 289 |
-
)
|
| 290 |
-
|
| 291 |
-
reranked_documents = rank.rerank(
|
| 292 |
-
documents_ids=documents_ids,
|
| 293 |
-
queries_embeddings=queries_embeddings,
|
| 294 |
-
documents_embeddings=documents_embeddings,
|
| 295 |
-
)
|
| 296 |
```
|
| 297 |
|
|
|
|
| 298 |
|
| 299 |
-
|
| 300 |
|
| 301 |
-
##
|
| 302 |
-
- Python: 3.11.10
|
| 303 |
-
- Sentence Transformers: 5.1.1
|
| 304 |
-
- PyLate: 1.3.4
|
| 305 |
-
- Transformers: 4.57.5
|
| 306 |
-
- PyTorch: 2.9.0+cu128
|
| 307 |
-
- Accelerate: 1.12.0
|
| 308 |
-
- Datasets: 3.6.0
|
| 309 |
-
- Tokenizers: 0.22.1
|
| 310 |
|
| 311 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 312 |
|
| 313 |
-
##
|
| 314 |
|
| 315 |
-
|
| 316 |
|
| 317 |
-
|
| 318 |
-
|
| 319 |
-
|
| 320 |
-
|
| 321 |
-
year={2026},
|
| 322 |
-
howpublished={\url{https://huggingface.co/blog/lightonai/denseon-lateon}},
|
| 323 |
-
}
|
| 324 |
-
```
|
| 325 |
|
| 326 |
-
|
| 327 |
|
| 328 |
-
|
| 329 |
-
@inproceedings{DBLP:conf/cikm/ChaffinS25,
|
| 330 |
-
author = {Antoine Chaffin and
|
| 331 |
-
Rapha{\"{e}}l Sourty},
|
| 332 |
-
editor = {Meeyoung Cha and
|
| 333 |
-
Chanyoung Park and
|
| 334 |
-
Noseong Park and
|
| 335 |
-
Carl Yang and
|
| 336 |
-
Senjuti Basu Roy and
|
| 337 |
-
Jessie Li and
|
| 338 |
-
Jaap Kamps and
|
| 339 |
-
Kijung Shin and
|
| 340 |
-
Bryan Hooi and
|
| 341 |
-
Lifang He},
|
| 342 |
-
title = {PyLate: Flexible Training and Retrieval for Late Interaction Models},
|
| 343 |
-
booktitle = {Proceedings of the 34th {ACM} International Conference on Information
|
| 344 |
-
and Knowledge Management, {CIKM} 2025, Seoul, Republic of Korea, November
|
| 345 |
-
10-14, 2025},
|
| 346 |
-
pages = {6334--6339},
|
| 347 |
-
publisher = {{ACM}},
|
| 348 |
-
year = {2025},
|
| 349 |
-
url = {https://github.com/lightonai/pylate},
|
| 350 |
-
doi = {10.1145/3746252.3761608},
|
| 351 |
-
}
|
| 352 |
-
```
|
| 353 |
|
| 354 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 355 |
|
| 356 |
-
|
| 357 |
-
@inproceedings{reimers-2019-sentence-bert,
|
| 358 |
-
title = "Sentence-BERT: Sentence Embeddings using Siamese BERT-Networks",
|
| 359 |
-
author = "Reimers, Nils and Gurevych, Iryna",
|
| 360 |
-
booktitle = "Proceedings of the 2019 Conference on Empirical Methods in Natural Language Processing",
|
| 361 |
-
month = "11",
|
| 362 |
-
year = "2019",
|
| 363 |
-
publisher = "Association for Computational Linguistics",
|
| 364 |
-
url = "https://arxiv.org/abs/1908.10084"
|
| 365 |
-
}
|
| 366 |
-
```
|
| 367 |
-
## Acknowledgements
|
| 368 |
|
| 369 |
-
|
| 370 |
|
| 371 |
-
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
license: apache-2.0
|
| 3 |
+
language:
|
| 4 |
+
- en
|
| 5 |
+
library_name: PyLate
|
| 6 |
+
pipeline_tag: decision-model
|
| 7 |
+
base_model: lightonai/LateOn
|
| 8 |
+
datasets:
|
| 9 |
+
- tasksource/tasksource-jev-typed-decisions
|
| 10 |
tags:
|
| 11 |
+
- decision-model
|
| 12 |
+
- jev
|
| 13 |
- ColBERT
|
| 14 |
- multi-vector
|
| 15 |
- PyLate
|
| 16 |
- sentence-transformers
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
---
|
| 18 |
|
| 19 |
+
# tasksource-jev-nano-v1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
|
| 21 |
+
A **149M-parameter decision model**. Given a state, a question and a set of options, it returns a probability for each option. It follows the "Jev-style" typed-decision interface (choice / noul) and is evaluated on the [Decision Index](https://huggingface.co/spaces/multimodalart/jev-decision-index).
|
|
|
|
|
|
|
| 22 |
|
| 23 |
+
It is [LateOn](https://huggingface.co/lightonai/LateOn) (ModernBERT-base, ColBERT multi-vector), fine-tuned on Tasksource typed decisions. Options are scored by **late interaction**:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
|
| 25 |
```
|
| 26 |
+
context = state + "\nQuestion: " + question → encoded once (ColBERT document side)
|
| 27 |
+
option_i → encoded independently (ColBERT query side)
|
| 28 |
+
logit_i = MaxSim(option_i, context) / T → softmax over options (T = 0.3168)
|
|
|
|
|
|
|
|
|
|
| 29 |
```
|
| 30 |
|
| 31 |
+
The context never sees the options, so you can encode a state once and score any number of options against it. This also makes the scores permutation-equivariant.
|
|
|
|
|
|
|
| 32 |
|
| 33 |
+
## Usage
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
|
| 35 |
```python
|
| 36 |
+
import torch
|
| 37 |
+
from pylate import models
|
| 38 |
+
from pylate.scores import colbert_scores
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
|
| 40 |
+
model = models.ColBERT("tasksource/tasksource-jev-nano-v1")
|
| 41 |
+
T = 0.31683406233787537 # learned temperature (decision_meta.json: init_temperature)
|
|
|
|
|
|
|
| 42 |
|
| 43 |
+
def decide(state, question, options):
|
| 44 |
+
ctx = model.encode([f"{state}\nQuestion: {question}"], is_query=False)[0]
|
| 45 |
+
opts = model.encode(options, is_query=True)
|
| 46 |
+
scores = torch.stack([colbert_scores(torch.as_tensor(o)[None], torch.as_tensor(ctx)[None])[0, 0] for o in opts])
|
| 47 |
+
return dict(zip(options, torch.softmax(scores / T, 0).tolist()))
|
| 48 |
|
| 49 |
+
decide("The movie was a total waste of two hours.", "What is the sentiment?", ["positive", "negative"])
|
| 50 |
+
# {'positive': 0.0088, 'negative': 0.9912}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
```
|
| 52 |
|
| 53 |
+
This snippet reproduces our evaluation engine's probabilities exactly. For **noul** (yes/no) questions, score the two options `false` and `true` and report P(true).
|
| 54 |
|
| 55 |
+
When an option has both a key and a description, the engine renders it as `"key: description"`, or as the description alone when the key is a placeholder like `A` or `option_1`.
|
| 56 |
|
| 57 |
+
## Training
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
|
| 59 |
+
- **Init:** `lightonai/LateOn`.
|
| 60 |
+
- **Data:** grouped requests (one state, 1–5 questions, 2–235 options each) from [tasksource-jev-typed-decisions](https://huggingface.co/datasets/tasksource/tasksource-jev-typed-decisions), covering 503 Tasksource training tasks.
|
| 61 |
+
- Training used a 64k-request **double-firewalled** manifest: every row that fingerprint-matches a Decision Index suite row was removed before training.
|
| 62 |
+
- **Recipe:**
|
| 63 |
+
- Stage 1: 4,000 steps of grouped MaxSim training with soft cross-entropy over options and a learned temperature.
|
| 64 |
+
- Stage 2: continued for 400 steps with *question packing* at p=0.5 (several questions share one context half the time).
|
| 65 |
+
- **Checkpoint selection:** NLL on a held-out set of unseen Tasksource tasks.
|
| 66 |
|
| 67 |
+
## Decision Index results (public index)
|
| 68 |
|
| 69 |
+
These are scores on the **public** part of the Decision Index, run with the official kit: full suite, 100% coverage, chance-corrected skill, 0–100.
|
| 70 |
|
| 71 |
+
| Edition | Public index (skill) | Raw |
|
| 72 |
+
|---|---|---|
|
| 73 |
+
| 0.3 | **10.84** | 33.12 |
|
| 74 |
+
| 0.2.1 | 10.46 | 32.09 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 75 |
|
| 76 |
+
0.3 areas (skill): Knowledge & Reasoning 2.2 · Language Understanding 5.0 · Retrieval & Classification 23.5 · Tools & Automation 13.6 · Arts & Human Taste 17.7.
|
| 77 |
|
| 78 |
+
**This is not the board's headline number.** From 0.3 on, the board ranks a *Full* score:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 79 |
|
| 80 |
+
| Part | Weight | Who runs it |
|
| 81 |
+
|---|---|---|
|
| 82 |
+
| Public index | 20% | Anyone, with the kit; the table above |
|
| 83 |
+
| Private tests of the same skills | 50% | Maintainers |
|
| 84 |
+
| Private tasks from new domains | 30% | Maintainers |
|
| 85 |
|
| 86 |
+
We do not have this model's Full score; see the board for it once it has been scored.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 87 |
|
| 88 |
+
## Limitations
|
| 89 |
|
| 90 |
+
- **Small model, broad but shallow.** It does well on retrieval, classification and tool selection. Knowledge and reasoning are near chance: 149M parameters do not store much world knowledge.
|
| 91 |
+
- **Typed decisions only.** It handles `choice` and `noul`. It does not generate text, and it does not natively produce scores or multilabel outputs.
|
| 92 |
+
- **English only.**
|