Zero-Shot Classification
Transformers
Safetensors
Arabic
llama
feature-extraction
arabic
prompt-routing
router
text-generation-inference
Instructions to use oddadmix/Nawah-Router-v3 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use oddadmix/Nawah-Router-v3 with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("zero-shot-classification", model="oddadmix/Nawah-Router-v3")# pip install -U transformers accelerate # Load model directly from transformers import AutoTokenizer, AutoModel tokenizer = AutoTokenizer.from_pretrained("oddadmix/Nawah-Router-v3") model = AutoModel.from_pretrained("oddadmix/Nawah-Router-v3", device_map="auto") - Notebooks
- Google Colab
- Kaggle
Nawah-Router-v3: 52M, 0.9305 unseen lanes / 0.6976 unseen domains
Browse filesTrained on the 233,720-row arabic-prompt-routing corpus with 12 routing axes.
Adds an unseen_axis eval: two routing dimensions absent from training entirely.
- README.md +75 -0
- build_router_dataset_v2.py +164 -0
- config.json +32 -0
- model.safetensors +3 -0
- router_axes.py +460 -0
- router_model.pt +3 -0
- routing_model.py +85 -0
- tokenizer.json +0 -0
- tokenizer_config.json +11 -0
- train_metrics.json +1157 -0
- train_router_head.py +218 -0
README.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: apache-2.0
|
| 3 |
+
language:
|
| 4 |
+
- ar
|
| 5 |
+
base_model: oddadmix/50M-2048-Emhotob
|
| 6 |
+
library_name: transformers
|
| 7 |
+
tags: [arabic, zero-shot-classification, prompt-routing, router]
|
| 8 |
+
---
|
| 9 |
+
|
| 10 |
+
# Nawah-Router-v3 — موجّه عربي صفري
|
| 11 |
+
|
| 12 |
+
**52M parameters.** Give it a text and **any categories in plain Arabic**; it scores all of them in
|
| 13 |
+
**one forward pass**. Categories are chosen at inference — no fixed taxonomy.
|
| 14 |
+
|
| 15 |
+
> **بالعربية:** نموذج عربي يوجّه أي نص إلى فئة من فئات تكتبها أنت بلغة طبيعية، في مسار واحد.
|
| 16 |
+
|
| 17 |
+
## Results
|
| 18 |
+
|
| 19 |
+
Trained on [`oddadmix/arabic-prompt-routing`](https://huggingface.co/datasets/oddadmix/arabic-prompt-routing)
|
| 20 |
+
(233,720 rows, 12 routing axes).
|
| 21 |
+
|
| 22 |
+
| eval | v3 | v2 (51K corpus) | random |
|
| 23 |
+
|---|---:|---:|---:|
|
| 24 |
+
| unseen category sets | **0.9305** | 0.9199 | 0.2137 |
|
| 25 |
+
| unseen domains | **0.6976** | 0.6665 | 0.2521 |
|
| 26 |
+
| **unseen axes** | **0.6130** | *(n/a)* | 0.2358 |
|
| 27 |
+
| deliberately adjacent categories | 0.9008 | 0.9149 | 0.2109 |
|
| 28 |
+
|
| 29 |
+
`unseen_axis` is the strongest claim here: `tools` and `retrieval` appear **nowhere** in training,
|
| 30 |
+
and the model still routes along them at 0.61 against a 0.24 baseline.
|
| 31 |
+
|
| 32 |
+
## Usage
|
| 33 |
+
|
| 34 |
+
```python
|
| 35 |
+
from transformers import AutoTokenizer
|
| 36 |
+
from routing_model import RouterModel, route # ships in this repo
|
| 37 |
+
|
| 38 |
+
M = "oddadmix/Nawah-Router-v3"
|
| 39 |
+
tok = AutoTokenizer.from_pretrained(M)
|
| 40 |
+
model = RouterModel.from_pretrained(M)
|
| 41 |
+
|
| 42 |
+
route(model, tok, "كم صار سعر صرف الدولار اليوم؟",
|
| 43 |
+
["بحث في الويب", "حاسبة", "تقويم ومواعيد", "لا يحتاج أداة"])
|
| 44 |
+
```
|
| 45 |
+
|
| 46 |
+
## Choosing a checkpoint
|
| 47 |
+
|
| 48 |
+
No single configuration wins everything, and the trade-off is real:
|
| 49 |
+
|
| 50 |
+
| epochs | unseen lanes | unseen domains | unseen axes |
|
| 51 |
+
|---:|---:|---:|---:|
|
| 52 |
+
| 1 | **0.9327** | 0.6968 | 0.5950 |
|
| 53 |
+
| **2** (this) | 0.9305 | **0.6976** | 0.6130 |
|
| 54 |
+
| 3 | 0.9181 | 0.6496 | **0.6376** |
|
| 55 |
+
|
| 56 |
+
Longer training helps the hardest transfer (unseen axes) and costs the everyday cases. 2 epochs is
|
| 57 |
+
shipped as the balance. Higher learning rates are simply worse — 6e-4 and 1e-3 both degrade.
|
| 58 |
+
|
| 59 |
+
## How the head works
|
| 60 |
+
|
| 61 |
+
Text and categories share one sequence, **text first**. Each category's span is mean-pooled into
|
| 62 |
+
its own vector and a **shared** scorer turns each into one logit; the softmax runs over the
|
| 63 |
+
categories supplied. Because the scorer is shared it reads category *content*, not slot index —
|
| 64 |
+
which is what makes the label set free text.
|
| 65 |
+
|
| 66 |
+
A fixed-slot head (`num_labels = max_lanes`) scored **exactly 1/n at every lane count**: its
|
| 67 |
+
weights were positional, and the corpus randomises category order, so there was nothing to learn.
|
| 68 |
+
|
| 69 |
+
## Limitations
|
| 70 |
+
|
| 71 |
+
Unseen domains (0.70) and unseen axes (0.61) trail unseen category sets (0.93) — it generalises
|
| 72 |
+
best inside verticals and dimensions it has seen. Confidence is **not calibrated**: clear cases
|
| 73 |
+
saturate near 1.0, so use the ranking, not the number. Arabic, 1–3 line messages.
|
| 74 |
+
|
| 75 |
+
3 epochs at LR 3e-4 cosine, batch 32, bf16, `max_length` 320.
|
build_router_dataset_v2.py
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Merge the v1 and v2 router caches, shuffle lanes, audit for shortcuts, and write the splits.
|
| 3 |
+
|
| 4 |
+
v1 (out_router, task ids 100000-116063) is topical routing across 18 business verticals.
|
| 5 |
+
v2 (out_router_v2, ids 1000000+) adds compound lane sets, ten single-axis taxonomies and 45
|
| 6 |
+
verticals. The id ranges are disjoint by construction, so the two caches concatenate safely and
|
| 7 |
+
v1 never had to be regenerated.
|
| 8 |
+
|
| 9 |
+
Four splits, in increasing order of how much they ask of the model:
|
| 10 |
+
|
| 11 |
+
unseen_lanes - new lane sets, axes and domains seen in training
|
| 12 |
+
unseen_domain - three business verticals held out entirely (kept identical to v1 so the 0.6665
|
| 13 |
+
number stays comparable)
|
| 14 |
+
unseen_axis - `tools` and `retrieval` never appear in training at all. The strongest
|
| 15 |
+
zero-shot claim available: routing on a dimension the model was never taught.
|
| 16 |
+
hard - deliberately adjacent lanes
|
| 17 |
+
|
| 18 |
+
Lanes are shuffled here and the label recomputed, so whatever positional bias the generator had
|
| 19 |
+
cannot survive into training.
|
| 20 |
+
"""
|
| 21 |
+
import json
|
| 22 |
+
import os
|
| 23 |
+
import random
|
| 24 |
+
from collections import Counter, defaultdict
|
| 25 |
+
from pathlib import Path
|
| 26 |
+
|
| 27 |
+
import router_axes as ra
|
| 28 |
+
|
| 29 |
+
V1 = Path("out_router"); V2 = Path("out_router_v2")
|
| 30 |
+
OUT = Path(os.environ.get("DATA_DIR", "data_v2")); OUT.mkdir(exist_ok=True)
|
| 31 |
+
HELD_DOMAINS = ["فرز طبي أولي", "استشارات قانونية", "شركة تأمين"]
|
| 32 |
+
HELD_AXES = ["tools", "retrieval"]
|
| 33 |
+
EVAL_TASK_FRAC = float(os.environ.get("EVAL_TASK_FRAC", 0.02))
|
| 34 |
+
SEED = 42
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def axes_map(cache):
|
| 38 |
+
m = {}
|
| 39 |
+
p = cache / "generations.jsonl"
|
| 40 |
+
if not p.exists():
|
| 41 |
+
return m
|
| 42 |
+
for line in open(p, encoding="utf-8"):
|
| 43 |
+
try:
|
| 44 |
+
r = json.loads(line)
|
| 45 |
+
except json.JSONDecodeError:
|
| 46 |
+
continue
|
| 47 |
+
m[r["task_id"]] = r["axes"]
|
| 48 |
+
return m
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
def load(cache, amap, default_axis):
|
| 52 |
+
kept, amb = [], 0
|
| 53 |
+
p = cache / "verified.jsonl"
|
| 54 |
+
if not p.exists():
|
| 55 |
+
return kept, amb
|
| 56 |
+
for line in open(p, encoding="utf-8"):
|
| 57 |
+
try:
|
| 58 |
+
r = json.loads(line)
|
| 59 |
+
except json.JSONDecodeError:
|
| 60 |
+
continue
|
| 61 |
+
if not r["agree"]:
|
| 62 |
+
amb += 1
|
| 63 |
+
continue
|
| 64 |
+
a = amap.get(r["task_id"], {})
|
| 65 |
+
axis = a.get("axis", default_axis)
|
| 66 |
+
r["axis"] = axis
|
| 67 |
+
r["family"] = axis.split(":")[0] if ":" in axis else axis
|
| 68 |
+
r["mode"] = a.get("mode", "topical")
|
| 69 |
+
kept.append(r)
|
| 70 |
+
return kept, amb
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
def main():
|
| 74 |
+
rng = random.Random(SEED)
|
| 75 |
+
a1, a2 = axes_map(V1), axes_map(V2)
|
| 76 |
+
r1, amb1 = load(V1, a1, "topical")
|
| 77 |
+
r2, amb2 = load(V2, a2, "topical")
|
| 78 |
+
print(f"v1 kept {len(r1):,} (ambiguous {amb1:,}) | v2 kept {len(r2):,} (ambiguous {amb2:,})")
|
| 79 |
+
|
| 80 |
+
rows = []
|
| 81 |
+
for r in r1 + r2:
|
| 82 |
+
order = list(range(len(r["routes"])))
|
| 83 |
+
rng.shuffle(order)
|
| 84 |
+
rows.append({"task_id": r["task_id"], "text": r["text"],
|
| 85 |
+
"routes": [r["routes"][i] for i in order],
|
| 86 |
+
"label": order.index(r["label"]),
|
| 87 |
+
"axis": r["axis"], "family": r["family"], "mode": r["mode"],
|
| 88 |
+
"domain": r.get("domain", ""), "style": r.get("style", "phrase"),
|
| 89 |
+
"difficulty": r.get("difficulty", "easy"),
|
| 90 |
+
"has_other": r.get("has_other", False)})
|
| 91 |
+
|
| 92 |
+
seen, ded = set(), []
|
| 93 |
+
for r in rows:
|
| 94 |
+
k = ra.dedup_key(r["text"])
|
| 95 |
+
if k in seen:
|
| 96 |
+
continue
|
| 97 |
+
seen.add(k); ded.append(r)
|
| 98 |
+
print(f"merged {len(rows):,} -> {len(ded):,} after dedup ({len(rows)-len(ded):,} duplicates)")
|
| 99 |
+
rows = ded
|
| 100 |
+
|
| 101 |
+
axis_rows = [r for r in rows if r["family"] in HELD_AXES]
|
| 102 |
+
rest = [r for r in rows if r["family"] not in HELD_AXES]
|
| 103 |
+
dom_rows = [r for r in rest if r["domain"] in HELD_DOMAINS]
|
| 104 |
+
rest = [r for r in rest if r["domain"] not in HELD_DOMAINS]
|
| 105 |
+
tasks = sorted({r["task_id"] for r in rest}); rng.shuffle(tasks)
|
| 106 |
+
ev_tasks = set(tasks[: max(1, int(len(tasks) * EVAL_TASK_FRAC))])
|
| 107 |
+
unseen_lanes = [r for r in rest if r["task_id"] in ev_tasks]
|
| 108 |
+
train = [r for r in rest if r["task_id"] not in ev_tasks]
|
| 109 |
+
|
| 110 |
+
# A lane set invented twice by different tasks would put a vocabulary the model trained on
|
| 111 |
+
# into a set labelled "unseen". Drop those from eval rather than weaken the claim.
|
| 112 |
+
tls = {ra.lane_set_key(r["routes"]) for r in train}
|
| 113 |
+
before = len(unseen_lanes), len(dom_rows), len(axis_rows)
|
| 114 |
+
unseen_lanes = [r for r in unseen_lanes if ra.lane_set_key(r["routes"]) not in tls]
|
| 115 |
+
dom_rows = [r for r in dom_rows if ra.lane_set_key(r["routes"]) not in tls]
|
| 116 |
+
axis_rows = [r for r in axis_rows if ra.lane_set_key(r["routes"]) not in tls]
|
| 117 |
+
print(f"lane-set overlap dropped: lanes {before[0]-len(unseen_lanes)}, "
|
| 118 |
+
f"domain {before[1]-len(dom_rows)}, axis {before[2]-len(axis_rows)}")
|
| 119 |
+
hard = [r for r in unseen_lanes if r["difficulty"] == "hard"]
|
| 120 |
+
|
| 121 |
+
for name, s in (("train", train), ("eval_unseen_lanes", unseen_lanes),
|
| 122 |
+
("eval_unseen_domain", dom_rows), ("eval_unseen_axis", axis_rows),
|
| 123 |
+
("eval_hard", hard)):
|
| 124 |
+
with open(OUT / f"{name}.jsonl", "w", encoding="utf-8") as fh:
|
| 125 |
+
for r in s:
|
| 126 |
+
fh.write(json.dumps(r, ensure_ascii=False) + "\n")
|
| 127 |
+
print(f" {name:<20}{len(s):>8,}")
|
| 128 |
+
|
| 129 |
+
leaked = {r["family"] for r in train} & set(HELD_AXES)
|
| 130 |
+
print(f"\nheld-out axes present in train: {leaked or 'none'} (must be none)")
|
| 131 |
+
print(f"train texts also in any eval: "
|
| 132 |
+
f"{len({r['text'] for r in train} & {r['text'] for r in unseen_lanes+dom_rows+axis_rows})}")
|
| 133 |
+
|
| 134 |
+
print("\n--- composition ---")
|
| 135 |
+
print("by mode:", dict(Counter(r["mode"] for r in rows).most_common()))
|
| 136 |
+
fam = Counter(r["family"] for r in rows)
|
| 137 |
+
print("by axis family:", dict(fam.most_common()))
|
| 138 |
+
print(f"distinct lane sets: {len({ra.lane_set_key(r['routes']) for r in rows}):,}")
|
| 139 |
+
|
| 140 |
+
print("\n--- shortcut audit ---")
|
| 141 |
+
groups = defaultdict(list)
|
| 142 |
+
for r in rows:
|
| 143 |
+
groups[len(r["routes"])].append(r)
|
| 144 |
+
for k in sorted(groups):
|
| 145 |
+
g = groups[k]
|
| 146 |
+
if len(g) < 200:
|
| 147 |
+
continue
|
| 148 |
+
c = Counter(r["label"] for r in g); exp = len(g) / k
|
| 149 |
+
chi = sum((c[i] - exp) ** 2 / exp for i in range(k))
|
| 150 |
+
crit = {1: 3.8, 2: 6.0, 3: 7.8, 4: 9.5, 5: 11.1, 6: 12.6, 7: 14.1, 8: 15.5}.get(k - 1, 15.5)
|
| 151 |
+
print(f" {k} lanes n={len(g):<7} chi2={chi:7.1f} crit={crit:<5} "
|
| 152 |
+
f"{'FLAT' if chi < crit else 'SKEWED'}")
|
| 153 |
+
ranks = []
|
| 154 |
+
for r in rows:
|
| 155 |
+
L = [len(x) for x in r["routes"]]
|
| 156 |
+
ranks.append(sorted(L, reverse=True).index(L[r["label"]]) / max(len(L) - 1, 1))
|
| 157 |
+
print(f" correct-lane length rank: {sum(ranks)/len(ranks):.3f} (0.5 = no bias)")
|
| 158 |
+
give = sum(1 for r in rows if r["routes"][r["label"]] in r["text"])
|
| 159 |
+
print(f" verbatim lane in prompt: {give} ({give/len(rows):.2%})")
|
| 160 |
+
print(f" TOTAL ROWS: {len(rows):,}")
|
| 161 |
+
|
| 162 |
+
|
| 163 |
+
if __name__ == "__main__":
|
| 164 |
+
main()
|
config.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"architectures": [
|
| 3 |
+
"LlamaModel"
|
| 4 |
+
],
|
| 5 |
+
"attention_bias": false,
|
| 6 |
+
"attention_dropout": 0.0,
|
| 7 |
+
"bos_token_id": 0,
|
| 8 |
+
"dtype": "float32",
|
| 9 |
+
"eos_token_id": 2,
|
| 10 |
+
"head_dim": 64,
|
| 11 |
+
"hidden_act": "silu",
|
| 12 |
+
"hidden_size": 512,
|
| 13 |
+
"initializer_range": 0.02,
|
| 14 |
+
"intermediate_size": 1408,
|
| 15 |
+
"max_position_embeddings": 2048,
|
| 16 |
+
"mlp_bias": false,
|
| 17 |
+
"model_type": "llama",
|
| 18 |
+
"num_attention_heads": 8,
|
| 19 |
+
"num_hidden_layers": 12,
|
| 20 |
+
"num_key_value_heads": 4,
|
| 21 |
+
"pad_token_id": 1,
|
| 22 |
+
"pretraining_tp": 1,
|
| 23 |
+
"rms_norm_eps": 1e-06,
|
| 24 |
+
"rope_parameters": {
|
| 25 |
+
"rope_theta": 10000,
|
| 26 |
+
"rope_type": "default"
|
| 27 |
+
},
|
| 28 |
+
"tie_word_embeddings": true,
|
| 29 |
+
"transformers_version": "5.15.1",
|
| 30 |
+
"use_cache": false,
|
| 31 |
+
"vocab_size": 32000
|
| 32 |
+
}
|
model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b5200d894303508b35530632e7f86e433596cb9dd9a0e6eb124aaf20a75b8f8c
|
| 3 |
+
size 207156480
|
router_axes.py
ADDED
|
@@ -0,0 +1,460 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Arabic prompt-routing corpus v2 — many routing axes, and lane sets that mix them.
|
| 3 |
+
|
| 4 |
+
v1 (router_common.py) generated one axis only: topical intent inside a business vertical, 18
|
| 5 |
+
domains. It reached 0.9199 on unseen lane sets but stalled at 0.6665 on unseen domains, and the
|
| 6 |
+
reference demo shows why that is the wrong shape rather than merely too small. LiquidAI's shipped
|
| 7 |
+
presets mix axes inside a single lane set:
|
| 8 |
+
|
| 9 |
+
Simple function call · Simple tool use · Complex multi-step agentic task ·
|
| 10 |
+
Quick factual question · Casual conversation · Creative writing · Translation ·
|
| 11 |
+
Needs a bigger model
|
| 12 |
+
|
| 13 |
+
That is complexity, task type, tool use and an escalation lane together. Every v1 lane set was
|
| 14 |
+
single-axis, so the model never saw categories that differ along different dimensions at once.
|
| 15 |
+
|
| 16 |
+
Three generation modes here:
|
| 17 |
+
|
| 18 |
+
topical - v1's mode, widened from 18 to 45 verticals. The model invents the lanes.
|
| 19 |
+
axis - lanes drawn from one of ten taxonomies (task type, complexity, safety, retrieval,
|
| 20 |
+
tools, subject, subdomain, language, urgency, tone), each with several paraphrased
|
| 21 |
+
wordings so the model learns the concept and not the string.
|
| 22 |
+
mixed - lanes sampled across two or three axes, as the reference does. The largest share.
|
| 23 |
+
|
| 24 |
+
`router_common.py` is deliberately untouched: it defines build_task for task ids 100000-116063 and
|
| 25 |
+
editing it would silently redraw prompts for the 51,392 rows already generated. This module owns a
|
| 26 |
+
disjoint range (START_TASK=1000000) and its output is merged with v1's at build time.
|
| 27 |
+
|
| 28 |
+
Labels are still established by construction and confirmed by the independent back-classification
|
| 29 |
+
in verify_router.py, which is axis-agnostic and needs no change.
|
| 30 |
+
"""
|
| 31 |
+
import random
|
| 32 |
+
import re
|
| 33 |
+
import unicodedata
|
| 34 |
+
|
| 35 |
+
ITEMS_PER_TASK = 4
|
| 36 |
+
|
| 37 |
+
C, Q, A, E = "### فئات", "### نص", "### الفئة", "### نهاية"
|
| 38 |
+
|
| 39 |
+
# Varied on purpose. v1 used one fixed string, which teaches the token rather than the concept;
|
| 40 |
+
# the reference ships a catch-all in most presets under several different names.
|
| 41 |
+
OTHER_LANES = ["أخرى / لا ينطبق", "غير ذلك", "لا ينطبق أي مما سبق", "أخرى",
|
| 42 |
+
"خارج التصنيفات المذكورة"]
|
| 43 |
+
|
| 44 |
+
# ---------------------------------------------------------------- axis taxonomies
|
| 45 |
+
# Each lane carries several wordings; build_task picks one per task so the corpus never ties a
|
| 46 |
+
# concept to a single surface form. Wordings deliberately avoid a shared give-away token
|
| 47 |
+
# (e.g. not every complexity lane contains بسيط/معقد).
|
| 48 |
+
|
| 49 |
+
AXES = {
|
| 50 |
+
"task_type": {
|
| 51 |
+
"hint": "مستخدم يطلب من مساعد ذكي مهمة",
|
| 52 |
+
"lanes": [
|
| 53 |
+
["ترجمة", "نقل نص من لغة إلى أخرى", "طلب ترجمة"],
|
| 54 |
+
["برمجة", "كتابة أو إصلاح كود", "مهمة برمجية"],
|
| 55 |
+
["تلخيص", "اختصار نص طويل", "طلب ملخّص"],
|
| 56 |
+
["كتابة إبداعية", "تأليف قصة أو نص أدبي", "صياغة محتوى إبداعي"],
|
| 57 |
+
["رياضيات", "حساب أو مسألة رياضية", "عملية حسابية"],
|
| 58 |
+
["استخراج بيانات", "انتزاع حقول من نص", "تحويل نص إلى بيانات منظمة"],
|
| 59 |
+
["سؤال معلومات", "طلب معلومة مباشرة", "سؤال معرفي عام"],
|
| 60 |
+
["محادثة", "دردشة غير مهمّية", "كلام عابر"],
|
| 61 |
+
["إعادة صياغة", "تحسين صياغة نص قائم", "تحرير وتنقيح"],
|
| 62 |
+
["تصنيف", "تحديد فئة نص", "فرز محتوى"],
|
| 63 |
+
],
|
| 64 |
+
},
|
| 65 |
+
"complexity": {
|
| 66 |
+
"hint": "مستخدم يكتب طلبًا يتفاوت في صعوبته",
|
| 67 |
+
"lanes": [
|
| 68 |
+
["طلب بسيط ومباشر", "يُنجز بخطوة واحدة", "مهمة سهلة لا تحتاج تفكيرًا"],
|
| 69 |
+
["طلب متوسط", "يحتاج خطوتين أو ثلاثًا", "مهمة معتدلة"],
|
| 70 |
+
["طلب معقّد متعدد الخطوات", "يحتاج تخطيطًا وتسلسلًا طويلًا", "مهمة مركّبة"],
|
| 71 |
+
["يحتاج نموذجًا أكبر", "يفوق قدرة نموذج صغير", "يُحال إلى نموذج أقوى"],
|
| 72 |
+
["يحتاج استدلالًا خطوة بخطوة", "يتطلب سلسلة تفكير", "حل يحتاج برهنة"],
|
| 73 |
+
],
|
| 74 |
+
},
|
| 75 |
+
"safety": {
|
| 76 |
+
"hint": "رسالة واردة تحتاج فرزًا من ناحية السلامة",
|
| 77 |
+
"lanes": [
|
| 78 |
+
["محتوى آمن", "لا مشكلة فيه", "مقبول للنشر"],
|
| 79 |
+
["رسائل مزعجة", "إعلانات متكررة غير مرغوبة", "سبام تجاري"],
|
| 80 |
+
["يحتوي بيانات شخصية", "فيه معلومات تعريف حساسة", "يكشف خصوصية أحدهم"],
|
| 81 |
+
["لغة مسيئة", "ألفاظ جارحة", "إهانة أو تنمّر"],
|
| 82 |
+
],
|
| 83 |
+
},
|
| 84 |
+
"retrieval": {
|
| 85 |
+
"hint": "سؤال قد يحتاج مصدرًا خارجيًا أو لا",
|
| 86 |
+
"lanes": [
|
| 87 |
+
["يُجاب من المعرفة العامة", "لا يحتاج بحثًا", "إجابة مباشرة بلا مصادر"],
|
| 88 |
+
["يحتاج بحثًا واحدًا", "يكفيه مصدر واحد", "استعلام واحد يكفي"],
|
| 89 |
+
["يحتاج بحثًا متعدد الخطوات", "يجمع بين أكثر من مصدر", "يتطلب تتبع عدة معلومات"],
|
| 90 |
+
["يحتاج معلومة لحظية", "يعتمد على بيانات متغيرة الآن", "يحتاج تحديثًا آنيًا"],
|
| 91 |
+
],
|
| 92 |
+
},
|
| 93 |
+
"tools": {
|
| 94 |
+
"hint": "طلب قد يستدعي أداة معينة",
|
| 95 |
+
"lanes": [
|
| 96 |
+
["بحث في الويب", "استعلام محرك بحث", "تصفح الإنترنت"],
|
| 97 |
+
["حاسبة", "إجراء عملية حسابية", "أداة حساب"],
|
| 98 |
+
["تقويم ومواعيد", "جدولة موعد", "إدارة الأجندة"],
|
| 99 |
+
["بريد ورسائل", "إرسال رسالة", "التعامل مع البريد"],
|
| 100 |
+
["قاعدة بيانات", "استعلام من سجلات", "جلب صف من جدول"],
|
| 101 |
+
["لا يحتاج أداة", "يُجاب بلا استدعاء خارجي", "بدون أدوات"],
|
| 102 |
+
["تشغيل كود", "تنفيذ سكربت", "مفسّر برمجي"],
|
| 103 |
+
],
|
| 104 |
+
},
|
| 105 |
+
"subject": {
|
| 106 |
+
"hint": "سؤال أكاديمي في تخصص ما",
|
| 107 |
+
"lanes": [
|
| 108 |
+
["أحياء", "علوم الحياة", "بيولوجيا"],
|
| 109 |
+
["قانون", "مسائل قانونية", "تشريع وأنظمة"],
|
| 110 |
+
["اقتصاد", "مسائل اقتصادية", "اقتصاد وأسواق"],
|
| 111 |
+
["هندسة", "مسائل هندسية", "تصميم وتنفيذ هندسي"],
|
| 112 |
+
["طب وصحة", "مسائل طبية", "صحة وعلاج"],
|
| 113 |
+
["تاريخ", "أحداث ووقائع تاريخية", "ماضٍ وسير"],
|
| 114 |
+
["فلسفة", "مسائل فلسفية", "فكر ومنطق"],
|
| 115 |
+
["فيزياء", "مسائل فيزيائية", "قوانين الطبيعة"],
|
| 116 |
+
["حاسوب", "علوم الحاسب", "تقنية معلومات"],
|
| 117 |
+
["علم نفس", "مسائل نفسية", "سلوك وإدراك"],
|
| 118 |
+
],
|
| 119 |
+
},
|
| 120 |
+
"language": {
|
| 121 |
+
"hint": "رسالة مكتوبة بلهجة أو لغة ما",
|
| 122 |
+
"lanes": [
|
| 123 |
+
["عربية فصحى", "لغة عربية رسمية", "فصحى معاصرة"],
|
| 124 |
+
["لهجة مصرية", "عامية مصر", "مصري"],
|
| 125 |
+
["لهجة خليجية", "عامية الخليج", "خليجي"],
|
| 126 |
+
["لهجة شامية", "عامية بلاد الشام", "شامي"],
|
| 127 |
+
["لهجة مغاربية", "عامية المغرب العربي", "مغاربي"],
|
| 128 |
+
["إنجليزية", "نص بالإنجليزية", "لغة إنجليزية"],
|
| 129 |
+
["عربي مختلط بالإنجليزية", "كتابة مزدوجة اللغة", "عربيزي أو تبديل لغوي"],
|
| 130 |
+
],
|
| 131 |
+
},
|
| 132 |
+
"urgency": {
|
| 133 |
+
"hint": "رسالة تتفاوت في إلحاحها",
|
| 134 |
+
"lanes": [
|
| 135 |
+
["عاجل", "يحتاج تدخلًا فوريًا", "أولوية قصوى"],
|
| 136 |
+
["أولوية عادية", "يمكن معالجته ضمن الدور", "غير مستعجل"],
|
| 137 |
+
["أولوية منخفضة", "يمكن تأجيله", "لا يستدعي استعجالًا"],
|
| 138 |
+
],
|
| 139 |
+
},
|
| 140 |
+
"tone": {
|
| 141 |
+
"hint": "رسالة من عميل بنبرة معينة",
|
| 142 |
+
"lanes": [
|
| 143 |
+
["شكوى غاضبة", "امتعاض شديد", "نبرة تصعيد"],
|
| 144 |
+
["استفسار محايد", "سؤال هادئ", "نبرة عادية"],
|
| 145 |
+
["شكر وثناء", "رسالة امتنان", "إطراء على الخدمة"],
|
| 146 |
+
["طلب اعتذار أو تعويض", "مطالبة بحق", "طلب جبر ضرر"],
|
| 147 |
+
],
|
| 148 |
+
},
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
# Mixed lane sets use COMPOUND lanes, not a union of two axes' lanes.
|
| 152 |
+
#
|
| 153 |
+
# The first attempt sampled lanes from two axes at once and produced ill-posed rows: an insulting
|
| 154 |
+
# message written in Gulf dialect belongs to both 'لهجة خليجية' and 'إهانة أو تنمر', and the task
|
| 155 |
+
# is single-label. Constraining to "compatible" axes did not fix it either - an angry complaint is
|
| 156 |
+
# also urgent. Any two independent axes overlap by construction.
|
| 157 |
+
#
|
| 158 |
+
# The reference avoids this because its lanes are already compound: "Simple function call" fuses
|
| 159 |
+
# complexity with tool use, "Complex multi-step agentic task" fuses complexity with task type.
|
| 160 |
+
# Each lane names a point in the joint space, so the set partitions rather than overlaps. These
|
| 161 |
+
# pools mirror that, one per facet-family; a lane set is drawn from a single pool.
|
| 162 |
+
COMPOUND_POOLS = {
|
| 163 |
+
"assistant": (
|
| 164 |
+
"مستخدم يطلب من مساعد ذكي مهمة",
|
| 165 |
+
["استدعاء دالة بسيط", "استخدام أداة بسيط", "مهمة وكيلة معقدة متعددة الخطوات",
|
| 166 |
+
"استدلال بسيط", "استدلال معقد يحتاج خطوات", "مهمة برمجية بسيطة",
|
| 167 |
+
"مهمة برمجية معقدة", "إصلاح خطأ برمجي صغير", "إعادة هيكلة كود واسعة",
|
| 168 |
+
"مراجعة كود", "كتابة اختبارات", "شرح كود قائم",
|
| 169 |
+
"مسألة حسابية بسيطة", "مسألة رياضية معقدة", "ترجمة", "تلخيص",
|
| 170 |
+
"كتابة إبداعية", "إعادة صياغة نص", "بحث عن معلومة مباشرة",
|
| 171 |
+
"سؤال سريع تُعرف إجابته", "محادثة عابرة", "يحتاج نموذجًا أكبر",
|
| 172 |
+
"يحتاج بحثًا في الويب", "يحتاج تنفيذ كود", "استعلام قاعدة بيانات",
|
| 173 |
+
"تحليل بيانات", "إنشاء رسم بياني", "استخراج حقول من نص",
|
| 174 |
+
"جدولة موعد في التقويم", "صياغة رسالة بريد"],
|
| 175 |
+
),
|
| 176 |
+
"triage": (
|
| 177 |
+
"رسالة واردة إلى فريق خدمة العملاء",
|
| 178 |
+
["شكوى غاضبة تحتاج تصعيدًا فوريًا", "استفسار عادي غير مستعجل",
|
| 179 |
+
"بلاغ عطل حرج يوقف الخدمة", "بلاغ عطل بسيط يمكن تأجيله",
|
| 180 |
+
"طلب استرجاع مبلغ", "طلب إلغاء اشتراك", "رسالة شكر وثناء",
|
| 181 |
+
"رسالة مزعجة إعلانية", "إساءة لفظية تستوجب حظرًا",
|
| 182 |
+
"طلب حذف بيانات شخصية", "استفسار عن الفاتورة", "طلب ميزة جديدة",
|
| 183 |
+
"مشكلة في الدخول إلى الحساب", "سؤال عام عن الخدمة"],
|
| 184 |
+
),
|
| 185 |
+
"content": (
|
| 186 |
+
"نص يُراد تصنيف موضوعه ومستواه",
|
| 187 |
+
["خبر سياسي", "خبر رياضي", "خبر اقتصادي", "تقرير علمي مبسّط",
|
| 188 |
+
"مقال رأي", "محتوى تعليمي للمبتدئين", "محتوى تقني متقدم",
|
| 189 |
+
"وصفة أو إرشادات عملية", "مراجعة منتج", "إعلان تجاري",
|
| 190 |
+
"نص قانوني رسمي", "نص طبي متخصص", "محتوى ترفيهي خفيف"],
|
| 191 |
+
),
|
| 192 |
+
}
|
| 193 |
+
|
| 194 |
+
# "Which flavour of X" — the reference's `lang` preset generalised. The model invents the members.
|
| 195 |
+
SUBDOMAIN_FAMILIES = [
|
| 196 |
+
("لغة البرمجة المستخدمة في السؤال", "مبرمج يسأل عن لغة معينة"),
|
| 197 |
+
("نوع الوثيقة الرسمية المطلوبة", "مواطن يطلب مستندًا"),
|
| 198 |
+
("فرع التأمين المعني", "عميل يسأل عن وثيقته"),
|
| 199 |
+
("نوع الحساب البنكي المقصود", "عميل بنك"),
|
| 200 |
+
("تخصص الطبيب المطلوب", "مريض يبحث عن عيادة"),
|
| 201 |
+
("نوع العقار المطلوب", "باحث عن سكن"),
|
| 202 |
+
("نوع الشحنة المرسلة", "عميل شركة شحن"),
|
| 203 |
+
("مرحلة دراسية", "ولي أمر يسأل عن التسجيل"),
|
| 204 |
+
]
|
| 205 |
+
|
| 206 |
+
# v1's 18, plus 27 more.
|
| 207 |
+
DOMAINS = [
|
| 208 |
+
("دعم فني لشركة برمجيات", "مستخدم يراسل الدعم الفني"),
|
| 209 |
+
("خدمة عملاء بنك", "عميل يتواصل مع بنكه"),
|
| 210 |
+
("متجر إلكتروني", "مشترٍ يسأل عن طلب أو منتج"),
|
| 211 |
+
("حجز سفر وطيران", "مسافر يرتب رحلة"),
|
| 212 |
+
("خدمات حكومية إلكترونية", "مواطن يطلب معاملة"),
|
| 213 |
+
("فرز طبي أولي", "مريض يصف حالته"),
|
| 214 |
+
("شركة اتصالات", "مشترك يسأل عن باقته"),
|
| 215 |
+
("منصة تعليمية", "طالب أو ولي أمر يستفسر"),
|
| 216 |
+
("موارد بشرية داخل شركة", "موظف يراسل الموارد البشرية"),
|
| 217 |
+
("وساطة عقارية", "باحث عن سكن أو مالك"),
|
| 218 |
+
("تطبيق توصيل طعام", "زبون يتابع طلبه"),
|
| 219 |
+
("استشارات قانونية", "شخص يسأل عن حقوقه"),
|
| 220 |
+
("تصنيف مواضيع الأخبار", "قارئ يبحث عن خبر"),
|
| 221 |
+
("مراجعة المحتوى والإبلاغ", "مستخدم يبلّغ عن محتوى"),
|
| 222 |
+
("توجيه مساعد ذكي", "مستخدم يطلب من مساعد ذكي مهمة"),
|
| 223 |
+
("إدارة مالية شخصية", "شخص يدير مصروفاته"),
|
| 224 |
+
("شركة تأمين", "عميل يسأل عن وثيقته"),
|
| 225 |
+
("صيانة منزلية", "ساكن يطلب صيانة"),
|
| 226 |
+
("مطعم وحجز طاولات", "زبون يحجز أو يشتكي"),
|
| 227 |
+
("صيدلية وطلب دواء", "مريض يسأل عن دواء"),
|
| 228 |
+
("نادٍ رياضي واشتراكات", "مشترك في صالة رياضية"),
|
| 229 |
+
("شحن ولوجستيات", "عميل يتابع شحنة"),
|
| 230 |
+
("معرض وصيانة سيارات", "مالك سيارة"),
|
| 231 |
+
("بنك استثماري ومحافظ", "مستثمر يسأل عن محفظته"),
|
| 232 |
+
("سياحة دينية وحج وعمرة", "معتمر ينظّم رحلته"),
|
| 233 |
+
("جامعة وقبول وتسجيل", "طالب جامعي"),
|
| 234 |
+
("مكتب محاماة", "موكّل يتابع قضيته"),
|
| 235 |
+
("زراعة وإرشاد زراعي", "مزارع يسأل عن محصوله"),
|
| 236 |
+
("خدمة كهرباء ومياه", "مشترك يبلّغ عن انقطاع"),
|
| 237 |
+
("تأجير سيارات", "مستأجر يحجز مركبة"),
|
| 238 |
+
("فندق وضيافة", "نزيل يحجز أو يشتكي"),
|
| 239 |
+
("منصة توظيف", "باحث عن عمل"),
|
| 240 |
+
("متجر إلكترونيات وضمان", "مشترٍ يطالب بالضمان"),
|
| 241 |
+
("خدمات بريدية", "مرسِل يتابع طردًا"),
|
| 242 |
+
("مركز تدريب ودورات", "متدرب يسجّل في دورة"),
|
| 243 |
+
("عيادة أسنان ومواعيد", "مريض يحجز موعدًا"),
|
| 244 |
+
("شركة تنظيف منازل", "زبون يطلب خدمة"),
|
| 245 |
+
("منصة بث ومحتوى", "مشترك يسأل عن اشتراكه"),
|
| 246 |
+
("متجر ملابس ومقاسات", "زبون يستبدل قطعة"),
|
| 247 |
+
("خدمة استضافة ونطاقات", "صاحب موقع"),
|
| 248 |
+
("جمعية خيرية وتبرعات", "متبرع يسأل"),
|
| 249 |
+
("نقل عام وتذاكر", "راكب يستفسر"),
|
| 250 |
+
("مكتبة وبيع كتب", "قارئ يطلب كتابًا"),
|
| 251 |
+
("خدمة محاسبة وضرائب", "صاحب منشأة"),
|
| 252 |
+
("متجر حيوانات أليفة", "مربّي حيوان"),
|
| 253 |
+
]
|
| 254 |
+
|
| 255 |
+
STYLES = {
|
| 256 |
+
"noun": ("كلمة واحدة أو كلمتين", "مثل: برمجة، فواتير، شكاوى"),
|
| 257 |
+
"phrase": ("عبارة قصيرة من ٢ إلى ٤ كلمات", "مثل: كتابة إبداعية، إلغاء الاشتراك"),
|
| 258 |
+
"desc": ("جملة وصفية كاملة", "مثل: أسئلة حول الفواتير والمدفوعات وطلبات الاسترجاع"),
|
| 259 |
+
}
|
| 260 |
+
|
| 261 |
+
DIFFICULTY = {
|
| 262 |
+
"easy": "اجعل الفئات متباعدة وواضحة الفروق بينها.",
|
| 263 |
+
"hard": ("اجعل بعض الفئات متقاربة جدًا في المعنى بحيث يصعب التمييز بينها دون قراءة النص "
|
| 264 |
+
"بعناية."),
|
| 265 |
+
}
|
| 266 |
+
|
| 267 |
+
# Mode 1: the model invents the lanes (topical / subdomain).
|
| 268 |
+
PROMPT_INVENT = """أنت تكتب بيانات تدريبية لنموذج يوجّه النصوص إلى فئات يحددها المستخدم.
|
| 269 |
+
|
| 270 |
+
المجال: {domain} ({hint})
|
| 271 |
+
|
| 272 |
+
الخطوة الأولى — اقترح {n} فئة للتوجيه في هذا المجال:
|
| 273 |
+
- اكتب كل فئة بأسلوب: {style_desc} ({style_ex}).
|
| 274 |
+
- {difficulty}
|
| 275 |
+
- الفئات يجب أن تغطي المجال دون تداخل كامل بينها.{other_note}
|
| 276 |
+
|
| 277 |
+
الخطوة الثانية — اكتب {k} نصوص مستقلة، كل نص من شخص حقيقي ({hint}).
|
| 278 |
+
النص رقم i يجب أن ينتمي إلى الفئة المطلوبة له في القائمة أدناه:
|
| 279 |
+
{targets}
|
| 280 |
+
|
| 281 |
+
{fmt}"""
|
| 282 |
+
|
| 283 |
+
# Mode 2/3: the lanes are given (single axis or mixed axes); the model only writes the texts.
|
| 284 |
+
PROMPT_GIVEN = """أنت تكتب بيانات تدريبية لنموذج يوجّه النصوص إلى فئات يحددها المستخدم.
|
| 285 |
+
|
| 286 |
+
الفئات المعطاة (استخدمها كما هي حرفيًا وبنفس الترتيب):
|
| 287 |
+
{lanes_block}
|
| 288 |
+
|
| 289 |
+
السياق: {hint}
|
| 290 |
+
|
| 291 |
+
اكتب {k} نصوص عربية مستقلة وواقعية. النص رقم i يجب أن ينتمي إلى الفئة المطلوبة له:
|
| 292 |
+
{targets}
|
| 293 |
+
|
| 294 |
+
{fmt}"""
|
| 295 |
+
|
| 296 |
+
FMT = """اكتب بهذا الشكل بالضبط:
|
| 297 |
+
|
| 298 |
+
{C}
|
| 299 |
+
(فئة في كل سطر، مسبوقة بـ "- "، بالترتيب وبنفس الصياغة في كل مرة)
|
| 300 |
+
{Q}
|
| 301 |
+
(النص العربي الأول، من سطر إلى ثلاثة أسطر)
|
| 302 |
+
{A}
|
| 303 |
+
(اسم الفئة التي ينتمي إليها هذا النص، منسوخًا حرفيًا من قائمة الفئات)
|
| 304 |
+
{Q}
|
| 305 |
+
(النص الثاني)
|
| 306 |
+
{A}
|
| 307 |
+
(فئته)
|
| 308 |
+
... وهكذا حتى {k} نصوص
|
| 309 |
+
{E}
|
| 310 |
+
|
| 311 |
+
قواعد مهمة:
|
| 312 |
+
- لا تذكر اسم الفئة داخل النص نفسه. النص يجب أن يدل على فئته بالمعنى لا بالكلمة.
|
| 313 |
+
- اكتب نصوصًا طبيعية كما يكتبها الناس فعلًا، بأطوال مختلفة.
|
| 314 |
+
- نوّع الأسماء والتفاصيل والأسلوب بين النصوص.
|
| 315 |
+
- لا تكتب أي شيء خارج الوسوم."""
|
| 316 |
+
|
| 317 |
+
|
| 318 |
+
def _targets_block(rng, n_lanes, has_other):
|
| 319 |
+
real = list(range(n_lanes))
|
| 320 |
+
targets = [rng.choice(real) for _ in range(ITEMS_PER_TASK)]
|
| 321 |
+
if has_other:
|
| 322 |
+
targets[rng.randrange(ITEMS_PER_TASK)] = n_lanes
|
| 323 |
+
return targets, "\n".join(f"- النص {i+1}: الفئة رقم {t+1}"
|
| 324 |
+
for i, t in enumerate(targets))
|
| 325 |
+
|
| 326 |
+
|
| 327 |
+
def build_task(task_id: int, seed: int = 1234):
|
| 328 |
+
"""task_id -> (axes, prompt). Deterministic, so a resumed run redraws identical prompts."""
|
| 329 |
+
rng = random.Random(seed * 7_000_003 + task_id)
|
| 330 |
+
mode = rng.choices(["mixed", "axis", "topical"], weights=[45, 35, 20])[0]
|
| 331 |
+
style = rng.choice(["noun", "phrase", "phrase", "desc"])
|
| 332 |
+
difficulty = "hard" if rng.random() < 0.4 else "easy"
|
| 333 |
+
has_other = rng.random() < 0.30 # v1 used 0.15; the reference uses a catch-all often
|
| 334 |
+
other_lane = rng.choice(OTHER_LANES)
|
| 335 |
+
fmt = FMT.format(C=C, Q=Q, A=A, E=E, k=ITEMS_PER_TASK)
|
| 336 |
+
|
| 337 |
+
if mode == "topical":
|
| 338 |
+
use_sub = rng.random() < 0.2
|
| 339 |
+
domain, hint = rng.choice(SUBDOMAIN_FAMILIES if use_sub else DOMAINS)
|
| 340 |
+
n = rng.choice([2, 3, 3, 4, 4, 4, 5, 5, 6, 7, 8])
|
| 341 |
+
sd, sx = STYLES[style]
|
| 342 |
+
other_note = (f"\n- أضف في نهاية القائمة فئة أخيرة اسمها بالضبط: {other_lane}"
|
| 343 |
+
"\n- واجعل أحد النصوص لا ينتمي لأي فئة إلا هذه الفئة الأخيرة.") \
|
| 344 |
+
if has_other else ""
|
| 345 |
+
targets, tgt = _targets_block(rng, n, has_other)
|
| 346 |
+
axes = {"mode": mode, "axis": "subdomain" if use_sub else "topical", "domain": domain,
|
| 347 |
+
"style": style, "difficulty": difficulty, "has_other": has_other,
|
| 348 |
+
# total lane count, Other included - the axis/mixed branch counts the same way
|
| 349 |
+
"n_routes": n + (1 if has_other else 0), "targets": targets}
|
| 350 |
+
return axes, PROMPT_INVENT.format(domain=domain, hint=hint, n=n, k=ITEMS_PER_TASK,
|
| 351 |
+
style_desc=sd, style_ex=sx,
|
| 352 |
+
difficulty=DIFFICULTY[difficulty],
|
| 353 |
+
other_note=other_note, targets=tgt, fmt=fmt)
|
| 354 |
+
|
| 355 |
+
if mode == "axis":
|
| 356 |
+
name = rng.choice(list(AXES))
|
| 357 |
+
spec = AXES[name]
|
| 358 |
+
k = min(len(spec["lanes"]), rng.choice([3, 3, 4, 4, 5, 5, 6, 7]))
|
| 359 |
+
picked = rng.sample(spec["lanes"], k)
|
| 360 |
+
lanes = [rng.choice(w) for w in picked] # one wording per lane, per task
|
| 361 |
+
hint = spec["hint"]
|
| 362 |
+
axis_label, domain = name, name
|
| 363 |
+
else: # mixed - compound lanes from one pool
|
| 364 |
+
pool_name = rng.choice(list(COMPOUND_POOLS))
|
| 365 |
+
hint, pool = COMPOUND_POOLS[pool_name]
|
| 366 |
+
k = min(len(pool), rng.choice([3, 4, 4, 5, 5, 6, 6, 7, 8]))
|
| 367 |
+
lanes = rng.sample(pool, k)
|
| 368 |
+
axis_label, domain = "compound:" + pool_name, pool_name
|
| 369 |
+
|
| 370 |
+
if has_other:
|
| 371 |
+
lanes = lanes + [other_lane]
|
| 372 |
+
rng.shuffle(lanes)
|
| 373 |
+
n = len(lanes) - (1 if has_other else 0)
|
| 374 |
+
other_idx = lanes.index(other_lane) if has_other else None
|
| 375 |
+
real_idx = [i for i in range(len(lanes)) if i != other_idx]
|
| 376 |
+
targets = [rng.choice(real_idx) for _ in range(ITEMS_PER_TASK)]
|
| 377 |
+
if has_other:
|
| 378 |
+
targets[rng.randrange(ITEMS_PER_TASK)] = other_idx
|
| 379 |
+
tgt = "\n".join(f"- النص {i+1}: الفئة رقم {t+1}" for i, t in enumerate(targets))
|
| 380 |
+
lanes_block = "\n".join(f"- {c}" for c in lanes)
|
| 381 |
+
axes = {"mode": mode, "axis": axis_label, "domain": domain, "style": style,
|
| 382 |
+
"difficulty": difficulty, "has_other": has_other,
|
| 383 |
+
"n_routes": len(lanes), "targets": targets}
|
| 384 |
+
return axes, PROMPT_GIVEN.format(lanes_block=lanes_block, hint=hint, k=ITEMS_PER_TASK,
|
| 385 |
+
targets=tgt, fmt=fmt)
|
| 386 |
+
|
| 387 |
+
|
| 388 |
+
# ---------------------------------------------------------------- parsing / validation
|
| 389 |
+
# Identical contract to router_common; the tag format and structural checks carry over unchanged.
|
| 390 |
+
|
| 391 |
+
BLOCK_RE = re.compile(re.escape(C) + r"(?P<cats>.*?)(?=" + re.escape(Q) + r")", re.S)
|
| 392 |
+
PAIR_RE = re.compile(re.escape(Q) + r"(?P<text>.*?)" + re.escape(A) + r"(?P<label>.*?)"
|
| 393 |
+
r"(?=" + re.escape(Q) + r"|" + re.escape(E) + r"|\Z)", re.S)
|
| 394 |
+
|
| 395 |
+
|
| 396 |
+
def norm(s: str) -> str:
|
| 397 |
+
s = unicodedata.normalize("NFKC", s or "")
|
| 398 |
+
s = re.sub(r"[ً-ْٰـ]", "", s)
|
| 399 |
+
return re.sub(r"\s+", " ", s).strip()
|
| 400 |
+
|
| 401 |
+
|
| 402 |
+
def parse_items(raw: str):
|
| 403 |
+
m = BLOCK_RE.search(raw or "")
|
| 404 |
+
if not m:
|
| 405 |
+
return []
|
| 406 |
+
routes = []
|
| 407 |
+
for line in m.group("cats").split("\n"):
|
| 408 |
+
line = line.strip()
|
| 409 |
+
c = re.match(r"^[-*•]\s*(.+)$", line) or re.match(r"^\d+[.)]\s*(.+)$", line)
|
| 410 |
+
if c:
|
| 411 |
+
r = norm(c.group(1)).strip(" .:،")
|
| 412 |
+
if 2 <= len(r) <= 120:
|
| 413 |
+
routes.append(r)
|
| 414 |
+
if not routes:
|
| 415 |
+
return []
|
| 416 |
+
out = []
|
| 417 |
+
for p in PAIR_RE.finditer(raw):
|
| 418 |
+
out.append({"routes": routes, "text": norm(p.group("text")),
|
| 419 |
+
"label_text": norm(p.group("label")).strip(" .:،").lstrip("- ")})
|
| 420 |
+
return out
|
| 421 |
+
|
| 422 |
+
|
| 423 |
+
def _match_route(label, routes):
|
| 424 |
+
if label in routes:
|
| 425 |
+
return routes.index(label)
|
| 426 |
+
hits = [i for i, r in enumerate(routes) if r and (r in label or label in r)]
|
| 427 |
+
return hits[0] if len(hits) == 1 else None
|
| 428 |
+
|
| 429 |
+
|
| 430 |
+
def validate(item, min_text=15, max_text=600):
|
| 431 |
+
"""Structural only. Semantic correctness is decided by verify_router.py, not here."""
|
| 432 |
+
routes, text, label = item["routes"], item["text"], item["label_text"]
|
| 433 |
+
if not (2 <= len(routes) <= 9):
|
| 434 |
+
return False, "route_count"
|
| 435 |
+
if len(set(routes)) != len(routes):
|
| 436 |
+
return False, "duplicate_routes"
|
| 437 |
+
if not (min_text <= len(text) <= max_text):
|
| 438 |
+
return False, "text_length"
|
| 439 |
+
if any(t in text for t in (C, Q, A, E)):
|
| 440 |
+
return False, "tag_leak"
|
| 441 |
+
idx = _match_route(label, routes)
|
| 442 |
+
if idx is None:
|
| 443 |
+
return False, "label_not_in_routes"
|
| 444 |
+
if routes[idx] and routes[idx] in text:
|
| 445 |
+
return False, "lexical_giveaway"
|
| 446 |
+
if len(text.split()) < 4:
|
| 447 |
+
return False, "text_too_few_words"
|
| 448 |
+
return True, "ok"
|
| 449 |
+
|
| 450 |
+
|
| 451 |
+
def label_index(item):
|
| 452 |
+
return _match_route(item["label_text"], item["routes"])
|
| 453 |
+
|
| 454 |
+
|
| 455 |
+
def dedup_key(text: str) -> str:
|
| 456 |
+
return re.sub(r"\d+", "#", re.sub(r"\W+", "", norm(text)))
|
| 457 |
+
|
| 458 |
+
|
| 459 |
+
def lane_set_key(routes) -> str:
|
| 460 |
+
return "|".join(sorted(norm(r) for r in routes))
|
router_model.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:90ff8180f65ed7ae63a3445b5418bf3f35ea051816e6f7ff367450da44a7c0fc
|
| 3 |
+
size 208245555
|
routing_model.py
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Inference for Nawah-Router-v2 — an Arabic zero-shot router with a routing head.
|
| 3 |
+
|
| 4 |
+
The text and every category share one sequence. Each category's character span is mapped to token
|
| 5 |
+
indices through the tokenizer's offset mapping and mean-pooled into its own vector; a shared
|
| 6 |
+
scorer turns each into one logit, and the softmax runs over the categories actually supplied.
|
| 7 |
+
Because the scorer is shared across positions it reads category *content*, not slot index — which
|
| 8 |
+
is what makes the label set free text chosen at inference.
|
| 9 |
+
|
| 10 |
+
Layout is text-first, categories-second on purpose. The backbone is causal, so this ordering is
|
| 11 |
+
what lets every category token attend to the whole text; reversed, the categories would be
|
| 12 |
+
encoded blind to it.
|
| 13 |
+
"""
|
| 14 |
+
import torch
|
| 15 |
+
import torch.nn as nn
|
| 16 |
+
from transformers import AutoModel, AutoTokenizer
|
| 17 |
+
|
| 18 |
+
MAX_ROUTES = 9
|
| 19 |
+
MAX_LENGTH = 320
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
class RouterModel(nn.Module):
|
| 23 |
+
def __init__(self, base_model):
|
| 24 |
+
super().__init__()
|
| 25 |
+
self.backbone = AutoModel.from_pretrained(base_model, dtype=torch.float32)
|
| 26 |
+
h = self.backbone.config.hidden_size
|
| 27 |
+
self.score = nn.Sequential(nn.Linear(h, h), nn.GELU(), nn.Linear(h, 1))
|
| 28 |
+
self.config = self.backbone.config
|
| 29 |
+
|
| 30 |
+
def forward(self, input_ids, attention_mask, cat_pool, n_routes):
|
| 31 |
+
hs = self.backbone(input_ids=input_ids, attention_mask=attention_mask).last_hidden_state
|
| 32 |
+
logits = self.score(torch.bmm(cat_pool.to(hs.dtype), hs)).squeeze(-1)
|
| 33 |
+
ar = torch.arange(logits.size(1), device=logits.device)[None, :]
|
| 34 |
+
return logits.masked_fill(ar >= n_routes[:, None], torch.finfo(logits.dtype).min)
|
| 35 |
+
|
| 36 |
+
@classmethod
|
| 37 |
+
def from_pretrained(cls, path, token=None):
|
| 38 |
+
import os
|
| 39 |
+
from huggingface_hub import hf_hub_download
|
| 40 |
+
m = cls(path)
|
| 41 |
+
w = (os.path.join(path, "router_model.pt") if os.path.isdir(path)
|
| 42 |
+
else hf_hub_download(path, "router_model.pt", token=token))
|
| 43 |
+
m.load_state_dict(torch.load(w, map_location="cpu", weights_only=True))
|
| 44 |
+
return m.eval()
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
def build_text(text, routes):
|
| 48 |
+
head = f"النص:\n{text}\n\nالفئات:\n"
|
| 49 |
+
s, spans = head, []
|
| 50 |
+
for c in routes:
|
| 51 |
+
s += "- "
|
| 52 |
+
spans.append((len(s), len(s) + len(c)))
|
| 53 |
+
s += c + "\n"
|
| 54 |
+
return s, spans
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
@torch.no_grad()
|
| 58 |
+
def route(model, tok, text, routes):
|
| 59 |
+
"""-> [{'route': str, 'score': float}] sorted high to low."""
|
| 60 |
+
routes = [r for r in routes if r and r.strip()][:MAX_ROUTES]
|
| 61 |
+
if not text.strip() or not routes:
|
| 62 |
+
return []
|
| 63 |
+
full, spans = build_text(text, routes)
|
| 64 |
+
enc = tok(full, return_offsets_mapping=True, add_special_tokens=False,
|
| 65 |
+
truncation=True, max_length=MAX_LENGTH)
|
| 66 |
+
ids, offs = enc["input_ids"], enc["offset_mapping"]
|
| 67 |
+
pool = torch.zeros(1, MAX_ROUTES, len(ids))
|
| 68 |
+
for ci, (s, e) in enumerate(spans):
|
| 69 |
+
idx = [t for t, (a, b) in enumerate(offs) if a < e and b > s and a != b]
|
| 70 |
+
if idx:
|
| 71 |
+
pool[0, ci, idx] = 1.0 / len(idx)
|
| 72 |
+
logits = model(torch.tensor([ids]), torch.ones(1, len(ids), dtype=torch.long),
|
| 73 |
+
pool, torch.tensor([len(routes)]))
|
| 74 |
+
probs = logits.softmax(-1)[0][: len(routes)].tolist()
|
| 75 |
+
out = [{"route": r, "score": p} for r, p in zip(routes, probs)]
|
| 76 |
+
return sorted(out, key=lambda x: -x["score"])
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
if __name__ == "__main__":
|
| 80 |
+
M = "oddadmix/Nawah-Router-v2"
|
| 81 |
+
tok = AutoTokenizer.from_pretrained(M)
|
| 82 |
+
model = RouterModel.from_pretrained(M)
|
| 83 |
+
for r in route(model, tok, "الطلب تأخر ساعة والسائق ما رد على الاتصال",
|
| 84 |
+
["استفسار عن التوصيل", "شكوى تأخير", "مشكلة في الدفع"]):
|
| 85 |
+
print(f"{r['score']:.3f} {r['route']}")
|
tokenizer.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
tokenizer_config.json
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"backend": "tokenizers",
|
| 3 |
+
"bos_token": "<s>",
|
| 4 |
+
"eos_token": "</s>",
|
| 5 |
+
"is_local": false,
|
| 6 |
+
"local_files_only": false,
|
| 7 |
+
"model_max_length": 1000000000000000019884624838656,
|
| 8 |
+
"pad_token": "<pad>",
|
| 9 |
+
"tokenizer_class": "TokenizersBackend",
|
| 10 |
+
"unk_token": "<unk>"
|
| 11 |
+
}
|
train_metrics.json
ADDED
|
@@ -0,0 +1,1157 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"results": {
|
| 3 |
+
"unseen_lanes": {
|
| 4 |
+
"accuracy": 0.9304995345950977,
|
| 5 |
+
"random_baseline": 0.2137126998901743,
|
| 6 |
+
"n": 3223,
|
| 7 |
+
"by_n_routes": {
|
| 8 |
+
"2": {
|
| 9 |
+
"acc": 0.954954954954955,
|
| 10 |
+
"n": 111
|
| 11 |
+
},
|
| 12 |
+
"4": {
|
| 13 |
+
"acc": 0.9449877750611247,
|
| 14 |
+
"n": 818
|
| 15 |
+
},
|
| 16 |
+
"5": {
|
| 17 |
+
"acc": 0.9423076923076923,
|
| 18 |
+
"n": 624
|
| 19 |
+
},
|
| 20 |
+
"8": {
|
| 21 |
+
"acc": 0.9341317365269461,
|
| 22 |
+
"n": 334
|
| 23 |
+
},
|
| 24 |
+
"3": {
|
| 25 |
+
"acc": 0.9104938271604939,
|
| 26 |
+
"n": 324
|
| 27 |
+
},
|
| 28 |
+
"7": {
|
| 29 |
+
"acc": 0.907928388746803,
|
| 30 |
+
"n": 391
|
| 31 |
+
},
|
| 32 |
+
"6": {
|
| 33 |
+
"acc": 0.9224952741020794,
|
| 34 |
+
"n": 529
|
| 35 |
+
},
|
| 36 |
+
"9": {
|
| 37 |
+
"acc": 0.8913043478260869,
|
| 38 |
+
"n": 92
|
| 39 |
+
}
|
| 40 |
+
},
|
| 41 |
+
"by_difficulty": {
|
| 42 |
+
"easy": {
|
| 43 |
+
"acc": 0.9478603049680275,
|
| 44 |
+
"n": 2033
|
| 45 |
+
},
|
| 46 |
+
"hard": {
|
| 47 |
+
"acc": 0.9008403361344538,
|
| 48 |
+
"n": 1190
|
| 49 |
+
}
|
| 50 |
+
},
|
| 51 |
+
"by_mode": {
|
| 52 |
+
"topical": {
|
| 53 |
+
"acc": 0.884,
|
| 54 |
+
"n": 1500
|
| 55 |
+
},
|
| 56 |
+
"mixed": {
|
| 57 |
+
"acc": 0.9772549019607844,
|
| 58 |
+
"n": 1275
|
| 59 |
+
},
|
| 60 |
+
"axis": {
|
| 61 |
+
"acc": 0.953125,
|
| 62 |
+
"n": 448
|
| 63 |
+
}
|
| 64 |
+
}
|
| 65 |
+
},
|
| 66 |
+
"unseen_domain": {
|
| 67 |
+
"accuracy": 0.6976068889556424,
|
| 68 |
+
"random_baseline": 0.25206113185236045,
|
| 69 |
+
"n": 9987,
|
| 70 |
+
"by_n_routes": {
|
| 71 |
+
"5": {
|
| 72 |
+
"acc": 0.6869671132764921,
|
| 73 |
+
"n": 1642
|
| 74 |
+
},
|
| 75 |
+
"4": {
|
| 76 |
+
"acc": 0.727150084317032,
|
| 77 |
+
"n": 2965
|
| 78 |
+
},
|
| 79 |
+
"3": {
|
| 80 |
+
"acc": 0.7427476737821566,
|
| 81 |
+
"n": 1827
|
| 82 |
+
},
|
| 83 |
+
"2": {
|
| 84 |
+
"acc": 0.7923497267759563,
|
| 85 |
+
"n": 915
|
| 86 |
+
},
|
| 87 |
+
"6": {
|
| 88 |
+
"acc": 0.6202393906420022,
|
| 89 |
+
"n": 919
|
| 90 |
+
},
|
| 91 |
+
"7": {
|
| 92 |
+
"acc": 0.5959595959595959,
|
| 93 |
+
"n": 792
|
| 94 |
+
},
|
| 95 |
+
"8": {
|
| 96 |
+
"acc": 0.5976608187134503,
|
| 97 |
+
"n": 855
|
| 98 |
+
},
|
| 99 |
+
"9": {
|
| 100 |
+
"acc": 0.6666666666666666,
|
| 101 |
+
"n": 72
|
| 102 |
+
}
|
| 103 |
+
},
|
| 104 |
+
"by_difficulty": {
|
| 105 |
+
"easy": {
|
| 106 |
+
"acc": 0.6926144520657203,
|
| 107 |
+
"n": 6269
|
| 108 |
+
},
|
| 109 |
+
"hard": {
|
| 110 |
+
"acc": 0.7060247444862829,
|
| 111 |
+
"n": 3718
|
| 112 |
+
}
|
| 113 |
+
},
|
| 114 |
+
"by_mode": {
|
| 115 |
+
"topical": {
|
| 116 |
+
"acc": 0.6976068889556424,
|
| 117 |
+
"n": 9987
|
| 118 |
+
}
|
| 119 |
+
}
|
| 120 |
+
},
|
| 121 |
+
"unseen_axis": {
|
| 122 |
+
"accuracy": 0.6129888942539836,
|
| 123 |
+
"random_baseline": 0.23578575644002975,
|
| 124 |
+
"n": 12426,
|
| 125 |
+
"by_n_routes": {
|
| 126 |
+
"4": {
|
| 127 |
+
"acc": 0.541494632535095,
|
| 128 |
+
"n": 4844
|
| 129 |
+
},
|
| 130 |
+
"5": {
|
| 131 |
+
"acc": 0.6220699603317706,
|
| 132 |
+
"n": 2773
|
| 133 |
+
},
|
| 134 |
+
"3": {
|
| 135 |
+
"acc": 0.6389937106918239,
|
| 136 |
+
"n": 2385
|
| 137 |
+
},
|
| 138 |
+
"6": {
|
| 139 |
+
"acc": 0.7419898819561551,
|
| 140 |
+
"n": 1186
|
| 141 |
+
},
|
| 142 |
+
"7": {
|
| 143 |
+
"acc": 0.7033898305084746,
|
| 144 |
+
"n": 944
|
| 145 |
+
},
|
| 146 |
+
"8": {
|
| 147 |
+
"acc": 0.6836734693877551,
|
| 148 |
+
"n": 294
|
| 149 |
+
}
|
| 150 |
+
},
|
| 151 |
+
"by_difficulty": {
|
| 152 |
+
"hard": {
|
| 153 |
+
"acc": 0.6019339242546333,
|
| 154 |
+
"n": 4964
|
| 155 |
+
},
|
| 156 |
+
"easy": {
|
| 157 |
+
"acc": 0.6203430715625837,
|
| 158 |
+
"n": 7462
|
| 159 |
+
}
|
| 160 |
+
},
|
| 161 |
+
"by_mode": {
|
| 162 |
+
"axis": {
|
| 163 |
+
"acc": 0.6129888942539836,
|
| 164 |
+
"n": 12426
|
| 165 |
+
}
|
| 166 |
+
}
|
| 167 |
+
},
|
| 168 |
+
"hard": {
|
| 169 |
+
"accuracy": 0.9008403361344538,
|
| 170 |
+
"random_baseline": 0.21085734293717487,
|
| 171 |
+
"n": 1190,
|
| 172 |
+
"by_n_routes": {
|
| 173 |
+
"4": {
|
| 174 |
+
"acc": 0.9182156133828996,
|
| 175 |
+
"n": 269
|
| 176 |
+
},
|
| 177 |
+
"5": {
|
| 178 |
+
"acc": 0.9043824701195219,
|
| 179 |
+
"n": 251
|
| 180 |
+
},
|
| 181 |
+
"8": {
|
| 182 |
+
"acc": 0.9291338582677166,
|
| 183 |
+
"n": 127
|
| 184 |
+
},
|
| 185 |
+
"3": {
|
| 186 |
+
"acc": 0.8571428571428571,
|
| 187 |
+
"n": 126
|
| 188 |
+
},
|
| 189 |
+
"7": {
|
| 190 |
+
"acc": 0.8662420382165605,
|
| 191 |
+
"n": 157
|
| 192 |
+
},
|
| 193 |
+
"6": {
|
| 194 |
+
"acc": 0.9045226130653267,
|
| 195 |
+
"n": 199
|
| 196 |
+
},
|
| 197 |
+
"2": {
|
| 198 |
+
"acc": 1.0,
|
| 199 |
+
"n": 34
|
| 200 |
+
},
|
| 201 |
+
"9": {
|
| 202 |
+
"acc": 0.8148148148148148,
|
| 203 |
+
"n": 27
|
| 204 |
+
}
|
| 205 |
+
},
|
| 206 |
+
"by_difficulty": {
|
| 207 |
+
"hard": {
|
| 208 |
+
"acc": 0.9008403361344538,
|
| 209 |
+
"n": 1190
|
| 210 |
+
}
|
| 211 |
+
},
|
| 212 |
+
"by_mode": {
|
| 213 |
+
"topical": {
|
| 214 |
+
"acc": 0.8300180831826401,
|
| 215 |
+
"n": 553
|
| 216 |
+
},
|
| 217 |
+
"mixed": {
|
| 218 |
+
"acc": 0.9680851063829787,
|
| 219 |
+
"n": 470
|
| 220 |
+
},
|
| 221 |
+
"axis": {
|
| 222 |
+
"acc": 0.9461077844311377,
|
| 223 |
+
"n": 167
|
| 224 |
+
}
|
| 225 |
+
}
|
| 226 |
+
}
|
| 227 |
+
},
|
| 228 |
+
"base_model": "oddadmix/50M-2048-Emhotob",
|
| 229 |
+
"formulation": "routing_head",
|
| 230 |
+
"log_history": [
|
| 231 |
+
{
|
| 232 |
+
"loss": 0.8975238800048828,
|
| 233 |
+
"grad_norm": 11.03390121459961,
|
| 234 |
+
"learning_rate": 7.4625e-05,
|
| 235 |
+
"epoch": 0.030902348578491966,
|
| 236 |
+
"step": 200
|
| 237 |
+
},
|
| 238 |
+
{
|
| 239 |
+
"loss": 0.47223701477050783,
|
| 240 |
+
"grad_norm": 11.903738975524902,
|
| 241 |
+
"learning_rate": 0.000149625,
|
| 242 |
+
"epoch": 0.06180469715698393,
|
| 243 |
+
"step": 400
|
| 244 |
+
},
|
| 245 |
+
{
|
| 246 |
+
"loss": 0.4622153091430664,
|
| 247 |
+
"grad_norm": 6.198873996734619,
|
| 248 |
+
"learning_rate": 0.000224625,
|
| 249 |
+
"epoch": 0.09270704573547589,
|
| 250 |
+
"step": 600
|
| 251 |
+
},
|
| 252 |
+
{
|
| 253 |
+
"loss": 0.49717689514160157,
|
| 254 |
+
"grad_norm": 4.740701198577881,
|
| 255 |
+
"learning_rate": 0.000299625,
|
| 256 |
+
"epoch": 0.12360939431396786,
|
| 257 |
+
"step": 800
|
| 258 |
+
},
|
| 259 |
+
{
|
| 260 |
+
"loss": 0.4837868118286133,
|
| 261 |
+
"grad_norm": 3.6331026554107666,
|
| 262 |
+
"learning_rate": 0.0002998012771863284,
|
| 263 |
+
"epoch": 0.15451174289245984,
|
| 264 |
+
"step": 1000
|
| 265 |
+
},
|
| 266 |
+
{
|
| 267 |
+
"eval_unseen_lanes_loss": 0.5073266625404358,
|
| 268 |
+
"eval_unseen_lanes_accuracy": 0.8163201985727583,
|
| 269 |
+
"eval_unseen_lanes_runtime": 0.5548,
|
| 270 |
+
"eval_unseen_lanes_samples_per_second": 5809.493,
|
| 271 |
+
"eval_unseen_lanes_steps_per_second": 91.928,
|
| 272 |
+
"epoch": 0.15451174289245984,
|
| 273 |
+
"step": 1000
|
| 274 |
+
},
|
| 275 |
+
{
|
| 276 |
+
"eval_unseen_domain_loss": 0.9687234163284302,
|
| 277 |
+
"eval_unseen_domain_accuracy": 0.6065885651346751,
|
| 278 |
+
"eval_unseen_domain_runtime": 1.5808,
|
| 279 |
+
"eval_unseen_domain_samples_per_second": 6317.746,
|
| 280 |
+
"eval_unseen_domain_steps_per_second": 99.318,
|
| 281 |
+
"epoch": 0.15451174289245984,
|
| 282 |
+
"step": 1000
|
| 283 |
+
},
|
| 284 |
+
{
|
| 285 |
+
"eval_unseen_axis_loss": 1.1325784921646118,
|
| 286 |
+
"eval_unseen_axis_accuracy": 0.5135200386286818,
|
| 287 |
+
"eval_unseen_axis_runtime": 1.2551,
|
| 288 |
+
"eval_unseen_axis_samples_per_second": 9900.252,
|
| 289 |
+
"eval_unseen_axis_steps_per_second": 155.364,
|
| 290 |
+
"epoch": 0.15451174289245984,
|
| 291 |
+
"step": 1000
|
| 292 |
+
},
|
| 293 |
+
{
|
| 294 |
+
"eval_hard_loss": 0.5369061231613159,
|
| 295 |
+
"eval_hard_accuracy": 0.807563025210084,
|
| 296 |
+
"eval_hard_runtime": 0.2574,
|
| 297 |
+
"eval_hard_samples_per_second": 4623.428,
|
| 298 |
+
"eval_hard_steps_per_second": 73.819,
|
| 299 |
+
"epoch": 0.15451174289245984,
|
| 300 |
+
"step": 1000
|
| 301 |
+
},
|
| 302 |
+
{
|
| 303 |
+
"loss": 0.4474765396118164,
|
| 304 |
+
"grad_norm": 9.281235694885254,
|
| 305 |
+
"learning_rate": 0.00029920164204065217,
|
| 306 |
+
"epoch": 0.18541409147095178,
|
| 307 |
+
"step": 1200
|
| 308 |
+
},
|
| 309 |
+
{
|
| 310 |
+
"loss": 0.4180959320068359,
|
| 311 |
+
"grad_norm": 6.990286827087402,
|
| 312 |
+
"learning_rate": 0.00029820269436406154,
|
| 313 |
+
"epoch": 0.21631644004944375,
|
| 314 |
+
"step": 1400
|
| 315 |
+
},
|
| 316 |
+
{
|
| 317 |
+
"loss": 0.4012123489379883,
|
| 318 |
+
"grad_norm": 2.00594425201416,
|
| 319 |
+
"learning_rate": 0.00029680710766818503,
|
| 320 |
+
"epoch": 0.24721878862793573,
|
| 321 |
+
"step": 1600
|
| 322 |
+
},
|
| 323 |
+
{
|
| 324 |
+
"loss": 0.39807247161865233,
|
| 325 |
+
"grad_norm": 4.734849452972412,
|
| 326 |
+
"learning_rate": 0.0002950186170007609,
|
| 327 |
+
"epoch": 0.27812113720642767,
|
| 328 |
+
"step": 1800
|
| 329 |
+
},
|
| 330 |
+
{
|
| 331 |
+
"loss": 0.37501571655273436,
|
| 332 |
+
"grad_norm": 2.752845048904419,
|
| 333 |
+
"learning_rate": 0.0002928420089494242,
|
| 334 |
+
"epoch": 0.30902348578491967,
|
| 335 |
+
"step": 2000
|
| 336 |
+
},
|
| 337 |
+
{
|
| 338 |
+
"eval_unseen_lanes_loss": 0.406538724899292,
|
| 339 |
+
"eval_unseen_lanes_accuracy": 0.8569655600372323,
|
| 340 |
+
"eval_unseen_lanes_runtime": 0.5556,
|
| 341 |
+
"eval_unseen_lanes_samples_per_second": 5801.001,
|
| 342 |
+
"eval_unseen_lanes_steps_per_second": 91.794,
|
| 343 |
+
"epoch": 0.30902348578491967,
|
| 344 |
+
"step": 2000
|
| 345 |
+
},
|
| 346 |
+
{
|
| 347 |
+
"eval_unseen_domain_loss": 1.1472351551055908,
|
| 348 |
+
"eval_unseen_domain_accuracy": 0.5958746370281366,
|
| 349 |
+
"eval_unseen_domain_runtime": 1.575,
|
| 350 |
+
"eval_unseen_domain_samples_per_second": 6340.999,
|
| 351 |
+
"eval_unseen_domain_steps_per_second": 99.683,
|
| 352 |
+
"epoch": 0.30902348578491967,
|
| 353 |
+
"step": 2000
|
| 354 |
+
},
|
| 355 |
+
{
|
| 356 |
+
"eval_unseen_axis_loss": 1.353710412979126,
|
| 357 |
+
"eval_unseen_axis_accuracy": 0.49806856591018833,
|
| 358 |
+
"eval_unseen_axis_runtime": 1.3077,
|
| 359 |
+
"eval_unseen_axis_samples_per_second": 9502.1,
|
| 360 |
+
"eval_unseen_axis_steps_per_second": 149.116,
|
| 361 |
+
"epoch": 0.30902348578491967,
|
| 362 |
+
"step": 2000
|
| 363 |
+
},
|
| 364 |
+
{
|
| 365 |
+
"eval_hard_loss": 0.4623798727989197,
|
| 366 |
+
"eval_hard_accuracy": 0.8378151260504202,
|
| 367 |
+
"eval_hard_runtime": 0.2506,
|
| 368 |
+
"eval_hard_samples_per_second": 4749.401,
|
| 369 |
+
"eval_hard_steps_per_second": 75.831,
|
| 370 |
+
"epoch": 0.30902348578491967,
|
| 371 |
+
"step": 2000
|
| 372 |
+
},
|
| 373 |
+
{
|
| 374 |
+
"loss": 0.3629868316650391,
|
| 375 |
+
"grad_norm": 3.957963228225708,
|
| 376 |
+
"learning_rate": 0.0002902831088312284,
|
| 377 |
+
"epoch": 0.3399258343634116,
|
| 378 |
+
"step": 2200
|
| 379 |
+
},
|
| 380 |
+
{
|
| 381 |
+
"loss": 0.3620159912109375,
|
| 382 |
+
"grad_norm": 2.070098638534546,
|
| 383 |
+
"learning_rate": 0.00028734876510218624,
|
| 384 |
+
"epoch": 0.37082818294190356,
|
| 385 |
+
"step": 2400
|
| 386 |
+
},
|
| 387 |
+
{
|
| 388 |
+
"loss": 0.33227527618408204,
|
| 389 |
+
"grad_norm": 3.895007371902466,
|
| 390 |
+
"learning_rate": 0.00028404683102855547,
|
| 391 |
+
"epoch": 0.40173053152039556,
|
| 392 |
+
"step": 2600
|
| 393 |
+
},
|
| 394 |
+
{
|
| 395 |
+
"loss": 0.3365111541748047,
|
| 396 |
+
"grad_norm": 3.198639154434204,
|
| 397 |
+
"learning_rate": 0.0002803861436689221,
|
| 398 |
+
"epoch": 0.4326328800988875,
|
| 399 |
+
"step": 2800
|
| 400 |
+
},
|
| 401 |
+
{
|
| 402 |
+
"loss": 0.31873382568359376,
|
| 403 |
+
"grad_norm": 2.5327401161193848,
|
| 404 |
+
"learning_rate": 0.0002763765002233335,
|
| 405 |
+
"epoch": 0.4635352286773795,
|
| 406 |
+
"step": 3000
|
| 407 |
+
},
|
| 408 |
+
{
|
| 409 |
+
"eval_unseen_lanes_loss": 0.34330183267593384,
|
| 410 |
+
"eval_unseen_lanes_accuracy": 0.8836487744337573,
|
| 411 |
+
"eval_unseen_lanes_runtime": 0.553,
|
| 412 |
+
"eval_unseen_lanes_samples_per_second": 5828.318,
|
| 413 |
+
"eval_unseen_lanes_steps_per_second": 92.226,
|
| 414 |
+
"epoch": 0.4635352286773795,
|
| 415 |
+
"step": 3000
|
| 416 |
+
},
|
| 417 |
+
{
|
| 418 |
+
"eval_unseen_domain_loss": 0.9895414113998413,
|
| 419 |
+
"eval_unseen_domain_accuracy": 0.6378291779313107,
|
| 420 |
+
"eval_unseen_domain_runtime": 1.5853,
|
| 421 |
+
"eval_unseen_domain_samples_per_second": 6299.774,
|
| 422 |
+
"eval_unseen_domain_steps_per_second": 99.035,
|
| 423 |
+
"epoch": 0.4635352286773795,
|
| 424 |
+
"step": 3000
|
| 425 |
+
},
|
| 426 |
+
{
|
| 427 |
+
"eval_unseen_axis_loss": 1.0701825618743896,
|
| 428 |
+
"eval_unseen_axis_accuracy": 0.5737164010944793,
|
| 429 |
+
"eval_unseen_axis_runtime": 1.2712,
|
| 430 |
+
"eval_unseen_axis_samples_per_second": 9774.846,
|
| 431 |
+
"eval_unseen_axis_steps_per_second": 153.396,
|
| 432 |
+
"epoch": 0.4635352286773795,
|
| 433 |
+
"step": 3000
|
| 434 |
+
},
|
| 435 |
+
{
|
| 436 |
+
"eval_hard_loss": 0.38013485074043274,
|
| 437 |
+
"eval_hard_accuracy": 0.873109243697479,
|
| 438 |
+
"eval_hard_runtime": 0.2542,
|
| 439 |
+
"eval_hard_samples_per_second": 4681.85,
|
| 440 |
+
"eval_hard_steps_per_second": 74.752,
|
| 441 |
+
"epoch": 0.4635352286773795,
|
| 442 |
+
"step": 3000
|
| 443 |
+
},
|
| 444 |
+
{
|
| 445 |
+
"loss": 0.29870388031005857,
|
| 446 |
+
"grad_norm": 2.18878173828125,
|
| 447 |
+
"learning_rate": 0.00027202863181277745,
|
| 448 |
+
"epoch": 0.49443757725587145,
|
| 449 |
+
"step": 3200
|
| 450 |
+
},
|
| 451 |
+
{
|
| 452 |
+
"loss": 0.30184398651123046,
|
| 453 |
+
"grad_norm": 3.0138494968414307,
|
| 454 |
+
"learning_rate": 0.00026735417475918285,
|
| 455 |
+
"epoch": 0.5253399258343634,
|
| 456 |
+
"step": 3400
|
| 457 |
+
},
|
| 458 |
+
{
|
| 459 |
+
"loss": 0.32383251190185547,
|
| 460 |
+
"grad_norm": 7.008852005004883,
|
| 461 |
+
"learning_rate": 0.00026236563944280554,
|
| 462 |
+
"epoch": 0.5562422744128553,
|
| 463 |
+
"step": 3600
|
| 464 |
+
},
|
| 465 |
+
{
|
| 466 |
+
"loss": 0.3035639762878418,
|
| 467 |
+
"grad_norm": 2.690004825592041,
|
| 468 |
+
"learning_rate": 0.0002570763768203474,
|
| 469 |
+
"epoch": 0.5871446229913473,
|
| 470 |
+
"step": 3800
|
| 471 |
+
},
|
| 472 |
+
{
|
| 473 |
+
"loss": 0.2934083366394043,
|
| 474 |
+
"grad_norm": 1.9328616857528687,
|
| 475 |
+
"learning_rate": 0.0002515005426934173,
|
| 476 |
+
"epoch": 0.6180469715698393,
|
| 477 |
+
"step": 4000
|
| 478 |
+
},
|
| 479 |
+
{
|
| 480 |
+
"eval_unseen_lanes_loss": 0.30602237582206726,
|
| 481 |
+
"eval_unseen_lanes_accuracy": 0.8920260626745269,
|
| 482 |
+
"eval_unseen_lanes_runtime": 0.5511,
|
| 483 |
+
"eval_unseen_lanes_samples_per_second": 5848.268,
|
| 484 |
+
"eval_unseen_lanes_steps_per_second": 92.542,
|
| 485 |
+
"epoch": 0.6180469715698393,
|
| 486 |
+
"step": 4000
|
| 487 |
+
},
|
| 488 |
+
{
|
| 489 |
+
"eval_unseen_domain_loss": 0.983905553817749,
|
| 490 |
+
"eval_unseen_domain_accuracy": 0.6368278762391109,
|
| 491 |
+
"eval_unseen_domain_runtime": 1.5835,
|
| 492 |
+
"eval_unseen_domain_samples_per_second": 6306.791,
|
| 493 |
+
"eval_unseen_domain_steps_per_second": 99.146,
|
| 494 |
+
"epoch": 0.6180469715698393,
|
| 495 |
+
"step": 4000
|
| 496 |
+
},
|
| 497 |
+
{
|
| 498 |
+
"eval_unseen_axis_loss": 1.2108259201049805,
|
| 499 |
+
"eval_unseen_axis_accuracy": 0.5799130854659584,
|
| 500 |
+
"eval_unseen_axis_runtime": 1.2562,
|
| 501 |
+
"eval_unseen_axis_samples_per_second": 9891.534,
|
| 502 |
+
"eval_unseen_axis_steps_per_second": 155.227,
|
| 503 |
+
"epoch": 0.6180469715698393,
|
| 504 |
+
"step": 4000
|
| 505 |
+
},
|
| 506 |
+
{
|
| 507 |
+
"eval_hard_loss": 0.3655548691749573,
|
| 508 |
+
"eval_hard_accuracy": 0.8756302521008403,
|
| 509 |
+
"eval_hard_runtime": 0.2592,
|
| 510 |
+
"eval_hard_samples_per_second": 4591.918,
|
| 511 |
+
"eval_hard_steps_per_second": 73.316,
|
| 512 |
+
"epoch": 0.6180469715698393,
|
| 513 |
+
"step": 4000
|
| 514 |
+
},
|
| 515 |
+
{
|
| 516 |
+
"loss": 0.2829387664794922,
|
| 517 |
+
"grad_norm": 2.094444513320923,
|
| 518 |
+
"learning_rate": 0.00024565305982296296,
|
| 519 |
+
"epoch": 0.6489493201483313,
|
| 520 |
+
"step": 4200
|
| 521 |
+
},
|
| 522 |
+
{
|
| 523 |
+
"loss": 0.2714531135559082,
|
| 524 |
+
"grad_norm": 2.0051519870758057,
|
| 525 |
+
"learning_rate": 0.00023954957799106823,
|
| 526 |
+
"epoch": 0.6798516687268232,
|
| 527 |
+
"step": 4400
|
| 528 |
+
},
|
| 529 |
+
{
|
| 530 |
+
"loss": 0.26623159408569336,
|
| 531 |
+
"grad_norm": 2.2412750720977783,
|
| 532 |
+
"learning_rate": 0.00023320643211700308,
|
| 533 |
+
"epoch": 0.7107540173053152,
|
| 534 |
+
"step": 4600
|
| 535 |
+
},
|
| 536 |
+
{
|
| 537 |
+
"loss": 0.2522362518310547,
|
| 538 |
+
"grad_norm": 1.7817517518997192,
|
| 539 |
+
"learning_rate": 0.000226640598539622,
|
| 540 |
+
"epoch": 0.7416563658838071,
|
| 541 |
+
"step": 4800
|
| 542 |
+
},
|
| 543 |
+
{
|
| 544 |
+
"loss": 0.2480511474609375,
|
| 545 |
+
"grad_norm": 5.033050537109375,
|
| 546 |
+
"learning_rate": 0.00021986964958311316,
|
| 547 |
+
"epoch": 0.7725587144622992,
|
| 548 |
+
"step": 5000
|
| 549 |
+
},
|
| 550 |
+
{
|
| 551 |
+
"eval_unseen_lanes_loss": 0.27606716752052307,
|
| 552 |
+
"eval_unseen_lanes_accuracy": 0.9053676698727893,
|
| 553 |
+
"eval_unseen_lanes_runtime": 0.552,
|
| 554 |
+
"eval_unseen_lanes_samples_per_second": 5838.329,
|
| 555 |
+
"eval_unseen_lanes_steps_per_second": 92.384,
|
| 556 |
+
"epoch": 0.7725587144622992,
|
| 557 |
+
"step": 5000
|
| 558 |
+
},
|
| 559 |
+
{
|
| 560 |
+
"eval_unseen_domain_loss": 0.96076899766922,
|
| 561 |
+
"eval_unseen_domain_accuracy": 0.6541503955141684,
|
| 562 |
+
"eval_unseen_domain_runtime": 1.5806,
|
| 563 |
+
"eval_unseen_domain_samples_per_second": 6318.291,
|
| 564 |
+
"eval_unseen_domain_steps_per_second": 99.326,
|
| 565 |
+
"epoch": 0.7725587144622992,
|
| 566 |
+
"step": 5000
|
| 567 |
+
},
|
| 568 |
+
{
|
| 569 |
+
"eval_unseen_axis_loss": 1.4210246801376343,
|
| 570 |
+
"eval_unseen_axis_accuracy": 0.5544825366167713,
|
| 571 |
+
"eval_unseen_axis_runtime": 1.2599,
|
| 572 |
+
"eval_unseen_axis_samples_per_second": 9862.704,
|
| 573 |
+
"eval_unseen_axis_steps_per_second": 154.774,
|
| 574 |
+
"epoch": 0.7725587144622992,
|
| 575 |
+
"step": 5000
|
| 576 |
+
},
|
| 577 |
+
{
|
| 578 |
+
"eval_hard_loss": 0.3613678812980652,
|
| 579 |
+
"eval_hard_accuracy": 0.8857142857142857,
|
| 580 |
+
"eval_hard_runtime": 0.2606,
|
| 581 |
+
"eval_hard_samples_per_second": 4565.623,
|
| 582 |
+
"eval_hard_steps_per_second": 72.897,
|
| 583 |
+
"epoch": 0.7725587144622992,
|
| 584 |
+
"step": 5000
|
| 585 |
+
},
|
| 586 |
+
{
|
| 587 |
+
"loss": 0.24242013931274414,
|
| 588 |
+
"grad_norm": 2.4511566162109375,
|
| 589 |
+
"learning_rate": 0.00021291170652769533,
|
| 590 |
+
"epoch": 0.8034610630407911,
|
| 591 |
+
"step": 5200
|
| 592 |
+
},
|
| 593 |
+
{
|
| 594 |
+
"loss": 0.2558748817443848,
|
| 595 |
+
"grad_norm": 1.6439733505249023,
|
| 596 |
+
"learning_rate": 0.00020578539111112834,
|
| 597 |
+
"epoch": 0.8343634116192831,
|
| 598 |
+
"step": 5400
|
| 599 |
+
},
|
| 600 |
+
{
|
| 601 |
+
"loss": 0.24663785934448243,
|
| 602 |
+
"grad_norm": 3.4409291744232178,
|
| 603 |
+
"learning_rate": 0.00019850977569083514,
|
| 604 |
+
"epoch": 0.865265760197775,
|
| 605 |
+
"step": 5600
|
| 606 |
+
},
|
| 607 |
+
{
|
| 608 |
+
"loss": 0.24483919143676758,
|
| 609 |
+
"grad_norm": 3.071554183959961,
|
| 610 |
+
"learning_rate": 0.00019110433220001754,
|
| 611 |
+
"epoch": 0.896168108776267,
|
| 612 |
+
"step": 5800
|
| 613 |
+
},
|
| 614 |
+
{
|
| 615 |
+
"loss": 0.23662748336791992,
|
| 616 |
+
"grad_norm": 2.491429567337036,
|
| 617 |
+
"learning_rate": 0.0001835888800343768,
|
| 618 |
+
"epoch": 0.927070457354759,
|
| 619 |
+
"step": 6000
|
| 620 |
+
},
|
| 621 |
+
{
|
| 622 |
+
"eval_unseen_lanes_loss": 0.2571614384651184,
|
| 623 |
+
"eval_unseen_lanes_accuracy": 0.9081600992863792,
|
| 624 |
+
"eval_unseen_lanes_runtime": 0.5519,
|
| 625 |
+
"eval_unseen_lanes_samples_per_second": 5839.58,
|
| 626 |
+
"eval_unseen_lanes_steps_per_second": 92.404,
|
| 627 |
+
"epoch": 0.927070457354759,
|
| 628 |
+
"step": 6000
|
| 629 |
+
},
|
| 630 |
+
{
|
| 631 |
+
"eval_unseen_domain_loss": 0.9326336979866028,
|
| 632 |
+
"eval_unseen_domain_accuracy": 0.6525483128066486,
|
| 633 |
+
"eval_unseen_domain_runtime": 1.5742,
|
| 634 |
+
"eval_unseen_domain_samples_per_second": 6344.232,
|
| 635 |
+
"eval_unseen_domain_steps_per_second": 99.734,
|
| 636 |
+
"epoch": 0.927070457354759,
|
| 637 |
+
"step": 6000
|
| 638 |
+
},
|
| 639 |
+
{
|
| 640 |
+
"eval_unseen_axis_loss": 1.3221510648727417,
|
| 641 |
+
"eval_unseen_axis_accuracy": 0.5856269113149847,
|
| 642 |
+
"eval_unseen_axis_runtime": 1.2492,
|
| 643 |
+
"eval_unseen_axis_samples_per_second": 9946.782,
|
| 644 |
+
"eval_unseen_axis_steps_per_second": 156.094,
|
| 645 |
+
"epoch": 0.927070457354759,
|
| 646 |
+
"step": 6000
|
| 647 |
+
},
|
| 648 |
+
{
|
| 649 |
+
"eval_hard_loss": 0.33343571424484253,
|
| 650 |
+
"eval_hard_accuracy": 0.888235294117647,
|
| 651 |
+
"eval_hard_runtime": 0.2587,
|
| 652 |
+
"eval_hard_samples_per_second": 4600.467,
|
| 653 |
+
"eval_hard_steps_per_second": 73.453,
|
| 654 |
+
"epoch": 0.927070457354759,
|
| 655 |
+
"step": 6000
|
| 656 |
+
},
|
| 657 |
+
{
|
| 658 |
+
"loss": 0.23579851150512696,
|
| 659 |
+
"grad_norm": 2.5624895095825195,
|
| 660 |
+
"learning_rate": 0.00017598353300890969,
|
| 661 |
+
"epoch": 0.957972805933251,
|
| 662 |
+
"step": 6200
|
| 663 |
+
},
|
| 664 |
+
{
|
| 665 |
+
"loss": 0.21076148986816406,
|
| 666 |
+
"grad_norm": 0.9841051697731018,
|
| 667 |
+
"learning_rate": 0.00016830864552674267,
|
| 668 |
+
"epoch": 0.9888751545117429,
|
| 669 |
+
"step": 6400
|
| 670 |
+
},
|
| 671 |
+
{
|
| 672 |
+
"loss": 0.17771633148193358,
|
| 673 |
+
"grad_norm": 0.9096925258636475,
|
| 674 |
+
"learning_rate": 0.00016058475810407297,
|
| 675 |
+
"epoch": 1.019777503090235,
|
| 676 |
+
"step": 6600
|
| 677 |
+
},
|
| 678 |
+
{
|
| 679 |
+
"loss": 0.14182785034179687,
|
| 680 |
+
"grad_norm": 3.3751485347747803,
|
| 681 |
+
"learning_rate": 0.00015283254239701005,
|
| 682 |
+
"epoch": 1.0506798516687268,
|
| 683 |
+
"step": 6800
|
| 684 |
+
},
|
| 685 |
+
{
|
| 686 |
+
"loss": 0.1347336483001709,
|
| 687 |
+
"grad_norm": 0.5445594787597656,
|
| 688 |
+
"learning_rate": 0.00014507274587744398,
|
| 689 |
+
"epoch": 1.0815822002472189,
|
| 690 |
+
"step": 7000
|
| 691 |
+
},
|
| 692 |
+
{
|
| 693 |
+
"eval_unseen_lanes_loss": 0.2655007839202881,
|
| 694 |
+
"eval_unseen_lanes_accuracy": 0.9162271175923054,
|
| 695 |
+
"eval_unseen_lanes_runtime": 0.5535,
|
| 696 |
+
"eval_unseen_lanes_samples_per_second": 5823.011,
|
| 697 |
+
"eval_unseen_lanes_steps_per_second": 92.142,
|
| 698 |
+
"epoch": 1.0815822002472189,
|
| 699 |
+
"step": 7000
|
| 700 |
+
},
|
| 701 |
+
{
|
| 702 |
+
"eval_unseen_domain_loss": 1.0792171955108643,
|
| 703 |
+
"eval_unseen_domain_accuracy": 0.6691699208971663,
|
| 704 |
+
"eval_unseen_domain_runtime": 1.5827,
|
| 705 |
+
"eval_unseen_domain_samples_per_second": 6310.28,
|
| 706 |
+
"eval_unseen_domain_steps_per_second": 99.2,
|
| 707 |
+
"epoch": 1.0815822002472189,
|
| 708 |
+
"step": 7000
|
| 709 |
+
},
|
| 710 |
+
{
|
| 711 |
+
"eval_unseen_axis_loss": 1.5451632738113403,
|
| 712 |
+
"eval_unseen_axis_accuracy": 0.5832930951231289,
|
| 713 |
+
"eval_unseen_axis_runtime": 1.2555,
|
| 714 |
+
"eval_unseen_axis_samples_per_second": 9897.184,
|
| 715 |
+
"eval_unseen_axis_steps_per_second": 155.316,
|
| 716 |
+
"epoch": 1.0815822002472189,
|
| 717 |
+
"step": 7000
|
| 718 |
+
},
|
| 719 |
+
{
|
| 720 |
+
"eval_hard_loss": 0.3464004695415497,
|
| 721 |
+
"eval_hard_accuracy": 0.8966386554621849,
|
| 722 |
+
"eval_hard_runtime": 0.2591,
|
| 723 |
+
"eval_hard_samples_per_second": 4593.088,
|
| 724 |
+
"eval_hard_steps_per_second": 73.335,
|
| 725 |
+
"epoch": 1.0815822002472189,
|
| 726 |
+
"step": 7000
|
| 727 |
+
},
|
| 728 |
+
{
|
| 729 |
+
"loss": 0.13339081764221192,
|
| 730 |
+
"grad_norm": 2.522960901260376,
|
| 731 |
+
"learning_rate": 0.00013732613630600555,
|
| 732 |
+
"epoch": 1.1124845488257107,
|
| 733 |
+
"step": 7200
|
| 734 |
+
},
|
| 735 |
+
{
|
| 736 |
+
"loss": 0.11780735015869141,
|
| 737 |
+
"grad_norm": 1.1648684740066528,
|
| 738 |
+
"learning_rate": 0.0001296134461507269,
|
| 739 |
+
"epoch": 1.1433868974042027,
|
| 740 |
+
"step": 7400
|
| 741 |
+
},
|
| 742 |
+
{
|
| 743 |
+
"loss": 0.13406469345092772,
|
| 744 |
+
"grad_norm": 1.038225531578064,
|
| 745 |
+
"learning_rate": 0.00012195531710015758,
|
| 746 |
+
"epoch": 1.1742892459826946,
|
| 747 |
+
"step": 7600
|
| 748 |
+
},
|
| 749 |
+
{
|
| 750 |
+
"loss": 0.1309179973602295,
|
| 751 |
+
"grad_norm": 1.6545023918151855,
|
| 752 |
+
"learning_rate": 0.00011437224481943516,
|
| 753 |
+
"epoch": 1.2051915945611866,
|
| 754 |
+
"step": 7800
|
| 755 |
+
},
|
| 756 |
+
{
|
| 757 |
+
"loss": 0.13036264419555665,
|
| 758 |
+
"grad_norm": 1.7858803272247314,
|
| 759 |
+
"learning_rate": 0.00010688452409716325,
|
| 760 |
+
"epoch": 1.2360939431396787,
|
| 761 |
+
"step": 8000
|
| 762 |
+
},
|
| 763 |
+
{
|
| 764 |
+
"eval_unseen_lanes_loss": 0.26563557982444763,
|
| 765 |
+
"eval_unseen_lanes_accuracy": 0.9162271175923054,
|
| 766 |
+
"eval_unseen_lanes_runtime": 0.5528,
|
| 767 |
+
"eval_unseen_lanes_samples_per_second": 5830.741,
|
| 768 |
+
"eval_unseen_lanes_steps_per_second": 92.264,
|
| 769 |
+
"epoch": 1.2360939431396787,
|
| 770 |
+
"step": 8000
|
| 771 |
+
},
|
| 772 |
+
{
|
| 773 |
+
"eval_unseen_domain_loss": 1.1347131729125977,
|
| 774 |
+
"eval_unseen_domain_accuracy": 0.6633623710824071,
|
| 775 |
+
"eval_unseen_domain_runtime": 1.5784,
|
| 776 |
+
"eval_unseen_domain_samples_per_second": 6327.271,
|
| 777 |
+
"eval_unseen_domain_steps_per_second": 99.467,
|
| 778 |
+
"epoch": 1.2360939431396787,
|
| 779 |
+
"step": 8000
|
| 780 |
+
},
|
| 781 |
+
{
|
| 782 |
+
"eval_unseen_axis_loss": 1.7664040327072144,
|
| 783 |
+
"eval_unseen_axis_accuracy": 0.5963302752293578,
|
| 784 |
+
"eval_unseen_axis_runtime": 1.2484,
|
| 785 |
+
"eval_unseen_axis_samples_per_second": 9953.248,
|
| 786 |
+
"eval_unseen_axis_steps_per_second": 156.195,
|
| 787 |
+
"epoch": 1.2360939431396787,
|
| 788 |
+
"step": 8000
|
| 789 |
+
},
|
| 790 |
+
{
|
| 791 |
+
"eval_hard_loss": 0.34612923860549927,
|
| 792 |
+
"eval_hard_accuracy": 0.8957983193277311,
|
| 793 |
+
"eval_hard_runtime": 0.2561,
|
| 794 |
+
"eval_hard_samples_per_second": 4646.719,
|
| 795 |
+
"eval_hard_steps_per_second": 74.191,
|
| 796 |
+
"epoch": 1.2360939431396787,
|
| 797 |
+
"step": 8000
|
| 798 |
+
},
|
| 799 |
+
{
|
| 800 |
+
"loss": 0.13536205291748046,
|
| 801 |
+
"grad_norm": 1.5142947435379028,
|
| 802 |
+
"learning_rate": 9.95121945299005e-05,
|
| 803 |
+
"epoch": 1.2669962917181705,
|
| 804 |
+
"step": 8200
|
| 805 |
+
},
|
| 806 |
+
{
|
| 807 |
+
"loss": 0.12326237678527832,
|
| 808 |
+
"grad_norm": 5.0126051902771,
|
| 809 |
+
"learning_rate": 9.227498688962761e-05,
|
| 810 |
+
"epoch": 1.2978986402966626,
|
| 811 |
+
"step": 8400
|
| 812 |
+
},
|
| 813 |
+
{
|
| 814 |
+
"loss": 0.12851189613342284,
|
| 815 |
+
"grad_norm": 3.0441036224365234,
|
| 816 |
+
"learning_rate": 8.519227031772971e-05,
|
| 817 |
+
"epoch": 1.3288009888751544,
|
| 818 |
+
"step": 8600
|
| 819 |
+
},
|
| 820 |
+
{
|
| 821 |
+
"loss": 0.11189216613769531,
|
| 822 |
+
"grad_norm": 1.7037580013275146,
|
| 823 |
+
"learning_rate": 7.828300048682143e-05,
|
| 824 |
+
"epoch": 1.3597033374536465,
|
| 825 |
+
"step": 8800
|
| 826 |
+
},
|
| 827 |
+
{
|
| 828 |
+
"loss": 0.12371747016906738,
|
| 829 |
+
"grad_norm": 0.7055680751800537,
|
| 830 |
+
"learning_rate": 7.156566886914933e-05,
|
| 831 |
+
"epoch": 1.3906056860321385,
|
| 832 |
+
"step": 9000
|
| 833 |
+
},
|
| 834 |
+
{
|
| 835 |
+
"eval_unseen_lanes_loss": 0.23261435329914093,
|
| 836 |
+
"eval_unseen_lanes_accuracy": 0.9221222463543283,
|
| 837 |
+
"eval_unseen_lanes_runtime": 0.5543,
|
| 838 |
+
"eval_unseen_lanes_samples_per_second": 5814.13,
|
| 839 |
+
"eval_unseen_lanes_steps_per_second": 92.001,
|
| 840 |
+
"epoch": 1.3906056860321385,
|
| 841 |
+
"step": 9000
|
| 842 |
+
},
|
| 843 |
+
{
|
| 844 |
+
"eval_unseen_domain_loss": 0.9834672808647156,
|
| 845 |
+
"eval_unseen_domain_accuracy": 0.6840893161109443,
|
| 846 |
+
"eval_unseen_domain_runtime": 1.579,
|
| 847 |
+
"eval_unseen_domain_samples_per_second": 6324.919,
|
| 848 |
+
"eval_unseen_domain_steps_per_second": 99.43,
|
| 849 |
+
"epoch": 1.3906056860321385,
|
| 850 |
+
"step": 9000
|
| 851 |
+
},
|
| 852 |
+
{
|
| 853 |
+
"eval_unseen_axis_loss": 1.5792756080627441,
|
| 854 |
+
"eval_unseen_axis_accuracy": 0.593996459037502,
|
| 855 |
+
"eval_unseen_axis_runtime": 1.2867,
|
| 856 |
+
"eval_unseen_axis_samples_per_second": 9657.248,
|
| 857 |
+
"eval_unseen_axis_steps_per_second": 151.55,
|
| 858 |
+
"epoch": 1.3906056860321385,
|
| 859 |
+
"step": 9000
|
| 860 |
+
},
|
| 861 |
+
{
|
| 862 |
+
"eval_hard_loss": 0.31886979937553406,
|
| 863 |
+
"eval_hard_accuracy": 0.9,
|
| 864 |
+
"eval_hard_runtime": 0.2641,
|
| 865 |
+
"eval_hard_samples_per_second": 4505.693,
|
| 866 |
+
"eval_hard_steps_per_second": 71.94,
|
| 867 |
+
"epoch": 1.3906056860321385,
|
| 868 |
+
"step": 9000
|
| 869 |
+
},
|
| 870 |
+
{
|
| 871 |
+
"loss": 0.11327756881713867,
|
| 872 |
+
"grad_norm": 2.5306780338287354,
|
| 873 |
+
"learning_rate": 6.505825324734749e-05,
|
| 874 |
+
"epoch": 1.4215080346106304,
|
| 875 |
+
"step": 9200
|
| 876 |
+
},
|
| 877 |
+
{
|
| 878 |
+
"loss": 0.11213048934936523,
|
| 879 |
+
"grad_norm": 3.7060656547546387,
|
| 880 |
+
"learning_rate": 5.8778169599994366e-05,
|
| 881 |
+
"epoch": 1.4524103831891224,
|
| 882 |
+
"step": 9400
|
| 883 |
+
},
|
| 884 |
+
{
|
| 885 |
+
"loss": 0.11299308776855468,
|
| 886 |
+
"grad_norm": 2.2346725463867188,
|
| 887 |
+
"learning_rate": 5.274222549074192e-05,
|
| 888 |
+
"epoch": 1.4833127317676142,
|
| 889 |
+
"step": 9600
|
| 890 |
+
},
|
| 891 |
+
{
|
| 892 |
+
"loss": 0.10625232696533203,
|
| 893 |
+
"grad_norm": 2.6063334941864014,
|
| 894 |
+
"learning_rate": 4.696657508576255e-05,
|
| 895 |
+
"epoch": 1.5142150803461063,
|
| 896 |
+
"step": 9800
|
| 897 |
+
},
|
| 898 |
+
{
|
| 899 |
+
"loss": 0.10512189865112305,
|
| 900 |
+
"grad_norm": 4.146987438201904,
|
| 901 |
+
"learning_rate": 4.146667591990211e-05,
|
| 902 |
+
"epoch": 1.5451174289245984,
|
| 903 |
+
"step": 10000
|
| 904 |
+
},
|
| 905 |
+
{
|
| 906 |
+
"eval_unseen_lanes_loss": 0.2341764271259308,
|
| 907 |
+
"eval_unseen_lanes_accuracy": 0.9286379149860379,
|
| 908 |
+
"eval_unseen_lanes_runtime": 0.5514,
|
| 909 |
+
"eval_unseen_lanes_samples_per_second": 5845.486,
|
| 910 |
+
"eval_unseen_lanes_steps_per_second": 92.498,
|
| 911 |
+
"epoch": 1.5451174289245984,
|
| 912 |
+
"step": 10000
|
| 913 |
+
},
|
| 914 |
+
{
|
| 915 |
+
"eval_unseen_domain_loss": 1.1408356428146362,
|
| 916 |
+
"eval_unseen_domain_accuracy": 0.6845899669570441,
|
| 917 |
+
"eval_unseen_domain_runtime": 1.5844,
|
| 918 |
+
"eval_unseen_domain_samples_per_second": 6303.222,
|
| 919 |
+
"eval_unseen_domain_steps_per_second": 99.089,
|
| 920 |
+
"epoch": 1.5451174289245984,
|
| 921 |
+
"step": 10000
|
| 922 |
+
},
|
| 923 |
+
{
|
| 924 |
+
"eval_unseen_axis_loss": 1.6913553476333618,
|
| 925 |
+
"eval_unseen_axis_accuracy": 0.6064703042008691,
|
| 926 |
+
"eval_unseen_axis_runtime": 1.2705,
|
| 927 |
+
"eval_unseen_axis_samples_per_second": 9780.492,
|
| 928 |
+
"eval_unseen_axis_steps_per_second": 153.484,
|
| 929 |
+
"epoch": 1.5451174289245984,
|
| 930 |
+
"step": 10000
|
| 931 |
+
},
|
| 932 |
+
{
|
| 933 |
+
"eval_hard_loss": 0.3436157703399658,
|
| 934 |
+
"eval_hard_accuracy": 0.9042016806722689,
|
| 935 |
+
"eval_hard_runtime": 0.2553,
|
| 936 |
+
"eval_hard_samples_per_second": 4661.691,
|
| 937 |
+
"eval_hard_steps_per_second": 74.43,
|
| 938 |
+
"epoch": 1.5451174289245984,
|
| 939 |
+
"step": 10000
|
| 940 |
+
},
|
| 941 |
+
{
|
| 942 |
+
"loss": 0.10526069641113281,
|
| 943 |
+
"grad_norm": 1.0956754684448242,
|
| 944 |
+
"learning_rate": 3.625724752724645e-05,
|
| 945 |
+
"epoch": 1.5760197775030902,
|
| 946 |
+
"step": 10200
|
| 947 |
+
},
|
| 948 |
+
{
|
| 949 |
+
"loss": 0.0974786376953125,
|
| 950 |
+
"grad_norm": 1.1272306442260742,
|
| 951 |
+
"learning_rate": 3.135223204682058e-05,
|
| 952 |
+
"epoch": 1.6069221260815822,
|
| 953 |
+
"step": 10400
|
| 954 |
+
},
|
| 955 |
+
{
|
| 956 |
+
"loss": 0.101556396484375,
|
| 957 |
+
"grad_norm": 3.4264066219329834,
|
| 958 |
+
"learning_rate": 2.6764756908851686e-05,
|
| 959 |
+
"epoch": 1.637824474660074,
|
| 960 |
+
"step": 10600
|
| 961 |
+
},
|
| 962 |
+
{
|
| 963 |
+
"loss": 0.10870396614074707,
|
| 964 |
+
"grad_norm": 1.7836824655532837,
|
| 965 |
+
"learning_rate": 2.2507099701460036e-05,
|
| 966 |
+
"epoch": 1.6687268232385661,
|
| 967 |
+
"step": 10800
|
| 968 |
+
},
|
| 969 |
+
{
|
| 970 |
+
"loss": 0.09275879859924316,
|
| 971 |
+
"grad_norm": 1.3714878559112549,
|
| 972 |
+
"learning_rate": 1.8590655311806385e-05,
|
| 973 |
+
"epoch": 1.6996291718170582,
|
| 974 |
+
"step": 11000
|
| 975 |
+
},
|
| 976 |
+
{
|
| 977 |
+
"eval_unseen_lanes_loss": 0.21319718658924103,
|
| 978 |
+
"eval_unseen_lanes_accuracy": 0.9304995345950977,
|
| 979 |
+
"eval_unseen_lanes_runtime": 0.5553,
|
| 980 |
+
"eval_unseen_lanes_samples_per_second": 5804.033,
|
| 981 |
+
"eval_unseen_lanes_steps_per_second": 91.842,
|
| 982 |
+
"epoch": 1.6996291718170582,
|
| 983 |
+
"step": 11000
|
| 984 |
+
},
|
| 985 |
+
{
|
| 986 |
+
"eval_unseen_domain_loss": 1.022688627243042,
|
| 987 |
+
"eval_unseen_domain_accuracy": 0.6976068889556424,
|
| 988 |
+
"eval_unseen_domain_runtime": 1.5825,
|
| 989 |
+
"eval_unseen_domain_samples_per_second": 6310.792,
|
| 990 |
+
"eval_unseen_domain_steps_per_second": 99.208,
|
| 991 |
+
"epoch": 1.6996291718170582,
|
| 992 |
+
"step": 11000
|
| 993 |
+
},
|
| 994 |
+
{
|
| 995 |
+
"eval_unseen_axis_loss": 1.5096590518951416,
|
| 996 |
+
"eval_unseen_axis_accuracy": 0.6129888942539836,
|
| 997 |
+
"eval_unseen_axis_runtime": 1.2878,
|
| 998 |
+
"eval_unseen_axis_samples_per_second": 9649.329,
|
| 999 |
+
"eval_unseen_axis_steps_per_second": 151.426,
|
| 1000 |
+
"epoch": 1.6996291718170582,
|
| 1001 |
+
"step": 11000
|
| 1002 |
+
},
|
| 1003 |
+
{
|
| 1004 |
+
"eval_hard_loss": 0.31117716431617737,
|
| 1005 |
+
"eval_hard_accuracy": 0.9008403361344538,
|
| 1006 |
+
"eval_hard_runtime": 0.2589,
|
| 1007 |
+
"eval_hard_samples_per_second": 4596.879,
|
| 1008 |
+
"eval_hard_steps_per_second": 73.396,
|
| 1009 |
+
"epoch": 1.6996291718170582,
|
| 1010 |
+
"step": 11000
|
| 1011 |
+
},
|
| 1012 |
+
{
|
| 1013 |
+
"loss": 0.09593048095703124,
|
| 1014 |
+
"grad_norm": 3.177462100982666,
|
| 1015 |
+
"learning_rate": 1.5025905429636426e-05,
|
| 1016 |
+
"epoch": 1.73053152039555,
|
| 1017 |
+
"step": 11200
|
| 1018 |
+
},
|
| 1019 |
+
{
|
| 1020 |
+
"loss": 0.09772712707519532,
|
| 1021 |
+
"grad_norm": 2.102013349533081,
|
| 1022 |
+
"learning_rate": 1.1822390494841139e-05,
|
| 1023 |
+
"epoch": 1.7614338689740419,
|
| 1024 |
+
"step": 11400
|
| 1025 |
+
},
|
| 1026 |
+
{
|
| 1027 |
+
"loss": 0.08881115913391113,
|
| 1028 |
+
"grad_norm": 0.3349379897117615,
|
| 1029 |
+
"learning_rate": 8.98868416411046e-06,
|
| 1030 |
+
"epoch": 1.792336217552534,
|
| 1031 |
+
"step": 11600
|
| 1032 |
+
},
|
| 1033 |
+
{
|
| 1034 |
+
"loss": 0.09125228881835938,
|
| 1035 |
+
"grad_norm": 1.5826376676559448,
|
| 1036 |
+
"learning_rate": 6.532370365015982e-06,
|
| 1037 |
+
"epoch": 1.823238566131026,
|
| 1038 |
+
"step": 11800
|
| 1039 |
+
},
|
| 1040 |
+
{
|
| 1041 |
+
"loss": 0.1032994556427002,
|
| 1042 |
+
"grad_norm": 2.430258274078369,
|
| 1043 |
+
"learning_rate": 4.460022998933166e-06,
|
| 1044 |
+
"epoch": 1.854140914709518,
|
| 1045 |
+
"step": 12000
|
| 1046 |
+
},
|
| 1047 |
+
{
|
| 1048 |
+
"eval_unseen_lanes_loss": 0.21029867231845856,
|
| 1049 |
+
"eval_unseen_lanes_accuracy": 0.9329816940738442,
|
| 1050 |
+
"eval_unseen_lanes_runtime": 0.5539,
|
| 1051 |
+
"eval_unseen_lanes_samples_per_second": 5818.497,
|
| 1052 |
+
"eval_unseen_lanes_steps_per_second": 92.071,
|
| 1053 |
+
"epoch": 1.854140914709518,
|
| 1054 |
+
"step": 12000
|
| 1055 |
+
},
|
| 1056 |
+
{
|
| 1057 |
+
"eval_unseen_domain_loss": 1.0129146575927734,
|
| 1058 |
+
"eval_unseen_domain_accuracy": 0.700010013016922,
|
| 1059 |
+
"eval_unseen_domain_runtime": 1.5764,
|
| 1060 |
+
"eval_unseen_domain_samples_per_second": 6335.382,
|
| 1061 |
+
"eval_unseen_domain_steps_per_second": 99.595,
|
| 1062 |
+
"epoch": 1.854140914709518,
|
| 1063 |
+
"step": 12000
|
| 1064 |
+
},
|
| 1065 |
+
{
|
| 1066 |
+
"eval_unseen_axis_loss": 1.5864043235778809,
|
| 1067 |
+
"eval_unseen_axis_accuracy": 0.6117817479478512,
|
| 1068 |
+
"eval_unseen_axis_runtime": 1.2684,
|
| 1069 |
+
"eval_unseen_axis_samples_per_second": 9796.563,
|
| 1070 |
+
"eval_unseen_axis_steps_per_second": 153.737,
|
| 1071 |
+
"epoch": 1.854140914709518,
|
| 1072 |
+
"step": 12000
|
| 1073 |
+
},
|
| 1074 |
+
{
|
| 1075 |
+
"eval_hard_loss": 0.30691978335380554,
|
| 1076 |
+
"eval_hard_accuracy": 0.9084033613445378,
|
| 1077 |
+
"eval_hard_runtime": 0.2602,
|
| 1078 |
+
"eval_hard_samples_per_second": 4573.644,
|
| 1079 |
+
"eval_hard_steps_per_second": 73.025,
|
| 1080 |
+
"epoch": 1.854140914709518,
|
| 1081 |
+
"step": 12000
|
| 1082 |
+
},
|
| 1083 |
+
{
|
| 1084 |
+
"loss": 0.08737665176391601,
|
| 1085 |
+
"grad_norm": 1.072799801826477,
|
| 1086 |
+
"learning_rate": 2.7771883471252034e-06,
|
| 1087 |
+
"epoch": 1.8850432632880099,
|
| 1088 |
+
"step": 12200
|
| 1089 |
+
},
|
| 1090 |
+
{
|
| 1091 |
+
"loss": 0.08102713584899902,
|
| 1092 |
+
"grad_norm": 1.5238364934921265,
|
| 1093 |
+
"learning_rate": 1.4883702270751197e-06,
|
| 1094 |
+
"epoch": 1.9159456118665017,
|
| 1095 |
+
"step": 12400
|
| 1096 |
+
},
|
| 1097 |
+
{
|
| 1098 |
+
"loss": 0.09933463096618653,
|
| 1099 |
+
"grad_norm": 0.16273926198482513,
|
| 1100 |
+
"learning_rate": 5.970179387931151e-07,
|
| 1101 |
+
"epoch": 1.9468479604449938,
|
| 1102 |
+
"step": 12600
|
| 1103 |
+
},
|
| 1104 |
+
{
|
| 1105 |
+
"loss": 0.10335576057434082,
|
| 1106 |
+
"grad_norm": 0.17151758074760437,
|
| 1107 |
+
"learning_rate": 1.0551703335823225e-07,
|
| 1108 |
+
"epoch": 1.9777503090234858,
|
| 1109 |
+
"step": 12800
|
| 1110 |
+
},
|
| 1111 |
+
{
|
| 1112 |
+
"eval_unseen_lanes_loss": 0.21011516451835632,
|
| 1113 |
+
"eval_unseen_lanes_accuracy": 0.9336022339435309,
|
| 1114 |
+
"eval_unseen_lanes_runtime": 0.5534,
|
| 1115 |
+
"eval_unseen_lanes_samples_per_second": 5823.753,
|
| 1116 |
+
"eval_unseen_lanes_steps_per_second": 92.154,
|
| 1117 |
+
"epoch": 2.0,
|
| 1118 |
+
"step": 12944
|
| 1119 |
+
},
|
| 1120 |
+
{
|
| 1121 |
+
"eval_unseen_domain_loss": 1.0266432762145996,
|
| 1122 |
+
"eval_unseen_domain_accuracy": 0.7009111845399019,
|
| 1123 |
+
"eval_unseen_domain_runtime": 1.5817,
|
| 1124 |
+
"eval_unseen_domain_samples_per_second": 6314.155,
|
| 1125 |
+
"eval_unseen_domain_steps_per_second": 99.261,
|
| 1126 |
+
"epoch": 2.0,
|
| 1127 |
+
"step": 12944
|
| 1128 |
+
},
|
| 1129 |
+
{
|
| 1130 |
+
"eval_unseen_axis_loss": 1.6092302799224854,
|
| 1131 |
+
"eval_unseen_axis_accuracy": 0.6111379365845807,
|
| 1132 |
+
"eval_unseen_axis_runtime": 1.2767,
|
| 1133 |
+
"eval_unseen_axis_samples_per_second": 9732.892,
|
| 1134 |
+
"eval_unseen_axis_steps_per_second": 152.737,
|
| 1135 |
+
"epoch": 2.0,
|
| 1136 |
+
"step": 12944
|
| 1137 |
+
},
|
| 1138 |
+
{
|
| 1139 |
+
"eval_hard_loss": 0.3078996539115906,
|
| 1140 |
+
"eval_hard_accuracy": 0.9084033613445378,
|
| 1141 |
+
"eval_hard_runtime": 0.2718,
|
| 1142 |
+
"eval_hard_samples_per_second": 4377.996,
|
| 1143 |
+
"eval_hard_steps_per_second": 69.901,
|
| 1144 |
+
"epoch": 2.0,
|
| 1145 |
+
"step": 12944
|
| 1146 |
+
},
|
| 1147 |
+
{
|
| 1148 |
+
"train_runtime": 262.1825,
|
| 1149 |
+
"train_samples_per_second": 1579.793,
|
| 1150 |
+
"train_steps_per_second": 49.37,
|
| 1151 |
+
"total_flos": 0.0,
|
| 1152 |
+
"train_loss": 0.2282541081106707,
|
| 1153 |
+
"epoch": 2.0,
|
| 1154 |
+
"step": 12944
|
| 1155 |
+
}
|
| 1156 |
+
]
|
| 1157 |
+
}
|
train_router_head.py
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Arabic zero-shot router with a real routing head.
|
| 3 |
+
|
| 4 |
+
Two earlier formulations, and why this one:
|
| 5 |
+
|
| 6 |
+
fixed-slot head - `num_labels = max_lanes` over one pooled vector. Scored exactly 1/n at every
|
| 7 |
+
lane count. The head is positional (slot i's logit is w_i . h) and the corpus
|
| 8 |
+
randomises lane order, so there is nothing to learn.
|
| 9 |
+
pairwise - score each (text, category) separately, argmax. Works (0.842 on unseen lane
|
| 10 |
+
sets) but costs n forward passes and each category is scored in isolation,
|
| 11 |
+
never against its competitors.
|
| 12 |
+
|
| 13 |
+
Here the categories live in the sequence and get their *own* pooled vectors, which a shared linear
|
| 14 |
+
head turns into one logit each; the softmax is over the categories present. The head is shared
|
| 15 |
+
across positions, so it scores category *content*, not slot index - which is what makes it
|
| 16 |
+
position-invariant and zero-shot.
|
| 17 |
+
|
| 18 |
+
Layout is text-first, categories-second, deliberately. The reference encoder is bidirectional so
|
| 19 |
+
order does not matter there; our base is causal, and this ordering is what lets every category
|
| 20 |
+
token attend to the whole text. Reversed, the categories would be encoded blind to the text.
|
| 21 |
+
|
| 22 |
+
النص:
|
| 23 |
+
{text}
|
| 24 |
+
|
| 25 |
+
الفئات:
|
| 26 |
+
- فئة أولى
|
| 27 |
+
- فئة ثانية
|
| 28 |
+
|
| 29 |
+
Each category's character span is mapped to token indices via the tokenizer's offset mapping and
|
| 30 |
+
mean-pooled. Slots beyond a row's category count are masked to -inf before the loss.
|
| 31 |
+
"""
|
| 32 |
+
import json
|
| 33 |
+
import os
|
| 34 |
+
from collections import defaultdict
|
| 35 |
+
from pathlib import Path
|
| 36 |
+
|
| 37 |
+
import numpy as np
|
| 38 |
+
import torch
|
| 39 |
+
import torch.nn as nn
|
| 40 |
+
import torch.nn.functional as F
|
| 41 |
+
from torch.utils.data import Dataset
|
| 42 |
+
from transformers import AutoModel, AutoTokenizer, Trainer, TrainingArguments
|
| 43 |
+
|
| 44 |
+
os.environ.setdefault("CUDA_VISIBLE_DEVICES", "0")
|
| 45 |
+
|
| 46 |
+
BASE_MODEL = os.environ.get("BASE_MODEL", "oddadmix/50M-2048-Emhotob")
|
| 47 |
+
OUTPUT_DIR = os.environ.get("OUTPUT_DIR", "./Nawah-Router-head-50M")
|
| 48 |
+
DATA = Path(os.environ.get("DATA_DIR", "data"))
|
| 49 |
+
MAX_ROUTES = int(os.environ.get("MAX_ROUTES", 9))
|
| 50 |
+
MAX_LENGTH = int(os.environ.get("MAX_LENGTH", 320))
|
| 51 |
+
LR = float(os.environ.get("LR", 3e-4))
|
| 52 |
+
EPOCHS = float(os.environ.get("EPOCHS", 3))
|
| 53 |
+
BATCH_SIZE = int(os.environ.get("BATCH_SIZE", 32))
|
| 54 |
+
WARMUP = int(os.environ.get("WARMUP", 500))
|
| 55 |
+
SEED = 42
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
def build_text(row):
|
| 59 |
+
"""-> (full string, [(start, end) char span per category])."""
|
| 60 |
+
head = f"النص:\n{row['text']}\n\nالفئات:\n"
|
| 61 |
+
s = head
|
| 62 |
+
spans = []
|
| 63 |
+
for c in row["routes"]:
|
| 64 |
+
s += "- "
|
| 65 |
+
spans.append((len(s), len(s) + len(c)))
|
| 66 |
+
s += c + "\n"
|
| 67 |
+
return s, spans
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
class RouterModel(nn.Module):
|
| 71 |
+
"""Backbone + a shared linear scorer applied to each category's pooled span."""
|
| 72 |
+
|
| 73 |
+
def __init__(self, base_model):
|
| 74 |
+
super().__init__()
|
| 75 |
+
self.backbone = AutoModel.from_pretrained(base_model, dtype=torch.float32)
|
| 76 |
+
h = self.backbone.config.hidden_size
|
| 77 |
+
self.score = nn.Sequential(nn.Linear(h, h), nn.GELU(), nn.Linear(h, 1))
|
| 78 |
+
self.config = self.backbone.config
|
| 79 |
+
|
| 80 |
+
def forward(self, input_ids, attention_mask, cat_pool, n_routes, labels=None):
|
| 81 |
+
hs = self.backbone(input_ids=input_ids, attention_mask=attention_mask).last_hidden_state
|
| 82 |
+
# cat_pool: (B, K, T) row-normalised selector -> (B, K, H)
|
| 83 |
+
cat_vecs = torch.bmm(cat_pool.to(hs.dtype), hs)
|
| 84 |
+
logits = self.score(cat_vecs).squeeze(-1) # (B, K)
|
| 85 |
+
ar = torch.arange(logits.size(1), device=logits.device)[None, :]
|
| 86 |
+
logits = logits.masked_fill(ar >= n_routes[:, None], torch.finfo(logits.dtype).min)
|
| 87 |
+
loss = F.cross_entropy(logits, labels) if labels is not None else None
|
| 88 |
+
return {"loss": loss, "logits": logits}
|
| 89 |
+
|
| 90 |
+
|
| 91 |
+
def load(name):
|
| 92 |
+
p = DATA / f"{name}.jsonl"
|
| 93 |
+
return [json.loads(l) for l in open(p, encoding="utf-8")] if p.exists() else []
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
class RouterDataset(Dataset):
|
| 97 |
+
def __init__(self, rows, tok, max_length):
|
| 98 |
+
self.rows, self.tok, self.max_length = rows, tok, max_length
|
| 99 |
+
|
| 100 |
+
def __len__(self):
|
| 101 |
+
return len(self.rows)
|
| 102 |
+
|
| 103 |
+
def __getitem__(self, i):
|
| 104 |
+
r = self.rows[i]
|
| 105 |
+
text, spans = build_text(r)
|
| 106 |
+
enc = self.tok(text, return_offsets_mapping=True, add_special_tokens=False,
|
| 107 |
+
truncation=True, max_length=self.max_length)
|
| 108 |
+
ids, offs = enc["input_ids"], enc["offset_mapping"]
|
| 109 |
+
pool = torch.zeros(MAX_ROUTES, len(ids))
|
| 110 |
+
for ci, (s, e) in enumerate(spans[:MAX_ROUTES]):
|
| 111 |
+
idxs = [t for t, (a, b) in enumerate(offs) if a < e and b > s and a != b]
|
| 112 |
+
if idxs:
|
| 113 |
+
pool[ci, idxs] = 1.0 / len(idxs)
|
| 114 |
+
return {"input_ids": torch.tensor(ids, dtype=torch.long), "cat_pool": pool,
|
| 115 |
+
"n_routes": torch.tensor(min(len(r["routes"]), MAX_ROUTES), dtype=torch.long),
|
| 116 |
+
"labels": torch.tensor(min(r["label"], MAX_ROUTES - 1), dtype=torch.long)}
|
| 117 |
+
|
| 118 |
+
|
| 119 |
+
class Collator:
|
| 120 |
+
def __init__(self, pad_id):
|
| 121 |
+
self.pad_id = pad_id
|
| 122 |
+
|
| 123 |
+
def __call__(self, feats):
|
| 124 |
+
T = max(f["input_ids"].size(0) for f in feats)
|
| 125 |
+
ids, att, pools = [], [], []
|
| 126 |
+
for f in feats:
|
| 127 |
+
n = f["input_ids"].size(0); pad = T - n
|
| 128 |
+
ids.append(torch.cat([f["input_ids"], torch.full((pad,), self.pad_id, dtype=torch.long)]))
|
| 129 |
+
att.append(torch.cat([torch.ones(n, dtype=torch.long), torch.zeros(pad, dtype=torch.long)]))
|
| 130 |
+
pools.append(F.pad(f["cat_pool"], (0, pad)))
|
| 131 |
+
return {"input_ids": torch.stack(ids), "attention_mask": torch.stack(att),
|
| 132 |
+
"cat_pool": torch.stack(pools),
|
| 133 |
+
"n_routes": torch.stack([f["n_routes"] for f in feats]),
|
| 134 |
+
"labels": torch.stack([f["labels"] for f in feats])}
|
| 135 |
+
|
| 136 |
+
|
| 137 |
+
def metrics_fn(p):
|
| 138 |
+
return {"accuracy": float((np.asarray(p.predictions).argmax(-1) ==
|
| 139 |
+
np.asarray(p.label_ids)).mean())}
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
@torch.no_grad()
|
| 143 |
+
def report(model, tok, rows, name, batch=64):
|
| 144 |
+
model.eval()
|
| 145 |
+
ds = RouterDataset(rows, tok, MAX_LENGTH); coll = Collator(tok.pad_token_id)
|
| 146 |
+
preds = []
|
| 147 |
+
for i in range(0, len(rows), batch):
|
| 148 |
+
b = coll([ds[j] for j in range(i, min(i + batch, len(rows)))])
|
| 149 |
+
b = {k: v.to(next(model.parameters()).device) for k, v in b.items()}
|
| 150 |
+
b.pop("labels")
|
| 151 |
+
preds += model(**b)["logits"].argmax(-1).tolist()
|
| 152 |
+
correct = [int(p == r["label"]) for p, r in zip(preds, rows)]
|
| 153 |
+
acc = sum(correct) / len(rows)
|
| 154 |
+
rand = sum(1 / len(r["routes"]) for r in rows) / len(rows)
|
| 155 |
+
print(f"\n[{name}] n={len(rows):,} route accuracy {acc:.4f} random {rand:.4f}")
|
| 156 |
+
out = {"accuracy": acc, "random_baseline": rand, "n": len(rows)}
|
| 157 |
+
for key in ("n_routes", "difficulty", "mode"):
|
| 158 |
+
if key == "mode" and not all("mode" in r for r in rows):
|
| 159 |
+
continue
|
| 160 |
+
b = defaultdict(lambda: [0, 0])
|
| 161 |
+
for c, r in zip(correct, rows):
|
| 162 |
+
k = len(r["routes"]) if key == "n_routes" else r[key]
|
| 163 |
+
b[k][1] += 1; b[k][0] += c
|
| 164 |
+
print(f" by {key:<10} " +
|
| 165 |
+
" ".join(f"{k}:{v[0]/v[1]:.3f}(n={v[1]})" for k, v in sorted(b.items(), key=str)))
|
| 166 |
+
out[f"by_{key}"] = {str(k): {"acc": v[0]/v[1], "n": v[1]} for k, v in b.items()}
|
| 167 |
+
return out
|
| 168 |
+
|
| 169 |
+
|
| 170 |
+
def main():
|
| 171 |
+
tok = AutoTokenizer.from_pretrained(BASE_MODEL)
|
| 172 |
+
if tok.pad_token_id is None:
|
| 173 |
+
tok.pad_token = tok.eos_token
|
| 174 |
+
model = RouterModel(BASE_MODEL)
|
| 175 |
+
print(f"[*] {BASE_MODEL} | params {sum(p.numel() for p in model.parameters())/1e6:.2f}M "
|
| 176 |
+
f"| hidden {model.config.hidden_size}")
|
| 177 |
+
|
| 178 |
+
train = load("train")
|
| 179 |
+
evals = {"unseen_lanes": load("eval_unseen_lanes"),
|
| 180 |
+
"unseen_domain": load("eval_unseen_domain"),
|
| 181 |
+
# v2 only: axes held out of training entirely. The strongest zero-shot test, so the
|
| 182 |
+
# checkpoint is selected on it when it exists.
|
| 183 |
+
"unseen_axis": load("eval_unseen_axis"),
|
| 184 |
+
"hard": load("eval_hard")}
|
| 185 |
+
evals = {k: v for k, v in evals.items() if v}
|
| 186 |
+
print(f"[*] train {len(train):,} | " + " | ".join(f"{k} {len(v):,}" for k, v in evals.items()))
|
| 187 |
+
|
| 188 |
+
args = TrainingArguments(
|
| 189 |
+
output_dir=OUTPUT_DIR, num_train_epochs=EPOCHS,
|
| 190 |
+
per_device_train_batch_size=BATCH_SIZE, per_device_eval_batch_size=64,
|
| 191 |
+
learning_rate=LR, lr_scheduler_type="cosine", warmup_steps=WARMUP,
|
| 192 |
+
max_grad_norm=1.0, bf16=True, logging_steps=200,
|
| 193 |
+
eval_strategy="steps", eval_steps=1000, save_strategy="steps", save_steps=1000,
|
| 194 |
+
save_total_limit=2, load_best_model_at_end=True,
|
| 195 |
+
metric_for_best_model=("eval_unseen_axis_accuracy" if "unseen_axis" in evals
|
| 196 |
+
else "eval_unseen_domain_accuracy"), greater_is_better=True,
|
| 197 |
+
report_to=[], seed=SEED, dataloader_num_workers=4, remove_unused_columns=False,
|
| 198 |
+
label_names=["labels"])
|
| 199 |
+
|
| 200 |
+
trainer = Trainer(model=model, args=args,
|
| 201 |
+
train_dataset=RouterDataset(train, tok, MAX_LENGTH),
|
| 202 |
+
eval_dataset={k: RouterDataset(v, tok, MAX_LENGTH)
|
| 203 |
+
for k, v in evals.items() if v},
|
| 204 |
+
data_collator=Collator(tok.pad_token_id), compute_metrics=metrics_fn)
|
| 205 |
+
trainer.train()
|
| 206 |
+
|
| 207 |
+
Path(OUTPUT_DIR).mkdir(exist_ok=True)
|
| 208 |
+
torch.save(model.state_dict(), Path(OUTPUT_DIR, "router_model.pt"))
|
| 209 |
+
model.backbone.save_pretrained(OUTPUT_DIR); tok.save_pretrained(OUTPUT_DIR)
|
| 210 |
+
results = {k: report(model, tok, v, k) for k, v in evals.items() if v}
|
| 211 |
+
Path(OUTPUT_DIR, "train_metrics.json").write_text(json.dumps(
|
| 212 |
+
{"results": results, "base_model": BASE_MODEL, "formulation": "routing_head",
|
| 213 |
+
"log_history": trainer.state.log_history}, ensure_ascii=False, indent=2), encoding="utf-8")
|
| 214 |
+
print(f"\n[+] done -> {OUTPUT_DIR}")
|
| 215 |
+
|
| 216 |
+
|
| 217 |
+
if __name__ == "__main__":
|
| 218 |
+
main()
|