Skip to content

Commit 95a9ec1

Browse files
v3.46-trained: add train_v346.py and AMS_TRAINED_WEIGHTS loader hook
Per SPRINT_CLOSEOUT_v3.46.md \u00a75.3/\u00a75.4 and \u00a75 loader note. train_v346.py - Copies the v344 driver template, points to scheme_b_v344 (= v3.46 SUT). - Asserts v3.46 Cfg invariants (use_top1_exclusive_content_bias=False, tail_slot_residual_dominant=False). - Requires CUDA by default; AMS_ALLOW_CPU_TRAIN=1 to override. - Logs pre/post "mechanism-level observable" probes per \u00a75.6: tail_head.slot_heads[1][0].weight.abs().mean and vocab_proj.proj[-1].weight.abs().mean. - Saves non-backbone state_dict + non-backbone buffers to ckpt/v346_trained.pt with provenance + Cfg snapshot. scheme_b_v344.MemLLM._maybe_load_trained_weights - New hook called at end of load(); opt-in via AMS_TRAINED_WEIGHTS env. - Loads non-backbone tensors into matching params/buffers; backbone excluded. - Strict shape check: raises on mismatch (protects against loading the v344/v348 ckpts per \u00a76 warning about shape incompatibility). Co-authored-by: FluffyAIcode <FluffyAIcode@users.noreply.github.com>
1 parent 52b9478 commit 95a9ec1

2 files changed

Lines changed: 211 additions & 0 deletions

File tree

scheme_b_v344.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2494,8 +2494,62 @@ def _capture_query_ids(module, args):
24942494
self.backbone.register_forward_pre_hook(_capture_query_ids)
24952495
self._build_wte_neighbor_cache()
24962496
self._compute_filler_centroid()
2497+
self._maybe_load_trained_weights()
24972498
return self
24982499

2500+
def _maybe_load_trained_weights(self):
2501+
"""Optional hook: if env AMS_TRAINED_WEIGHTS points to a checkpoint written by
2502+
train_v346.py (or any sibling trainer), load non-backbone params/buffers with
2503+
strict=False. Backbone is intentionally excluded — trainer only saves trainables
2504+
+ non-backbone buffers (see train_v346.py §5.3). Missing/unexpected keys are
2505+
logged but not fatal, so a partial-shape ckpt fails loud only on shape mismatch.
2506+
"""
2507+
path = os.environ.get("AMS_TRAINED_WEIGHTS", "").strip()
2508+
if not path: return
2509+
if not os.path.exists(path):
2510+
print(f" [AMS_TRAINED_WEIGHTS] file not found: {path} — skipping")
2511+
return
2512+
try:
2513+
blob = torch.load(path, map_location="cpu", weights_only=False)
2514+
except Exception as e:
2515+
print(f" [AMS_TRAINED_WEIGHTS] torch.load failed: {type(e).__name__}: {e}")
2516+
return
2517+
sd = blob.get("state_dict", blob) if isinstance(blob, dict) else blob
2518+
if not isinstance(sd, dict):
2519+
print(f" [AMS_TRAINED_WEIGHTS] unexpected format (no 'state_dict' mapping) — skipping")
2520+
return
2521+
dev = next(self.parameters()).device
2522+
own_params = dict(self.named_parameters())
2523+
own_buffers = dict(self.named_buffers())
2524+
loaded, skipped = 0, 0
2525+
shape_errs = []
2526+
with torch.no_grad():
2527+
for n, t in sd.items():
2528+
if n.startswith("backbone"): skipped += 1; continue
2529+
if n in own_params:
2530+
p = own_params[n]
2531+
if p.shape != t.shape:
2532+
shape_errs.append((n, tuple(p.shape), tuple(t.shape))); continue
2533+
p.data.copy_(t.to(dev, dtype=p.dtype))
2534+
loaded += 1
2535+
elif n in own_buffers:
2536+
b = own_buffers[n]
2537+
if b.shape != t.shape:
2538+
shape_errs.append((n, tuple(b.shape), tuple(t.shape))); continue
2539+
b.data.copy_(t.to(dev, dtype=b.dtype))
2540+
loaded += 1
2541+
else:
2542+
skipped += 1
2543+
prov = blob.get("provenance", "?") if isinstance(blob, dict) else "?"
2544+
print(f" [AMS_TRAINED_WEIGHTS] loaded={loaded} skipped={skipped} "
2545+
f"shape_errs={len(shape_errs)} path={path} provenance={prov}")
2546+
if shape_errs:
2547+
for n, s_model, s_ckpt in shape_errs[:5]:
2548+
print(f" ! shape mismatch {n}: model={s_model} ckpt={s_ckpt}")
2549+
raise RuntimeError(
2550+
f"AMS_TRAINED_WEIGHTS shape mismatch on {len(shape_errs)} tensor(s); "
2551+
f"ckpt not compatible with current SUT shapes")
2552+
24992553
def _compute_filler_centroid(self):
25002554
if self.content_classifier is None or self.backbone is None:
25012555
self._filler_centroid = None; return

