Text Generation
Transformers
English
Russian
diffusion-language-model
dllm
decoding-strategy
levenshtein-editing
LLaDA
inference-time
research
Instructions to use Freedomform/wet-ink-v5 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use Freedomform/wet-ink-v5 with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="Freedomform/wet-ink-v5")# pip install -U transformers accelerate # Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("Freedomform/wet-ink-v5", device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use Freedomform/wet-ink-v5 with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "Freedomform/wet-ink-v5" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "Freedomform/wet-ink-v5", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker
docker model run hf.co/Freedomform/wet-ink-v5
- SGLang
How to use Freedomform/wet-ink-v5 with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "Freedomform/wet-ink-v5" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "Freedomform/wet-ink-v5", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "Freedomform/wet-ink-v5" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "Freedomform/wet-ink-v5", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }' - Docker Model Runner
How to use Freedomform/wet-ink-v5 with Docker Model Runner:
docker model run hf.co/Freedomform/wet-ink-v5
Download kernel_v5.py from Freedomform/wet-ink-v5: direct link, hf CLI and curl.
- Browser
- Download file 108 kB
-
https://huggingface.co/Freedomform/wet-ink-v5/resolve/main/kernel_v5.py
- Command line
-
hf download hf://Freedomform/wet-ink-v5/kernel_v5.py
-
curl -L -o kernel_v5.py https://huggingface.co/Freedomform/wet-ink-v5/resolve/main/kernel_v5.py
108 kB
| #!/usr/bin/env python3 | |
| # -*- coding: utf-8 -*- | |
| """ | |
| Wet-Ink v5 — OUR METHOD, implemented: sliding-window frontier decoder on | |
| LLaDA2.2-mini's own formulas (2×Tesla T4, 4-bit NF4, one model per GPU). | |
| WHAT CHANGED vs v4 (owner's correction, 7 Nov 2026): v4 only ablated the | |
| model's stock generate() parameters. That measured the base, not our idea. | |
| v5 implements the idea from the report §2.1 as a real decoder: | |
| (1) FRONTIER: open EXACTLY ONE token per diffusion step, left-to-right | |
| (AR commit of the leftmost mask). This is the left-to-right end of the | |
| published interpolation spectrum: BD3-LM (Arriola et al., ICLR 2025 | |
| Oral) and Set Diffusion (Arriola et al. 2026) treat tokens-per-step / | |
| position orderings as free inference-time variables. | |
| (2) WET WINDOW: the model's OWN trained T2T gate (LLaDA2.2 L-EBPO; | |
| LLaDA2.1 "Speeding Up Text Diffusion via Token Editing", | |
| arXiv:2602.08676) — p0 > editing_threshold & old != x0 -> greedy | |
| rewrite — restricted to the sliding window [f-W, f) behind the | |
| frontier. Hard dry edge: "ink dries with distance" (the idea's core). | |
| (3) Trained edit ops SPLIT/DELETE, anti-loop resampler, M2T/T2T write | |
| semantics, block-diagonal attention formula — ALL reused verbatim | |
| from the model (Levenshtein-Transformer lineage, Gu et al. 2019; | |
| trained into LLaDA2.2 via L-EBPO). | |
| THE FOUR RULES (report §2.2, owner's clarification of 7 Nov 2026): | |
| (a) study the base model's formulas from primary sources — done, | |
| modeling_llada2_moe.py read verbatim (1 801 lines); | |
| (b) no retraining — inference-time only; | |
| (c) pick the MOST EFFECTIVE formulas: the trained T2T gate over any | |
| training-free gate (our v3: training-free remasking hurt, -12.5..-26 | |
| pp; corroborated by "Re-evaluating Confidence Remasking", | |
| arXiv:2606.12232 — flip-flop behaviour); | |
| (d) no self-invented formulas; combining published formulas (and their | |
| surrounding code) from any architectures IS allowed after a | |
| compatibility check. The compatibility argument: every component | |
| operates on the model's own trained primitives; the ONLY new thing is | |
| the decoding SCHEDULE (which position opens / which window stays | |
| editable per step) — exactly the free variable identified by | |
| BD3-LM / Set Diffusion. THE GOAL: realize the owner's idea, in the | |
| most effective published way. | |
| ARMS (v5): wetink W∈{8,16,32} (T2T ON), wetink_noedit_w16 (T2T OFF — | |
| frontier-only control), he_wetink_w16 (HumanEval). Baselines stock_b32 / | |
| noedit_b32 / edit0.5/0.7 come from the completed v4b run (same model, same | |
| 4-bit quant, same prompts, same gen_length=160) — paired McNemar offline. | |
| Expected cost (honest): NFE ≈ one forward per committed token ≈ 160-200 per | |
| task vs stock's ~39 — the price of the one-token frontier (~4-5×). Reported | |
| as NFE ratio in every comparison. | |
| Output: /kaggle/working/results_v5.json | |
| """ | |
| import base64 | |
| import gzip | |
| import json | |
| import math | |
| import os | |
| import re | |
| import subprocess | |
| import sys | |
| import tempfile | |
| import threading | |
| import time | |
| from concurrent.futures import ThreadPoolExecutor | |
| from queue import Empty, Queue | |
| # Mitigate CUDA fragmentation (push-2 OOM'd on GPU 1 with 9 GiB "reserved but | |
| # unallocated" — classic fragmentation pattern in materialize_copy). | |
| os.environ.setdefault("PYTORCH_CUDA_ALLOC_CONF", "expandable_segments:True") | |
| def _pip(*pkgs): | |
| print("pip install:", *pkgs, flush=True) | |
| subprocess.run([sys.executable, "-m", "pip", "install", "-q", *pkgs], check=False) | |
| # transformers 5.2.0 is REQUIRED by LLaDA2.2-mini (config.json: transformers_version=5.2.0) | |
| # bitsandbytes for int8 quantization on T4; accelerate for device_map="auto" (2×T4) | |
| # bnb >= 0.48.0 ships the libbitsandbytes_cuda130.so binary that Kaggle (CUDA 13) needs; | |
| # earlier bnb 0.46.x only had cuda12x — that was the v4 push-1 failure. | |
| _pip("transformers==5.2.0", "datasets", "accelerate", "bitsandbytes>=0.48.2", | |
| "sentencepiece", "protobuf") | |
| import torch # noqa: E402 | |
| import transformers # noqa: E402 | |
| import transformers.utils.loading_report as _lr # noqa: E402 | |
| import transformers.modeling_utils as _mu # noqa: E402 | |
| # ---- bnb 0.46+ renamed Int8Params.SCB -> CB; transformers 5.2.0's loading_report | |
| # still calls .SCB and raises AttributeError+RuntimeError at finalize time, | |
| # AFTER the model has actually loaded. Patch log_state_dict_report to swallow | |
| # those reporting-only errors so from_pretrained returns the loaded model. | |
| # (Quantization itself succeeds — this is a post-load reporting bug only.) | |
| _orig_log_state_dict_report = _lr.log_state_dict_report | |
| def _safe_log_state_dict_report(*a, **kw): | |
| try: | |
| return _orig_log_state_dict_report(*a, **kw) | |
| except (AttributeError, RuntimeError) as e: # noqa: BLE001 | |
| # Most common: "'Int8Params' object has no attribute 'SCB'. Did you mean: 'CB'?" | |
| print(f"[loading_report patched] swallowed non-fatal: {type(e).__name__}: {e}", | |
| flush=True) | |
| _lr.log_state_dict_report = _safe_log_state_dict_report | |
| _mu.log_state_dict_report = _safe_log_state_dict_report | |
| from datasets import load_dataset # noqa: E402 | |
| from huggingface_hub import snapshot_download # noqa: E402 | |
| from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig # noqa: E402 | |
| import bitsandbytes as _bnb # noqa: E402 | |
| print("bitsandbytes version:", _bnb.__version__, flush=True) | |
| MODEL_ID = "inclusionAI/LLaDA2.2-mini" | |
| OUT_DIR = "/kaggle/working" if os.path.isdir("/kaggle/working") else "." | |
| RESULTS_PATH = os.path.join(OUT_DIR, "results_v5.json") | |
| MASK_ID = 156895 | |
| DELETE_ID = 156930 | |
| SPLIT_ID = 156931 | |
| EOS_ID = 156892 | |
| # Kaggle session limit is 9h; keep a 1.5h safety margin | |
| TIME_LIMIT_S = 7.5 * 3600 | |
| T0 = time.time() | |
| RESULTS = { | |
| "meta": { | |
| "model": MODEL_ID, | |
| "gpu": torch.cuda.get_device_name(0) if torch.cuda.is_available() else "CPU", | |
| "cuda": torch.version.cuda, | |
| "transformers": transformers.__version__, | |
| "torch": torch.__version__, | |
| "quantization": "int4 NF4 (bitsandbytes, double-quant, fp16 compute)", | |
| "attn_impl": "eager", | |
| "suite": "v5: wet-ink sliding-window frontier decoder (OUR idea §2.1) " | |
| "on LLaDA2.2's own formulas; baselines from v4b", | |
| "idea": "frontier opens ONE token/step left-to-right; trailing window " | |
| "W stays editable via the model's trained T2T gate; hard dry " | |
| "edge at distance W (ink dries)", | |
| "components": { | |
| "frontier": "AR commit of leftmost mask (BD3-LM / Set Diffusion " | |
| "spectrum end; our schedule)", | |
| "revision": "LLaDA2.2 trained T2T gate p0>editing_threshold & " | |
| "old!=x0 (L-EBPO), windowed to [f-W, f)", | |
| "edit_ops": "SPLIT/DELETE via model's own " | |
| "_apply_edit_operations_with_tracking (LevT lineage)", | |
| "anti_loop": "model's own _resample_to_escape_loop", | |
| "attention": "model's own block-diagonal formula (verbatim)", | |
| }, | |
| "v4b_baselines": "stock_b32 / noedit_b32 / edit0.5/0.7 from the " | |
| "completed v4b run (results_v4.json); paired offline", | |
| "rules": "no self-invented formulas; combining published formulas + " | |
| "code from any architectures allowed after compatibility " | |
| "check; goal = implement the owner's wet-ink idea most " | |
| "effectively (rules clarified 7 Nov 2026)", | |
| "dropped_from_v3": ["RemeDi (training-free remasking: harmful, v3)", | |
| "CoDR (training-free drift pass: neutral, v3)"], | |
| }, | |
| "sanity": {}, | |
| "equivalence": {}, | |
| "gsm8k": {}, | |
| "humaneval": {}, | |
| "stats": {}, | |
| } | |
| EST = {} | |
| LOCK = threading.RLock() # guards RESULTS + EST (two worker threads) | |
| ACTIVE = {"n": 0} # workers currently consuming the wall clock | |
| ACT_LOCK = threading.Lock() | |
| def dump(): | |
| with LOCK: | |
| tmp = RESULTS_PATH + ".tmp" | |
| with open(tmp, "w") as f: | |
| json.dump(RESULTS, f, indent=1) | |
| os.replace(tmp, RESULTS_PATH) | |
| def log(*a): | |
| el = time.time() - T0 | |
| h, m = int(el // 3600), int((el % 3600) // 60) | |
| print(f"[{h:02d}:{m:02d}]", *a, flush=True) | |
| def remaining(): | |
| return TIME_LIMIT_S - (time.time() - T0) | |
| # ---------------------------------------------------------------- model load | |
| log("downloading model snapshot ...") | |
| t0 = time.time() | |
| local = snapshot_download(MODEL_ID) | |
| log(f"snapshot ready in {time.time()-t0:.0f}s -> {local}") | |
| tok = AutoTokenizer.from_pretrained(local, trust_remote_code=True) | |
| log("tokenizer ready; eos:", tok.eos_token_id, "| mask:", MASK_ID, | |
| "| pad:", tok.pad_token_id) | |
| def _load(gpu): | |
| """Load LLaDA2.2-mini in 4-bit NF4 onto ONE T4 (whole model, no split). | |
| - Why 4-bit (v4b): the int8 run (v4a) needed both GPUs (~17 GiB weights), | |
| forcing a 2-GPU pipeline; with bnb's int8 matmul path on SM75 this gave | |
| ~3.8-4.2 s per forward (~140-220 s per GSM8K task) and the 7.5 h budget | |
| covered only 2 of 14 arms. NF4 storage for the 16.3B MoE is ~8.1 GiB | |
| (quantized Linears: 19 MoE layers x 256 experts + attn) + fp16 | |
| lm_head/word_embeddings (~0.6 GiB each, 157k vocab) + fp32 router ≈ | |
| ~9.4 GiB total — a FULL copy fits on one 15.8 GiB T4 with ~6 GiB | |
| headroom for activations (use_cache=False: diffusion full-forwards). | |
| - bnb_4bit_compute_dtype=float16: T4 (SM75) has no bf16 tensor cores. | |
| - bnb_4bit_use_double_quant=True: saves ~0.4 GiB on a 16B checkpoint. | |
| - llm_int8_skip_modules=["lm_head"]: 157k-vocab output head stays fp16 | |
| (transformers' own default for bnb; kept explicit). | |
| - attn_implementation='eager': required — the model builds its block | |
| attention mask in bfloat16, and SDPA rejects a bf16 mask that does | |
| not match the query dtype. eager attention promotes the mask to fp32 | |
| via softmax(... dtype=torch.float32), so it accepts any mask dtype. | |
| - MoE experts are the model's own LLaDA2MoeMLP — ordinary nn.Linear, | |
| bnb-compatible; the router is a raw nn.Parameter (router_dtype fp32), | |
| so bnb leaves it unquantized automatically. | |
| - PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True (env, set above) | |
| still defeats the fragmentation pattern from the v4 push-2 OOM. | |
| """ | |
| bnb = BitsAndBytesConfig( | |
| load_in_4bit=True, | |
| bnb_4bit_quant_type="nf4", | |
| bnb_4bit_compute_dtype=torch.float16, | |
| bnb_4bit_use_double_quant=True, | |
| llm_int8_skip_modules=["lm_head"], | |
| ) | |
| m = AutoModelForCausalLM.from_pretrained( | |
| local, | |
| trust_remote_code=True, | |
| quantization_config=bnb, | |
| device_map={"": gpu}, | |
| torch_dtype=torch.float16, | |
| attn_implementation="eager", | |
| ) | |
| m.eval() | |
| m._nfe_state = dict(nfe=0, prev=None, churn=0, special_residual=0) | |
| return m | |
| def _attach_meter(model): | |
| """Observation-only per-instance NFE/churn counter (does NOT alter | |
| generation math). Each worker thread drives its own model instance, | |
| so the meter state lives on the model object itself.""" | |
| st = model._nfe_state | |
| _orig_forward = model.forward | |
| def _wrapped_forward(*a, **k): | |
| st["nfe"] += 1 | |
| ids = a[0] if a else k.get("input_ids") | |
| if ids is not None: | |
| cur = ids.detach() | |
| prev = st["prev"] | |
| if prev is not None and prev.shape == cur.shape: | |
| changed = (cur != prev) & (prev != MASK_ID) | |
| st["churn"] += int(changed.sum().item()) | |
| st["prev"] = cur.clone() | |
| return _orig_forward(*a, **k) | |
| model.forward = _wrapped_forward | |
| log("loading model #0 in 4-bit NF4 on GPU0 (this takes ~5-10 min) ...") | |
| t0 = time.time() | |
| M0 = _load(0) | |
| _attach_meter(M0) | |
| log(f"model #0 loaded in {time.time()-t0:.0f}s") | |
| RESULTS["meta"]["device_map"] = str(getattr(M0, "hf_device_map", "single")) | |
| dump() | |
| # ---------------------------------------------------------------- prompt builders | |
| def chat_ids(text, dev): | |
| messages = [{"role": "user", "content": text}] | |
| p = tok.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) | |
| return tok(p, return_tensors="pt").input_ids.to(dev) | |
| # ---------------------------------------------------------------- sanity + equivalence | |
| SANITY = ("Natalia sold clips to 48 of her friends in April, and then she sold " | |
| "half as many clips in May. How many clips did Natalia sell altogether " | |
| "in April and May?") | |
| def _degenerate(text): | |
| t = text.strip() | |
| if len(t) < 5: | |
| return True | |
| ws = t.split() | |
| if len(ws) >= 20 and len(set(ws[-20:])) <= 2: | |
| return True | |
| return False | |
| # ================================================================ OUR DECODER | |
| def wetink_generate(model, ids, gen_length=160, block_length=32, window=16, | |
| editing_threshold=0.0, max_post_steps=4, temperature=0.0, | |
| eos_early_stop=True): | |
| """THE WET-INK METHOD (report §2.1), built on the model's own formulas. | |
| Schedule (OUR idea — the only new thing, per BD3-LM/Set Diffusion the | |
| schedule is a legitimate free variable, not a formula change): | |
| * FRONTIER: each step opens EXACTLY ONE token — the LEFTMOST remaining | |
| mask of the current block — committing it AR-style (sampled x_s, | |
| greedy at temperature=0). Progress is guaranteed: one mask fewer | |
| per step. This is the one-token-per-step left-to-right frontier of | |
| the idea; the AR end of the published AR↔diffusion spectrum. | |
| * WET WINDOW: positions [f-W, f) behind the frontier (clipped to the | |
| current block) stay revisable through the model's TRAINED T2T gate | |
| (verbatim formula from _joint_decode_block / L-EBPO): | |
| p0 > editing_threshold AND old != x0 -> rewrite to x0 | |
| Hard dry edge: outside the window (or in frozen blocks) a token is | |
| never touched again — "ink dries with distance". | |
| * Post-phase: once all masks of the block are resolved, up to | |
| max_post_steps further steps keep the last W positions wet (the | |
| drying tail), then the block freezes forever (stock's semantics, | |
| smaller budget). | |
| Everything else is reused verbatim from the model (rule (d)): | |
| - block-diagonal attention mask — exact formula from generate(); | |
| - _diffusion_sample — the model's own sampler; | |
| - _apply_edit_operations_with_tracking — trained SPLIT/DELETE ops; | |
| - _resample_to_escape_loop — the model's own anti-loop resampler; | |
| - SPLIT/DELETE suppression on the final round — the model's own | |
| termination guarantee; EOS tail-cut — the model's own output rule. | |
| Compatibility check (rule (d)): all writes go through the same gates | |
| and ops the model was trained with (L-EBPO); the attention pattern is | |
| the trained blockwise-causal one; only WHICH position opens per step | |
| (one, leftmost) and WHICH open positions may be rewritten per step | |
| (window W behind the frontier) differ from stock. | |
| Returns (output_ids, stats) with stats = {steps, opened, rewrites, resid}. | |
| """ | |
| device = model.device | |
| input_ids = ids.to(device) | |
| prompt_length = input_ids.shape[1] | |
| num_blocks = (prompt_length + gen_length + block_length - 1) // block_length | |
| total_length = num_blocks * block_length | |
| # --- attention mask: the model's OWN block-diagonal formula (verbatim) --- | |
| block_mask = torch.tril(torch.ones(num_blocks, num_blocks, device=device)) | |
| bd_mask = ( | |
| block_mask.repeat_interleave(block_length, dim=0) | |
| .repeat_interleave(block_length, dim=1) | |
| .unsqueeze(0) | |
| .unsqueeze(0) | |
| .log() | |
| .to(torch.bfloat16) | |
| ) | |
| position_ids = torch.arange(total_length, device=device).unsqueeze(0) | |
| x = torch.full((1, total_length), MASK_ID, dtype=torch.long, device=device) | |
| x[:, :prompt_length] = input_ids.clone() | |
| stats = dict(steps=0, opened=0, rewrites=0, resid=0) | |
| prefill_blocks = prompt_length // block_length | |
| stop = False | |
| for num_block in range(prefill_blocks, num_blocks): | |
| if stop: | |
| break | |
| block_start = num_block * block_length | |
| block_end = (num_block + 1) * block_length | |
| cur_attn = bd_mask[:, :, :block_end, :block_end] | |
| cur_pos = position_ids[:, :block_end] | |
| prompt_mask_block = (x[0, block_start:block_end] != MASK_ID).clone() | |
| is_original_mask = (x[0, block_start:block_end] == MASK_ID).tolist() | |
| if sum(is_original_mask) == 0: | |
| continue # fully prompt/context block | |
| seen = set() | |
| post_steps = 0 | |
| step_id = 0 | |
| # one opened token per step + SPLIT insertions + drying tail | |
| step_cap = 3 * block_length + max_post_steps + 8 | |
| while True: | |
| blk = x[0, block_start:block_end] | |
| old_block = blk.clone() | |
| mask_index = (old_block == MASK_ID) & (~prompt_mask_block) | |
| n_mask = int(mask_index.sum().item()) | |
| if n_mask == 0 and post_steps > max_post_steps: | |
| break | |
| if step_id >= step_cap: | |
| break # residual masks (if any) are counted in stats["resid"] | |
| logits = model.forward( | |
| x[:, :block_end], attention_mask=cur_attn, position_ids=cur_pos | |
| ).logits | |
| block_logits = logits[0, block_start:block_end, :] | |
| x_s, p_s = model._diffusion_sample(block_logits, temperature, None, None) | |
| if temperature != 0.0: | |
| x0, p0 = model._diffusion_sample(block_logits, 0.0, None, None) | |
| else: | |
| x0, p0 = x_s, p_s | |
| neg_inf = torch.full_like(p0, -float("inf")) | |
| # ---- FRONTIER: open exactly ONE token — the leftmost mask ---- | |
| mt2_index = torch.zeros(block_length, dtype=torch.bool, device=device) | |
| frontier = block_length | |
| if n_mask > 0: | |
| f = int( | |
| torch.nonzero(mask_index, as_tuple=True)[0][0].item() | |
| ) | |
| mt2_index[f] = True | |
| frontier = f | |
| stats["opened"] += 1 | |
| # ---- WET WINDOW: trained T2T gate, restricted to [f-W, f) ---- | |
| editable = (~mask_index) & (~prompt_mask_block) | |
| win = torch.zeros(block_length, dtype=torch.bool, device=device) | |
| lo = max(0, frontier - window) | |
| win[lo:frontier] = True | |
| t2t_scope = editable & win | |
| editing_confidence = torch.where(t2t_scope, p0, neg_inf) | |
| t2t_index = (editing_confidence > editing_threshold) & t2t_scope | |
| t2t_index = t2t_index & (old_block != x0) | |
| # ---- final round: suppress SPLIT/DELETE so the block can end ---- | |
| final_round = (n_mask == 0) and (post_steps >= max_post_steps) | |
| if final_round: | |
| m2t_sd = mt2_index & ((x_s == SPLIT_ID) | (x_s == DELETE_ID)) | |
| if m2t_sd.any(): | |
| sd_logits = block_logits[m2t_sd].clone() | |
| sd_logits[:, SPLIT_ID] = float("-inf") | |
| sd_logits[:, DELETE_ID] = float("-inf") | |
| new_tokens, _ = model._diffusion_sample( | |
| sd_logits, temperature, None, None | |
| ) | |
| x_s[m2t_sd] = new_tokens | |
| t2t_sd = t2t_index & ((x0 == SPLIT_ID) | (x0 == DELETE_ID)) | |
| if t2t_sd.any(): | |
| sd_logits = block_logits[t2t_sd].clone() | |
| sd_logits[:, SPLIT_ID] = float("-inf") | |
| sd_logits[:, DELETE_ID] = float("-inf") | |
| new_tokens, _ = model._diffusion_sample( | |
| sd_logits, 0.0, None, None | |
| ) | |
| x0[t2t_sd] = new_tokens | |
| # ---- writes: M2T sampled, T2T greedy (the model's semantics) ---- | |
| if mt2_index.any(): | |
| blk[mt2_index] = x_s[mt2_index] | |
| if t2t_index.any(): | |
| blk[t2t_index] = x0[t2t_index] | |
| stats["rewrites"] += int(t2t_index.sum().item()) | |
| # ---- anti-loop: the model's own resampler ---- | |
| if not final_round and (mt2_index.any() or t2t_index.any()): | |
| model._resample_to_escape_loop( | |
| blk, old_block, block_logits, mt2_index, t2t_index, seen, | |
| temperature=temperature, top_k=None, top_p=None, | |
| ) | |
| seen.add(tuple(blk.tolist())) | |
| # ---- trained SPLIT/DELETE edit ops (block stays fixed length) ---- | |
| is_original_mask_snapshot = list(is_original_mask) | |
| edited_block, is_original_mask = ( | |
| model._apply_edit_operations_with_tracking( | |
| blk.tolist(), | |
| old_block.tolist(), | |
| is_original_mask_snapshot, | |
| MASK_ID, | |
| block_length, | |
| delete_token_id=DELETE_ID, | |
| split_token_id=SPLIT_ID, | |
| ) | |
| ) | |
| x[0, block_start:block_end] = torch.tensor( | |
| edited_block, device=device, dtype=x.dtype | |
| ) | |
| if n_mask == 0: | |
| post_steps += 1 | |
| else: | |
| post_steps = 0 | |
| step_id += 1 | |
| stats["steps"] += 1 | |
| # block frozen from here on ("fully dry") | |
| if ( | |
| eos_early_stop | |
| and (x[0, prompt_length:block_end] == EOS_ID).any() | |
| ): | |
| stop = True | |
| # ---- output: the model's own tail-cut rule (cut at first EOS) ---- | |
| generated = x[:, : prompt_length + gen_length] | |
| eos_positions = (generated[0][prompt_length:] == EOS_ID).nonzero(as_tuple=True)[0] | |
| first_eos = int(eos_positions[0].item()) if len(eos_positions) > 0 else gen_length | |
| output = generated[:, prompt_length: prompt_length + first_eos + 1] | |
| stats["resid"] = int( | |
| ((output == MASK_ID) | (output == DELETE_ID) | (output == SPLIT_ID)).sum().item() | |
| ) | |
| return output, stats | |
| def gen(model, ids, mode="stock", window=16, gen_length=256, block_length=32, | |
| threshold=0.5, editing_threshold=0.0, max_post_steps=16, temperature=0.0): | |
| """Decode one task. | |
| mode="stock": the model's OWN generate() — v4b baseline arms. | |
| mode="wetink": OUR §2.1 decoder (wetink_generate) — one-token frontier | |
| + sliding trained-T2T window on the model's formulas. | |
| """ | |
| _NFE_STATE = model._nfe_state | |
| _NFE_STATE.update(nfe=0, prev=None, churn=0, special_residual=0, | |
| wetink_stats=None) | |
| if mode == "wetink": | |
| out, wstats = wetink_generate( | |
| model, ids, gen_length=gen_length, block_length=block_length, | |
| window=window, editing_threshold=editing_threshold, | |
| max_post_steps=max_post_steps, temperature=temperature, | |
| ) | |
| else: | |
| out = model.generate( | |
| inputs=ids, | |
| temperature=temperature, | |
| block_length=block_length, | |
| steps=block_length, | |
| gen_length=gen_length, | |
| threshold=threshold, | |
| editing_threshold=editing_threshold, | |
| max_post_steps=max_post_steps, | |
| eos_early_stop=True, | |
| eos_id=EOS_ID, | |
| mask_id=MASK_ID, | |
| delete_token_id=DELETE_ID, | |
| split_token_id=SPLIT_ID, | |
| max_steps_per_block=1000, | |
| ) | |
| nfe = _NFE_STATE["nfe"] | |
| churn = _NFE_STATE["churn"] | |
| resid = int(((out == MASK_ID) | (out == DELETE_ID) | (out == SPLIT_ID)).sum().item()) | |
| _NFE_STATE["special_residual"] = resid | |
| if mode == "wetink": | |
| _NFE_STATE["wetink_stats"] = wstats | |
| return out, nfe, churn, resid | |
| ids0 = chat_ids(SANITY, M0.device) | |
| t0 = time.time() | |
| out_s, nfe_s, churn_s, resid_s = gen(M0, ids0, mode="stock", gen_length=96, | |
| block_length=32, threshold=0.5, | |
| editing_threshold=0.0) | |
| text_s = tok.decode(out_s[0], skip_special_tokens=True) | |
| sanity_wall = time.time() - t0 | |
| log(f"sanity stock b32: nfe={nfe_s} churn={churn_s} resid={resid_s} " | |
| f"wall={sanity_wall:.0f}s out={text_s[:200]!r}") | |
| RESULTS["sanity"]["stock_b32"] = dict( | |
| nfe=int(nfe_s), churn=int(churn_s), special_residual=int(resid_s), | |
| wall_seconds=sanity_wall, output_prefix=text_s[:300], | |
| ) | |
| dump() | |
| log("sanity: OUR wet-ink decoder (W=16, one-token frontier, trained T2T window)") | |
| t0 = time.time() | |
| out_w, nfe_w, churn_w, resid_w = gen(M0, ids0, mode="wetink", window=16, | |
| gen_length=128, block_length=32, | |
| editing_threshold=0.0, max_post_steps=4) | |
| text_w = tok.decode(out_w[0], skip_special_tokens=True) | |
| wet_wall = time.time() - t0 | |
| ws = M0._nfe_state.get("wetink_stats") or {} | |
| log(f"sanity wetink W=16: nfe={nfe_w} churn={churn_w} resid={resid_w} " | |
| f"steps={ws.get('steps')} opened={ws.get('opened')} rewrites={ws.get('rewrites')} " | |
| f"wall={wet_wall:.0f}s out={text_w[:200]!r}") | |
| RESULTS["sanity"]["wetink_w16"] = dict( | |
| nfe=int(nfe_w), churn=int(churn_w), special_residual=int(resid_w), | |
| wall_seconds=wet_wall, wetink=ws, output_prefix=text_w[:300], | |
| ) | |
| dump() | |
| log("equivalence: OUR decoder greedy determinism (same config twice -> identical ids)") | |
| for W in (16,): | |
| o1, n1, c1, _ = gen(M0, ids0, mode="wetink", window=W, gen_length=64, | |
| block_length=32, editing_threshold=0.0, max_post_steps=4) | |
| o2, n2, c2, _ = gen(M0, ids0, mode="wetink", window=W, gen_length=64, | |
| block_length=32, editing_threshold=0.0, max_post_steps=4) | |
| ok = bool(torch.equal(o1, o2)) and n1 == n2 | |
| RESULTS["equivalence"][f"wetink_w{W}"] = dict( | |
| ids_equal=ok, nfe1=int(n1), nfe2=int(n2), | |
| churn1=int(c1), churn2=int(c2)) | |
| log(f"eq wetink W={W}: ids_equal={ok} nfe {n1}=={n2} churn {c1}=={c2}") | |
| dump() | |
| # ---------------------------------------------------------------- statistics helpers | |
| def mcnemar_exact(b, c): | |
| """Two-sided exact binomial (McNemar) test on discordant pairs b, c.""" | |
| from math import comb | |
| n = b + c | |
| if n == 0: | |
| return 1.0 | |
| k = min(b, c) | |
| p = sum(comb(n, i) for i in range(k + 1)) / 2 ** n | |
| return min(1.0, 2 * p) | |
| def wilson(k, n, z=1.96): | |
| if n == 0: | |
| return 0.0, 0.0, 0.0 | |
| p = k / n | |
| d = 1 + z * z / n | |
| c = (p + z * z / (2 * n)) / d | |
| h = z * math.sqrt(p * (1 - p) / n + z * z / (4 * n * n)) / d | |
| return p, max(0.0, c - h), min(1.0, c + h) | |
| def ok_of(d): | |
| v = d.get("ok", d.get("passed")) | |
| return bool(v) | |
| # Per-task wall priors, CALIBRATED from v4b actuals (results_v4.json, | |
| # kernel freedomform/wet-ink-llada22-mini, 4-bit NF4, 2 workers): | |
| # per_fwd = stock_b32.wall/n/avg_nfe = 2.858 s/NFE (gsm8k) | |
| # per_fwd_he = he_stock_b32.wall/n/avg_nfe = 3.295 s/NFE (humaneval) | |
| # wetink = per_fwd * 195 NFE/task (one forward per committed frontier token). | |
| # plan_n() recalibrates from each arm's MEASURED wall/total, so these are | |
| # priors only (first-batch planning). | |
| INIT_EST = { | |
| ("gsm8k", "stock", 32): 121.0, # measured: 121.4 s/task | |
| ("gsm8k", "stock", 64): 111.0, # measured: 111.0 s/task | |
| ("gsm8k", "stock", 128): 140.0, # no data (skipped in v4b), prior kept | |
| ("humaneval", "stock", 32): 49.0, # measured: 48.6 s/task | |
| ("humaneval", "stock", 64): 60.0, # scaled from gsm8k b64 x he ratio | |
| ("gsm8k", "wetink", 32): 557.0, # per_fwd * 195 = 2.858 * 195 | |
| ("humaneval", "wetink", 32): 642.0, # per_fwd_he * 195 = 3.295 * 195 | |
| } | |
| def plan_n(bench, mode, block, cap): | |
| """How many tasks of this arm can the remaining budget afford? | |
| Uses the measured per-task time of the same mode+block when available, | |
| else the calibrated prior. The wall clock is consumed by ACTIVE["n"] | |
| workers in parallel, so the affordable count is divided by the number | |
| of live workers. Reserves 900 s for paired stats + summary + dump. | |
| """ | |
| per_task = EST.get((bench, mode, block)) or INIT_EST.get((bench, mode, block), 250.0) | |
| n_aff = int((remaining() - 900) / (max(ACTIVE["n"], 1) * per_task)) | |
| n_run = max(0, min(cap, n_aff)) | |
| log(f"plan_n[{bench}/{mode}/b{block}]: cap={cap} per_task_est={per_task:.0f}s " | |
| f"active={ACTIVE['n']} remaining={remaining():.0f}s -> n_run={n_run}") | |
| return n_run | |
| # ---------------------------------------------------------------- GSM8K | |
| INSTRUCTION = ( | |
| "Solve the following math problem. Put the final numerical answer " | |
| "inside \\boxed{} at the very end.\n\n" | |
| ) | |
| _NUMBER_RE = re.compile(r"-?\d+(?:\.\d+)?") | |
| _BOXED_RE = re.compile(r"\\boxed\{([^{}]+)\}") | |
| def _last_number(text): | |
| cleaned = text.replace(",", "") | |
| matches = _NUMBER_RE.findall(cleaned) | |
| return matches[-1] if matches else None | |
| def _boxed_answer(text): | |
| matches = _BOXED_RE.findall(text) | |
| return matches[-1].strip() if matches else None | |
| def _numbers_equal(a, b): | |
| try: | |
| return abs(float(a) - float(b)) < 1e-6 | |
| except (TypeError, ValueError): | |
| return a.strip() == b.strip() | |
| def score_gsm8k(model_out, gold): | |
| pred = _boxed_answer(model_out) or _last_number(model_out) | |
| return pred is not None and _numbers_equal(pred, gold) | |
| _DS_GSM = None | |
| _DS_LOCK = threading.Lock() | |
| def get_gsm8k(): | |
| global _DS_GSM | |
| with _DS_LOCK: | |
| if _DS_GSM is None: | |
| for repo in ("gsm8k", "openai/gsm8k"): | |
| try: | |
| _DS_GSM = load_dataset(repo, "main", split="test") | |
| break | |
| except Exception as e: # noqa: BLE001 | |
| log(f"load_dataset({repo}) failed: {e}") | |
| if _DS_GSM is None: | |
| raise RuntimeError("cannot load GSM8K") | |
| return _DS_GSM | |
| def run_gsm8k(name, model, mode="stock", window=16, editing_threshold=0.0, | |
| block_length=32, threshold=0.5, max_post_steps=16, | |
| gen_length=160, limit=200): | |
| if remaining() < 900: | |
| RESULTS["gsm8k"][name] = {"skipped": "time budget"} | |
| dump() | |
| return | |
| ds = get_gsm8k() | |
| n = min(limit, len(ds)) | |
| log(f"gsm8k {name}: limit={n} block={block_length} thr={threshold} " | |
| f"edit_thr={editing_threshold} mps={max_post_steps}") | |
| t0 = time.time() | |
| correct = 0 | |
| tot_tok = 0 | |
| tot_nfe = 0 | |
| tot_churn = 0 | |
| tot_resid = 0 | |
| details = [] | |
| for i in range(n): | |
| if remaining() < 900 and i > 0: | |
| log(f" {name}: task-level early stop at {i}/{n} (time budget)") | |
| break | |
| row = ds[i] | |
| gold = row["answer"].split("####")[-1].strip().replace(",", "") | |
| ids = chat_ids(INSTRUCTION + row["question"], model.device) | |
| try: | |
| out, nfe, churn, resid = gen( | |
| model, ids, mode=mode, window=window, gen_length=gen_length, | |
| block_length=block_length, threshold=threshold, | |
| editing_threshold=editing_threshold, | |
| max_post_steps=max_post_steps, | |
| ) | |
| text = tok.decode(out[0], skip_special_tokens=True) | |
| ok = score_gsm8k(text, gold) | |
| if ok: | |
| correct += 1 | |
| tot_tok += int(out.numel()) | |
| tot_nfe += nfe | |
| tot_churn += churn | |
| tot_resid += resid | |
| if i < 3 or (i + 1) % 20 == 0: | |
| log(f" {name}[{i+1}/{n}] ok={int(ok)} nfe={nfe} churn={churn} " | |
| f"tok={int(out.numel())} gold={gold}") | |
| ws = model._nfe_state.get("wetink_stats") or {} | |
| details.append(dict(i=i, ok=bool(ok), n_tokens=int(out.numel()), | |
| nfe=int(nfe), churn=int(churn), resid=int(resid), | |
| opened=ws.get("opened"), | |
| rewrites=ws.get("rewrites"), | |
| gold=gold, out_prefix=text[:200])) | |
| if (i + 1) % 10 == 0: | |
| with LOCK: | |
| RESULTS["gsm8k"][name] = dict( | |
| mode=mode, window=window, | |
| editing_threshold=editing_threshold, block_length=block_length, | |
| threshold=threshold, max_post_steps=max_post_steps, | |
| gen_length=gen_length, limit=n, partial=i + 1, | |
| correct=correct, details=list(details)) | |
| dump() | |
| except torch.cuda.OutOfMemoryError: | |
| log(f" {name}[{i}] OOM -> skipping") | |
| torch.cuda.empty_cache() | |
| details.append(dict(i=i, error="oom")) | |
| except Exception as e: # noqa: BLE001 | |
| log(f" {name}[{i}] error: {e!r}") | |
| details.append(dict(i=i, error=str(e))) | |
| wall = time.time() - t0 | |
| total = len([d for d in details if "error" not in d]) | |
| if total > 0: | |
| with LOCK: | |
| EST[("gsm8k", mode, block_length)] = wall / total | |
| res = dict( | |
| mode=mode, window=window, | |
| editing_threshold=editing_threshold, block_length=block_length, | |
| threshold=threshold, max_post_steps=max_post_steps, | |
| gen_length=gen_length, limit=n, attempted=total, | |
| correct=correct, | |
| accuracy=100.0 * correct / max(total, 1), | |
| avg_tokens=tot_tok / max(total, 1), | |
| avg_nfe=tot_nfe / max(total, 1), | |
| avg_churn=tot_churn / max(total, 1), | |
| avg_resid=tot_resid / max(total, 1), | |
| wall_seconds=wall, details=list(details), | |
| ) | |
| with LOCK: | |
| RESULTS["gsm8k"][name] = res | |
| log(f"== {name}: acc={res['accuracy']:.2f}% n={total} " | |
| f"avg_tok={res['avg_tokens']:.0f} avg_nfe={res['avg_nfe']:.1f} " | |
| f"avg_churn={res['avg_churn']:.1f} wall={wall:.0f}s") | |
| dump() | |
| # ---------------------------------------------------------------- HumanEval | |
| # HumanEval.jsonl embedded (gzip+base64), identical artifact to the v3 kernel | |
| # — canonical OpenAI HumanEval, 164 problems. Embedded so the run does not | |
| # depend on HF dataset availability or URI-format changes (push-3 failed on | |
| # the openai_humaneval -> namespace/name migration). | |
| HUMANEVAL_GZ_B64 = "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" | |
| def load_humaneval(): | |
| raw = gzip.decompress(base64.b64decode(HUMANEVAL_GZ_B64)) | |
| return [json.loads(line) for line in raw.decode("utf-8").splitlines() if line] | |
| def he_prompt_ids(doc, dev): | |
| """Saber (ACL 2026) prompt protocol, verbatim.""" | |
| user = ("Write a solution to the following problem and make sure that it " | |
| "passes the tests:\n```python\n" + doc["prompt"] + "\n```") | |
| trailing = "Here is the completed function:\n```python\n" + doc["prompt"] + "\n" | |
| messages = [{"role": "user", "content": user}] | |
| p = tok.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) + trailing | |
| return tok(p, return_tensors="pt").input_ids.to(dev) | |
| def he_extract(gen_text, doc): | |
| """Saber's extract_answer, verbatim.""" | |
| text_with_prefix = f"```python\n{doc['prompt']}\n" + gen_text | |
| entry_point = doc["entry_point"] | |
| pattern = re.compile(rf"def\s+{entry_point}.*?:\n(.*?)\n```", re.DOTALL) | |
| match = pattern.search(text_with_prefix) | |
| if match: | |
| return match.group(1).rstrip() | |
| fallback = re.split(r"```", gen_text, maxsplit=1) | |
| if fallback: | |
| return fallback[0].rstrip() | |
| return gen_text | |
| def _run_check_program(args): | |
| idx, program, timeout = args | |
| fd, path = tempfile.mkstemp(suffix=".py") | |
| try: | |
| with os.fdopen(fd, "w") as f: | |
| f.write(program) | |
| proc = subprocess.Popen( | |
| [sys.executable, path], | |
| stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, | |
| stdin=subprocess.DEVNULL, start_new_session=True, | |
| ) | |
| try: | |
| rc = proc.wait(timeout=timeout) | |
| return idx, rc == 0, "ok" | |
| except subprocess.TimeoutExpired: | |
| try: | |
| os.killpg(os.getpgid(proc.pid), 9) | |
| except OSError: | |
| pass | |
| proc.wait() | |
| return idx, False, "timeout" | |
| except Exception as e: # noqa: BLE001 | |
| return idx, False, f"error: {e}" | |
| finally: | |
| try: | |
| os.unlink(path) | |
| except OSError: | |
| pass | |
| def he_execute(details, docs, timeout=10, workers=8): | |
| jobs = [] | |
| for d in details: | |
| if "error" in d or d.get("completion") is None: | |
| continue | |
| doc = docs[d["i"]] | |
| program = (doc["prompt"] + d["completion"] + "\n" + doc["test"] | |
| + "\n" + f"check({doc['entry_point']})") | |
| jobs.append((d["i"], program, timeout)) | |
| outcomes = {} | |
| if jobs: | |
| with ThreadPoolExecutor(max_workers=workers) as ex: | |
| for idx, passed, info in ex.map(_run_check_program, jobs): | |
| outcomes[idx] = dict(passed=bool(passed), exec=info) | |
| for d in details: | |
| o = outcomes.get(d["i"]) | |
| if o is None: | |
| d["passed"] = None | |
| else: | |
| d["passed"] = o["passed"] | |
| d["exec"] = o["exec"] | |
| return outcomes | |
| def run_humaneval(name, model, mode="stock", window=16, editing_threshold=0.0, | |
| block_length=32, threshold=0.5, max_post_steps=16, | |
| gen_length=160, limit=164): | |
| docs = load_humaneval() | |
| n = min(limit, len(docs)) | |
| log(f"humaneval {name}: n={n} block={block_length} thr={threshold} " | |
| f"edit_thr={editing_threshold} mps={max_post_steps}") | |
| t0 = time.time() | |
| tot_nfe = 0 | |
| tot_tok = 0 | |
| tot_churn = 0 | |
| tot_resid = 0 | |
| details = [] | |
| for i, doc in enumerate(docs): | |
| if i >= n: | |
| break | |
| if remaining() < 900 and i > 0: | |
| log(f" {name}: task-level early stop at {i}/{n} (time budget)") | |
| break | |
| ids = he_prompt_ids(doc, model.device) | |
| try: | |
| out, nfe, churn, resid = gen( | |
| model, ids, mode=mode, window=window, gen_length=gen_length, | |
| block_length=block_length, threshold=threshold, | |
| editing_threshold=editing_threshold, | |
| max_post_steps=max_post_steps, | |
| ) | |
| gen_text = tok.decode(out[0], skip_special_tokens=True) | |
| completion = he_extract(gen_text, doc) | |
| tot_tok += int(out.numel()) | |
| tot_nfe += nfe | |
| tot_churn += churn | |
| tot_resid += resid | |
| if i < 3 or (i + 1) % 20 == 0: | |
| log(f" {name}[{i+1}/{n}] nfe={nfe} churn={churn} tok={int(out.numel())}") | |
| ws = model._nfe_state.get("wetink_stats") or {} | |
| details.append(dict(i=i, n_tokens=int(out.numel()), nfe=int(nfe), | |
| churn=int(churn), resid=int(resid), | |
| opened=ws.get("opened"), | |
| rewrites=ws.get("rewrites"), | |
| completion=completion[:600], full=gen_text[:300])) | |
| if (i + 1) % 10 == 0: | |
| with LOCK: | |
| RESULTS["humaneval"][name] = dict( | |
| mode=mode, window=window, | |
| editing_threshold=editing_threshold, block_length=block_length, | |
| threshold=threshold, max_post_steps=max_post_steps, | |
| gen_length=gen_length, limit=n, partial=i + 1, | |
| details=list(details)) | |
| dump() | |
| except torch.cuda.OutOfMemoryError: | |
| log(f" {name}[{i}] OOM -> skipping") | |
| torch.cuda.empty_cache() | |
| details.append(dict(i=i, error="oom")) | |
| except Exception as e: # noqa: BLE001 | |
| log(f" {name}[{i}] error: {e!r}") | |
| details.append(dict(i=i, error=str(e))) | |
| gen_wall = time.time() - t0 | |
| total = len([d for d in details if "error" not in d]) | |
| log(f" {name}: gen done ({total} tasks, {gen_wall:.0f}s); executing checks ...") | |
| t1 = time.time() | |
| he_execute(details, docs, timeout=10) | |
| passed = sum(1 for d in details if d.get("passed")) | |
| exec_wall = time.time() - t1 | |
| if total > 0: | |
| with LOCK: | |
| EST[("humaneval", mode, block_length)] = gen_wall / total | |
| res = dict( | |
| mode=mode, window=window, | |
| editing_threshold=editing_threshold, block_length=block_length, | |
| threshold=threshold, max_post_steps=max_post_steps, | |
| gen_length=gen_length, limit=n, attempted=total, passed=passed, | |
| pass_at_1=100.0 * passed / max(total, 1), | |
| avg_tokens=tot_tok / max(total, 1), | |
| avg_nfe=tot_nfe / max(total, 1), | |
| avg_churn=tot_churn / max(total, 1), | |
| avg_resid=tot_resid / max(total, 1), | |
| gen_wall_seconds=gen_wall, exec_wall_seconds=exec_wall, | |
| details=list(details), | |
| ) | |
| with LOCK: | |
| RESULTS["humaneval"][name] = res | |
| log(f"== {name}: pass@1={res['pass_at_1']:.2f}% n={total} " | |
| f"avg_tok={res['avg_tokens']:.0f} avg_nfe={res['avg_nfe']:.1f} " | |
| f"avg_churn={res['avg_churn']:.1f} gen={gen_wall:.0f}s exec={exec_wall:.0f}s") | |
| dump() | |
| # ---------------------------------------------------------------- run suite | |
| # v5: two worker threads, one 4-bit model copy per GPU, pulling arms from a | |
| # shared priority queue (same proven machinery as v4b). The arms are OUR | |
| # wet-ink decoder at different window widths; baselines come from v4b. | |
| # | |
| # P0 (core, must run): wetink_w16 — the idea, T2T ON, W=16 | |
| # wetink_noedit_w16 — frontier-only control (T2T | |
| # OFF): isolates the effect of | |
| # the one-token frontier itself | |
| # P1 (window ablation): wetink_w8 (narrower), wetink_w32 (whole block wet; | |
| # bridges to stock T2T scope) | |
| # P2 (transfer): he_wetink_w16 (HumanEval, small n) | |
| ARMS = [ | |
| # (name, bench, mode, window, editing_threshold, block, threshold, mps, gen_len, cap) | |
| ("wetink_w16", "gsm8k", "wetink", 16, 0.0, 32, 0.5, 4, 160, 45), | |
| ("wetink_noedit_w16", "gsm8k", "wetink", 16, 2.0, 32, 0.5, 4, 160, 45), | |
| ("wetink_w8", "gsm8k", "wetink", 8, 0.0, 32, 0.5, 4, 160, 30), | |
| ("wetink_w32", "gsm8k", "wetink", 32, 0.0, 32, 0.5, 4, 160, 30), | |
| ("he_wetink_w16", "humaneval", "wetink", 16, 0.0, 32, 0.5, 4, 160, 25), | |
| ] | |
| _QUEUE = Queue() | |
| for _a in ARMS: | |
| _QUEUE.put(_a) | |
| RUN_FN = {"gsm8k": run_gsm8k, "humaneval": run_humaneval} | |
| def _worker_loop(wid, model): | |
| with ACT_LOCK: | |
| ACTIVE["n"] += 1 | |
| try: | |
| while remaining() > 900: | |
| try: | |
| arm = _QUEUE.get_nowait() | |
| except Empty: | |
| break | |
| (name, bench, mode, window, et, bl, thr, mps, gl, cap) = arm | |
| prev = RESULTS[bench].get(name) | |
| if prev and (prev.get("attempted") or 0) > 0 and "error" not in prev: | |
| continue # already done — do not rerun | |
| n = plan_n(bench, mode, bl, cap) | |
| if n < 8: | |
| with LOCK: | |
| RESULTS[bench][name] = {"skipped": "time budget"} | |
| dump() | |
| continue | |
| log(f"[w{wid}] arm {name}: n={n} mode={mode} W={window} block={bl} " | |
| f"edit_thr={et} thr={thr} mps={mps}") | |
| try: | |
| RUN_FN[bench](name, model, mode=mode, window=window, | |
| editing_threshold=et, block_length=bl, | |
| threshold=thr, max_post_steps=mps, | |
| gen_length=gl, limit=n) | |
| except Exception as e: # noqa: BLE001 | |
| log(f"[w{wid}] arm {name} CRASHED: {e!r}") | |
| with LOCK: | |
| RESULTS[bench][name] = {"error": str(e)} | |
| dump() | |
| finally: | |
| with ACT_LOCK: | |
| ACTIVE["n"] -= 1 | |
| log(f"[w{wid}] worker finished (remaining={remaining():.0f}s)") | |
| def _worker_main(wid): | |
| if wid == 0: | |
| _worker_loop(0, M0) | |
| return | |
| log("[w1] loading model #1 in 4-bit NF4 on GPU1 ...") | |
| t0 = time.time() | |
| try: | |
| m1 = _load(1) | |
| _attach_meter(m1) | |
| log(f"[w1] model #1 loaded in {time.time()-t0:.0f}s") | |
| except Exception as e: # noqa: BLE001 | |
| log(f"[w1] model #1 load FAILED: {e!r} -> single-worker mode") | |
| return | |
| _worker_loop(1, m1) | |
| _THREADS = [threading.Thread(target=_worker_main, args=(i,)) for i in range(2)] | |
| for _t in _THREADS: | |
| _t.start() | |
| for _t in _THREADS: | |
| _t.join() | |
| # ---------------------------------------------------------------- paired stats | |
| def _pair(stock_arm, wet_arm): | |
| det_s = [d for d in stock_arm.get("details", []) if "error" not in d] | |
| det_w = [d for d in wet_arm.get("details", []) if "error" not in d] | |
| s_map = {d["i"]: d for d in det_s} | |
| w_map = {d["i"]: d for d in det_w} | |
| common = sorted(set(s_map) & set(w_map)) | |
| b = c = 0 | |
| for i in common: | |
| os_, ow_ = ok_of(s_map[i]), ok_of(w_map[i]) | |
| if not os_ and ow_: | |
| b += 1 | |
| elif os_ and not ow_: | |
| c += 1 | |
| k = sum(1 for d in det_w if ok_of(d)) | |
| n = len(det_w) | |
| p, lo, hi = wilson(k, n) | |
| sk = sum(1 for d in det_s if ok_of(d)) | |
| sn = len(det_s) | |
| return dict( | |
| n=n, k=k, acc=100.0 * k / max(n, 1), | |
| ci95=[100.0 * lo, 100.0 * hi], | |
| fixed=b, broken=c, mcnemar_p=mcnemar_exact(b, c), | |
| avg_nfe=sum(d.get("nfe", 0) for d in det_w) / max(n, 1), | |
| stock_acc=100.0 * sk / max(sn, 1), | |
| stock_avg_nfe=sum(d.get("nfe", 0) for d in det_s) / max(sn, 1), | |
| nfe_ratio=(sum(d.get("nfe", 0) for d in det_w) / max(n, 1)) / | |
| (sum(d.get("nfe", 0) for d in det_s) / max(sn, 1)) | |
| if sn and sum(d.get("nfe", 0) for d in det_s) else float("nan"), | |
| ) | |
| def paired_stats(bench): | |
| """In-run pairing: every T2T-ON wet-ink arm vs the frontier-only control | |
| (wetink_noedit_w16, editing_threshold>1). Cross-run pairing vs the v4b | |
| baselines (stock_b32 / noedit_b32) is done offline by analyze_v5.py.""" | |
| arms = RESULTS[bench] | |
| ctrl = None | |
| for name, r in arms.items(): | |
| if "skipped" in r or "error" in r or "details" not in r: | |
| continue | |
| if r.get("editing_threshold", 0.0) > 1.0: | |
| ctrl = (name, r) | |
| break | |
| out = {} | |
| if ctrl is not None: | |
| for name, r in arms.items(): | |
| if r.get("editing_threshold", 0.0) > 1.0: | |
| continue | |
| if "skipped" in r or "error" in r or "details" not in r: | |
| continue | |
| entry = _pair(ctrl[1], r) | |
| entry["vs"] = ctrl[0] | |
| out[name] = entry | |
| RESULTS["stats"][bench] = { | |
| "control": ctrl[0] if ctrl else None, | |
| "vs_control": out, | |
| } | |
| paired_stats("gsm8k") | |
| paired_stats("humaneval") | |
| # ---------------------------------------------------------------- summary | |
| log("=========== SUMMARY v5 (wet-ink: OUR decoder) ===========") | |
| for bench, metric in (("gsm8k", "accuracy"), ("humaneval", "pass_at_1")): | |
| log(f"--- {bench} ---") | |
| for name, r in RESULTS[bench].items(): | |
| if "skipped" in r: | |
| log(f"{name:<24} SKIPPED") | |
| continue | |
| if "error" in r: | |
| log(f"{name:<24} ERROR: {str(r['error'])[:90]}") | |
| continue | |
| wall = r.get("wall_seconds", r.get("gen_wall_seconds", 0)) | |
| log(f"{name:<24} {metric}={r[metric]:6.2f}% n={r['attempted']:>3} " | |
| f"nfe={r['avg_nfe']:7.1f} churn={r.get('avg_churn',0):6.1f} " | |
| f"tok={r['avg_tokens']:5.0f} wall={wall:6.0f}s " | |
| f"W={r.get('window')} et={r.get('editing_threshold')}") | |
| st = RESULTS["stats"].get(bench, {}) | |
| for name, s in st.get("vs_control", {}).items(): | |
| log(f" {name:<22} vs {s['vs']:<18} acc={s['acc']:6.2f}% " | |
| f"CI[{s['ci95'][0]:.1f},{s['ci95'][1]:.1f}] fixed/broken={s['fixed']}/" | |
| f"{s['broken']} McNemar p={s['mcnemar_p']:.4f}" | |
| + (f" NFE x{s['nfe_ratio']:.2f}" if s.get("nfe_ratio") else "")) | |
| dump() | |
| log("DONE. results_v5.json written to", RESULTS_PATH) | |