Text Classification
Transformers
Safetensors
English
nli
cross-encoder
qwen3.5
reranker
image-text-to-text
Instructions to use ldov/openjevv with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use ldov/openjevv with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-classification", model="ldov/openjevv")# Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("ldov/openjevv", device_map="auto") - Notebooks
- Google Colab
- Kaggle
| #!/usr/bin/env python | |
| """Vibe test: can the NLI cross-encoder (and its latent + MLP) play Flappy Bird? | |
| The game state is rendered as text (premise); the two actions are the options ("flap" / "do nothing"). | |
| Policies: | |
| random, never (always "do nothing"), oracle (heuristic on the true state), | |
| nli : zero-shot, argmax P(entailment) over "The correct action is: {a}", | |
| mlp : latent of the frozen NLI model for both options -> MLP trained with soft BCE on oracle labels | |
| collected from noisy oracle rollouts (same recipe as latent_mlp.py). | |
| python flappy.py --ckpt ckpt/qwen3.5-4b-nli --episodes 20 --out results/flappy_4b.json | |
| """ | |
| import argparse | |
| import json | |
| import random | |
| import time | |
| import numpy as np | |
| import torch | |
| import torch.nn as nn | |
| from latent_mlp import MLP, fit, predict, grouped_split | |
| # ----------------------------------------------------------------------------- game | |
| GRAVITY, FLAP_V, SPEED = 0.003, 0.015, 0.015 | |
| PIPE_EVERY, GAP, PIPE_HW, BIRD_X, BIRD_HW = 0.45, 0.28, 0.04, 0.2, 0.03 | |
| class Flappy: | |
| def __init__(self, seed=0, max_steps=2000): | |
| self.rng = random.Random(seed) | |
| self.max_steps = max_steps | |
| self.reset() | |
| def reset(self): | |
| self.y, self.vy, self.t, self.score, self.done = 0.5, 0.0, 0, 0, False | |
| self.pipes = [[1.2, self._gap()]] # [x, gap_lo] | |
| return self.state() | |
| def _gap(self): | |
| return self.rng.uniform(0.15, 0.85 - GAP) | |
| def next_pipe(self): | |
| for x, lo in self.pipes: | |
| if x + PIPE_HW >= BIRD_X - BIRD_HW: | |
| return x, lo | |
| return None | |
| def step(self, flap): | |
| if self.done: | |
| return self.state(), 0.0, True | |
| self.vy = FLAP_V if flap else self.vy - GRAVITY | |
| self.y += self.vy | |
| self.t += 1 | |
| for p in self.pipes: | |
| p[0] -= SPEED | |
| if self.pipes[-1][0] < 1.2 - PIPE_EVERY: | |
| self.pipes.append([self.pipes[-1][0] + PIPE_EVERY, self._gap()]) | |
| if self.pipes[0][0] + PIPE_HW < BIRD_X - BIRD_HW: | |
| self.pipes.pop(0) | |
| self.score += 1 | |
| x, lo = self.next_pipe() | |
| hit = self.y <= 0 or self.y >= 1 | |
| if abs(x - BIRD_X) < PIPE_HW + BIRD_HW and not (lo < self.y < lo + GAP): | |
| hit = True | |
| if hit or self.t >= self.max_steps: | |
| self.done = True | |
| return self.state(), (0.0 if hit else 1.0), self.done | |
| def state(self): | |
| x, lo = self.next_pipe() | |
| return {"y": self.y, "vy": self.vy, "dx": x - BIRD_X, "lo": lo, "hi": lo + GAP, "score": self.score, "t": self.t} | |
| def oracle(s, margin=0.03, lookahead=3): | |
| """flap if the predicted height a few frames ahead falls below the gap centre (minus a margin).""" | |
| target = (s["lo"] + s["hi"]) / 2 - margin | |
| y_pred = s["y"] + s["vy"] * lookahead - GRAVITY * lookahead * (lookahead - 1) / 2 | |
| return y_pred < target | |
| def render_text(s): | |
| pos = "inside the gap" if s["lo"] < s["y"] < s["hi"] else ("above the gap" if s["y"] >= s["hi"] else "below the gap") | |
| move = "rising" if s["vy"] > 0 else "falling" | |
| centre = (s["lo"] + s["hi"]) / 2 | |
| return (f"Flappy Bird. The bird is at height {s['y']:.2f} (0 = ground, 1 = ceiling) and is {move} " | |
| f"with vertical velocity {s['vy']:+.3f} per frame; gravity pulls it down every frame and flapping pushes it up. " | |
| f"The next pipe is {s['dx']:.2f} ahead; its gap spans heights {s['lo']:.2f} to {s['hi']:.2f} (centre {centre:.2f}). " | |
| f"The bird is currently {pos}, {s['y'] - centre:+.2f} relative to the gap centre. " | |
| f"The bird must fly through the gap without touching the pipe, the ground or the ceiling.") | |
| def render_numeric(s): | |
| return (f"Flappy Bird state: y={s['y']:.2f} vy={s['vy']:+.3f} pipe_dx={s['dx']:.2f} " | |
| f"gap_lo={s['lo']:.2f} gap_hi={s['hi']:.2f} gap_centre={(s['lo'] + s['hi']) / 2:.2f} " | |
| f"offset_from_centre={s['y'] - (s['lo'] + s['hi']) / 2:+.2f}") | |
| def render_coach(s): | |
| centre = (s["lo"] + s["hi"]) / 2 | |
| off = s["y"] - centre | |
| move = "rising" if s["vy"] > 0 else "falling" | |
| return (f"Flappy Bird. Rule of thumb: flap when the bird is below the centre of the next gap or falling towards it; " | |
| f"do nothing when it is above the centre or rising. Right now the bird is {abs(off):.2f} {'above' if off > 0 else 'below'} " | |
| f"the gap centre and {move} at {abs(s['vy']):.3f} per frame. The pipe is {s['dx']:.2f} ahead.") | |
| def render_ascii_prompt(s): | |
| return "Flappy Bird screen (the bird is '>', pipes are '#', top row is the ceiling, bottom row is the ground):\n" + render_ascii(s) | |
| PROMPTS = {"base": render_text, "numeric": render_numeric, "coach": render_coach, "ascii": render_ascii_prompt} | |
| HYPS = {"action": lambda a: f"The correct action is: {a}", | |
| "should": lambda a: "The bird should flap now." if a == "flap" else "The bird should not flap now.", | |
| # statements about the state that map to actions (zero-shot: NLI only has to verify the statement) | |
| "position": lambda a: "The bird is below the centre of the gap." if a == "flap" else "The bird is above the centre of the gap.", | |
| "position_v": lambda a: ("The bird is below the centre of the gap, or it is falling fast." if a == "flap" | |
| else "The bird is above the centre of the gap and not falling fast."), | |
| "sign": lambda a: "The offset relative to the gap centre is negative." if a == "flap" else "The offset relative to the gap centre is positive."} | |
| def render_ascii(s, h=12, w=30): | |
| grid = [[" "] * w for _ in range(h)] | |
| col = int(min(max(s["dx"] / 0.6, 0), 1) * (w - 1)) | |
| for r in range(h): | |
| yy = 1 - r / (h - 1) | |
| if not (s["lo"] < yy < s["hi"]): | |
| grid[r][col] = "#" | |
| br = int(round((1 - s["y"]) * (h - 1))) | |
| if 0 <= br < h: | |
| grid[br][2] = ">" | |
| return "\n".join("".join(r) for r in grid) | |
| ACTIONS = ["flap", "do nothing"] | |
| # ----------------------------------------------------------------------------- model-backed policies | |
| class Scorer: | |
| def __init__(self, ckpt, prompt="base", hyp="action"): | |
| self.render, self.hyp = PROMPTS[prompt], HYPS[hyp] | |
| from transformers import AutoModelForSequenceClassification, AutoTokenizer | |
| self.tok = AutoTokenizer.from_pretrained(ckpt) | |
| self.model = AutoModelForSequenceClassification.from_pretrained(ckpt, dtype=torch.bfloat16).cuda().eval() | |
| self.template = getattr(self.model.config, "nli_template", None) or "Premise: {premise}\nHypothesis: {hypothesis}" | |
| if self.model.config.get_text_config().pad_token_id is None: | |
| self.model.config.get_text_config().pad_token_id = self.tok.pad_token_id | |
| self.tok.padding_side = "right" | |
| self.backbone = getattr(self.model, self.model.base_model_prefix) | |
| def latents(self, texts, bs=64): | |
| X, L = [], [] | |
| for s in range(0, len(texts), bs): | |
| enc = self.tok(texts[s:s + bs], truncation=True, max_length=512, padding=True, return_tensors="pt").to("cuda") | |
| h = self.backbone(**enc).last_hidden_state | |
| last = enc["attention_mask"].sum(1) - 1 | |
| pooled = h[torch.arange(h.shape[0], device=h.device), last] | |
| X.append(pooled.float().cpu().numpy()); L.append(self.model.score(pooled).float().cpu().numpy()) | |
| return np.concatenate(X), np.concatenate(L) | |
| def pair_texts(self, s): | |
| return [self.template.format(premise=self.render(s), hypothesis=self.hyp(a)) for a in ACTIONS] | |
| def play(env_seed, policy, max_steps, fps=None, record=False): | |
| """fps=None: turn-based (the game waits for the policy). fps=30: real time - while the policy is thinking the | |
| game keeps ticking with no flap, so a slow policy acts on stale states and skips frames.""" | |
| env = Flappy(seed=env_seed, max_steps=max_steps) | |
| s = env.reset() | |
| frames, replay, lats, skipped_total = [], [], [], 0 | |
| def snap(a, lat_ms, skipped, probs=None): | |
| if record: | |
| replay.append({"t": env.t, "y": round(env.y, 4), "pipes": [[round(x, 3), round(lo, 3)] for x, lo in env.pipes[:3]], | |
| "a": int(a), "lat_ms": round(lat_ms, 1), "skipped": skipped, "score": env.score, | |
| "probs": [round(float(x), 4) for x in probs] if probs is not None else None}) | |
| while not env.done: | |
| t0 = time.perf_counter() | |
| a = policy(s) | |
| probs = None | |
| if isinstance(a, tuple): | |
| a, probs = a | |
| lat = time.perf_counter() - t0 | |
| lats.append(lat) | |
| skipped = int(lat * fps) if fps else 0 | |
| if record and env.t % 3 == 0 and len(frames) < 12: | |
| frames.append((render_ascii(s), "FLAP" if a else "----")) | |
| snap(a, lat * 1000, 0, probs) | |
| s, _, _ = env.step(a) | |
| for _ in range(skipped): # model still thinking: bird glides | |
| if env.done: | |
| break | |
| skipped_total += 1 | |
| snap(False, 0.0, 1) | |
| s, _, _ = env.step(False) | |
| return {"score": env.score, "steps": env.t, "frames": frames, "replay": replay, | |
| "lat_ms": float(np.mean(lats) * 1000), "skipped": skipped_total, "decisions": len(lats)} | |
| def main(): | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("--ckpt", default="ckpt/qwen3.5-4b-nli") | |
| ap.add_argument("--episodes", type=int, default=20) | |
| ap.add_argument("--max-steps", type=int, default=1500) | |
| ap.add_argument("--collect-episodes", type=int, default=60, help="noisy oracle rollouts for MLP training data") | |
| ap.add_argument("--noise", type=float, default=0.15) | |
| ap.add_argument("--eps", type=float, default=0.1) | |
| ap.add_argument("--out", default="results/flappy.json") | |
| ap.add_argument("--seed", type=int, default=0) | |
| ap.add_argument("--fps", type=float, default=30.0, help="real-time tick rate; 0 = turn-based") | |
| ap.add_argument("--record-only", action="store_true", help="few episodes, replay with probabilities (for the video)") | |
| ap.add_argument("--prompt", default="base", choices=list(PROMPTS)) | |
| ap.add_argument("--hyp", default="action", choices=list(HYPS)) | |
| ap.add_argument("--lookahead", type=int, default=3, help="oracle lookahead used for labels and the oracle policy") | |
| ap.add_argument("--margin", type=float, default=0.03) | |
| ap.add_argument("--skip-nli", action="store_true") | |
| ap.add_argument("--zero-shot-only", action="store_true", help="stop after the zero-shot NLI policy (no MLP)") | |
| args = ap.parse_args() | |
| fps = args.fps or None | |
| rng = random.Random(args.seed) | |
| results = {} | |
| def evaluate(name, policy, record_first=True): | |
| eps = [play(1000 + i, policy, args.max_steps, fps=fps, record=record_first) for i in range(args.episodes)] | |
| best = max(eps, key=lambda e: e["score"]) # keep the replay of the best episode | |
| sc = [e["score"] for e in eps] | |
| lat = float(np.mean([e["lat_ms"] for e in eps])); skip = float(np.mean([e["skipped"] / max(e["steps"], 1) for e in eps])) | |
| results[name] = {"mean_score": float(np.mean(sc)), "median_score": float(np.median(sc)), "max_score": int(max(sc)), | |
| "mean_steps": float(np.mean([e["steps"] for e in eps])), "lat_ms": lat, "skipped_frac": skip, | |
| "frames": best["frames"], "replay": best["replay"], "replay_score": best["score"]} | |
| print(f"{name:10s} score mean {np.mean(sc):6.2f} median {np.median(sc):5.1f} max {max(sc):3d} steps {np.mean([e['steps'] for e in eps]):7.1f}" | |
| f" latency {lat:6.1f} ms skipped frames {skip:5.1%}", flush=True) | |
| if not args.record_only: | |
| evaluate("random", lambda s: rng.random() < 0.1) | |
| evaluate("never", lambda s: False) | |
| orc = lambda s: oracle(s, margin=args.margin, lookahead=args.lookahead) | |
| evaluate("oracle", orc) | |
| scorer = Scorer(args.ckpt, args.prompt, args.hyp) | |
| # zero-shot NLI: argmax entailment over the two action hypotheses | |
| def nli_policy(s): | |
| _, L = scorer.latents(scorer.pair_texts(s)) | |
| p = torch.softmax(torch.tensor(L), -1).numpy() | |
| return int(p[:, 1].argmax()) == 0, p[:, 1] # index 0 = flap; probs = P(entailment) per option | |
| if not args.skip_nli: | |
| t0 = time.time(); evaluate("nli", nli_policy); print(f" ({time.time()-t0:.0f}s)") | |
| if args.zero_shot_only: | |
| json.dump({"args": vars(args), "results": results}, open(args.out, "w"), indent=2) | |
| return | |
| # latent + MLP trained on noisy-oracle rollouts | |
| states, labels = [], [] | |
| for i in range(args.collect_episodes): | |
| env = Flappy(seed=i, max_steps=600); s = env.reset() | |
| while not env.done: | |
| a_or = orc(s) | |
| states.append(dict(s)); labels.append(int(a_or)) | |
| a = (not a_or) if rng.random() < args.noise else a_or | |
| s, _, _ = env.step(a) | |
| print(f"collected {len(states)} states, flap rate {np.mean(labels):.2f}", flush=True) | |
| texts = [t for s in states for t in scorer.pair_texts(s)] | |
| X, _ = scorer.latents(texts) | |
| qid = np.repeat(np.arange(len(states)), 2) | |
| gold = np.array([[1, 0] if l == 1 else [0, 1] for l in labels]).ravel() | |
| tr, va = grouped_split(qid, 0.1, args.seed) | |
| ns = argparse.Namespace(hidden=512, dropout=0.1, lr=1e-3, wd=1e-2, bs=512, epochs=60, patience=8, eps=args.eps, seed=args.seed) | |
| model, stats, va_acc, _ = fit(X[tr], gold[tr], qid[tr], X[va], gold[va], qid[va], ns) | |
| print(f"mlp val agreement with oracle: {va_acc:.3f}", flush=True) | |
| results["mlp_val_acc"] = va_acc | |
| def mlp_policy(s): | |
| Xs, _ = scorer.latents(scorer.pair_texts(s)) | |
| z = predict(model, stats, Xs) | |
| return int(z.argmax()) == 0, 1 / (1 + np.exp(-z)) # probs = sigmoid score per option (flap, do nothing) | |
| t0 = time.time(); evaluate("mlp", mlp_policy); print(f" ({time.time()-t0:.0f}s)") | |
| json.dump({"args": vars(args), "results": results}, open(args.out, "w"), indent=2) | |
| for name in [n for n in ["nli", "mlp"] if n in results]: | |
| print(f"\n=== {name}: first frames of episode 0 (bird '>', pipe '#')") | |
| for fr, a in results[name]["frames"][:4]: | |
| print(fr); print("action:", a); print("-" * 30) | |
| if __name__ == "__main__": | |
| main() | |