epoyraz commited on
Commit
bb8de71
·
verified ·
1 Parent(s): 57a1624

Upload model support files

Browse files
Files changed (1) hide show
  1. generate.py +135 -0
generate.py ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+ import time
3
+
4
+ import torch
5
+ from tokenizers import Tokenizer
6
+
7
+ from config import CHECKPOINT_DIR, DEVICE, TOKENIZER_PATH
8
+ from model import GPT
9
+ from msvc_env import ensure_msvc_env
10
+
11
+
12
+ DEFAULT_CHECKPOINT = f"{CHECKPOINT_DIR}/final.pt"
13
+
14
+
15
+ def parse_args():
16
+ parser = argparse.ArgumentParser(description="Generate text from a trained checkpoint.")
17
+ parser.add_argument("--checkpoint", default=DEFAULT_CHECKPOINT)
18
+ parser.add_argument("--prompt", default=None)
19
+ parser.add_argument("--max-tokens", type=int, default=200)
20
+ parser.add_argument("--temperature", type=float, default=0.8)
21
+ parser.add_argument("--top-k", type=int, default=40)
22
+ parser.add_argument("--top-p", type=float, default=None)
23
+ parser.add_argument("--min-p", type=float, default=None)
24
+ parser.add_argument("--speculative", action="store_true")
25
+ parser.add_argument("--speculate-tokens", type=int, default=None)
26
+ parser.add_argument("--turboquant", action="store_true")
27
+ parser.add_argument("--no-turboquant", action="store_true")
28
+ parser.add_argument("--no-kv-cache", action="store_true")
29
+ parser.add_argument("--compile", action="store_true",
30
+ help="torch.compile the decode step (~2x faster after warmup; needs MSVC+Triton)")
31
+ return parser.parse_args()
32
+
33
+
34
+ def load_model(checkpoint_path):
35
+ probe = torch.load(checkpoint_path, map_location="cpu", weights_only=False)
36
+ if probe.get("format") == "ternary_packed":
37
+ from export_ternary import load_ternary
38
+ model, config = load_ternary(checkpoint_path, device=DEVICE)
39
+ return model, {"config": config, "step": probe.get("step", 0)}
40
+ ckpt = torch.load(checkpoint_path, map_location=DEVICE, weights_only=True)
41
+ model = GPT(ckpt["config"]).to(DEVICE)
42
+ model.load_state_dict(ckpt["model"])
43
+ model.eval()
44
+ return model, ckpt
45
+
46
+
47
+ def resolve_turboquant(args, config):
48
+ if args.turboquant:
49
+ return True
50
+ if args.no_turboquant:
51
+ return False
52
+ return config.get("use_turboquant", False)
53
+
54
+
55
+ def generate_text(model, tokenizer, prompt, args, use_turboquant):
56
+ ids = tokenizer.encode(prompt).ids
57
+ idx = torch.tensor([ids], dtype=torch.long, device=DEVICE)
58
+
59
+ if DEVICE == "cuda":
60
+ torch.cuda.synchronize()
61
+ started = time.perf_counter()
62
+ with torch.no_grad():
63
+ out = model.generate(
64
+ idx,
65
+ max_new_tokens=args.max_tokens,
66
+ temperature=args.temperature,
67
+ top_k=args.top_k,
68
+ top_p=args.top_p,
69
+ min_p=args.min_p,
70
+ speculative=args.speculative,
71
+ speculate_tokens=args.speculate_tokens,
72
+ use_turboquant=use_turboquant,
73
+ use_kv_cache=not args.no_kv_cache,
74
+ )
75
+ if DEVICE == "cuda":
76
+ torch.cuda.synchronize()
77
+ elapsed = time.perf_counter() - started
78
+
79
+ generated_tokens = out.shape[1] - idx.shape[1]
80
+ tps = generated_tokens / elapsed if elapsed > 0 else float("inf")
81
+ return tokenizer.decode(out[0].tolist()), generated_tokens, elapsed, tps
82
+
83
+
84
+ def print_generation(model, tokenizer, prompt, args, use_turboquant):
85
+ text, generated_tokens, elapsed, tps = generate_text(model, tokenizer, prompt, args, use_turboquant)
86
+ print(f"Prompt: {prompt}")
87
+ print(f"Output: {text}")
88
+ print(f"Generated: {generated_tokens} tokens in {elapsed:.3f}s ({tps:.2f} tok/s)")
89
+ print("-" * 60)
90
+
91
+
92
+ def main():
93
+ args = parse_args()
94
+ tokenizer = Tokenizer.from_file(TOKENIZER_PATH)
95
+ model, ckpt = load_model(args.checkpoint)
96
+ config = ckpt["config"]
97
+ use_turboquant = resolve_turboquant(args, config)
98
+
99
+ if args.compile:
100
+ if DEVICE == "cuda":
101
+ ensure_msvc_env() # Triton needs MSVC on PATH to build CUDA shims on Windows
102
+ # dynamic=True is essential: the KV-cache sequence length changes every step and
103
+ # every prompt, so static compilation would recompile per length (slower than eager).
104
+ # Dynamic shapes compile once and then run any prompt length at a steady ~160 tok/s.
105
+ model._forward_inference = torch.compile(model._forward_inference, dynamic=True)
106
+ print("Compiled decode step (dynamic shapes; first generation is slow while compiling).")
107
+
108
+ if args.speculative and not config.get("use_mtp", False):
109
+ print("Speculative mode requested, but this checkpoint has no MTP heads. Falling back to normal generation.")
110
+ print(f"Loaded {args.checkpoint} on {DEVICE}")
111
+ print(f"Config: {config}")
112
+ print(f"Mode: speculative={args.speculative and config.get('use_mtp', False)}, kv_cache={not args.no_kv_cache}, turboquant={use_turboquant}\n")
113
+
114
+ if args.prompt is not None:
115
+ print_generation(model, tokenizer, args.prompt, args, use_turboquant)
116
+ return
117
+
118
+ prompts = [
119
+ "The history of",
120
+ "In physics, the",
121
+ "The city was founded",
122
+ ]
123
+ for prompt in prompts:
124
+ print_generation(model, tokenizer, prompt, args, use_turboquant)
125
+
126
+ print("\nInteractive mode (type 'quit' to exit):")
127
+ while True:
128
+ prompt = input("\n> ")
129
+ if prompt.lower() == "quit":
130
+ break
131
+ print_generation(model, tokenizer, prompt, args, use_turboquant)
132
+
133
+
134
+ if __name__ == "__main__":
135
+ main()