Download ar/eval/generate.py from AjayRangoji/AR: direct link, hf CLI and curl.
- Browser
- Download file 2.32 kB
-
https://huggingface.co/AjayRangoji/AR/resolve/main/ar/eval/generate.py
- Command line
-
hf download hf://AjayRangoji/AR/ar/eval/generate.py
-
curl -L -o generate.py https://huggingface.co/AjayRangoji/AR/resolve/main/ar/eval/generate.py
2.32 kB
| """Generate text from an exported checkpoint (quick quality check).""" | |
| import argparse | |
| import torch | |
| from ar.model.config import ARConfig | |
| from ar.model.model import ARModel | |
| from ar.model.mask import build_doc_block_mask | |
| from ar.model.rope import build_rope_cache | |
| from ar.data.tokenizer import Tokenizer | |
| SEQ = 256 # fixed length, so FlexAttention compiles once instead of for every new length | |
| def load_model(path, device): | |
| cfg = ARConfig() | |
| with torch.device(device): | |
| model = ARModel(cfg) # real init also builds correct RoPE tables | |
| model.load_state_dict(torch.load(path, map_location=device)) | |
| model = model.to(torch.bfloat16).eval() | |
| return model | |
| def generate(model, tok, prompt, device, max_new=150, temperature=0.8, top_k=50): | |
| ids = tok.encode(prompt) | |
| n = len(ids) | |
| # fixed-size buffer; slots after the current position are placeholders | |
| # that the causal mask hides from earlier tokens | |
| buf = torch.full((1, SEQ), tok.eot_id, dtype=torch.long, device=device) | |
| buf[0, :n] = torch.tensor(ids, device=device) | |
| seg = torch.zeros(1, SEQ, dtype=torch.int32, device=device) # one document | |
| mask = build_doc_block_mask(seg, SEQ, device=device) | |
| pos = n | |
| for pos in range(n, min(SEQ, n + max_new)): | |
| logits = model(buf, mask)[0, pos - 1].float() / temperature | |
| # keep only the top_k most likely tokens, then sample one of them | |
| kth = torch.topk(logits, top_k).values[-1] | |
| logits[logits < kth] = -float("inf") | |
| nxt = torch.multinomial(torch.softmax(logits, -1), 1) | |
| buf[0, pos] = nxt | |
| if nxt.item() == tok.eot_id: # model decided the text is over | |
| break | |
| return tok.decode(buf[0, : pos + 1].tolist()) | |
| if __name__ == "__main__": | |
| p = argparse.ArgumentParser() | |
| p.add_argument("--model", required=True) | |
| args = p.parse_args() | |
| device = "cuda" | |
| tok = Tokenizer() | |
| model = load_model(args.model, device) | |
| torch.manual_seed(0) | |
| prompts = [ | |
| "The capital of France is", | |
| "Once upon a time, there was a little", | |
| "def fibonacci(n):", | |
| "Question: What is 12 + 7?\nAnswer:", | |
| ] | |
| for pr in prompts: | |
| print("=" * 60, flush=True) | |
| print(generate(model, tok, pr, device), flush=True) |