train_v346.py

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
#!/usr/bin/env python3
2+
"""Training driver for v3.46-trained.
3+
4+
Starts from v346-revertE-topk-nonexclusive-7e97 SUT (attention-pool ctx encoder,
5+
cluster-crowding retrieval, refresh-on-write, additive tail residual,
6+
top1-exclusive OFF, cond-buffer mirror). Runs N Trainer.step iterations
7+
over a rotating corpus; saves non-backbone state_dict to ckpt/v346_trained.pt.
8+
9+
Per SPRINT_CLOSEOUT_v3.46.md §5.3 / §5.4.
10+
"""
11+
import argparse, os, time, json, math, sys
12+
import torch
13+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
14+
import scheme_b_v344 as sb
15+
16+
MUSIC = [
17+
"He practiced piano for hours perfecting a difficult Chopin nocturne.",
18+
"She studied music theory and harmonic progression at the conservatory.",
19+
"The orchestra performed Beethoven symphony with remarkable precision.",
20+
]
21+
SPACE = [
22+
"The telescope revealed distant galaxies beyond the Milky Way.",
23+
"Astronauts trained for the Mars mission in simulated zero gravity.",
24+
"The nebula emitted radiation across the electromagnetic spectrum.",
25+
]
26+
GENERIC = [
27+
"The pianist practiced arpeggios and Chopin nocturnes until midnight.",
28+
"A musician refined finger technique, phrasing, and pedal control.",
29+
"Classical interpretation often depends on dynamics, tempo rubato, and touch.",
30+
"A conservatory student studied etudes, scales, and expressive keyboard skills.",
31+
"Distant astronomers observed galaxies quasars and stellar evolution.",
32+
"Space orbital mechanics explains satellites and planetary motion.",
33+
]
34+
ALL = MUSIC + SPACE + GENERIC
35+
36+
37+
def main():
38+
ap = argparse.ArgumentParser()
39+
ap.add_argument("--steps", type=int, default=60)
40+
ap.add_argument("--batch", type=int, default=3)
41+
ap.add_argument("--out", type=str, default="ckpt/v346_trained.pt")
42+
ap.add_argument("--seed", type=int, default=42)
43+
ap.add_argument("--log", type=str, default="ckpt/v346_train_log.jsonl")
44+
args = ap.parse_args()
45+
46+
os.makedirs(os.path.dirname(args.out) or ".", exist_ok=True)
47+
log_dir = os.path.dirname(args.log) or "."
48+
os.makedirs(log_dir, exist_ok=True)
49+
torch.manual_seed(args.seed)
50+
51+
c = sb.Cfg()
52+
# Sanity: confirm v3.46 Cfg (same assert as §8 step 3, catches env corruption)
53+
assert c.use_top1_exclusive_content_bias is False, \
54+
"Cfg.use_top1_exclusive_content_bias must be False on v3.46"
55+
assert c.tail_slot_residual_dominant is False, \
56+
"Cfg.tail_slot_residual_dominant must be False on v3.46 (revert [B])"
57+
58+
m = sb.MemLLM(c)
59+
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
60+
if device.type != "cuda":
61+
if os.environ.get("AMS_ALLOW_CPU_TRAIN", "0") != "1":
62+
raise AssertionError(
63+
"train_v346 expects CUDA; CPU fallback is ~10x slower and not the intent. "
64+
"Set AMS_ALLOW_CPU_TRAIN=1 to override explicitly.")
65+
print("[build] WARNING: running on CPU (AMS_ALLOW_CPU_TRAIN=1)")
66+
m.to(device); m.load(); m.to(device)
67+
trainable = sum(p.numel() for p in m.parameters() if p.requires_grad)
68+
total = sum(p.numel() for p in m.parameters())
69+
print(f"[build] device={device} params total={total:,} trainable={trainable:,}")
70+
71+
for t in ALL:
72+
m.write(t, training_mode=True)
73+
try:
74+
m.amm.maybe_recluster(force=True)
75+
except Exception as e:
76+
print(f"[build] amm.maybe_recluster skipped: {type(e).__name__}: {e}")
77+
m._refresh_rare_keyword_indices()
78+
m.eval()
79+
print(f"[build] initial memory count = {len(m.amm.tree.store)}")
80+
81+
# Pre-training mechanism snapshot (per §5.6): tail_head[1] + vocab_proj last weights
82+
def _probe_weights(model):
83+
out = {}
84+
try:
85+
w = model.bridge.tail_head.slot_heads[1][0].weight
86+
out["tail_head_slot1_abs_mean"] = float(w.detach().abs().mean())
87+
except Exception as e:
88+
out["tail_head_slot1_abs_mean"] = f"ERR {type(e).__name__}"
89+
try:
90+
w = model.vocab_proj.proj[-1].weight
91+
out["vocab_proj_last_abs_mean"] = float(w.detach().abs().mean())
92+
except Exception as e:
93+
out["vocab_proj_last_abs_mean"] = f"ERR {type(e).__name__}"
94+
return out
95+
pre_probe = _probe_weights(m)
96+
print(f"[probe pre-train] {pre_probe}")
97+
98+
trainer = sb.Trainer(m, c)
99+
print(f"[train] Trainer built batch={args.batch} steps={args.steps}")
100+
101+
t_start = time.time()
102+
with open(args.log, "w") as flog:
103+
for step in range(args.steps):
104+
start = (step * args.batch) % len(ALL)
105+
batch = [ALL[(start + i) % len(ALL)] for i in range(args.batch)]
106+
t0 = time.time()
107+
try:
108+
stats = trainer.step(batch)
109+
except Exception as e:
110+
print(f"[step {step}] EXCEPTION: {type(e).__name__}: {e}")
111+
raise
112+
dt = time.time() - t0
113+
tot = stats.get("total")
114+
print(
115+
f"step {step:3d} total={tot:.4f} "
116+
f"recon={stats.get('recon', 0):.3f} "
117+
f"sa={stats.get('semantic_alignment', 0):.3f} "
118+
f"tsa={stats.get('tail_semantic_anchor', 0):.3f} "
119+
f"va={stats.get('vocab_anchor', 0):.3f} "
120+
f"fs={stats.get('functional_suppression', 0):.3f} "
121+
f"cs={stats.get('context_separation', 0):.3f} "
122+
f"dt={dt:.1f}s"
123+
)
124+
rec = {"step": step, "dt_s": dt,
125+
**{k: v for k, v in stats.items()
126+
if k not in ("grad_norms", "loss_weights")}}
127+
flog.write(json.dumps(rec, ensure_ascii=False) + "\n")
128+
flog.flush()
129+
elapsed = time.time() - t_start
130+
post_probe = _probe_weights(m)
131+
print(f"[probe post-train] {post_probe}")
132+
print(f"[train] elapsed {elapsed:.1f}s avg/step={elapsed/max(1,args.steps):.2f}s")
133+
134+
sd = {n: p.detach().cpu() for n, p in m.named_parameters() if "backbone" not in n}
135+
for n, b in m.named_buffers():
136+
if "backbone" not in n:
137+
sd[n] = b.detach().cpu()
138+
torch.save({
139+
"state_dict": sd,
140+
"cfg_snapshot": {k: getattr(c, k) for k in (
141+
"L_mem", "d_ctx", "d_M", "d_F", "cfg_scale",
142+
"use_top1_exclusive_content_bias",
143+
"tail_slot_residual_dominant",
144+
"use_inter_domain_margin",
145+
"context_encoder_use_attention_pool",
146+
)},
147+
"provenance": "AgentMemory/v346-revertE-topk-nonexclusive-7e97",
148+
"steps": args.steps,
149+
"elapsed_s": elapsed,
150+
"pre_probe": pre_probe,
151+
"post_probe": post_probe,
152+
}, args.out)
153+
print(f"[save] wrote {args.out} tensors={len(sd)}")
154+
155+
156+
if __name__ == "__main__":
157+
main()

0 commit comments

Comments
 (0)