Instructions to use emrevrg/AUBIN-12B-Control with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use emrevrg/AUBIN-12B-Control with PEFT:
from peft import PeftModel from transformers import AutoModelForCausalLM base_model = AutoModelForCausalLM.from_pretrained("google/gemma-4-12B-it") model = PeftModel.from_pretrained(base_model, "emrevrg/AUBIN-12B-Control") - Notebooks
- Google Colab
- Kaggle
File size: 14,989 Bytes
b707206 9bc99d7 b707206 9bc99d7 b707206 9bc99d7 b707206 9bc99d7 b707206 9bc99d7 b707206 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 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 256 257 258 259 260 261 262 263 264 | """AUBIN bilgisayar kullanımı (web ajanı) ölçümü — Mind2Web (Deng et al., 2023), MindAct çoktan-seçmeli protokolü.
Her adım: görev + önceki eylemler + resmi sıralayıcının (scores_all_data.pkl) ilk-K adayı → AUBIN tipli kararlar:
1) element: hangi öğe? (K seçenek; >26 ise 26'lık gruplar + final turu)
2) op: CLICK / TYPE / SELECT
3) value: TYPE/SELECT ise kısa üretim
Ölçüler (Mind2Web ile aynı): Element Accuracy, Operation F1 (op+değer token F1), Step Success Rate.
Pozitif öğe ilk-K'da değilse adım başarısız sayılır (MindAct ile aynı).
python mind2web_eval.py --model google/gemma-4-12B-it --adapter <lora> --split test_task --steps 200 --out m2w.json
"""
import argparse, json, os, pickle, random, re, sys, time
import torch
HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, HERE)
OPS = ["CLICK", "TYPE", "SELECT"]
KEEP = ("aria_label", "aria-label", "placeholder", "title", "name", "type", "value", "alt", "role", "id", "input_value", "label")
def load_split(split, limit_files=0):
from huggingface_hub import HfApi, hf_hub_download
import pyarrow.parquet as pq
fs = sorted(f for f in HfApi().list_repo_files("osunlp/Multimodal-Mind2Web", repo_type="dataset")
if f.startswith(f"data/{split}-") and f.endswith(".parquet"))
rows = []
for f in fs[: limit_files or None]:
p = hf_hub_download("osunlp/Multimodal-Mind2Web", f, repo_type="dataset")
t = pq.read_table(p, columns=["action_uid", "cleaned_html", "operation", "pos_candidates", "neg_candidates",
"annotation_id", "confirmed_task", "action_reprs", "target_action_index", "website"])
rows += t.to_pylist()
return rows
def load_scores():
from huggingface_hub import hf_hub_download
p = hf_hub_download("osunlp/Mind2Web", "scores_all_data.pkl", repo_type="dataset")
with open(p, "rb") as f:
return pickle.load(f)
def describe(cand, html_index):
"""Aday öğenin MindAct benzeri kısa metni: <etiket öznitelikler> görünen metin </etiket> + üst öğe bağlamı."""
c = json.loads(cand) if isinstance(cand, str) else cand
attrs = json.loads(c["attributes"]) if isinstance(c.get("attributes"), str) else (c.get("attributes") or {})
nid = str(attrs.get("backend_node_id"))
bits = " ".join(f'{k}="{str(attrs[k])[:40]}"' for k in KEEP if attrs.get(k))
own, parent = html_index.get(nid, ("", ""))
s = f"<{c.get('tag', '?')} {bits}> {own[:90]} </{c.get('tag', '?')}>".replace(" ", " ")
if parent and parent != own:
s += f" (inside: {parent[:70]})"
return nid, s[:260]
def html_text_index(cleaned_html):
from lxml import html as lh
idx = {}
try:
root = lh.fromstring(cleaned_html)
except Exception:
return idx
for el in root.iter():
nid = el.get("backend_node_id") if hasattr(el, "get") else None
if nid:
try:
own = re.sub(r"\s+", " ", el.text_content()).strip()
par = el.getparent()
ptxt = re.sub(r"\s+", " ", par.text_content()).strip() if par is not None else ""
idx[nid] = (own[:160], ptxt[:160])
except Exception:
pass
return idx
def tournament(S, st, cands, group=5):
"""MindAct çoktan-seçmeli: 5'li gruplar + 'None of the above'; seçilenler bir sonraki tura; tek aday kalana dek."""
alive, rounds = list(cands), 0
while len(alive) > 1:
nxt = []
for i in range(0, len(alive), group):
g = alive[i:i + group]
it = {"state": st, "q": "Which page element should be acted on next to accomplish the task? Choose 'None of the above' if none fits.",
"keys": [c[0] for c in g] + ["none"], "texts": [c[1] for c in g] + ["None of the above"], "y": 0}
with torch.no_grad():
lp = S.score(it)
j = int(lp.argmax())
if j < len(g):
nxt.append((g[j], float(torch.softmax(lp, -1)[j])))
rounds += 1
if not nxt:
return None, 0.0, rounds
alive = [x[0] for x in nxt]
if len(alive) == 1:
return alive[0], nxt[0][1], rounds
return (alive[0], 1.0, rounds) if alive else (None, 0.0, rounds)
def train_items(rows, scores, topk, rng, per_action=2):
"""Mind2Web EĞİTİM bölümünden MindAct tarzı çoktan-seçmeli örnekler (kev_llm item biçimi):
grup = 5 aday (+ 'None of the above'); pozitif içeren grupta cevap pozitif, içermeyende 'None'."""
out = []
for r in rows:
key = f"{r['annotation_id']}_{r['action_uid']}"
sc = scores.get(key) if isinstance(scores, dict) else None
idx = html_text_index(r["cleaned_html"])
pos = [describe(c, idx) for c in r["pos_candidates"]]
neg = [describe(c, idx) for c in r["neg_candidates"]]
if not pos or not neg:
continue
if sc:
neg.sort(key=lambda x: -float(sc.get(x[0], -1e9)))
neg = neg[:topk]
hist = r["action_reprs"][: int(r["target_action_index"])]
st = json.dumps({"task": r["confirmed_task"], "website": r["website"], "previous_actions": hist[-6:] or ["(none)"]}, ensure_ascii=False)
q = "Which page element should be acted on next to accomplish the task? Choose 'None of the above' if none fits."
n_pos = max(1, per_action - 1) # son grup hariç hepsi pozitif içerir (farklı negatiflerle)
for k in range(per_action):
g = rng.sample(neg, min(4 if k < n_pos else 5, len(neg)))
if k < n_pos:
g = g + [rng.choice(pos)]
rng.shuffle(g)
keys = [c[0] for c in g] + ["none"]; texts = [c[1] for c in g] + ["None of the above"]
y = next((i for i, c in enumerate(g) if c in pos), len(g))
out.append({"key": f"{key}/{k}", "src": "mind2web_train", "state": st, "q": q, "type": "choice",
"keys": keys, "texts": texts, "y": y})
opr = json.loads(r["operation"]) if isinstance(r["operation"], str) else r["operation"]
out.append({"key": f"{key}/op", "src": "mind2web_train", "state": st + f"\nChosen element: {pos[0][1]}",
"q": "Which operation should be performed on the chosen element?", "type": "choice",
"keys": OPS, "texts": ["CLICK: click it", "TYPE: type text into it", "SELECT: choose an option from it"],
"y": OPS.index(opr["op"]) if opr["op"] in OPS else 0})
return out
def f1(pred, gold):
p, g = pred.lower().split(), gold.lower().split()
if not p and not g:
return 1.0
common = sum(min(p.count(w), g.count(w)) for w in set(p))
if common == 0:
return 0.0
pr, rc = common / len(p), common / len(g)
return 2 * pr * rc / (pr + rc)
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--model", default="google/gemma-4-12B-it"); ap.add_argument("--adapter", default="")
ap.add_argument("--split", default="test_task"); ap.add_argument("--steps", type=int, default=200)
ap.add_argument("--topk", type=int, default=50); ap.add_argument("--files", type=int, default=0)
ap.add_argument("--no4bit", action="store_true"); ap.add_argument("--device_map", default="")
ap.add_argument("--work", default=""); ap.add_argument("--out", default="m2w.json"); ap.add_argument("--seed", type=int, default=0)
ap.add_argument("--train_steps", type=int, default=0); ap.add_argument("--train_files", type=int, default=10)
ap.add_argument("--lr", type=float, default=3e-5); ap.add_argument("--bs", type=int, default=4)
ap.add_argument("--save_adapter", default="lora_m2w"); ap.add_argument("--per_action", type=int, default=2)
ap.add_argument("--value_fmt", type=int, default=1) # 1: değer Mind2Web yazımında (eğitim verisindeki gibi ":" "," boşluk)
ap.add_argument("--select", default="tournament", choices=["tournament", "flat"]) # flat: tek K-yollu seçim (26'lık gruplar + final)
a = ap.parse_args()
t0 = time.time()
rows = load_split(a.split, a.files)
S_ = load_scores()
scores = S_.get("scores", S_) if isinstance(S_, dict) else S_
print({"rows": len(rows), "score_keys_sample": list(scores)[:2] if isinstance(scores, dict) else type(scores).__name__,
"load_s": round(time.time() - t0, 1)}, flush=True)
rng = random.Random(a.seed)
order = list(range(len(rows))); rng.shuffle(order)
from kev_llm import Scorer, resolve_adapter
S = Scorer(a.model, four_bit=not a.no4bit, device_map=a.device_map)
train_info = None
if a.train_steps: # Mind2Web EĞİTİM bölümüyle ince ayar (MindAct gibi), sonra aynı test ölçümü
from kev_llm import train_lora
tr_rows = load_split("train", a.train_files)
tr = train_items(tr_rows, scores, a.topk, random.Random(a.seed + 1), per_action=a.per_action)
random.Random(a.seed + 2).shuffle(tr)
dev, tr = tr[:150], tr[150:]
print({"train_actions": len(tr_rows), "train_items": len(tr), "dev_items": len(dev)}, flush=True)
tr_rows = None
t1 = time.time()
train_lora(S, tr, a.train_steps, a.lr, a.bs, a.save_adapter, seed=a.seed, init_adapter=resolve_adapter(a.adapter) if a.adapter else "",
dev=dev, eval_every=max(100, a.train_steps // 6))
S.m.eval()
train_info = {"steps": a.train_steps, "items": len(tr), "lr": a.lr, "bs": a.bs, "minutes": round((time.time() - t1) / 60, 1),
"best_dev": getattr(S, "best_dev", None), "adapter_dir": a.save_adapter}
print(train_info, flush=True)
elif a.adapter:
from peft import PeftModel
S.m = PeftModel.from_pretrained(S.m, resolve_adapter(a.adapter)).eval()
R = {"train": train_info, "split": a.split, "select": a.select, "protocol": (f"MindAct multi-choice (groups of 5 + None, iterative), top-{a.topk} by official ranker" if a.select == "tournament" else f"single {a.topk}-way choice (26-way groups + final), top-{a.topk} by official ranker"), "steps": [], "model": a.model,
"adapter": a.adapter}
n_done = 0
for i in order:
if n_done >= a.steps:
break
r = rows[i]
key = f"{r['annotation_id']}_{r['action_uid']}"
sc = scores.get(key) if isinstance(scores, dict) else None
idx = html_text_index(r["cleaned_html"])
pos = [describe(c, idx) for c in r["pos_candidates"]]
neg = [describe(c, idx) for c in r["neg_candidates"]]
allc = pos + neg
if not pos:
continue
if sc:
allc.sort(key=lambda x: -float(sc.get(x[0], -1e9)))
else:
rng.shuffle(allc)
cands = allc[: a.topk]
pos_ids = {p[0] for p in pos}
hist = r["action_reprs"][: int(r["target_action_index"])]
state = {"task": r["confirmed_task"], "website": r["website"], "previous_actions": hist[-6:] or ["(none)"]}
st = json.dumps(state, ensure_ascii=False)
if a.select == "flat":
item = {"state": st, "q": "Which page element should be acted on next to accomplish the task?",
"keys": [c[0] for c in cands], "texts": [c[1] for c in cands], "y": 0}
with torch.no_grad():
lpf = S.score(item)
jf = int(lpf.argmax()); win, p_pick = cands[jf], float(torch.softmax(lpf, -1)[jf])
else:
win, p_pick, _r = tournament(S, st, cands)
if win is None: # model "hiçbiri" dedi: adım başarısız, yine de ilk adayla devam
win = cands[0]
pick_id = win[0]
pick = [c[0] for c in cands].index(pick_id)
op_item = {"state": st + f"\nChosen element: {cands[pick][1]}", "q": "Which operation should be performed on the chosen element?",
"keys": OPS, "texts": ["CLICK: click it", "TYPE: type text into it", "SELECT: choose an option from it"], "y": 0}
with torch.no_grad():
op = OPS[int(S.score(op_item).argmax())]
val = ""
if op in ("TYPE", "SELECT"):
msgs = [{"role": "user", "content": f"Task: {r['confirmed_task']}\nPrevious actions: {hist[-6:]}\nElement: {cands[pick][1]}\n"
f"Operation: {op}. Reply with ONLY the exact text to {'type' if op == 'TYPE' else 'select'}."}]
p = S.tok.apply_chat_template(msgs, add_generation_prompt=True, tokenize=False)
enc = S.tok([p], return_tensors="pt", add_special_tokens=False).to(S.dev)
with torch.no_grad():
g = S.m.generate(**enc, max_new_tokens=24, do_sample=False, pad_token_id=S.tok.pad_token_id)
val = S.tok.decode(g[0, enc["input_ids"].shape[1]:], skip_special_tokens=True).strip().split("\n")[0].strip().strip('"')
if a.value_fmt:
val = re.sub(r"[:,]", " ", val).strip()
opr = json.loads(r["operation"]) if isinstance(r["operation"], str) else r["operation"]
gold_op = opr["op"]; gold_val = opr.get("value", "") or ""
ele_ok = pick_id in pos_ids
op_f1 = f1(f"{op} {val}".strip(), f"{gold_op} {gold_val}".strip())
R["steps"].append({"key": key, "pos_in_topk": bool(pos_ids & {c[0] for c in cands}), "ele": ele_ok, "op": op, "val": val,
"gold_op": gold_op, "gold_val": gold_val, "op_f1": round(op_f1, 4),
"step_sr": bool(ele_ok and op == gold_op and (gold_op == "CLICK" or f1(val, gold_val) == 1.0)),
"p_pick": round(p_pick, 4)})
n_done += 1
if n_done % 20 == 0:
s = R["steps"]
print({"n": n_done, "ele_acc": round(sum(x["ele"] for x in s) / len(s), 4), "op_f1": round(sum(x["op_f1"] for x in s) / len(s), 4),
"step_sr": round(sum(x["step_sr"] for x in s) / len(s), 4), "min": round((time.time() - t0) / 60, 1)}, flush=True)
json.dump(R, open(a.out, "w"), indent=1)
s = R["steps"]
R["summary"] = {"n": len(s), "element_accuracy": round(sum(x["ele"] for x in s) / len(s), 4),
"operation_f1": round(sum(x["op_f1"] for x in s) / len(s), 4),
"step_success_rate": round(sum(x["step_sr"] for x in s) / len(s), 4),
"pos_in_topk_rate": round(sum(x["pos_in_topk"] for x in s) / len(s), 4), "minutes": round((time.time() - t0) / 60, 1)}
json.dump(R, open(a.out, "w"), indent=1)
print("SONUC", json.dumps(R["summary"]), flush=True)
if __name__ == "__main__":
main()
|