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
Download code/aubin/core.py from emrevrg/AUBIN-12B-Control: direct link, hf CLI and curl.
- Browser
- Download file 18 kB
-
https://huggingface.co/emrevrg/AUBIN-12B-Control/resolve/main/code/aubin/core.py
- Command line
-
hf download hf://emrevrg/AUBIN-12B-Control/code/aubin/core.py
-
curl -L -o core.py https://huggingface.co/emrevrg/AUBIN-12B-Control/resolve/main/code/aubin/core.py
18 kB
| """AUBIN çekirdeği: tipli durum + tipli sorular → kalibre olasılıklar (tek ileri geçiş, metin üretimi yok). | |
| Soru biçimi Jev/TypeSafe ve Kev ile uyumludur: | |
| questions = {"iade": {"type": "choice", "instructions": "...", "criteria": {"a": "...", "b": "..."}}, | |
| "acil": {"type": "noul", "instructions": "..."}, | |
| "puan": {"type": "score", "instructions": "...", "criteria": ["kötü", "orta", "iyi"]}} | |
| Aubin("emrevrg/AUBIN-12B").decide(state, questions) | |
| → {"iade": {"answer": "a", "confidence": 0.93, "probabilities": {"a": 0.93, "b": 0.07}}, ...} | |
| """ | |
| from __future__ import annotations | |
| import json, os | |
| import torch | |
| import torch.nn.functional as F | |
| L = [chr(65 + i) for i in range(26)] | |
| def options(q): | |
| t, c = q["type"], q.get("criteria") | |
| if t == "noul": | |
| keys = ["false", "true"] | |
| if isinstance(c, dict): | |
| return keys, [f"false — {c.get('false', 'no')}", f"true — {c.get('true', 'yes')}"] | |
| return keys, ["false — no", "true — yes"] | |
| if t == "choice": | |
| return list(c.keys()), [f"{k}: {v}" for k, v in c.items()] | |
| if isinstance(c, list): | |
| return [str(i) for i in range(len(c))], [str(v) for v in c] | |
| return list(c.keys()), [f"{k}: {v}" for k, v in c.items()] | |
| class Aubin: | |
| """AUBIN karar modeli. base: açık taban (Apache-2.0), adapter: AUBIN LoRA'sı (yerel dizin veya HF repo).""" | |
| def __init__(self, adapter="emrevrg/AUBIN-12B", base=None, four_bit=True, device_map=None, temperature=None, | |
| perms=1, max_state=6000, cache_state=False, think_margin=None, think_tokens=256, think_mix=None, | |
| think_samples=1, think_temp=0.7): | |
| # önbellek: Gemma-4 GPU'da birebir değil (fark 0.355) → varsayılan KAPALI | |
| # think_margin: en iyi iki seçeneğin log-olasılık farkı bunun altındaysa kısa akıl yürütme + yeniden puan | |
| # ("eminsizse düşün"; Kev dev'de 31B: transfer .852→.864, ~%14 soruda üretim yapılır) | |
| from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig | |
| meta = self._meta(adapter[0] if isinstance(adapter, (list, tuple)) else adapter) | |
| base = base or meta.get("base_model", "google/gemma-4-12B-it") | |
| self.T = float(temperature or meta.get("temperature", 1.0)) | |
| self.perms, self.max_state = perms, max_state | |
| self.think_margin = float(think_margin if think_margin is not None else meta.get("think_margin", 0.0)) | |
| self.think_tokens = think_tokens | |
| # think_mix: eminsiz soruda düşünen yolun payı (1.0 = yalnız düşünen yol; Duo tarifi 0.5 = hızlı + düşünen yarı yarıya) | |
| self.think_mix = float(think_mix if think_mix is not None else meta.get("think_mix", 1.0)) | |
| # think_samples>1: self-consistency — açgözlü akıl yürütme + (n-1) örneklenmiş; cevap olasılıkları ortalanır | |
| self.think_samples, self.think_temp = int(think_samples), float(think_temp) | |
| self.cache_state, self._pc = cache_state, None | |
| self.tok = AutoTokenizer.from_pretrained(base) | |
| self.tok.padding_side = "left" | |
| if self.tok.pad_token is None: | |
| self.tok.pad_token = self.tok.eos_token | |
| # AUBIN_DEVICE=xla: Kaggle/Cloud TPU (torch_xla) — bf16, 4-bit yok, uzunluk 256'nın katına dolgu (derleme tekrar kullanılır) | |
| self.xla = os.environ.get("AUBIN_DEVICE", "") == "xla" | |
| if self.xla: | |
| import torch_xla.core.xla_model as xm | |
| if os.environ.get("AUBIN_XLA_SPMD", "") == "1": | |
| import torch_xla.runtime as xr | |
| xr.use_spmd() # cihaz alınmadan önce açılmalı | |
| dev = xm.xla_device() | |
| kw = dict(dtype=torch.bfloat16, low_cpu_mem_usage=True) | |
| four_bit = False | |
| else: | |
| dev = "cuda:0" if torch.cuda.is_available() else "cpu" | |
| device_map = device_map or meta.get("device_map") | |
| kw = dict(device_map=device_map or dev, dtype=torch.float16 if dev != "cpu" else torch.float32) | |
| if four_bit and dev != "cpu": | |
| kw["quantization_config"] = BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_quant_type="nf4", | |
| bnb_4bit_compute_dtype=torch.float16, bnb_4bit_use_double_quant=True) | |
| try: | |
| m = AutoModelForCausalLM.from_pretrained(base, **kw) | |
| except Exception: | |
| from transformers import AutoModelForImageTextToText | |
| m = AutoModelForImageTextToText.from_pretrained(base, **kw) | |
| self.adapters = [] | |
| ads = adapter if isinstance(adapter, (list, tuple)) else ([adapter] if adapter else []) | |
| if meta.get("no_adapter"): # sürüm yalnız protokol + kalibrasyon (ağırlık değişikliği yok) | |
| ads = [] | |
| if ads: # birden çok adaptör = ansambl (log-olasılık ortalaması) | |
| from peft import PeftModel | |
| m = PeftModel.from_pretrained(m, ads[0], adapter_name="a0") | |
| for i, ad in enumerate(ads[1:], 1): | |
| m.load_adapter(ad, adapter_name=f"a{i}") | |
| self.adapters = [f"a{i}" for i in range(len(ads))] | |
| if self.xla: | |
| m = self._to_xla(m, dev) | |
| self.m = m.eval() | |
| self.dev = dev | |
| self.letter_ids = [sorted({self.tok.encode(a, add_special_tokens=False)[0], | |
| self.tok.encode(" " + a, add_special_tokens=False)[-1]}) for a in L] | |
| def attach(cls, model, tok, adapter=None, temperature=None, think_margin=None): | |
| """Zaten yüklü bir modele (ör. AubinOmni'nin çok-adaptörlü tabanı) Aubin puanlayıcısı bağlar — yeniden yükleme yok. | |
| Etkin adaptör dışarıdan seçilir (set_adapter); kalibrasyon sıcaklığı/düşünme eşiği adaptörün aubin.json'undan.""" | |
| a = cls.__new__(cls) | |
| meta = cls._meta(adapter) if adapter else {} | |
| a.T = float(temperature or meta.get("temperature", 1.0)) | |
| a.perms, a.max_state = 1, 6000 | |
| a.think_margin = float(think_margin if think_margin is not None else meta.get("think_margin", 0.0)) | |
| a.think_tokens, a.think_mix, a.think_samples, a.think_temp = 256, float(meta.get("think_mix", 1.0)), 1, 0.7 | |
| a.cache_state, a._pc, a.xla, a.adapters = False, None, False, [] | |
| a.tok = tok | |
| a.tok.padding_side = "left" | |
| if a.tok.pad_token is None: | |
| a.tok.pad_token = a.tok.eos_token | |
| a.m = model | |
| a.dev = model.device if hasattr(model, "device") else next(model.parameters()).device | |
| a.letter_ids = [sorted({tok.encode(x, add_special_tokens=False)[0], tok.encode(" " + x, add_special_tokens=False)[-1]}) for x in L] | |
| return a | |
| def _to_xla(m, dev): | |
| """TPU'ya taşı. AUBIN_XLA_SPMD=1: tüm çiplere (v5e-8 = 8 x 16 GB) satır-bölmeli SPMD — 12B/31B bf16 tek çipe sığmaz. | |
| Parametreler tek tek taşınıp hemen bölünür; tam kopya hiçbir çipte birikmez.""" | |
| if os.environ.get("AUBIN_XLA_SPMD", "") != "1": | |
| return m.to(dev) | |
| import numpy as np | |
| import torch_xla.runtime as xr | |
| import torch_xla.distributed.spmd as xs | |
| n =xr.global_runtime_device_count() | |
| mesh = xs.Mesh(np.arange(n), (1, n), ("data", "model")) | |
| for mod in m.modules(): | |
| for name, p in list(mod.named_parameters(recurse=False)) + list(mod.named_buffers(recurse=False)): | |
| t = p.data.to(dev) | |
| if t.dim() == 2 and t.shape[0] % n == 0: | |
| xs.mark_sharding(t, mesh, ("model", None)) | |
| if isinstance(p, torch.nn.Parameter): | |
| p.data = t | |
| else: | |
| mod._buffers[name] = t | |
| return m | |
| def _meta(adapter): | |
| try: | |
| if adapter and os.path.isdir(adapter): | |
| return json.load(open(os.path.join(adapter, "aubin.json"))) | |
| if adapter: | |
| from huggingface_hub import hf_hub_download | |
| return json.load(open(hf_hub_download(adapter, "aubin.json"))) | |
| except Exception: | |
| pass | |
| return {} | |
| def _prompt(self, state_text, q, texts, order): | |
| st = state_text if len(state_text) <= self.max_state else state_text[: self.max_state] + " …" | |
| opts = "\n".join(f"{L[j]}) {texts[i]}" for j, i in enumerate(order)) | |
| u = (f"Decide based ONLY on the state below.\n\nSTATE:\n{st}\n\nQUESTION: {q}\n\nOPTIONS:\n{opts}\n\n" | |
| f"Reply with the single letter of the correct option.") | |
| msgs = [{"role": "user", "content": u}] | |
| try: | |
| p = self.tok.apply_chat_template(msgs, add_generation_prompt=True, tokenize=False, enable_thinking=False) | |
| except Exception: | |
| p = self.tok.apply_chat_template(msgs, add_generation_prompt=True, tokenize=False) | |
| return p + "Answer: " | |
| def _letters(self, prompts): | |
| if self.cache_state and len(prompts) == 1 and "\n\nQUESTION:" in prompts[0]: | |
| return self._letters_cached(prompts[0]) | |
| enc = self.tok(prompts, return_tensors="pt", padding=True, add_special_tokens=False, | |
| pad_to_multiple_of=256 if self.xla else None).to(self.dev) | |
| try: | |
| out = self.m(**enc, logits_to_keep=1) | |
| except TypeError: | |
| out = self.m(**enc) | |
| last = out.logits[:, -1].float() | |
| r = torch.stack([last[:, ids].logsumexp(-1) for ids in self.letter_ids], -1) | |
| return r.cpu() if self.xla else r | |
| def _letters_cached(self, prompt): | |
| """Durum önbelleği: aynı duruma sorulan her soruda durum kısmı (önek) BİR kez işlenir, KV-önbelleği | |
| kopyalanıp yalnız soru+seçenekler (sonek) hesaplanır → çok soruda büyük hız kazancı.""" | |
| import copy | |
| full = self.tok(prompt, add_special_tokens=False).input_ids | |
| pre_ids = self.tok(prompt[: prompt.index("\n\nQUESTION:")], add_special_tokens=False).input_ids | |
| k = 0 # token düzeyinde ortak önek: bölme sınırı birebir aynı tokenlarla | |
| while k < min(len(full), len(pre_ids)) - 1 and full[k] == pre_ids[k]: | |
| k += 1 | |
| key = (tuple(full[:k]), getattr(self.m, "active_adapter", None)) | |
| if self._pc is None or self._pc[0] != key: | |
| out = self.m(input_ids=torch.tensor([full[:k]], device=self.dev), use_cache=True) | |
| self._pc = (key, k, out.past_key_values) | |
| n_pre, pkv = self._pc[1], copy.deepcopy(self._pc[2]) | |
| sids = torch.tensor([full[k:]], device=self.dev) | |
| cp = torch.arange(n_pre, n_pre + sids.shape[1], device=self.dev) | |
| pos = cp.unsqueeze(0) | |
| # cache_position açıkça verilir: kayan pencereli katmanların önbelleği kırpılmış tutulur, get_seq_length() önek | |
| # uzunluğunu değil pencere boyunu döndürebilir → maske/konum kayar (Gemma-4 12B'de görülen 0.355 fark) | |
| try: | |
| out = self.m(input_ids=sids, past_key_values=pkv, position_ids=pos, cache_position=cp, use_cache=True, logits_to_keep=1) | |
| except TypeError: | |
| out = self.m(input_ids=sids, past_key_values=pkv, position_ids=pos, cache_position=cp, use_cache=True) | |
| last = out.logits[:, -1].float() | |
| return torch.stack([last[:, ids].logsumexp(-1) for ids in self.letter_ids], -1) | |
| def _think(self, state_text, q, texts): | |
| """Kısa akıl yürütme üret, 'Answer: ' konumunda harf log-olasılıkları (kev_llm.think_scores ile aynı).""" | |
| st = state_text if len(state_text) <= self.max_state else state_text[: self.max_state] + " …" | |
| opts = "\n".join(f"{L[j]}) {t}" for j, t in enumerate(texts)) | |
| u = (f"Decide based ONLY on the state below.\n\nSTATE:\n{st}\n\nQUESTION: {q}\n\nOPTIONS:\n{opts}\n\n" | |
| f"Think briefly step by step (at most 6 short sentences), weighing the most plausible options. " | |
| f"Then write the final line exactly as 'Answer: <letter>'.") | |
| msgs = [{"role": "user", "content": u}] | |
| try: | |
| p = self.tok.apply_chat_template(msgs, add_generation_prompt=True, tokenize=False, enable_thinking=False) | |
| except Exception: | |
| p = self.tok.apply_chat_template(msgs, add_generation_prompt=True, tokenize=False) | |
| enc = self.tok([p], return_tensors="pt", add_special_tokens=False).to(self.dev) | |
| probs, reasons = None, [] | |
| for s in range(max(1, self.think_samples)): | |
| kw = dict(do_sample=False) if s == 0 else dict(do_sample=True, temperature=self.think_temp, top_p=0.95) | |
| with torch.no_grad(): | |
| gen = self.m.generate(**enc, max_new_tokens=self.think_tokens, pad_token_id=self.tok.pad_token_id, **kw) | |
| t = self.tok.decode(gen[0, enc["input_ids"].shape[1]:], skip_special_tokens=True) | |
| k = t.find("Answer:") | |
| reasons.append((t[:k] if k >= 0 else t).strip()) | |
| lg = self._letters([p + (t[:k] if k >= 0 else t).rstrip() + "\nAnswer: "])[0, :len(texts)].cpu() | |
| pr = torch.softmax(lg.float(), -1) | |
| probs = pr if probs is None else probs + pr | |
| self.last_reasoning = reasons[0] | |
| return torch.log(probs / max(1, self.think_samples) + 1e-12) | |
| def _maybe_think(self, lp, state_text, q, texts): | |
| if not self.think_margin or len(texts) > 26 or len(texts) < 2: | |
| return lp, False | |
| v = torch.sort(lp, descending=True).values | |
| if float(v[0] - v[1]) >= self.think_margin: | |
| return lp, False | |
| return self._think(state_text, q, texts), True | |
| def _mixed(self, fast, state_text, q, texts): | |
| """Sıcaklıkla ölçeklenmiş log-olasılık; eminsizse düşünen yol think_mix oranında karıştırılır | |
| (jev_compare.combine ile birebir aynı hesap).""" | |
| z = torch.log_softmax(fast / self.T, -1) | |
| think, did = self._maybe_think(fast, state_text, q, texts) | |
| if did and self.think_mix > 0: | |
| z = (1 - self.think_mix) * z + self.think_mix * torch.log_softmax(think / self.T, -1) | |
| return z | |
| def _score(self, state_text, q, texts): | |
| """Sıcaklık UYGULANMIŞ log-olasılıklar.""" | |
| if len(self.adapters) > 1: | |
| outs = [] | |
| for name in self.adapters: | |
| self.m.set_adapter(name) | |
| outs.append(self._mixed(self._score_one(state_text, q, texts), state_text, q, texts)) | |
| return torch.log_softmax(torch.stack(outs).mean(0), -1) | |
| return self._mixed(self._score_one(state_text, q, texts), state_text, q, texts) | |
| def _score_one(self, state_text, q, texts): | |
| n = len(texts); idx = list(range(n)) | |
| if n > 26: # 26'lık gruplar + final turu | |
| full, winners = torch.full((n,), -1e4), [] | |
| for s in range(0, n, 26): | |
| g = idx[s:s + 26] | |
| lg = self._letters([self._prompt(state_text, q, texts, g)])[0, :len(g)].cpu() | |
| full[torch.tensor(g)] = lg; winners.append(g[int(lg.argmax())]) | |
| lg = self._letters([self._prompt(state_text, q, texts, winners)])[0, :len(winners)].cpu() | |
| full[torch.tensor(winners)] = lg + 50.0 | |
| return torch.log_softmax(full, -1) | |
| acc = torch.zeros(n) | |
| shifts = sorted({(k * n) // self.perms for k in range(self.perms)}) | |
| for s in shifts: # seçenek sırası döndürülür: konum yanlılığı ortalanır | |
| order = idx[s:] + idx[:s] | |
| lg = torch.log_softmax(self._letters([self._prompt(state_text, q, texts, order)])[0, :n].cpu(), -1) | |
| back = torch.empty(n); back[torch.tensor(order)] = lg; acc += back | |
| return acc / len(shifts) | |
| def logprobs(self, state, questions): | |
| """Her soru için sıcaklıkla ölçeklenmiş log-olasılıklar {id: (keys, tensor)} — ansambl bunları birleştirir.""" | |
| st = state if isinstance(state, str) else json.dumps(state, ensure_ascii=False) | |
| out = {} | |
| for qid, q in questions.items(): | |
| keys, texts = options(q) | |
| out[qid] = (keys, torch.log_softmax(self._score(st, q.get("instructions") or qid, texts), -1)) | |
| return out | |
| def decide(self, state, questions): | |
| """state: dict/str; questions: {id: {type, instructions, criteria}} → {id: {answer, confidence, probabilities}}""" | |
| return _package(self.logprobs(state, questions), 1.0) | |
| def _package(lps, T): | |
| out = {} | |
| for qid, (keys, lp) in lps.items(): | |
| p = F.softmax(lp / T, -1) | |
| j = int(p.argmax()) | |
| out[qid] = {"answer": keys[j], "confidence": round(float(p[j]), 4), | |
| "probabilities": {k: round(float(v), 4) for k, v in zip(keys, p)}} | |
| return out | |
| class AubinEnsemble: | |
| """Farklı tabanlardaki AUBIN üyelerinin ağırlıklı log-olasılık birleşimi (ör. 31B + 12B). | |
| members: [(Aubin, ağırlık), ...]; temperature: birleşim sonrası sıcaklık (Kev dev'de ölçülen tarif: T=0.8).""" | |
| def __init__(self, members, temperature=0.8): | |
| s = sum(w for _, w in members) | |
| self.members = [(m, w / s) for m, w in members] | |
| self.T = temperature | |
| def decide(self, state, questions): | |
| acc = None | |
| for m, w in self.members: | |
| lp = m.logprobs(state, questions) | |
| acc = {k: (v[0], w * v[1]) for k, v in lp.items()} if acc is None else \ | |
| {k: (acc[k][0], acc[k][1] + w * lp[k][1]) for k in acc} | |
| return _package(acc, self.T) | |