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
v4: same recipe trained for 48,000 steps on 480k requests (Decision Index 0.3 public 30.90); v3 kept at tag v3
Browse files- README.md +14 -13
- decider.py +25 -6
- decider_config.json +6 -4
- model.safetensors +2 -2
README.md
CHANGED
|
@@ -8,14 +8,15 @@ datasets:
|
|
| 8 |
tags:
|
| 9 |
- typed-decisions
|
| 10 |
- decision-index
|
| 11 |
-
- cross-encoder
|
| 12 |
- decision-model
|
|
|
|
| 13 |
---
|
| 14 |
|
| 15 |
# tasksource-decider-nano
|
| 16 |
|
| 17 |
-
This repository was `tasksource/tasksource-jev-nano-v1`. Its `main` (tag `
|
| 18 |
-
|
|
|
|
| 19 |
[`v2`](https://huggingface.co/tasksource/tasksource-decider-nano/tree/v2), and the previous multi-vector model at tag
|
| 20 |
[`v1`](https://huggingface.co/tasksource/tasksource-decider-nano/tree/v1).
|
| 21 |
|
|
@@ -25,9 +26,9 @@ generate text.
|
|
| 25 |
|
| 26 |
| | |
|
| 27 |
|---|---|
|
| 28 |
-
| Decision Index 0.3, public index | **
|
| 29 |
| Requests | 140,171 `ok`, 7 `unsupported` (pairs above 8,192 tokens) |
|
| 30 |
-
| Latency, 1× NVIDIA A10 23 GB, one request at a time | median
|
| 31 |
| Complete results | [runs/tasksource-decider-nano](https://huggingface.co/datasets/tasksource/decision-index-results/tree/main/runs/tasksource-decider-nano) |
|
| 32 |
|
| 33 |
## Architecture
|
|
@@ -67,8 +68,8 @@ python -m decision_index pipeline --engine decision_index_engine:DeciderEngine \
|
|
| 67 |
|
| 68 |
## Training
|
| 69 |
|
| 70 |
-
|
| 71 |
-
cross-entropy over each question's options. The training mix has
|
| 72 |
|
| 73 |
| Share | Source |
|
| 74 |
|---:|---|
|
|
@@ -87,10 +88,10 @@ request.
|
|
| 87 |
|
| 88 |
| Area | Skill | Raw |
|
| 89 |
|---|---:|---:|
|
| 90 |
-
| Knowledge & Reasoning |
|
| 91 |
-
| Language Understanding |
|
| 92 |
-
| Retrieval & Classification |
|
| 93 |
-
| Tools & Automation | 43.
|
| 94 |
-
| Arts & Human Taste |
|
| 95 |
|
| 96 |
-
Raw index
|
|
|
|
| 8 |
tags:
|
| 9 |
- typed-decisions
|
| 10 |
- decision-index
|
|
|
|
| 11 |
- decision-model
|
| 12 |
+
- cross-encoder
|
| 13 |
---
|
| 14 |
|
| 15 |
# tasksource-decider-nano
|
| 16 |
|
| 17 |
+
This repository was `tasksource/tasksource-jev-nano-v1`. Its `main` (tag `v4`) is the joint cross-encoder trained for
|
| 18 |
+
48,000 steps. The same recipe at 24,000 steps (public index 29.05) stays at tag
|
| 19 |
+
[`v3`](https://huggingface.co/tasksource/tasksource-decider-nano/tree/v3), at 12,000 steps (26.77) at tag
|
| 20 |
[`v2`](https://huggingface.co/tasksource/tasksource-decider-nano/tree/v2), and the previous multi-vector model at tag
|
| 21 |
[`v1`](https://huggingface.co/tasksource/tasksource-decider-nano/tree/v1).
|
| 22 |
|
|
|
|
| 26 |
|
| 27 |
| | |
|
| 28 |
|---|---|
|
| 29 |
+
| Decision Index 0.3, public index | **30.90** |
|
| 30 |
| Requests | 140,171 `ok`, 7 `unsupported` (pairs above 8,192 tokens) |
|
| 31 |
+
| Latency, 1× NVIDIA A10 23 GB, one request at a time | median 52 ms · mean 65 ms · p80 63 ms |
|
| 32 |
| Complete results | [runs/tasksource-decider-nano](https://huggingface.co/datasets/tasksource/decision-index-results/tree/main/runs/tasksource-decider-nano) |
|
| 33 |
|
| 34 |
## Architecture
|
|
|
|
| 68 |
|
| 69 |
## Training
|
| 70 |
|
| 71 |
+
48,000 steps, batches of 8 requests, learning rate 2e-5, inputs up to 2,048 tokens, seed 7. The loss is soft
|
| 72 |
+
cross-entropy over each question's options. The training mix has 480,000 requests:
|
| 73 |
|
| 74 |
| Share | Source |
|
| 75 |
|---:|---|
|
|
|
|
| 88 |
|
| 89 |
| Area | Skill | Raw |
|
| 90 |
|---|---:|---:|
|
| 91 |
+
| Knowledge & Reasoning | 7.8 | 30.8 |
|
| 92 |
+
| Language Understanding | 37.7 | 54.7 |
|
| 93 |
+
| Retrieval & Classification | 49.4 | 63.3 |
|
| 94 |
+
| Tools & Automation | 43.6 | 48.3 |
|
| 95 |
+
| Arts & Human Taste | 12.8 | 42.7 |
|
| 96 |
|
| 97 |
+
Raw index 47.86; kit `9eb2dbe`, edition 0.3, 140,171 requests scored.
|
decider.py
CHANGED
|
@@ -106,6 +106,7 @@ class Decider:
|
|
| 106 |
self.net = net.to(self.device).eval()
|
| 107 |
self.layout = self.config.get("layout", "pair")
|
| 108 |
self.pool = self.config.get("pool", "opt")
|
|
|
|
| 109 |
self.window = getattr(cfg, "sliding_window", None)
|
| 110 |
|
| 111 |
@classmethod
|
|
@@ -149,19 +150,35 @@ class Decider:
|
|
| 149 |
start += len(opts)
|
| 150 |
return out
|
| 151 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 152 |
def _score_shared(self, items, row_extra: int = 2048) -> List[np.ndarray]:
|
| 153 |
torch, tok = self.torch, self.tok
|
| 154 |
rows, oid, prefix = [], 0, {}
|
| 155 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 156 |
p = prefix.setdefault(s, tok(s)["input_ids"])
|
|
|
|
| 157 |
qi = tok(f"Question: {q}\nOption:", add_special_tokens=False)["input_ids"]
|
| 158 |
ob = [tok(" " + o, add_special_tokens=False)["input_ids"] + [tok.sep_token_id] for o in opts]
|
| 159 |
longest = len(p) + len(qi) + max(map(len, ob))
|
| 160 |
if longest > self.max_length:
|
| 161 |
raise TooLong(f"a (state, question, option) pair needs {longest} tokens > {self.max_length}")
|
| 162 |
cap = max(2 * len(p), len(p) + row_extra)
|
| 163 |
-
if not rows or rows[-1][0] is not p or rows[-1][2] + len(qi) + len(ob[0]) > cap:
|
| 164 |
-
rows.append([p, [], len(p)])
|
| 165 |
k = 0
|
| 166 |
while k < len(ob):
|
| 167 |
row = rows[-1]
|
|
@@ -170,7 +187,7 @@ class Decider:
|
|
| 170 |
take.append((oid + k + len(take), ob[k + len(take)]))
|
| 171 |
size += len(take[-1][1])
|
| 172 |
if row[1] and row[2] + size > cap:
|
| 173 |
-
rows.append([p, [], len(p)])
|
| 174 |
continue
|
| 175 |
row[1].append((qi, take))
|
| 176 |
row[2] += size
|
|
@@ -193,7 +210,8 @@ class Decider:
|
|
| 193 |
qix = torch.full((B, L), -1, dtype=torch.long)
|
| 194 |
oix = torch.full((B, L), -1, dtype=torch.long)
|
| 195 |
spans = []
|
| 196 |
-
|
|
|
|
| 197 |
ids[r, :len(p)], pos[r, :len(p)], kind[r, :len(p)] = torch.tensor(p), torch.arange(len(p)), 0
|
| 198 |
c = len(p)
|
| 199 |
for b, (qi, take) in enumerate(blocks):
|
|
@@ -208,11 +226,12 @@ class Decider:
|
|
| 208 |
kind[r, c:c + m], qix[r, c:c + m], oix[r, c:c + m] = 2, b, o
|
| 209 |
spans.append((o, r, c, m, len(p), (r, len(p) + sum(len(bb[0]) + sum(len(y) for _, y in bb[1]) for bb in blocks[:b])), n))
|
| 210 |
c += m
|
| 211 |
-
ids, pos, kind, qix, oix = (t.to(self.device) for t in (ids, pos, kind, qix, oix))
|
| 212 |
ki, kj = kind[:, :, None], kind[:, None, :]
|
| 213 |
allow = (kj == 0) & (ki >= 0)
|
| 214 |
allow |= (kj == 1) & (ki >= 1) & (qix[:, :, None] == qix[:, None, :])
|
| 215 |
allow |= (kj == 2) & (ki == 2) & (oix[:, :, None] == oix[:, None, :])
|
|
|
|
| 216 |
allow |= torch.eye(L, dtype=torch.bool, device=self.device)[None]
|
| 217 |
masks = {"full_attention": allow[:, None]}
|
| 218 |
if self.window is not None:
|
|
|
|
| 106 |
self.net = net.to(self.device).eval()
|
| 107 |
self.layout = self.config.get("layout", "pair")
|
| 108 |
self.pool = self.config.get("pool", "opt")
|
| 109 |
+
self.attn = self.config.get("attn", "cached") # shared layout: "cached" | "full" | "auto"
|
| 110 |
self.window = getattr(cfg, "sliding_window", None)
|
| 111 |
|
| 112 |
@classmethod
|
|
|
|
| 150 |
start += len(opts)
|
| 151 |
return out
|
| 152 |
|
| 153 |
+
def _full(self, n_questions: int, state_len: int, auto_extra: int = 4096) -> bool:
|
| 154 |
+
"""cached: the state reads only itself and is shared by all questions of a request; full: one row per
|
| 155 |
+
question, the state also reads its question; auto: full when that costs <= auto_extra extra tokens."""
|
| 156 |
+
if self.attn == "auto":
|
| 157 |
+
return (n_questions - 1) * state_len <= auto_extra
|
| 158 |
+
return self.attn == "full"
|
| 159 |
+
|
| 160 |
def _score_shared(self, items, row_extra: int = 2048) -> List[np.ndarray]:
|
| 161 |
torch, tok = self.torch, self.tok
|
| 162 |
rows, oid, prefix = [], 0, {}
|
| 163 |
+
runs = [] # questions per request = consecutive items with the same state
|
| 164 |
+
for s, _, _ in items:
|
| 165 |
+
if runs and runs[-1][0] == s:
|
| 166 |
+
runs[-1][1] += 1
|
| 167 |
+
else:
|
| 168 |
+
runs.append([s, 1])
|
| 169 |
+
nq = [n for _, n in runs for _ in range(n)]
|
| 170 |
+
first = [k == 0 for _, n in runs for k in range(n)]
|
| 171 |
+
for (s, q, opts), n_q, new_req in zip(items, nq, first): # rows of max(2P, P + row_extra) tokens
|
| 172 |
p = prefix.setdefault(s, tok(s)["input_ids"])
|
| 173 |
+
full = self._full(n_q, len(p))
|
| 174 |
qi = tok(f"Question: {q}\nOption:", add_special_tokens=False)["input_ids"]
|
| 175 |
ob = [tok(" " + o, add_special_tokens=False)["input_ids"] + [tok.sep_token_id] for o in opts]
|
| 176 |
longest = len(p) + len(qi) + max(map(len, ob))
|
| 177 |
if longest > self.max_length:
|
| 178 |
raise TooLong(f"a (state, question, option) pair needs {longest} tokens > {self.max_length}")
|
| 179 |
cap = max(2 * len(p), len(p) + row_extra)
|
| 180 |
+
if not rows or rows[-1][0] is not p or new_req or full or rows[-1][2] + len(qi) + len(ob[0]) > cap:
|
| 181 |
+
rows.append([p, [], len(p), full])
|
| 182 |
k = 0
|
| 183 |
while k < len(ob):
|
| 184 |
row = rows[-1]
|
|
|
|
| 187 |
take.append((oid + k + len(take), ob[k + len(take)]))
|
| 188 |
size += len(take[-1][1])
|
| 189 |
if row[1] and row[2] + size > cap:
|
| 190 |
+
rows.append([p, [], len(p), full])
|
| 191 |
continue
|
| 192 |
row[1].append((qi, take))
|
| 193 |
row[2] += size
|
|
|
|
| 210 |
qix = torch.full((B, L), -1, dtype=torch.long)
|
| 211 |
oix = torch.full((B, L), -1, dtype=torch.long)
|
| 212 |
spans = []
|
| 213 |
+
rowfull = torch.tensor([r[3] for r in batch], dtype=torch.bool)
|
| 214 |
+
for r, (p, blocks, _, _) in enumerate(batch):
|
| 215 |
ids[r, :len(p)], pos[r, :len(p)], kind[r, :len(p)] = torch.tensor(p), torch.arange(len(p)), 0
|
| 216 |
c = len(p)
|
| 217 |
for b, (qi, take) in enumerate(blocks):
|
|
|
|
| 226 |
kind[r, c:c + m], qix[r, c:c + m], oix[r, c:c + m] = 2, b, o
|
| 227 |
spans.append((o, r, c, m, len(p), (r, len(p) + sum(len(bb[0]) + sum(len(y) for _, y in bb[1]) for bb in blocks[:b])), n))
|
| 228 |
c += m
|
| 229 |
+
ids, pos, kind, qix, oix, rowfull = (t.to(self.device) for t in (ids, pos, kind, qix, oix, rowfull))
|
| 230 |
ki, kj = kind[:, :, None], kind[:, None, :]
|
| 231 |
allow = (kj == 0) & (ki >= 0)
|
| 232 |
allow |= (kj == 1) & (ki >= 1) & (qix[:, :, None] == qix[:, None, :])
|
| 233 |
allow |= (kj == 2) & (ki == 2) & (oix[:, :, None] == oix[:, None, :])
|
| 234 |
+
allow |= rowfull[:, None, None] & (ki == 0) & (kj == 1) # full rows: the state reads its question
|
| 235 |
allow |= torch.eye(L, dtype=torch.bool, device=self.device)[None]
|
| 236 |
masks = {"full_attention": allow[:, None]}
|
| 237 |
if self.window is not None:
|
decider_config.json
CHANGED
|
@@ -4,19 +4,19 @@
|
|
| 4 |
"base": "cross-encoder/ettin-reranker-150m-v1",
|
| 5 |
"train_max_length": 2048,
|
| 6 |
"inference_max_length": 8192,
|
| 7 |
-
"step":
|
| 8 |
"train": {
|
| 9 |
"arch": "joint",
|
| 10 |
"opt_pool": "marker",
|
| 11 |
"shuffle_options": false,
|
| 12 |
-
"manifest": "runs/manifests/
|
| 13 |
"extra_manifest": null,
|
| 14 |
"extra_frac": 0.0,
|
| 15 |
"lr": 2e-05,
|
| 16 |
"batch_requests": 8,
|
| 17 |
"max_k": 32,
|
| 18 |
"seed": 7,
|
| 19 |
-
"total_steps":
|
| 20 |
"max_length": 2048,
|
| 21 |
"pack": 0,
|
| 22 |
"init": null,
|
|
@@ -28,5 +28,7 @@
|
|
| 28 |
"tok_budget": 12288
|
| 29 |
},
|
| 30 |
"layout": "shared",
|
| 31 |
-
"pool": "opt"
|
|
|
|
|
|
|
| 32 |
}
|
|
|
|
| 4 |
"base": "cross-encoder/ettin-reranker-150m-v1",
|
| 5 |
"train_max_length": 2048,
|
| 6 |
"inference_max_length": 8192,
|
| 7 |
+
"step": 48000,
|
| 8 |
"train": {
|
| 9 |
"arch": "joint",
|
| 10 |
"opt_pool": "marker",
|
| 11 |
"shuffle_options": false,
|
| 12 |
+
"manifest": "runs/manifests/mix_all_480k.jsonl",
|
| 13 |
"extra_manifest": null,
|
| 14 |
"extra_frac": 0.0,
|
| 15 |
"lr": 2e-05,
|
| 16 |
"batch_requests": 8,
|
| 17 |
"max_k": 32,
|
| 18 |
"seed": 7,
|
| 19 |
+
"total_steps": 48000,
|
| 20 |
"max_length": 2048,
|
| 21 |
"pack": 0,
|
| 22 |
"init": null,
|
|
|
|
| 28 |
"tok_budget": 12288
|
| 29 |
},
|
| 30 |
"layout": "shared",
|
| 31 |
+
"pool": "opt",
|
| 32 |
+
"attn": "cached",
|
| 33 |
+
"weights_dtype": "bf16"
|
| 34 |
}
|
model.safetensors
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:e26e29f12339163b473f985270ebb4b9b3b90ee3b7ffd488715d45550842bef4
|
| 3 |
+
size 298044578
|