thefinalboss commited on
Commit
669473d
Β·
verified Β·
1 Parent(s): 7b235a4

Upload infer_optimized.py

Browse files
Files changed (1) hide show
  1. infer_optimized.py +272 -0
infer_optimized.py ADDED
@@ -0,0 +1,272 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ CogNet Optimized Inference Engine
3
+ ==================================
4
+ Inference for the optimized CogNet model.
5
+ Supports: generate, analyze, benchmark
6
+
7
+ Usage:
8
+ python infer_optimized.py generate --prompt "The future of AI is" --max-tokens 100
9
+ python infer_optimized.py analyze --prompt "CogNet is"
10
+ python infer_optimized.py benchmark
11
+ """
12
+
13
+ import argparse
14
+ import json
15
+ import math
16
+ import os
17
+ import sys
18
+ import time
19
+ from typing import Dict, List, Optional
20
+
21
+ import torch
22
+ import torch.nn.functional as F
23
+
24
+ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
25
+ from cognet_1b_optimized import CogNet1BOptimized, create_cognet_1b_optimized
26
+
27
+
28
+ # ─── Model & Tokenizer Loading ───────────────────────────────────────────────
29
+
30
+ CKPT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'checkpoints')
31
+ TOKENIZER_PATH = os.path.join(CKPT_DIR, 'bpe_tokenizer_32000.json')
32
+
33
+
34
+ _model_cache = {'model': None, 'tokenizer': None, 'device': None, 'loaded': False}
35
+
36
+
37
+ def load_model_and_tokenizer(checkpoint_path: Optional[str] = None):
38
+ """Load model and tokenizer with caching."""
39
+ if _model_cache['loaded']:
40
+ return _model_cache['model'], _model_cache['tokenizer'], _model_cache['device']
41
+
42
+ device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
43
+
44
+ # Load tokenizer
45
+ tokenizer = None
46
+ if os.path.exists(TOKENIZER_PATH):
47
+ try:
48
+ from tokenizers import Tokenizer
49
+ tokenizer = Tokenizer.from_file(TOKENIZER_PATH)
50
+ print(f"Loaded BPE tokenizer (vocab={tokenizer.get_vocab_size()})")
51
+ except ImportError:
52
+ pass
53
+
54
+ if tokenizer is None:
55
+ # Fallback: simple char tokenizer
56
+ print("Using fallback character tokenizer")
57
+ tokenizer = _SimpleCharTokenizer()
58
+
59
+ vocab_size = tokenizer.get_vocab_size() if hasattr(tokenizer, 'get_vocab_size') else tokenizer.vocab_size
60
+
61
+ # Create model
62
+ model = create_cognet_1b_optimized(
63
+ vocab_size=vocab_size,
64
+ max_seq_len=4096,
65
+ use_gradient_checkpointing=False,
66
+ )
67
+
68
+ # Load weights
69
+ if checkpoint_path is None:
70
+ checkpoint_path = os.path.join(CKPT_DIR, 'best.pt')
71
+ if not os.path.exists(checkpoint_path):
72
+ checkpoint_path = os.path.join(CKPT_DIR, 'latest.pt')
73
+
74
+ if checkpoint_path and os.path.exists(checkpoint_path):
75
+ ckpt = torch.load(checkpoint_path, map_location=device, weights_only=False)
76
+ model.load_state_dict(ckpt['model_state_dict'])
77
+ step = ckpt.get('step', ckpt.get('metrics', {}).get('step', '?'))
78
+ print(f"Loaded model from {checkpoint_path} (step={step})")
79
+ else:
80
+ print("WARNING: No trained weights found. Using random initialization.")
81
+
82
+ model = model.to(device)
83
+ model.eval()
84
+
85
+ # Try to compile for inference
86
+ try:
87
+ model = torch.compile(model, mode="reduce-overhead")
88
+ print("Model compiled for inference")
89
+ except Exception:
90
+ pass
91
+
92
+ _model_cache['model'] = model
93
+ _model_cache['tokenizer'] = tokenizer
94
+ _model_cache['device'] = device
95
+ _model_cache['loaded'] = True
96
+
97
+ return model, tokenizer, device
98
+
99
+
100
+ class _SimpleCharTokenizer:
101
+ """Fallback character tokenizer."""
102
+ def __init__(self, vocab_size=256):
103
+ self.vocab_size = vocab_size
104
+ self._id_to_char = {i: chr(i) for i in range(min(vocab_size, 256))}
105
+ self._char_to_id = {v: k for k, v in self._id_to_char.items()}
106
+
107
+ def encode(self, text):
108
+ return [self._char_to_id.get(c, 0) for c in text]
109
+
110
+ def decode(self, ids):
111
+ return ''.join(self._id_to_char.get(i, ' ') for i in ids)
112
+
113
+ def get_vocab_size(self):
114
+ return self.vocab_size
115
+
116
+
117
+ # ─── Actions ──────────────────────────────────────────────────────────────────
118
+
119
+ def handle_generate(prompt: str, max_tokens: int = 100,
120
+ temperature: float = 0.8, top_k: int = 40) -> Dict:
121
+ """Generate text from a prompt."""
122
+ model, tokenizer, device = load_model_and_tokenizer()
123
+
124
+ ids = tokenizer.encode(prompt)
125
+ if not isinstance(ids, list):
126
+ ids = ids.ids if hasattr(ids, 'ids') else list(ids)
127
+ if len(ids) == 0:
128
+ ids = [0]
129
+
130
+ input_ids = torch.tensor([ids], dtype=torch.long, device=device)
131
+
132
+ t0 = time.time()
133
+ with torch.no_grad():
134
+ output_ids = model.generate(
135
+ input_ids, max_new_tokens=max_tokens,
136
+ temperature=temperature, top_k=top_k,
137
+ )
138
+ elapsed = time.time() - t0
139
+
140
+ gen_ids = output_ids[0].tolist()
141
+ gen_text = tokenizer.decode(gen_ids) if hasattr(tokenizer, 'decode') else str(gen_ids[:100])
142
+
143
+ return {
144
+ 'action': 'generate',
145
+ 'prompt': prompt,
146
+ 'generated_text': gen_text,
147
+ 'num_tokens': len(gen_ids),
148
+ 'time_seconds': elapsed,
149
+ 'tokens_per_second': len(gen_ids) / max(elapsed, 0.001),
150
+ }
151
+
152
+
153
+ def handle_analyze(prompt: str) -> Dict:
154
+ """Analyze logits, entropy, and top predictions."""
155
+ model, tokenizer, device = load_model_and_tokenizer()
156
+
157
+ ids = tokenizer.encode(prompt)
158
+ if not isinstance(ids, list):
159
+ ids = ids.ids if hasattr(ids, 'ids') else list(ids)
160
+
161
+ input_ids = torch.tensor([ids], dtype=torch.long, device=device)
162
+
163
+ with torch.no_grad():
164
+ result = model(input_ids, return_stats=True)
165
+ logits = result['logits']
166
+
167
+ # Last token predictions
168
+ last_logits = logits[0, -1, :]
169
+ probs = F.softmax(last_logits, dim=-1)
170
+ entropy = -(probs * (probs + 1e-10).log()).sum().item()
171
+
172
+ # Top 10 predictions
173
+ topk_vals, topk_ids = torch.topk(probs, min(10, probs.size(0)))
174
+ top_predictions = []
175
+ for prob, tid in zip(topk_vals.tolist(), topk_ids.tolist()):
176
+ char = tokenizer.decode([tid]) if hasattr(tokenizer, 'decode') else f'token_{tid}'
177
+ top_predictions.append({
178
+ 'token_id': tid,
179
+ 'char': char,
180
+ 'probability': prob,
181
+ })
182
+
183
+ return {
184
+ 'action': 'analyze',
185
+ 'prompt': prompt,
186
+ 'entropy': entropy,
187
+ 'top_predictions': top_predictions,
188
+ }
189
+
190
+
191
+ def handle_benchmark() -> Dict:
192
+ """Benchmark model throughput."""
193
+ model, tokenizer, device = load_model_and_tokenizer()
194
+ vocab_size = tokenizer.get_vocab_size() if hasattr(tokenizer, 'get_vocab_size') else tokenizer.vocab_size
195
+
196
+ # Param count
197
+ params = sum(p.numel() for p in model.parameters())
198
+
199
+ # Warmup
200
+ warmup_input = torch.randint(0, vocab_size, (1, 128), device=device)
201
+ with torch.no_grad():
202
+ for _ in range(5):
203
+ model(warmup_input)
204
+
205
+ # Benchmark different sequence lengths
206
+ results = {}
207
+ for seq_len in [128, 256, 512, 1024, 2048]:
208
+ try:
209
+ input_ids = torch.randint(0, vocab_size, (1, seq_len), device=device)
210
+
211
+ # Timed runs
212
+ torch.cuda.synchronize() if torch.cuda.is_available() else None
213
+ t0 = time.time()
214
+
215
+ n_runs = 20
216
+ with torch.no_grad():
217
+ for _ in range(n_runs):
218
+ model(input_ids)
219
+
220
+ torch.cuda.synchronize() if torch.cuda.is_available() else None
221
+ elapsed = time.time() - t0
222
+
223
+ tokens_per_sec = (seq_len * n_runs) / elapsed
224
+ latency_ms = (elapsed / n_runs) * 1000
225
+
226
+ results[f'seq_{seq_len}'] = {
227
+ 'tokens_per_second': tokens_per_sec,
228
+ 'latency_ms': latency_ms,
229
+ }
230
+ print(f" seq_len={seq_len:>5d}: {tokens_per_sec:>10,.0f} tokens/s, {latency_ms:.1f}ms latency")
231
+ except torch.cuda.OutOfMemoryError:
232
+ results[f'seq_{seq_len}'] = {'error': 'OOM'}
233
+ print(f" seq_len={seq_len:>5d}: OOM")
234
+
235
+ return {
236
+ 'action': 'benchmark',
237
+ 'parameters': params,
238
+ 'device': str(device),
239
+ 'results': results,
240
+ }
241
+
242
+
243
+ # ─── CLI ──────────────────────────────────────────────────────────────────────
244
+
245
+ def main():
246
+ parser = argparse.ArgumentParser(description='CogNet Optimized Inference')
247
+ parser.add_argument('action', choices=['generate', 'analyze', 'benchmark'])
248
+ parser.add_argument('--prompt', type=str, default='The ')
249
+ parser.add_argument('--max-tokens', type=int, default=100)
250
+ parser.add_argument('--temperature', type=float, default=0.8)
251
+ parser.add_argument('--top-k', type=int, default=40)
252
+ parser.add_argument('--checkpoint', type=str, default=None)
253
+ args = parser.parse_args()
254
+
255
+ if args.checkpoint:
256
+ # Override checkpoint path
257
+ global TOKENIZER_PATH
258
+ # Load from specified checkpoint
259
+ _model_cache['loaded'] = False
260
+
261
+ if args.action == 'generate':
262
+ result = handle_generate(args.prompt, args.max_tokens, args.temperature, args.top_k)
263
+ elif args.action == 'analyze':
264
+ result = handle_analyze(args.prompt)
265
+ elif args.action == 'benchmark':
266
+ result = handle_benchmark()
267
+
268
+ print(json.dumps(result, indent=2, ensure_ascii=False, default=str))
269
+
270
+
271
+ if __name__ == '__main__':
272
+ main()