Download scripts/audit_recursive_native_lineage.py from LIghtJUNction/LightNest: direct link, hf CLI and curl.
- Browser
- Download file 15 kB
-
https://huggingface.co/LIghtJUNction/LightNest/resolve/main/scripts/audit_recursive_native_lineage.py
- Command line
-
hf download hf://LIghtJUNction/LightNest/scripts/audit_recursive_native_lineage.py
-
curl -L -o audit_recursive_native_lineage.py https://huggingface.co/LIghtJUNction/LightNest/resolve/main/scripts/audit_recursive_native_lineage.py
15 kB
| """Controlled recursive native lineage audit, not an on-policy learning recipe.""" | |
| import copy | |
| import hashlib | |
| import json | |
| import os | |
| from pathlib import Path | |
| import random | |
| import resource | |
| import subprocess | |
| import time | |
| import torch | |
| from lightnest.learned_patch import encode, load_predictor | |
| from lightnest.pack_feedback import build, SCHEMA | |
| from lightnest.train_patch_rl import evaluate, execution_reward, apply_action, passes | |
| from lightnest.train_robust_patch_rl import make_task | |
| from lightnest import rv32 | |
| ROOT = Path(__file__).resolve().parents[1] | |
| OUT = ROOT / "work/recursive-lineage-reproduction" | |
| HEADS = ('pointer.', 'none.', 'replacement.') | |
| CHECKPOINT = ROOT / 'work/patch-rl-v2/patch-rl.pt' | |
| def digest(path): | |
| return hashlib.sha256(Path(path).read_bytes()).hexdigest() | |
| def write(name, obj): | |
| (OUT / name).write_text(json.dumps(obj, indent=2, sort_keys=True) + '\n') | |
| def invoke(exe, *args): | |
| result = subprocess.run([str(exe), *map(str, args)], capture_output=True, timeout=15) | |
| if result.returncode: | |
| raise RuntimeError(result.stderr.decode()) | |
| return result.stdout | |
| def decode(blob, model): | |
| assert blob[:8] == b'LNPATCH1' and len(blob) == 32 + 4 * 107994 | |
| values = torch.frombuffer(bytearray(blob[32:]), dtype=torch.float32) | |
| state, offset = {}, 0 | |
| for name in SCHEMA: | |
| value = model.state_dict()[name] | |
| state[name] = values[offset:offset + value.numel()].reshape(value.shape).clone() | |
| offset += value.numel() | |
| assert offset == values.numel() | |
| return state | |
| def logits(model, task): | |
| c, b = encode(task.command, task.binary) | |
| return model(torch.tensor([c]), torch.tensor([b])) | |
| def greedy(model, task): | |
| with torch.no_grad(): | |
| scores, bits = logits(model, task) | |
| pos = int(scores.argmax(-1)[0]) | |
| byte = 0 if pos == 256 else sum(int(x >= 0) << i for i, x in enumerate(bits[0, pos])) | |
| return pos, byte | |
| def reference_step(model, task, pos, byte, reward, lr): | |
| model.zero_grad(set_to_none=True) | |
| scores, bits = logits(model, task) | |
| logp = scores.log_softmax(-1)[0, pos] | |
| if pos != 256: | |
| target = torch.tensor([(byte >> i) & 1 for i in range(8)], dtype=torch.bool) | |
| logp = logp + torch.where(target, torch.nn.functional.logsigmoid(bits[0, pos]), torch.nn.functional.logsigmoid(-bits[0, pos])).sum() | |
| logp.backward() | |
| with torch.no_grad(): | |
| if reward != 0: | |
| for name, parameter in model.named_parameters(): | |
| if name.startswith(HEADS) and parameter.grad is not None: | |
| parameter.add_((lr * reward * parameter.grad).clamp(-.1, .1)).clamp_(-16, 16) | |
| return float(logp.detach()) | |
| def detailed(model, frozen): | |
| rows = [] | |
| for family, entries in frozen.items(): | |
| for index, (task, cases) in enumerate(entries): | |
| with torch.no_grad(): | |
| scores, bits = logits(model, task) | |
| probabilities = scores.softmax(-1)[0] | |
| pos = int(probabilities.argmax()) | |
| byte = 0 | |
| confidence = float(probabilities[pos]) | |
| if pos != 256: | |
| bp = bits[0, pos].sigmoid() | |
| byte = sum(int(x >= .5) << i for i, x in enumerate(bp)) | |
| confidence = min(confidence, float(torch.maximum(bp, 1-bp).min())) | |
| gated = 256 if pos == 256 or confidence < .55 or byte == task.binary[pos] else pos | |
| raw_binary = apply_action(task.binary, pos, byte) | |
| gated_binary = apply_action(task.binary, gated, byte) | |
| rows.append(dict(family=family, index=index, position=pos, byte=byte, confidence=confidence, gated_position=gated, | |
| raw_success=passes(raw_binary, cases), gated_success=passes(gated_binary, cases), | |
| expected=[y for _, y in cases], raw_outputs=[rv32.simulate(raw_binary, xs) for xs, _ in cases], gated_outputs=[rv32.simulate(gated_binary, xs) for xs, _ in cases])) | |
| return rows | |
| def run(): | |
| OUT.mkdir(parents=True, exist_ok=True) | |
| if any(OUT.iterdir()): | |
| raise RuntimeError('Refusing to overwrite a frozen run') | |
| resource.setrlimit(resource.RLIMIT_CPU, (110, 120)) | |
| torch.set_num_threads(2) | |
| torch.set_num_interop_threads(2) | |
| torch.manual_seed(771249) | |
| started = time.monotonic() | |
| rng = random.Random(771249) | |
| erng = random.Random(771250) | |
| frozen = {family: [make_task(erng, family, True) for _ in range(32)] for family in ('simple', 'already_correct', 'negation', 'keep')} | |
| serial = {family: [dict(command=t.command, binary_hex=t.binary.hex(), cases=c) for t, c in rows] for family, rows in frozen.items()} | |
| write('frozen-cases.json', serial) | |
| # Fix all contexts/action rules before evaluating or updating any model. | |
| schedule = [] | |
| for cycle in range(8): | |
| for family, rule in [('already_correct', 'none'), ('simple', 'none'), ('simple', 'greedy'), ('simple', 'zero_first_byte')]: | |
| task, cases = make_task(rng, family) | |
| schedule.append((task, cases, family, rule)) | |
| task, cases = make_task(rng, 'simple') | |
| schedule.append((task, cases, 'simple', 'zero_reward_identity')) | |
| write('training-contexts.json', [dict(command=t.command, binary_hex=t.binary.hex(), cases=c, family=f, action_rule=r) for t,c,f,r in schedule]) | |
| protocol = dict(seed=771249, evaluation_seed=771250, steps=33, learning_rate=.03, threads=2, | |
| cpu_budget_seconds=120, address_space_budget_gib=4, wall_budget_seconds=100, | |
| amendment='Initial 13-step pilot preserved separately; parent requested 24-64 steps before inspecting its findings. This33-step extension uses the same seeds and evaluation, so it is not a new independent efficacy trial.', | |
| hypothesis='Three or more successive native descendants preserve cumulative C/autograd gradient parity under mixed positive, negative, no-op and zero-reward updates.', | |
| checkpoint_sha256=digest(CHECKPOINT), frozen_sha256=digest(OUT/'frozen-cases.json'), contexts_sha256=digest(OUT/'training-contexts.json'), | |
| source_sha256=digest(ROOT/'linux/feedback_nest.c'), driver_sha256=digest(__file__), | |
| compile_policy='Exactly one initial build; every subsequent generation is invoked from its immediate parent executable, with no repacking or recompilation.', | |
| action_policy='Eight cycles: NONE on already-correct task; NONE on edit-needed task; current-native greedy action on edit-needed task; position 0 byte 0 on edit-needed task. Last transition applies zero reward to a greedy action.', | |
| reward='Independent arithmetic cases and RV32 simulator via execution_reward; last zero reward is an explicit mechanism control, not judged task reward.', | |
| reference='Independent cumulative Torch autograd initialized only once; never reset from native descendants.', | |
| selection='Initial and final only. No best-checkpoint selection. Frozen .55 gate and raw argmax.', | |
| evaluation='128 new cases, 32 per family, 12 arithmetic inputs each, test-only registers and held-out command templates. Existing generator is familiar; no broad novelty claim.', | |
| interpretation='Controlled off-policy score-gradient mechanism experiment, not an unbiased REINFORCE learning trial. Task success reported separately. Fixed architecture/trainer and frozen encoder; no autonomous bootstrap.') | |
| write('protocol.json', protocol) | |
| # Guard total address-space after torch startup (shared libraries consume VSZ). | |
| resource.setrlimit(resource.RLIMIT_AS, (4*1024**3, 4*1024**3)) | |
| model = load_predictor(CHECKPOINT).model.eval() | |
| reference = copy.deepcopy(model) | |
| initial_state = copy.deepcopy(model.state_dict()) | |
| baseline = evaluate(model, frozen) | |
| write('baseline.json', baseline) | |
| write('baseline-cases.json', detailed(model, frozen)) | |
| initial = build(CHECKPOINT, OUT/'policy-000') | |
| # Disallow another compiler/packer execution after initial construction. | |
| real_run = subprocess.run | |
| def guarded_run(argv, *args, **kwargs): | |
| assert str(argv[0]).startswith(str(OUT/'policy-')), 'Only emitted lineage executables permitted after initial build' | |
| return real_run(argv, *args, **kwargs) | |
| subprocess.run = guarded_run | |
| current = initial | |
| initial_hash = digest(initial) | |
| lineage = [] | |
| all_parents = {str(initial): initial_hash} | |
| for step, (task, cases, family, rule) in enumerate(schedule, 1): | |
| if time.monotonic() - started > 100: | |
| raise TimeoutError('Wall budget exceeded') | |
| parent_bytes = current.read_bytes() | |
| parent_blob = invoke(current, '--dump-weights') | |
| model.load_state_dict(decode(parent_blob, model)) | |
| if rule == 'none': | |
| pos, byte = 256, 0 | |
| elif rule == 'zero_first_byte': | |
| pos, byte = 0, 0 | |
| else: | |
| pos, byte = greedy(model, task) | |
| judged_reward = execution_reward(task.binary, pos, byte, cases) | |
| reward = 0.0 if rule == 'zero_reward_identity' else judged_reward | |
| reference_logp = reference_step(reference, task, pos, byte, reward, .03) | |
| window = OUT/f'window-{step:03d}.bin' | |
| window.write_bytes(task.binary) | |
| child = OUT/f'policy-{step:03d}' | |
| native = json.loads(invoke(current, '--feedback', task.command, window, pos, byte, reward, .03, '-o', child)) | |
| child_blob = invoke(child, '--dump-weights') | |
| actual = decode(child_blob, model) | |
| errors = {key: float((actual[key]-reference.state_dict()[key]).abs().max()) for key in SCHEMA} | |
| for key in SCHEMA: | |
| torch.testing.assert_close(actual[key], reference.state_dict()[key], atol=2e-6, rtol=3e-5) | |
| if not key.startswith(HEADS): | |
| assert torch.equal(actual[key], initial_state[key]) | |
| at = parent_bytes.index(parent_blob) | |
| child_bytes = child.read_bytes() | |
| assert parent_bytes.count(parent_blob) == 1 | |
| assert parent_bytes[:at] == child_bytes[:at] and parent_bytes[at+len(parent_blob):] == child_bytes[at+len(parent_blob):] | |
| assert current.read_bytes() == parent_bytes | |
| if reward == 0: | |
| assert child_bytes == parent_bytes | |
| assert abs(native['log_probability'] - reference_logp) < 2e-4 | |
| lineage.append(dict(step=step, parent=current.name, child=child.name, parent_sha256=digest(current), child_sha256=digest(child), | |
| parent_blob_sha256=hashlib.sha256(parent_blob).hexdigest(), child_blob_sha256=hashlib.sha256(child_blob).hexdigest(), | |
| family=family, action_rule=rule, position=pos, byte=byte, judged_reward=judged_reward, applied_reward=reward, | |
| native_log_probability=native['log_probability'], reference_log_probability=reference_logp, | |
| cumulative_max_weight_error=max(errors.values()), per_tensor_max_error=errors, | |
| changed_weight_floats=sum(int((actual[k] != model.state_dict()[k]).sum()) for k in SCHEMA), | |
| outside_blob_unchanged=True, parent_unchanged=True)) | |
| all_parents[str(child)] = digest(child) | |
| write('lineage.json', lineage) | |
| current = child | |
| model.load_state_dict(actual) | |
| final = evaluate(model, frozen) | |
| reference_final = evaluate(reference, frozen) | |
| write('reference-final.json', reference_final) | |
| native_rows = detailed(model, frozen) | |
| reference_rows = detailed(reference, frozen) | |
| write('reference-final-cases.json', reference_rows) | |
| decision_disagreements = sum(any(a[k] != b[k] for k in ('position','byte','gated_position','raw_success','gated_success')) for a,b in zip(native_rows, reference_rows)) | |
| write('final-cases.json', detailed(model, frozen)) | |
| # Native forward cross-check on every final held-out raw action; task judging remains independent. | |
| probe_errors = [] | |
| for family, entries in frozen.items(): | |
| for index, (task, _) in enumerate(entries): | |
| pos, byte = greedy(model, task) | |
| scores, bits = logits(model, task) | |
| logp = scores.log_softmax(-1)[0, pos] | |
| if pos != 256: | |
| target = torch.tensor([(byte >> i) & 1 for i in range(8)], dtype=torch.bool) | |
| logp = logp + torch.where(target, torch.nn.functional.logsigmoid(bits[0,pos]), torch.nn.functional.logsigmoid(-bits[0,pos])).sum() | |
| window = OUT/'eval-window.bin' | |
| window.write_bytes(task.binary) | |
| observed = json.loads(invoke(current, '--prob', task.command, window, pos, byte)) | |
| error = abs(float(logp.detach())-observed['log_probability']) | |
| assert error < 2e-4 | |
| probe_errors.append(dict(family=family,index=index,error=error)) | |
| write('native-heldout-parity.json', probe_errors) | |
| assert digest(CHECKPOINT) == protocol['checkpoint_sha256'] | |
| assert all(digest(p) == h for p,h in all_parents.items()) | |
| assert digest(OUT/'frozen-cases.json') == protocol['frozen_sha256'] | |
| report = dict(protocol=protocol, baseline=baseline, final=final, transitions=len(lineage), reference_final=reference_final, native_reference_decision_disagreements=decision_disagreements, compiler_calls=1, | |
| positive_rewards=sum(x['applied_reward']>0 for x in lineage), negative_rewards=sum(x['applied_reward']<0 for x in lineage), zero_rewards=sum(x['applied_reward']==0 for x in lineage), | |
| max_cumulative_weight_error=max(x['cumulative_max_weight_error'] for x in lineage), | |
| max_cumulative_log_probability_error=max(abs(x['native_log_probability']-x['reference_log_probability']) for x in lineage), | |
| max_heldout_native_log_probability_error=max(x['error'] for x in probe_errors), | |
| all_parent_executables_unchanged=True, source_checkpoint_unchanged=True, frozen_encoder_unchanged=True, | |
| initial_executable_sha256=initial_hash, final_executable_sha256=digest(current), | |
| elapsed_seconds=time.monotonic()-started, process_cpu_seconds=time.process_time(), peak_rss_kib=resource.getrusage(resource.RUSAGE_SELF).ru_maxrss, | |
| limitations=['Controlled actions are off-policy; no claim of unbiased REINFORCE.', 'Final zero-reward transition intentionally has identical bytes/hash despite being separately emitted.', 'External orchestration, reward and sampling/argmax remain required.', 'Fixed executable code and architecture, output-head changes only.', '128 finite generated cases are not correctness proof or broad generalization.']) | |
| write('report.json', report) | |
| manifest = {p.name:digest(p) for p in OUT.iterdir() if p.is_file() and p.name not in ('manifest.json','run.log')} | |
| write('manifest.json',manifest) | |
| print(json.dumps(report, indent=2), flush=True) | |
| return report | |
| if __name__ == '__main__': | |
| import argparse | |
| parser = argparse.ArgumentParser(description=__doc__) | |
| parser.add_argument('--output', type=Path, default=OUT) | |
| parser.add_argument('--checkpoint', type=Path, default=CHECKPOINT) | |
| args = parser.parse_args() | |
| OUT = args.output.resolve() | |
| CHECKPOINT = args.checkpoint.resolve() | |
| run() | |