Instructions to use briscoooe/tiny-cube-deep20 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use briscoooe/tiny-cube-deep20 with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="briscoooe/tiny-cube-deep20")# Load model directly from transformers import AutoTokenizer, AutoModelForCausalLM tokenizer = AutoTokenizer.from_pretrained("briscoooe/tiny-cube-deep20") model = AutoModelForCausalLM.from_pretrained("briscoooe/tiny-cube-deep20", device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use briscoooe/tiny-cube-deep20 with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "briscoooe/tiny-cube-deep20" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "briscoooe/tiny-cube-deep20", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker
docker model run hf.co/briscoooe/tiny-cube-deep20
- SGLang
How to use briscoooe/tiny-cube-deep20 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 "briscoooe/tiny-cube-deep20" \ --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": "briscoooe/tiny-cube-deep20", "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 "briscoooe/tiny-cube-deep20" \ --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": "briscoooe/tiny-cube-deep20", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }' - Docker Model Runner
How to use briscoooe/tiny-cube-deep20 with Docker Model Runner:
docker model run hf.co/briscoooe/tiny-cube-deep20
File size: 8,512 Bytes
cdea7a9 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 | """
Serves the trained model behind an OpenAI-shaped /v1/chat/completions endpoint so
the existing harness can score it unchanged.
## Why a shim instead of a Python eval loop
The scrambles, the scorer, the JSONL writer, the D1 upload path and the
leaderboard are all in TypeScript, and the scramble seeds are index-addressed so
every model faces the identical puzzles. Re-implementing scramble generation in
Python to run a separate eval loop would risk silently diverging from those
scrambles, which would quietly destroy the matched-pairs property that makes
cross-model comparison meaningful. Pointing `callModel` at a local URL instead
keeps one harness, one scorer and one code path, and the model becomes just
another row in the results table.
Nothing here is a general LLM server. It extracts the cube state from whatever
prompt it is handed, greedily decodes a solution, and returns it in the response
shape the harness already parses.
"""
import argparse, json, re, time
import torch
from transformers import LlamaForCausalLM
import cube_tokenizer as T
def extract_state(text: str) -> str:
"""Reads the 54-facelet state out of the benchmark prompt's net diagram.
Parsed structurally rather than by regex over the whole prompt. The obvious
shortcut -- strip everything that is not a facelet letter and take 54 of them
-- silently produces a wrong state, because the surrounding prose is full of
face letters on both sides of the diagram: the preamble names the colours
("U=White (Up), R=Red (Right)...") and the trailing instruction lists the
move vocabulary ("(U, D, L, R, F, or B)"). Taking the first or last run picks
up prose either way, and the result still looks like a valid 54-character
state, so the failure would surface only as an unexplained low solve rate.
Stickers are space-separated individually, so a net line is either 3 cells
(a U or D row) or 12 cells (a row spanning L, F, R and B in that order).
Facelet strings are ordered U R F D L B, so the wide rows are split by face
and reassembled rather than concatenated in reading order.
"""
narrow, wide = [], []
for line in text.splitlines():
cells = line.split()
if not cells or not all(len(c) == 1 and c in "URFDLB" for c in cells):
continue
if len(cells) == 3:
narrow.append("".join(cells))
elif len(cells) == 12:
wide.append("".join(cells))
if len(narrow) != 6 or len(wide) != 3:
raise ValueError(f"unexpected net shape: {len(narrow)} narrow rows, {len(wide)} wide rows")
up = "".join(narrow[:3])
down = "".join(narrow[3:])
left = "".join(r[0:3] for r in wide)
front = "".join(r[3:6] for r in wide)
right = "".join(r[6:9] for r in wide)
back = "".join(r[9:12] for r in wide)
return up + right + front + down + left + back
@torch.no_grad()
def _decode(model, state: str, device: str, temperature: float = 0.0, n: int = 1):
"""Decodes n solutions at once. temperature=0 is greedy (n is then pointless)."""
prompt = torch.tensor([T.encode_state(state)] * n, device=device)
ids = prompt
finished = torch.zeros(n, dtype=torch.bool, device=device)
for _ in range(T.MAX_SOLUTION + 1):
logits = model(input_ids=ids).logits[:, -1, :]
if temperature > 0:
nxt = torch.multinomial(torch.softmax(logits / temperature, dim=-1), 1)[:, 0]
else:
nxt = logits.argmax(-1)
nxt = torch.where(finished, torch.full_like(nxt, T.PAD), nxt)
finished |= nxt == T.EOS
ids = torch.cat([ids, nxt[:, None]], dim=1)
if bool(finished.all()):
break
start = prompt.shape[1]
return [T.decode_solution(row) for row in ids[:, start:].tolist()]
def solve(model, state: str, device: str, attempts: int = 1, temperature: float = 1.5) -> str:
"""Returns a solution, verifying candidates against the engine when allowed more
than one attempt.
With attempts=1 this is a plain greedy decode -- the bare-model number, and the
one to quote as the model's own solve rate.
With attempts>1 the model proposes and the engine disposes: sampled candidates
are each replayed, and the first that actually solves is returned. That is
legitimate (the verifier is exact and free) but it is a *system* score, not a
model score, so the two must be reported separately and never blended. It
exists because a 20-move one-shot solve needs per-move accuracy around 0.9995
to hit 99% unaided, whereas a handful of verified samples buys the same result
from a much weaker model.
Temperature defaults to 1.5, which is high on purpose. Measured on the sanity
checkpoint, 16 samples per state collapsed to only 2.8 distinct solutions at
0.7 and rescued *none* of the greedy failures; at 1.0, 4.0 distinct and 1 of 5;
at 1.5, 11.0 distinct and 2 of 5. The model is confidently wrong rather than
uncertain, so mild sampling just re-draws the same wrong answer -- the
candidates have to be genuinely diverse before an exact verifier can do any
work. A wrong candidate costs nothing here, since every one is checked.
"""
from gen_data import SOLVED, apply_sequence
greedy = _decode(model, state, device)[0]
if greedy and apply_sequence(state, greedy) == SOLVED:
return " ".join(greedy)
if attempts <= 1:
return " ".join(greedy)
for cand in _decode(model, state, device, temperature=temperature, n=attempts - 1):
if cand and apply_sequence(state, cand) == SOLVED:
return " ".join(cand)
return " ".join(greedy)
def build_app(model, device, model_name, args):
from fastapi import FastAPI, Request
app = FastAPI()
@app.get("/v1/models")
def models():
return {"object": "list", "data": [{"id": model_name, "object": "model"}]}
@app.post("/v1/chat/completions")
async def completions(req: Request):
body = await req.json()
text = "\n".join(m.get("content") or "" for m in body.get("messages", []))
t0 = time.time()
try:
answer = solve(model, extract_state(text), device, attempts=args.attempts)
except ValueError as e:
answer = f"ERROR: {e}"
return {
"id": "cube-local", "object": "chat.completion",
"created": int(t0), "model": model_name,
"choices": [{"index": 0, "finish_reason": "stop",
"message": {"role": "assistant", "content": answer}}],
# Reported honestly: this model has no hidden reasoning, so the
# harness should record zero rather than infer any from a blank field.
"usage": {"prompt_tokens": T.MAX_SEQ, "completion_tokens": len(answer.split()),
"total_tokens": T.MAX_SEQ + len(answer.split()),
"completion_tokens_details": {"reasoning_tokens": 0}},
}
return app
def main():
p = argparse.ArgumentParser(description=__doc__)
p.add_argument("--checkpoint", required=True, help="Local dir or Hub repo id.")
p.add_argument("--port", type=int, default=8000)
p.add_argument("--model-name", default="local/tiny-cube")
p.add_argument("--attempts", type=int, default=1,
help="1 = bare greedy model score. >1 samples extra candidates and "
"keeps the first the engine confirms solves (a system score).")
p.add_argument("--self-test", type=int, default=0,
help="Solve N generated scrambles and exit, instead of serving.")
args = p.parse_args()
device = "cuda" if torch.cuda.is_available() else "cpu"
model = LlamaForCausalLM.from_pretrained(args.checkpoint).to(device).eval()
print(f"loaded {args.checkpoint} on {device}", flush=True)
if args.self_test:
import random
from gen_data import SOLVED, apply_sequence, random_state
rng = random.Random(0)
solved = 0
for _ in range(args.self_test):
state = random_state(rng, 200)
moves = solve(model, state, device).split()
if moves and apply_sequence(state, moves) == SOLVED:
solved += 1
print(f"self-test: {solved}/{args.self_test} solved ({solved/args.self_test:.1%})")
return
import uvicorn
uvicorn.run(build_app(model, device, args.model_name, args), host="0.0.0.0", port=args.port)
if __name__ == "__main__":
main()
|