Download chat.py from Yougori/Ling-mini-2.0-Megakernel: direct link, hf CLI and curl.
- Browser
- Download file 4.05 kB
-
https://huggingface.co/Yougori/Ling-mini-2.0-Megakernel/resolve/main/chat.py
- Command line
-
hf download hf://Yougori/Ling-mini-2.0-Megakernel/chat.py
-
curl -L -o chat.py https://huggingface.co/Yougori/Ling-mini-2.0-Megakernel/resolve/main/chat.py
4.05 kB
| """Chat with Ling-mini-2.0 in a terminal, on the megakernel. | |
| python chat.py [--max-new 1024] | |
| Greedy decoding, thinking off. Each answer re-reads only the new part of the conversation (the rest | |
| is still in the kernel's cache). Windows lowers an idle GPU's clocks, so the kernel warms up at start | |
| and before each answer. The speed shown is the kernel's own while it writes. An empty line or | |
| "exit" quits. | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import sys | |
| import time | |
| from ling_kernel import HERE, LingKernel | |
| CHUNK = 32 # tokens per launch, printed as they arrive | |
| def calibrate(mk: LingKernel, tok, budget: float = 20.0) -> float: | |
| ids = tok("Hello")["input_ids"] | |
| first = mk.forced(ids)[-1] | |
| start, best, since = time.perf_counter(), float("inf"), time.perf_counter() | |
| while time.perf_counter() - start < budget: | |
| s = mk._launch([first], len(ids), CHUNK, False) | |
| if s < 0.97 * best: | |
| best, since = s, time.perf_counter() | |
| elif time.perf_counter() - since > 1.0: | |
| break | |
| mk.cached = [] | |
| return best | |
| def warm_up(mk: LingKernel, first: int, pos: int, budget: float = 3.0) -> None: | |
| start = time.perf_counter() | |
| while time.perf_counter() - start < budget: | |
| if mk._launch([first], pos, CHUNK, False) < 1.15 * mk.best_launch: | |
| break | |
| def answer(mk: LingKernel, tok, eos: set[int], messages: list[dict], max_new: int) -> str: | |
| ids = tok.apply_chat_template(messages, tokenize=True, add_generation_prompt=True) | |
| if hasattr(ids, "keys"): | |
| ids = ids["input_ids"] | |
| ids = list(ids) | |
| if len(ids) + max_new + CHUNK > mk.max_pos: | |
| print(f"[the conversation is too long for the {mk.max_pos}-token cache; type 'exit' and start again]") | |
| return "" | |
| n = 0 | |
| while n < min(len(ids) - 1, len(mk.cached)) and ids[n] == mk.cached[n]: | |
| n += 1 | |
| preds = mk.forced(ids[n:], pos0=n) | |
| warm_up(mk, preds[-1], len(ids)) | |
| out, seconds, steps, pos, shown = [preds[-1]], 0.0, 0, len(ids), "" | |
| print("Ling> ", end="", flush=True) | |
| while out[-1] not in eos and len(out) < max_new: | |
| k = min(CHUNK, max_new - len(out)) | |
| seconds += mk._launch([out[-1]], pos, k, False) | |
| steps += k | |
| pos += k | |
| for t in mk.state.out[:k].tolist(): | |
| out.append(t) | |
| if t in eos: | |
| break | |
| text = tok.decode([t for t in out if t not in eos], skip_special_tokens=True) | |
| print(text[len(shown):], end="", flush=True) | |
| shown = text | |
| mk.cached = ids + out[:-1] | |
| speed = f"{steps / seconds:.0f} tokens/s" if seconds else "-" | |
| print(f"\n[{len(out)} tokens; the kernel writes {speed}; read {len(ids) - n} new prompt tokens]\n", flush=True) | |
| return shown.strip() | |
| def main() -> None: | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("--max-new", type=int, default=1024) | |
| args = ap.parse_args() | |
| sys.stdout.reconfigure(encoding="utf-8") | |
| from transformers import AutoTokenizer | |
| tok = AutoTokenizer.from_pretrained(HERE) | |
| print("loading the Ling-mini-2.0 megakernel (4-bit) ...", flush=True) | |
| mk = LingKernel(max_pos=4096, log=lambda s: print(s, flush=True)) | |
| eos = {i for i in (tok.convert_tokens_to_ids("<|role_end|>"), tok.eos_token_id, mk.config.get("eos_token_id")) | |
| if isinstance(i, int) and i >= 0} | |
| print("warming up the GPU ...", flush=True) | |
| mk.best_launch = calibrate(mk, tok) | |
| print(f" {CHUNK / mk.best_launch:.0f} tokens/s at full speed", flush=True) | |
| history: list[dict] = [] | |
| print("type a message; an empty line or 'exit' quits\n", flush=True) | |
| while True: | |
| try: | |
| text = input("you> ").strip() | |
| except EOFError: | |
| break | |
| if not text or text.lower() in ("exit", "quit"): | |
| break | |
| messages = history + [{"role": "user", "content": text}] | |
| reply = answer(mk, tok, eos, messages, args.max_new) | |
| history = messages + [{"role": "assistant", "content": reply}] | |
| if __name__ == "__main__": | |
| main() | |