Download code/kenchat.py from GermannM/kenga-prophet-m5: direct link, hf CLI and curl.
- Browser
- Download file 23.5 kB
-
https://huggingface.co/GermannM/kenga-prophet-m5/resolve/main/code/kenchat.py
- Command line
-
hf download hf://GermannM/kenga-prophet-m5/code/kenchat.py
-
curl -L -o kenchat.py https://huggingface.co/GermannM/kenga-prophet-m5/resolve/main/code/kenchat.py
23.5 kB
| """tools/kenchat.py — generate-and-run pipeline for Kenga Prophet. | |
| Second metric: program validity rate (compile + run + correct value). | |
| Third metric (M3.2): identifier recovery (declared == expected params). | |
| Supports: | |
| --model v01 (linear K=8) | |
| --model k16 (linear K=16) | |
| --model m3 (transformer K=32 D=32 L=1, 28-token) | |
| --model m31 (transformer K=64 D=48 L=2, 28-token) | |
| --model m32 (transformer K=64 D=48 L=2, 64-token learned codec) | |
| For transformer generation we now left-align the real prompt tokens and | |
| right-pad with a mask (1=real, 0=pad). Padding positions are zeroed in the | |
| embeddings and masked out of attention, so short prompts stay in-distribution | |
| (no more ID-token contamination). Positional embeddings for real tokens start | |
| at 0, matching training windows. | |
| """ | |
| import argparse, os, sys, subprocess, tempfile, re, pickle | |
| import numpy as np | |
| VOCAB_TOKENS = [ | |
| 'fn', 'return', 'let', 'if', 'else', 'while', 'for', 'i64', | |
| ':', ',', ';', '{', '}', '(', ')', '->', | |
| '+', '-', '*', '/', '=', '==', '<', '<=', '>', 'println', | |
| 'ID', 'NUM', | |
| ] | |
| V = len(VOCAB_TOKENS) | |
| K_LITE = 'bootstrap/bin/kenga-lite.exe' | |
| def read_header(path): | |
| out = {} | |
| with open(path) as f: | |
| first = f.readline() | |
| for tok in first.split(): | |
| if '=' in tok: | |
| k, v = tok.split('=', 1) | |
| try: out[k] = int(v) | |
| except ValueError: out[k] = v | |
| return out | |
| def load_codec_vocab(path='minds/kenga_bpe.pkl'): | |
| """Load a codec token list from a pkl (bpe or digits variant).""" | |
| with open(path, 'rb') as f: | |
| data = pickle.load(f) | |
| tokens = data['tokens'] | |
| merges = data['merges'] | |
| token_to_id = {t: i for i, t in enumerate(tokens)} | |
| merge_set = set(a + b for a, b in merges) | |
| KEYWORDS = {'fn','return','let','if','else','while','for','i64','println'} | |
| def encode_word(w): | |
| if w in KEYWORDS: | |
| return [token_to_id[w]] | |
| spellable = all(ch in token_to_id for ch in w) | |
| if not spellable: | |
| return [token_to_id['ID']] | |
| toks = list(w) | |
| changed = True | |
| while changed: | |
| changed = False | |
| i = 0 | |
| while i < len(toks) - 1: | |
| merged = toks[i] + toks[i+1] | |
| if merged in merge_set: | |
| toks[i:i+2] = [merged] | |
| changed = True | |
| i += 1 | |
| return [token_to_id[t] for t in toks] | |
| return { | |
| 'tokens': tokens, 'token_to_id': token_to_id, | |
| 'encode_word': encode_word, 'merges': merges, | |
| } | |
| def tokenize(src, codec=None): | |
| KEYWORDS = {'fn','return','let','if','else','while','for','i64','println'} | |
| TWO_CHAR = {'->','==','<=','>=','!=','&&','||','<<','>>','&','|','^','~'} | |
| if codec: | |
| VOCAB_MAP = codec['token_to_id'] | |
| else: | |
| VOCAB_MAP = {t: i for i, t in enumerate(VOCAB_TOKENS)} | |
| out = [] | |
| i = 0 | |
| n = len(src) | |
| while i < n: | |
| c = src[i] | |
| if c in ' \t\n\r': i += 1; continue | |
| if c == '/' and i+1 < n and src[i+1] == '/': | |
| while i < n and src[i] != '\n': i += 1 | |
| continue | |
| two = src[i:i+2] | |
| if two in TWO_CHAR: | |
| out.append(VOCAB_MAP.get(two, VOCAB_MAP['ID'])); i += 2; continue | |
| if c in (':', ',', ';', '{', '}', '(', ')', '+', '-', '*', '/', '=', '<', '>'): | |
| if c == '-' and i+1 < n and src[i+1] == '>': | |
| out.append(VOCAB_MAP['->']); i += 2; continue | |
| out.append(VOCAB_MAP[c]); i += 1; continue | |
| if c.isdigit(): | |
| j = i | |
| while j < n and src[j].isdigit(): j += 1 | |
| if 'NUM' in VOCAB_MAP: | |
| out.append(VOCAB_MAP['NUM']); i = j; continue | |
| for d in src[i:j]: | |
| out.append(VOCAB_MAP.get(d, VOCAB_MAP['ID'])) | |
| i = j; continue | |
| if c.isalpha() or c == '_': | |
| j = i | |
| while j < n and (src[j].isalnum() or src[j] == '_'): | |
| j += 1 | |
| word = src[i:j] | |
| if codec: | |
| out.extend(codec['encode_word'](word)) | |
| else: | |
| out.append(VOCAB_MAP[word] if word in KEYWORDS else VOCAB_MAP['ID']) | |
| i = j; continue | |
| i += 1 | |
| return out | |
| def detokenize(toks, codec=None): | |
| """Rebuild source text from token ids. | |
| Codec mode: letter/merge tokens that are consecutive form a single | |
| identifier word (syntax tokens break words). This reconstructs the exact | |
| identifier the model emitted, e.g. [a,d,d] -> 'add'. | |
| """ | |
| out = [] | |
| if codec: | |
| tokens = codec['tokens'] | |
| token_to_id = codec['token_to_id'] | |
| SYNTAX_SET = set(token_to_id[t] for t in token_to_id if t in VOCAB_TOKENS) | |
| buf = [] | |
| for t in toks: | |
| if t >= len(tokens): | |
| out.append('mkid'); continue | |
| tok = tokens[t] | |
| if tok == 'ID': | |
| if buf: out.append(''.join(buf)); buf = [] | |
| out.append('mkid') | |
| elif tok == 'NUM': | |
| if buf: out.append(''.join(buf)); buf = [] | |
| out.append('0') | |
| elif t in SYNTAX_SET: | |
| if buf: out.append(''.join(buf)); buf = [] | |
| out.append(tok) | |
| else: | |
| buf.append(tok) | |
| if buf: | |
| out.append(''.join(buf)) | |
| return ' '.join(out) | |
| for t in toks: | |
| if t < len(VOCAB_TOKENS): | |
| tok = VOCAB_TOKENS[t] | |
| if tok == 'ID': | |
| out.append('mkid') | |
| elif tok == 'NUM': | |
| out.append('0') | |
| else: | |
| out.append(tok) | |
| else: | |
| out.append('mkid') | |
| return ' '.join(out) | |
| def load_weights(path): | |
| weights = {} | |
| with open(path) as f: | |
| for line in f: | |
| line = line.strip() | |
| if not line.startswith('[v='): | |
| continue | |
| rb = line.find(']') | |
| if rb < 0: | |
| continue | |
| name = line[1:rb].strip() | |
| body = line[rb+1:].strip() | |
| nums = [] | |
| for x in body.split(','): | |
| x = x.strip() | |
| if not x: continue | |
| try: nums.append(int(round(float(x) / 1000.0))) | |
| except ValueError: pass | |
| weights[name] = np.array(nums, dtype=np.int32) | |
| return weights | |
| def load_tensors(path): | |
| info = read_header(path) | |
| scale = info.get('scale', 1000) | |
| tensors = {} | |
| with open(path) as f: | |
| for line in f: | |
| line = line.strip() | |
| if not line.startswith('['): | |
| continue | |
| rb = line.find(']') | |
| if rb < 0: | |
| continue | |
| name = line[1:rb].strip() | |
| body = line[rb+1:].strip() | |
| shape = [] | |
| si = body.find('shape=[') | |
| if si >= 0: | |
| si += len('shape=[') | |
| ei = body.find(']', si) | |
| shape = [int(x) for x in body[si:ei].split(',') if x.strip()] | |
| body = body[ei+1:] | |
| nums = [float(x) for x in body.split(',') if x.strip()] | |
| arr = np.array(nums, dtype=np.float32) / scale | |
| if shape: | |
| arr = arr.reshape(shape) | |
| tensors[name] = arr | |
| return info, tensors | |
| def m3_forward(tensors, info, x, pad_mask=None, read_pos=None): | |
| """Forward a batch (B, K) token ids -> logits (B, V). | |
| pad_mask: (B, K) float, 1=real token, 0=padding. Padding positions are | |
| zeroed in the embedding and masked out of attention. | |
| read_pos: int or None. If None, reads logits at position K-1. | |
| Otherwise reads logits at the given absolute position. | |
| """ | |
| K, D = info['k'], info['d'] | |
| H = info['h'] | |
| HEAD = info.get('head', D // H) | |
| V = info['vocab'] | |
| L = info.get('layers', 1) | |
| B = x.shape[0] | |
| E_tok = tensors['E_tok'] | |
| E_pos = tensors['E_pos'] | |
| X = E_tok[x] + E_pos[np.arange(K)] | |
| if pad_mask is not None: | |
| X = X * pad_mask[:, :, None] | |
| cur = X | |
| mask = np.triu(np.ones((K, K), dtype=bool), k=1) | |
| key_pad_mask = None | |
| if pad_mask is not None: | |
| key_pad_mask = (pad_mask == 0)[:, None, None, :] # (B,1,1,K) | |
| for li in range(L): | |
| if L == 1: | |
| Wq, Wk, Wv, Wo = tensors['Wq'], tensors['Wk'], tensors['Wv'], tensors['Wo'] | |
| W1, b1, W2, b2 = tensors['W1'], tensors['b1'], tensors['W2'], tensors['b2'] | |
| else: | |
| Wq = tensors[f'{li}:Wq']; Wk = tensors[f'{li}:Wk'] | |
| Wv = tensors[f'{li}:Wv']; Wo = tensors[f'{li}:Wo'] | |
| W1 = tensors[f'{li}:W1']; b1 = tensors[f'{li}:b1'] | |
| W2 = tensors[f'{li}:W2']; b2 = tensors[f'{li}:b2'] | |
| Q = cur @ Wq | |
| K_ = cur @ Wk | |
| V_ = cur @ Wv | |
| q = Q.reshape(B, K, H, HEAD).transpose(0, 2, 1, 3) | |
| k = K_.reshape(B, K, H, HEAD).transpose(0, 2, 1, 3) | |
| v = V_.reshape(B, K, H, HEAD).transpose(0, 2, 1, 3) | |
| scores = q @ k.transpose(0, 1, 3, 2) / np.sqrt(HEAD) | |
| scores = scores + np.where(mask, -1e9, 0.0) | |
| if key_pad_mask is not None: | |
| scores = scores + np.where(key_pad_mask, -1e9, 0.0) | |
| attn = np.exp(scores - scores.max(axis=-1, keepdims=True)) | |
| attn = attn / attn.sum(axis=-1, keepdims=True) | |
| ctx = attn @ v | |
| ctx = ctx.transpose(0, 2, 1, 3).reshape(B, K, D) | |
| attn_out = cur + ctx @ Wo | |
| h1 = np.tanh(attn_out @ W1 + b1) | |
| h2 = h1 @ W2 + b2 | |
| cur = attn_out + h2 | |
| pos = K - 1 if read_pos is None else read_pos | |
| last_y = cur[:, pos, :] | |
| logits = last_y @ tensors['Wout'] + tensors['bout'] | |
| return logits | |
| def predict_m3(tensors, info, window, temperature=None, rng=None, pad_mask=None, read_pos=None): | |
| K = info['k'] | |
| x = np.array(window[-K:], dtype=np.int64).reshape(1, K) | |
| logits = m3_forward(tensors, info, x, pad_mask, read_pos)[0] | |
| if temperature: | |
| logits = logits / temperature | |
| logits = logits - logits.max() | |
| exp = np.exp(logits) | |
| probs = exp / exp.sum() | |
| if rng is None: | |
| rng = np.random.default_rng() | |
| return int(rng.choice(len(probs), p=probs)) | |
| return int(np.argmax(logits)) | |
| def gen_tokens(prompt, weights_path, max_tokens=80, temperature=None, codec=None, | |
| seed=None): | |
| """Generate token ids + source for a prompt. | |
| Transformer path uses a left-aligned real-token window with right-padding | |
| and a mask, so short prompts stay in-distribution (padding is zeroed and | |
| masked out of attention). The mask/read_pos are tracked across steps. | |
| seed: RNG seed for temperature sampling (None -> deterministic greedy). | |
| """ | |
| info = read_header(weights_path) | |
| K = info.get('k', 8) | |
| is_transformer = info.get('arch') == 'transformer' | |
| if is_transformer: | |
| _, tensors = load_tensors(weights_path) | |
| rng = np.random.default_rng(seed if seed is not None else 1) | |
| else: | |
| W_dict = load_weights(weights_path) | |
| arr_dict = {int(k_.split('=', 1)[1]): v_ for k_, v_ in W_dict.items() if k_.startswith('v=')} | |
| if not arr_dict: | |
| return [], '' | |
| V_ = max(arr_dict.keys()) + 1 | |
| row0 = arr_dict[0] | |
| W_arr = np.zeros((V_, row0.shape[0]), dtype=np.int32) | |
| for v, arr in arr_dict.items(): | |
| W_arr[v, :arr.shape[0]] = arr[:row0.shape[0]] | |
| toks = tokenize(prompt, codec) | |
| ID_IDX = codec['token_to_id']['ID'] if codec else VOCAB_TOKENS.index('ID') | |
| T_OPEN, T_CLOSE, T_LPAR, T_RPAR = ( | |
| VOCAB_TOKENS.index('{'), VOCAB_TOKENS.index('}'), | |
| VOCAB_TOKENS.index('('), VOCAB_TOKENS.index(')'), | |
| ) | |
| n_tokens = info['vocab'] if is_transformer else V_ | |
| def scores_fn(buf, temp): | |
| """Return logits over vocab for the next token after buf.""" | |
| if is_transformer: | |
| if len(buf) >= K: | |
| window = buf[-K:] | |
| pad_mask = np.ones((1, K), dtype=np.float32) | |
| read_pos = K - 1 | |
| else: | |
| window = buf + [ID_IDX] * (K - len(buf)) | |
| pad_mask = np.zeros((1, K), dtype=np.float32) | |
| pad_mask[0, :len(buf)] = 1.0 | |
| read_pos = len(buf) - 1 | |
| x = np.array(window, dtype=np.int64).reshape(1, K) | |
| return m3_forward(tensors, info, x, pad_mask, read_pos)[0] | |
| # linear path: right-align last K real tokens (legacy behaviour) | |
| window = buf[-K:] | |
| KV = V_ * K | |
| feat = np.zeros(KV, dtype=np.float32) | |
| for j, t in enumerate(window): | |
| if 0 <= t < V_: | |
| feat[j * V_ + t] = 1.0 | |
| logits = (feat @ W_arr[:, :KV].T + W_arr[:, KV]).astype(np.float64) | |
| return logits | |
| def pick(logits, temp, allowed): | |
| if temp: | |
| lp = logits / temp | |
| lp = lp - lp.max() | |
| exp = np.exp(lp) | |
| probs = exp / exp.sum() | |
| mask = np.full(probs.shape, -np.inf) | |
| mask[allowed] = np.log(probs[allowed] + 1e-9) | |
| mask = mask - mask.max() | |
| e = np.exp(mask) | |
| p = e / e.sum() | |
| return int(rng.choice(len(p), p=p)) | |
| best = -1 | |
| for a in allowed: | |
| if best < 0 or logits[a] > logits[best]: | |
| best = a | |
| return best | |
| generated = [] | |
| brace = 0 | |
| paren = 0 | |
| saw_open = False | |
| for t in toks: | |
| if t == T_OPEN: brace += 1; saw_open = True | |
| elif t == T_CLOSE: brace -= 1 | |
| elif t == T_LPAR: paren += 1 | |
| elif t == T_RPAR: paren -= 1 | |
| n_stmts = 0 | |
| buf = list(toks) | |
| for step in range(max_tokens): | |
| logits = scores_fn(buf, temperature) | |
| allowed = list(range(n_tokens)) | |
| if brace <= 0: | |
| allowed.remove(T_CLOSE) | |
| if paren <= 0: | |
| allowed.remove(T_RPAR) | |
| nxt = pick(logits, temperature, allowed) | |
| generated.append(nxt) | |
| buf.append(nxt) | |
| if nxt == T_OPEN: | |
| brace += 1; saw_open = True | |
| elif nxt == T_CLOSE: | |
| brace -= 1 | |
| elif nxt == T_LPAR: | |
| paren += 1 | |
| elif nxt == T_RPAR: | |
| paren -= 1 | |
| if len(generated) > 4 and brace == 0 and paren == 0: | |
| db = detokenize(buf, codec) | |
| if 'fn main' in db: | |
| idx = db.index('fn main') | |
| if db.find('}', idx) != -1: | |
| break | |
| return generated, detokenize(generated, codec) | |
| def run_via_kenga_lite(source, workdir='minds/_kenchat', timeout=60): | |
| os.makedirs(workdir, exist_ok=True) | |
| f = tempfile.NamedTemporaryFile(mode='w', suffix='.kenga', delete=False, | |
| dir=workdir, encoding='utf-8', newline='') | |
| f.write(source) | |
| f.close() | |
| try: | |
| result = subprocess.run( | |
| [K_LITE, 'run', f.name], | |
| capture_output=True, text=True, timeout=timeout, | |
| ) | |
| return result.returncode, result.stdout, result.stderr | |
| except subprocess.TimeoutExpired: | |
| return -1, '', 'timeout' | |
| except Exception as e: | |
| return -2, '', str(e) | |
| finally: | |
| os.unlink(f.name) | |
| def gen_verified(prompt, weights_path, codec=None, n_samples=16, max_tokens=200, | |
| temperature=1.0, want=None): | |
| """Self-consistency generation: sample n candidates, return the first that | |
| compiles, runs (rc==0) and, if want is given, prints the expected value. | |
| Falls back to the first runnable candidate (or last candidate) otherwise. | |
| Returns (tokens, src, full_program, rc, out, err). | |
| """ | |
| first_runnable = None | |
| last = None | |
| for i in range(n_samples): | |
| toks, src = gen_tokens(prompt, weights_path, max_tokens=max_tokens, | |
| temperature=temperature, codec=codec, seed=i) | |
| full = make_valid_program(prompt, src) | |
| rc, out, err = run_via_kenga_lite(full) | |
| last = (toks, src, full, rc, out, err) | |
| if rc == 0: | |
| if first_runnable is None: | |
| first_runnable = last | |
| if want is None: | |
| return last | |
| first = out.strip().split('\n')[0] if out else '' | |
| if first == want: | |
| return last | |
| return first_runnable if first_runnable is not None else last | |
| PROBES = [ | |
| ("fn add", "5", {'a', 'b'}), | |
| ("fn sub", "7", {'a', 'b'}), | |
| ("fn mul", "42", {'a', 'b'}), | |
| ("fn fact", "120", {'n'}), | |
| ("fn fib", "21", {'n'}), | |
| ("fn max", "7", {'a', 'b'}), | |
| ("fn sqr", "81", {'x'}), | |
| ("fn pow", "1024", {'a', 'b'}), | |
| ("fn sumto", "55", {'n'}), | |
| ] | |
| def make_valid_program(prompt, generated_source): | |
| if (prompt and prompt[-1] not in ' \t\n' | |
| and generated_source and generated_source[0] not in ' \t\n('): | |
| src = prompt + ' ' + generated_source | |
| else: | |
| src = prompt + generated_source | |
| if 'fn main' not in src: | |
| src = src + '\nfn main() -> i64 { println(0); return 0; }\n' | |
| else: | |
| src = src + '\n' | |
| return src | |
| def declared_params(src): | |
| """Extract declared param identifiers of the FIRST fn in src (set).""" | |
| m = re.search(r'fn\s+\w+\s*\(([^)]*)\)', src) | |
| if not m: | |
| return None | |
| params = set() | |
| for chunk in m.group(1).split(','): | |
| chunk = chunk.strip() | |
| mm = re.match(r'([a-zA-Z_]\w*)\s*:', chunk) | |
| if mm: | |
| params.add(mm.group(1)) | |
| return params | |
| def main(): | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument('prompt', nargs='?', help='generate from prompt') | |
| ap.add_argument('--probe', action='store_true', help='run all 9 probes') | |
| ap.add_argument('--model', default='v01', | |
| help='v01 (K=8), k16 (K=16), m3 (K=32), m31 (K=64 L=2), ' | |
| 'm32 (K=64 L=2, 64-token codec), ' | |
| 'm33 (K=64 L=2, 64-token codec, seeds-in-train), ' | |
| 'm34 (K=64 L=2, 64-token codec, seeds-in-train x20), ' | |
| 'm35 (K=64 L=2, 64-token codec, seeds-dominate x300)') | |
| ap.add_argument('--max-tokens', type=int, default=80) | |
| ap.add_argument('--temperature', type=float, default=None, | |
| help='sample with temperature (default: greedy argmax)') | |
| ap.add_argument('--verify', type=int, default=0, | |
| help='self-consistency: sample N candidates, pick first that runs (rc==0)') | |
| args = ap.parse_args() | |
| codec = None | |
| if args.model == 'v01': | |
| weights_path = 'minds/mid_prophet_m2_big_w.txt' | |
| label = 'kenga-prophet m2 v0.1 K=8' | |
| elif args.model == 'k16': | |
| weights_path = 'minds/mid_prophet_m2_k16_w.txt' | |
| label = 'kenga-prophet m2.1 K=16' | |
| elif args.model == 'm3': | |
| weights_path = 'minds/mid_prophet_m3_w.txt' | |
| label = 'kenga-prophet m3 transformer K=32' | |
| elif args.model == 'm31': | |
| weights_path = 'minds/mid_prophet_m31_w.txt' | |
| label = 'kenga-prophet m3.1 transformer K=64 D=48 L=2' | |
| elif args.model == 'm32': | |
| weights_path = 'minds/mid_prophet_m32_w.txt' | |
| label = 'kenga-prophet m3.2 transformer K=64 D=48 L=2 (64-token codec)' | |
| codec = load_codec_vocab() | |
| elif args.model == 'm33': | |
| weights_path = 'minds/mid_prophet_m33_w.txt' | |
| label = 'kenga-prophet m3.3 transformer K=64 D=48 L=2 (64-token codec, seeds-in-train)' | |
| codec = load_codec_vocab() | |
| elif args.model == 'm34': | |
| weights_path = 'minds/mid_prophet_m34_w.txt' | |
| label = 'kenga-prophet m3.4 transformer K=64 D=48 L=2 (64-token codec, seeds-in-train x20)' | |
| codec = load_codec_vocab() | |
| elif args.model == 'm35': | |
| weights_path = 'minds/mid_prophet_m35_w.txt' | |
| label = 'kenga-prophet m3.5 transformer K=64 D=48 L=2 (64-token codec, seeds-dominate x300)' | |
| codec = load_codec_vocab() | |
| elif args.model == 'm36': | |
| weights_path = 'minds/mid_prophet_m36_w.txt' | |
| label = 'kenga-prophet m3.6 transformer K=64 D=48 L=2 (64-token codec, per-position causal LM, seeds x300)' | |
| codec = load_codec_vocab() | |
| elif args.model == 'm37': | |
| weights_path = 'minds/mid_prophet_m37_w.txt' | |
| label = 'kenga-prophet m3.7 transformer K=64 D=48 L=2 (73-token digit codec, per-position causal LM, seeds x300)' | |
| codec = load_codec_vocab('minds/kenga_digits.pkl') | |
| elif args.model == 'm40': | |
| weights_path = 'minds/mid_prophet_m40_w.txt' | |
| label = 'kenga-prophet m4.0 transformer K=64 D=128 H=8 L=6 (128-token full codec, 830K params, full corpus incl big)' | |
| codec = load_codec_vocab('minds/kenga_full.pkl') | |
| elif args.model == 'm41': | |
| weights_path = 'minds/mid_prophet_m41_w.txt' | |
| label = 'kenga-prophet m4.1 transformer K=64 D=128 H=8 L=6 (128-token full codec, seeds x30, real code dominant)' | |
| codec = load_codec_vocab('minds/kenga_full.pkl') | |
| elif args.model == 'm42': | |
| weights_path = 'minds/mid_prophet_m42_w.txt' | |
| label = 'kenga-prophet m4.2 transformer K=128 D=128 H=8 L=6 (128-token full codec, 838K params, seeds x30)' | |
| codec = load_codec_vocab('minds/kenga_full.pkl') | |
| else: | |
| print('unknown model', file=sys.stderr); sys.exit(1) | |
| print(f'using model: {label}') | |
| if args.prompt: | |
| toks, src = gen_tokens(args.prompt, weights_path, args.max_tokens, | |
| args.temperature, codec) | |
| full = make_valid_program(args.prompt, src) | |
| print('=== generated program ===') | |
| print(full) | |
| rc, out, err = run_via_kenga_lite(full) | |
| print(f'=== run rc={rc} ===') | |
| if out: print('stdout:', out.strip()[:200]) | |
| if err: print('stderr:', err.strip()[:200]) | |
| return 0 | |
| if not args.probe and not args.prompt: | |
| ap.print_help(); return 1 | |
| print('=== program-validity probe (kenga-lite driven) ===') | |
| n_compile = 0; n_run = 0; n_correct = 0; n_recover = 0 | |
| for prompt, want, exp_ids in PROBES: | |
| if args.verify: | |
| _, src, full, rc, out, err = gen_verified( | |
| prompt, weights_path, codec, n_samples=args.verify, | |
| max_tokens=args.max_tokens, temperature=1.0, want=want) | |
| else: | |
| _, src = gen_tokens(prompt, weights_path, args.max_tokens, | |
| args.temperature, codec) | |
| full = make_valid_program(prompt, src) | |
| rc, out, err = run_via_kenga_lite(full) | |
| first = out.strip().split('\n')[0] if out else '' | |
| ok_compile = rc in (0, 2) | |
| ok_run = rc == 0 | |
| ok_value = first == want | |
| declared = declared_params(src) | |
| ok_recover = declared is not None and declared == exp_ids | |
| print(f'prompt={prompt!r:12s} want={want:>5} rc={rc:<3} out={first[:20]:<20} compile={ok_compile} run={ok_run} match={ok_value} ids={sorted(declared) if declared else None} recover={ok_recover}') | |
| if ok_compile: n_compile += 1 | |
| if ok_run: n_run += 1 | |
| if ok_value: n_correct += 1 | |
| if ok_recover: n_recover += 1 | |
| total = len(PROBES) | |
| print() | |
| sys.stdout.write('compile-ok: ' + str(n_compile) + '/' + str(total) + ' = %.1f%%\n' % (n_compile*100/total)) | |
| sys.stdout.write('run-ok: ' + str(n_run) + '/' + str(total) + ' = %.1f%%\n' % (n_run*100/total)) | |
| sys.stdout.write('match value: ' + str(n_correct) + '/' + str(total) + ' = %.1f%%\n' % (n_correct*100/total)) | |
| sys.stdout.write('id-recovery: ' + str(n_recover) + '/' + str(total) + ' = %.1f%%\n' % (n_recover*100/total)) | |
| sys.stdout.flush() | |
| return 0 | |
| if __name__ == '__main__': | |
| sys.exit(main()) |