Download chat.py from Crawlnet/queen-v2: direct link, hf CLI and curl.
- Browser
- Download file 3.25 kB
-
https://huggingface.co/Crawlnet/queen-v2/resolve/main/chat.py
- Command line
-
hf download hf://Crawlnet/queen-v2/chat.py
-
curl -L -o chat.py https://huggingface.co/Crawlnet/queen-v2/resolve/main/chat.py
3.25 kB
| """ | |
| Chat with a released Crawlnet queen from its folder. Copied into every release as chat.py. | |
| pip install torch tiktoken safetensors | |
| git clone https://github.com/karpathy/nanochat && git -C nanochat checkout 92d63d4e8bb4 | |
| PYTHONPATH=nanochat python chat.py "What is staking?" [--dir .] [--temperature 0.7] [--top-k 50] [--max-tokens 200] | |
| Needs only nanochat (MIT) for the model and tokenizer classes; no Crawlnet code. | |
| """ | |
| import argparse | |
| import base64 | |
| import json | |
| import os | |
| import tiktoken | |
| import torch | |
| from safetensors.torch import load_file | |
| from nanochat.engine import Engine | |
| from nanochat.gpt import GPT, GPTConfig | |
| from nanochat.tokenizer import RustBPETokenizer | |
| def load(folder, device): | |
| with open(os.path.join(folder, "config.json")) as f: | |
| cfg = json.load(f) | |
| with open(os.path.join(folder, "tokenizer.json")) as f: | |
| tj = json.load(f) | |
| ranks = {} | |
| with open(os.path.join(folder, "tokenizer.tiktoken")) as f: | |
| for line in f: | |
| tok, rank = line.split() | |
| ranks[base64.b64decode(tok)] = int(rank) | |
| enc = tiktoken.Encoding(name="queen", pat_str=tj["pattern"], mergeable_ranks=ranks, special_tokens=tj["special_tokens"]) | |
| tokenizer = RustBPETokenizer(enc, tj["bos_token"]) | |
| with torch.device("meta"): | |
| model = GPT(GPTConfig(**cfg["model_config"])) | |
| model.to_empty(device=device) | |
| model.init_weights() # rotary buffers; the weights are overwritten below | |
| state = load_file(os.path.join(folder, "model.safetensors"), device="cpu") | |
| if device != "cuda": # bf16 weights run in fp32 on CPU | |
| state = {k: (v.float() if v.is_floating_point() else v) for k, v in state.items()} | |
| model.load_state_dict({k: v.to(device) for k, v in state.items()}, strict=True, assign=True) | |
| model.eval() | |
| return model, tokenizer | |
| def answer(model, tokenizer, question, max_tokens=200, temperature=0.7, top_k=50, seed=42): | |
| sp = tokenizer.encode_special | |
| bos = tokenizer.get_bos_token_id() | |
| prompt = [bos, sp("<|user_start|>")] + tokenizer.encode(question) + [sp("<|user_end|>"), sp("<|assistant_start|>")] | |
| stop = {bos, sp("<|assistant_end|>"), sp("<|user_start|>")} | |
| out = [] | |
| for column, _ in Engine(model, tokenizer).generate(prompt, num_samples=1, max_tokens=max_tokens, | |
| temperature=temperature, top_k=top_k, seed=seed): | |
| if column[0] in stop: | |
| break | |
| out.append(column[0]) | |
| return tokenizer.decode(out).strip() | |
| def main(): | |
| ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) | |
| ap.add_argument("question") | |
| ap.add_argument("--dir", default=os.path.dirname(os.path.abspath(__file__))) | |
| ap.add_argument("--max-tokens", type=int, default=200) | |
| ap.add_argument("--temperature", type=float, default=0.7) | |
| ap.add_argument("--top-k", type=int, default=50) | |
| ap.add_argument("--seed", type=int, default=42) | |
| args = ap.parse_args() | |
| device = "cuda" if torch.cuda.is_available() else "cpu" | |
| model, tokenizer = load(args.dir, device) | |
| print(answer(model, tokenizer, args.question, args.max_tokens, args.temperature, args.top_k, args.seed)) | |
| if __name__ == "__main__": | |
| main() | |