Instructions to use emrevrg/AUBIN-E4B-Screen with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use emrevrg/AUBIN-E4B-Screen with PEFT:
from peft import PeftModel from transformers import AutoModelForCausalLM base_model = AutoModelForCausalLM.from_pretrained("google/gemma-4-E4B-it") model = PeftModel.from_pretrained(base_model, "emrevrg/AUBIN-E4B-Screen") - Notebooks
- Google Colab
- Kaggle
Download code/aubin/learn.py from emrevrg/AUBIN-E4B-Screen: direct link, hf CLI and curl.
- Browser
- Download file 18.9 kB
-
https://huggingface.co/emrevrg/AUBIN-E4B-Screen/resolve/main/code/aubin/learn.py
- Command line
-
hf download hf://emrevrg/AUBIN-E4B-Screen/code/aubin/learn.py
-
curl -L -o learn.py https://huggingface.co/emrevrg/AUBIN-E4B-Screen/resolve/main/code/aubin/learn.py
18.9 kB
| """AUBIN-Learn — Norovox öz-öğrenme çekirdeğinin karar modeline entegrasyonu. | |
| Norovox Alpha Mini ilkesi: bilgi ağırlıkta değil, DIŞ BELLEKTE tutulur; model düşünür, bellek hatırlar. | |
| Burada bu ilke AUBIN'in hızlı karar sürecine taşınır: | |
| learn(...) doğrulanmış bir vakayı belleğe yazar — gradyan yok, eğitim yok, ~milisaniye; bir sonraki soruda etkili. | |
| recall(...) aynı soru tipindeki (kaynak + seçenek kümesi) en benzer çözülmüş vakalardan seçeneklere oy dağılımı. | |
| fuse(...) modelin log-olasılıkları + bellek oyları (log-doğrusal); ağırlık kaynak-başına, YALNIZ dev'de ayarlanır. | |
| AubinLearner modeli sarar: emin değilse belleğe bakar; bellekte karşılığı yoksa araştırma kancası (Norovox | |
| Retrieval: yerel bilgi tabanı → web) kanıt getirir; geri bildirim gelince learn() ile eksiğini kapatır. | |
| Gömme (embedding) takılabilir: varsayılan sözcük+karakter n-gram karma vektörü (bağımlılıksız, CPU'da µs-ms), | |
| istenirse cümle gömme modeli (ör. BAAI/bge-small-en-v1.5) `embed_fn` olarak verilir. | |
| """ | |
| from __future__ import annotations | |
| import hashlib | |
| import math | |
| import re | |
| import time | |
| from collections import defaultdict | |
| import numpy as np | |
| DIM = int(__import__("os").environ.get("AUBIN_HASH_DIM", 2 ** 13)) | |
| def hash_embed(texts, dim: int = DIM) -> np.ndarray: | |
| """Sözcük (1-2 gram) + karakter 4-gram karma (hashing) vektörü, L2-normalize. Model indirmeden çalışır.""" | |
| out = np.zeros((len(texts), dim), dtype=np.float32) | |
| for r, t in enumerate(texts): | |
| t = re.sub(r"\s+", " ", str(t).lower()) | |
| ws = re.findall(r"[a-z0-9çğıöşü']+", t) | |
| feats = ws + [a + "_" + b for a, b in zip(ws, ws[1:])] + [t[i:i + 4] for i in range(0, max(0, len(t) - 3), 2)] | |
| for f in feats: | |
| h = int.from_bytes(hashlib.blake2b(f.encode(), digest_size=8).digest(), "little") | |
| out[r, h % dim] += 1.0 if (h >> 63) & 1 else -1.0 | |
| n = np.linalg.norm(out[r]) | |
| if n: | |
| out[r] /= n | |
| return out | |
| def sig(src, keys) -> str: | |
| """Bellek bölümü. ≤26 seçenek: kaynak + seçenek kümesinin tamamı. Geniş sorularda (banking77: 77–78 seçenek, testte | |
| seçenek kümesi değişebiliyor) yalnız kaynak — oylar etiket ADIYLA mevcut seçeneklere eşlenir.""" | |
| if len(keys) > 26: | |
| return f"{src}|wide" | |
| return f"{src}|{len(keys)}|" + hashlib.md5("\x1f".join(map(str, keys)).encode()).hexdigest()[:10] | |
| class DecisionMemory: | |
| """Soru tipine göre bölümlenmiş vaka belleği. Ekleme O(1); arama bölüm-içi kosinüs (matris çarpımı).""" | |
| def __init__(self, embed_fn=hash_embed): | |
| self.embed_fn = embed_fn | |
| self.vecs: dict[str, list] = defaultdict(list) # imza → vektör listesi (yeni eklenenler) | |
| self.mats: dict[str, np.ndarray] = {} # imza → donmuş matris (toplu arama için) | |
| self.labels: dict[str, list] = defaultdict(list) # imza → etiket ADI listesi (seçenek kümesinden bağımsız) | |
| self.n = 0 | |
| def _freeze(self, s): | |
| if self.vecs[s]: | |
| new = np.stack(self.vecs[s]) | |
| self.mats[s] = new if s not in self.mats else np.concatenate([self.mats[s], new]) | |
| self.vecs[s] = [] | |
| def learn(self, text, src, keys, y, vec=None): | |
| """Tek vaka öğren (anında etkili). Dönüş: geçen süre (ms).""" | |
| t0 = time.perf_counter() | |
| s = sig(src, keys) | |
| v = vec if vec is not None else self.embed_fn([text])[0] | |
| self.vecs[s].append(v.astype(np.float32)); self.labels[s].append(str(keys[int(y)])); self.n += 1 | |
| return (time.perf_counter() - t0) * 1e3 | |
| def learn_many(self, texts, srcs, keyss, ys, batch=2048): | |
| for i in range(0, len(texts), batch): | |
| self.learn_vectors(self.embed_fn(texts[i:i + batch]), srcs[i:i + batch], keyss[i:i + batch], ys[i:i + batch]) | |
| def learn_vectors(self, V, srcs, keyss, ys): | |
| """Önceden gömülmüş vakaları toplu öğren (gömme bir kez hesaplanır, farklı bellekler için yeniden kullanılır).""" | |
| for v, sr, ks, y in zip(V, srcs, keyss, ys): | |
| s = sig(sr, ks); self.vecs[s].append(np.asarray(v, dtype=np.float32)); self.labels[s].append(str(ks[int(y)])); self.n += 1 | |
| for s in list(self.vecs): | |
| self._freeze(s) | |
| def recall(self, text, src, keys, k=16, tau=0.05, vec=None, min_sim=0.0): | |
| """Seçenekler üzerinde bellek dağılımı (benzerlik-ağırlıklı oy) + en yüksek benzerlik. Bellek boşsa (None, 0). | |
| min_sim: bu benzerliğin altındaki komşular oy vermez (bellek küçükken alakasız tek vakanın her soruya oy vermesini önler).""" | |
| s = sig(src, keys) | |
| self._freeze(s) | |
| M = self.mats.get(s) | |
| if M is None or not len(M): | |
| return None, 0.0 | |
| q = vec if vec is not None else self.embed_fn([text])[0] | |
| sims = M @ q | |
| kk = min(k, len(sims)) | |
| top = np.argpartition(-sims, kk - 1)[:kk] | |
| top = top[sims[top] >= min_sim] | |
| if not len(top): | |
| return None, float(sims.max()) | |
| w = np.exp((sims[top] - sims[top].max()) / tau) | |
| p = vote([self.labels[s][i] for i in top], w, keys) | |
| return p, (float(sims[top].max()) if p is not None else 0.0) | |
| def vote(labels, weights, keys): | |
| """Komşu etiket adlarını mevcut seçeneklere eşle (seçenek kümesi değişse de çalışır). Eşleşen yoksa None.""" | |
| pos = {str(k): i for i, k in enumerate(keys)} | |
| p = np.zeros(len(keys), dtype=np.float64) | |
| for lab, wi in zip(labels, weights): | |
| j = pos.get(lab) | |
| if j is not None: | |
| p[j] += wi | |
| return p / p.sum() if p.sum() > 0 else None | |
| def fuse(lp_model, p_mem, w, T=1.0, eps=1e-3): | |
| """Log-doğrusal birleştirme: log p_model/T + w·log(p_mem + ε). p_mem yoksa model aynen kalır.""" | |
| lp = np.asarray(lp_model, dtype=np.float64) / T | |
| if p_mem is None or w == 0: | |
| return lp - np.logaddexp.reduce(lp) | |
| z = lp + w * np.log(np.asarray(p_mem) + eps) | |
| return z - np.logaddexp.reduce(z) | |
| class SelfCalibrator: | |
| """Öz-kalibrasyon (Hedge / çarpımsal ağırlıklar): her kaynak için uzmanlar — model, bellek, birleşik — arasında güveni | |
| geri bildirimle kendisi ayarlar. Kayıp = log-kayıp; π_e ← π_e·exp(−η·kayıp_e). Pişmanlık sınırı: zamanla en iyi uzmana yaklaşır, | |
| yani bellek bir kaynakta işe yaramıyorsa ona olan güven kendiliğinden söner (kendi eksiğini kendisi kapatır).""" | |
| EXPERTS = ("model", "memory", "fused") | |
| def __init__(self, eta=1.0, prior=(0.6, 0.1, 0.3)): | |
| self.eta, self.prior = eta, np.log(np.asarray(prior, dtype=np.float64)) | |
| self.logw = defaultdict(lambda: self.prior.copy()) | |
| def experts(lp_model, p_mem, w_fuse=1.0): | |
| pm = np.exp(np.asarray(lp_model, dtype=np.float64) - np.logaddexp.reduce(lp_model)) | |
| pk = pm if p_mem is None else 0.98 * np.asarray(p_mem) + 0.02 / len(pm) | |
| pf = np.exp(fuse(lp_model, p_mem, w_fuse)) | |
| return np.stack([pm, pk, pf]) | |
| def predict(self, src, E): | |
| pi = np.exp(self.logw[src] - np.logaddexp.reduce(self.logw[src])) | |
| return pi @ E, pi | |
| def update(self, src, E, y): | |
| self.logw[src] = self.logw[src] - self.eta * (-np.log(E[:, y] + 1e-12)) | |
| class Probe: | |
| """Bağımlılıksız çok sınıflı lojistik regresyon (numpy, L2, Adam, tam yığın) — beceri sınıflandırıcısı.""" | |
| def __init__(self, C=10.0, iters=300, lr=0.05): | |
| self.C, self.iters, self.lr = C, iters, lr | |
| def fit(self, X, y, classes): | |
| self.classes = list(classes); idx = {c: i for i, c in enumerate(self.classes)} | |
| X = np.asarray(X, dtype=np.float32); n, d = X.shape; k = len(self.classes) | |
| Y = np.zeros((n, k), dtype=np.float32); Y[np.arange(n), [idx[c] for c in y]] = 1 | |
| W, b = np.zeros((d, k), np.float32), np.zeros(k, np.float32) | |
| st = [np.zeros_like(W), np.zeros_like(W), np.zeros_like(b), np.zeros_like(b)] | |
| lam = 1.0 / (self.C * n) | |
| for t in range(1, self.iters + 1): | |
| Z = X @ W + b; Z -= Z.max(1, keepdims=True); P = np.exp(Z); P /= P.sum(1, keepdims=True) | |
| G = (P - Y) / n | |
| for g, m, v, p in ((X.T @ G + lam * W, st[0], st[1], W), (G.sum(0), st[2], st[3], b)): | |
| m *= 0.9; m += 0.1 * g; v *= 0.999; v += 0.001 * g * g | |
| p -= self.lr * (m / (1 - 0.9 ** t)) / (np.sqrt(v / (1 - 0.999 ** t)) + 1e-8) | |
| self.W, self.b = W, b | |
| return self | |
| def proba(self, x, keys): | |
| z = np.asarray(x, np.float32) @ self.W + self.b; z = np.exp(z - z.max()); z /= z.sum() | |
| pos = {c: j for j, c in enumerate(self.classes)} | |
| p = np.array([z[pos[str(k)]] if str(k) in pos else 0.0 for k in keys], dtype=np.float64) | |
| return p / p.sum() if p.sum() > 0 else None | |
| class SkillLibrary: | |
| """Kendine yetenek ekleme: soru tipi (qid) başına veriden öğrenilen beceri + KENDİNİ SINAMA. | |
| acquire(...) örneklerin bir kısmını ayırır, beceriyi kalanla öğrenir, ayrılan kısımda model-tek vs model+beceri karşılaştırır; | |
| beceri yalnız doğruluk ≥ min_gain soru artar VE log-kayıp düşerse AÇILIR (bozmadan deneyerek öğrenme). Rapor döner.""" | |
| WGRID = (0.1, 0.2, 0.35, 0.5, 0.75, 1.0, 1.5, 2.0, 3.0) | |
| def __init__(self, embed_fn=hash_embed): | |
| self.embed, self.skills = embed_fn, {} # qid -> {"probe", "w", "report"} | |
| def probs(self, qid, text, keys): | |
| s = self.skills.get(qid) | |
| if not s or s["w"] <= 0: | |
| return None, 0.0 | |
| return s["probe"].proba(self.embed([text])[0], keys), s["w"] | |
| def acquire(self, qid, texts, answers, keys_list, model_lp, holdout=0.25, min_gain=2, T=1.0, seed=0): | |
| """texts/answers/keys_list: örnekler; model_lp(i) → i. örnek için modelin log-olasılıkları (yalnız ayrılan kısımda çağrılır).""" | |
| n = len(texts); rng = np.random.default_rng(seed); order = rng.permutation(n) | |
| h = max(10, int(n * holdout)); te, tr = order[:h], order[h:] | |
| X = self.embed([texts[i] for i in range(n)]) | |
| classes = sorted({str(a) for a in answers}) | |
| t0 = time.perf_counter() | |
| probe = Probe().fit(X[tr], [str(answers[i]) for i in tr], classes) | |
| fit_ms = (time.perf_counter() - t0) * 1e3 | |
| rows = [] | |
| for i in te: | |
| keys = [str(k) for k in keys_list[i]] | |
| if str(answers[i]) not in keys: | |
| continue | |
| rows.append((np.asarray(model_lp(i), dtype=np.float64), probe.proba(X[i], keys), keys.index(str(answers[i])))) | |
| def ev(w): | |
| nl = ac = 0 | |
| for lp, p, y in rows: | |
| f = fuse(lp, p, w, T); nl -= f[y]; ac += int(np.argmax(f) == y) | |
| return nl / max(1, len(rows)), ac | |
| (n0, a0) = ev(0.0) | |
| w = min(self.WGRID, key=lambda w: ev(w)[0]); (n1, a1) = ev(w) | |
| on = a1 >= a0 + min_gain and n1 < n0 | |
| rep = {"qid": qid, "train": len(tr), "self_test": len(rows), "fit_ms": round(fit_ms, 1), | |
| "self_test_acc": [round(a0 / max(1, len(rows)), 4), round(a1 / max(1, len(rows)), 4)], | |
| "self_test_nll": [round(float(n0), 4), round(float(n1), 4)], "weight": float(w) if on else 0.0, "enabled": bool(on)} | |
| if on: # kanıtlandı → tüm veriyle yeniden öğren, aç | |
| probe = Probe().fit(X, [str(a) for a in answers], classes) | |
| self.skills[qid] = {"probe": probe, "w": w if on else 0.0, "report": rep} | |
| return rep | |
| class AubinLearning: | |
| """Ürün katmanı: herhangi bir AUBIN modelini (Aubin / AubinEnsemble — .logprobs(state, questions) sunan) öz-öğrenen hale getirir. | |
| smart = AubinLearning(Aubin("emrevrg/AUBIN-12B")) | |
| out = smart.decide(state, questions) # bellek + öz-kalibrasyonlu karar | |
| smart.learn(state, questions, {"q1": "refund"}) # doğru cevap → anında öğrenilir (eğitim yok) | |
| smart.save("mem.npz"); smart.load("mem.npz") # bellek kalıcı | |
| Bellek bölümü = soru kimliği + seçenek kümesi (geniş sorularda etiket ADI eşlemesi).""" | |
| def __init__(self, model, memory=None, calibrator=None, k=16, tau=0.05, w_fuse=1.0, min_sim=0.5): | |
| self.min_sim = min_sim # yalnız yeterince benzer geçmiş vakalar oy verir | |
| self.model, self.mem = model, (memory or DecisionMemory()) | |
| self.cal = calibrator or SelfCalibrator() | |
| self.k, self.tau, self.w = k, tau, w_fuse | |
| self.skills = SkillLibrary(self.mem.embed_fn) | |
| self._last = {} | |
| def acquire_skill(self, qid, examples, holdout=0.25, min_gain=2): | |
| """Yeni yetenek: examples = [(state, questions, {qid: doğru anahtar}), ...] aynı soru tipinden. | |
| Model yalnız kendini sınama kısmında çağrılır; beceri ancak kazanç kanıtlanırsa açılır. Dönüş: rapor.""" | |
| from .core import options | |
| texts, answers, keys_list, items = [], [], [], [] | |
| for st, qs, ans in examples: | |
| keys, _ = options(qs[qid]); texts.append(self._text(st, qs[qid])); answers.append(str(ans[qid])) | |
| keys_list.append([str(k) for k in keys]); items.append((st, qs)) | |
| def model_lp(i): | |
| st, qs = items[i] | |
| lp = self.model.logprobs(st, {qid: qs[qid]})[qid][1] | |
| return lp.detach().cpu().numpy() if hasattr(lp, "detach") else lp | |
| return self.skills.acquire(qid, texts, answers, keys_list, model_lp, holdout=holdout, min_gain=min_gain) | |
| def _text(state, q): | |
| import json as _j | |
| st = state if isinstance(state, str) else _j.dumps(state, ensure_ascii=False, sort_keys=True) | |
| return f"{st} || {(q or {}).get('instructions', '')}" | |
| def decide(self, state, questions): | |
| lps = self.model.logprobs(state, questions) | |
| out = {} | |
| for qid, (keys, lp) in lps.items(): | |
| lp = np.asarray(lp.detach().cpu() if hasattr(lp, "detach") else lp, dtype=np.float64) | |
| ps, ws = self.skills.probs(qid, self._text(state, questions[qid]), [str(k) for k in keys]) | |
| if ps is not None: # kanıtlanmış beceri → modele katılır (log-doğrusal) | |
| lp = fuse(lp, ps, ws) | |
| p, smax = self.mem.recall(self._text(state, questions[qid]), qid, keys, self.k, self.tau, min_sim=self.min_sim) | |
| E = SelfCalibrator.experts(lp, p, self.w) | |
| mix, pi = self.cal.predict(qid, E) | |
| self._last[(qid, self._text(state, questions[qid]))] = E | |
| j = int(np.argmax(mix)) | |
| out[qid] = {"answer": keys[j], "confidence": round(float(mix[j]), 4), | |
| "probabilities": {str(k): round(float(v), 4) for k, v in zip(keys, mix)}, | |
| "memory": {"similar_case": round(smax, 3), "trust_model_memory_fused": [round(float(x), 3) for x in pi]}} | |
| return out | |
| def learn(self, state, questions, answers): | |
| """answers: {qid: doğru seçenek anahtarı}. Belleğe yazar + (son decide varsa) güveni günceller. Dönüş: ms.""" | |
| from .core import options | |
| t0 = time.perf_counter() | |
| for qid, ans in answers.items(): | |
| keys, _ = options(questions[qid]) | |
| keys = [str(k) for k in keys] | |
| if str(ans) not in keys: | |
| continue | |
| y = keys.index(str(ans)); txt = self._text(state, questions[qid]) | |
| E = self._last.pop((qid, txt), None) | |
| if E is not None: | |
| self.cal.update(qid, E, y) | |
| self.mem.learn(txt, qid, keys, y) | |
| return round((time.perf_counter() - t0) * 1e3, 3) | |
| def save(self, path): | |
| for s in list(self.mem.vecs): | |
| self.mem._freeze(s) | |
| np.savez_compressed(path, **{f"M::{s}": m for s, m in self.mem.mats.items()}, | |
| **{f"L::{s}": np.asarray(self.mem.labels[s]) for s in self.mem.mats}) | |
| def load(self, path): | |
| Z = np.load(path, allow_pickle=False) | |
| for f in Z.files: | |
| if f.startswith("M::"): | |
| s = f[3:]; self.mem.mats[s] = Z[f]; self.mem.labels[s] = [str(x) for x in Z["L::" + s]] | |
| self.mem.n = sum(len(v) for v in self.mem.labels.values()) | |
| class AubinLearner: | |
| """Karar modeli + öz-öğrenme belleği + araştırma kancası. | |
| score_fn(item) → seçenek log-olasılıkları (ör. kev_llm.Scorer.score); item: {"state","q","keys","texts","src"}. | |
| research_fn(query) → kanıt metinleri listesi (ör. norovox_mini.retrieval.Retrieval().fetch). | |
| """ | |
| def __init__(self, score_fn, memory=None, weights=None, margin=99.0, research_fn=None, k=16, tau=0.05, calibrator=None): | |
| self.score_fn, self.mem = score_fn, (memory or DecisionMemory()) | |
| self.weights = weights or {} # kaynak → bellek birleştirme ağırlığı (dev'de ayarlanır); yoksa "*" ya da 0.5 | |
| self.margin, self.research_fn, self.k, self.tau = margin, research_fn, k, tau | |
| self.cal = calibrator if calibrator is not None else SelfCalibrator() | |
| self.log, self._last = [], {} | |
| def text(it): | |
| return f"{it['state']} || {it['q']}" | |
| def decide(self, it): | |
| t0 = time.perf_counter() | |
| lp = np.asarray(self.score_fn(it), dtype=np.float64) | |
| srt = np.sort(lp)[::-1] | |
| unsure = len(lp) > 1 and (srt[0] - srt[1]) < self.margin | |
| p, smax, evidence = self.mem.recall(self.text(it), it["src"], it["keys"], self.k, self.tau) + ([],) | |
| if p is None and unsure and self.research_fn is not None: # bellekte karşılığı yok: dışarıdan kanıt (Norovox Retrieval) | |
| try: | |
| evidence = self.research_fn(f"{it['q']} {str(it['state'])[:300]}")[:3] | |
| except Exception: | |
| evidence = [] | |
| E = SelfCalibrator.experts(lp, p, self.weights.get(it["src"], self.weights.get("*", 0.5))) | |
| mix, pi = self.cal.predict(it["src"], E) | |
| self._last[id(it)] = E | |
| ms = (time.perf_counter() - t0) * 1e3 | |
| self.log.append({"src": it["src"], "unsure": bool(unsure), "memory_sim": round(smax, 3), "trust": [round(float(x), 3) for x in pi], | |
| "evidence": len(evidence), "ms": round(ms, 2)}) | |
| return int(np.argmax(mix)), np.log(mix + 1e-12), evidence | |
| def feedback(self, it, y): | |
| """Doğru cevap gelince: (1) belleğe yaz — bilgi eksiği anında kapanır; (2) öz-kalibrasyon — bu kaynakta model mi bellek mi | |
| daha isabetli, güven kendiliğinden kayar. Dönüş: ms.""" | |
| t0 = time.perf_counter() | |
| E = self._last.pop(id(it), None) | |
| if E is not None: | |
| self.cal.update(it["src"], E, int(y)) | |
| self.mem.learn(self.text(it), it["src"], it["keys"], y) | |
| return (time.perf_counter() - t0) * 1e3 | |