summaryrefslogtreecommitdiff
path: root/ep_run/lt_ep_train.py
diff options
context:
space:
mode:
Diffstat (limited to 'ep_run/lt_ep_train.py')
-rw-r--r--ep_run/lt_ep_train.py46
1 files changed, 46 insertions, 0 deletions
diff --git a/ep_run/lt_ep_train.py b/ep_run/lt_ep_train.py
index 76bb9bb..0fd9180 100644
--- a/ep_run/lt_ep_train.py
+++ b/ep_run/lt_ep_train.py
@@ -137,6 +137,39 @@ class EQBlock:
return f
+def anderson_relax(blk, z, xin, budget, eps, m=5, tol=1e-6):
+ """Anderson acceleration (type-II, window m) for the free-phase fixed point g(z)=z+eps*F(z).
+ PURE-SPEED opt-in (--fastfp): z* is solver-independent, but the T1-residual acquires 'solved'
+ semantics (resreg fires less) — use for probes/sweeps/ladder, not for reg-ablation arms.
+ Safeguard: if the AA candidate's residual is worse than the plain step's, take the plain step."""
+ with torch.no_grad():
+ sh = z.shape
+ X, G = [], [] # iterate / g(iterate) histories, flattened
+ for k in range(budget):
+ f = eps * blk.force(z, xin).detach()
+ g = z + f
+ r = f.reshape(-1)
+ if r.norm() < tol * (z.norm() + 1e-12):
+ return g.detach(), k + 1
+ X.append(z.reshape(-1).clone()); G.append(g.reshape(-1).clone())
+ if len(X) > m + 1:
+ X.pop(0); G.pop(0)
+ if len(X) >= 2:
+ dR = torch.stack([(G[i + 1] - X[i + 1]) - (G[i] - X[i]) for i in range(len(X) - 1)], 1)
+ try:
+ al = torch.linalg.lstsq(dR, r.unsqueeze(1)).solution.squeeze(1)
+ dG = torch.stack([G[i + 1] - G[i] for i in range(len(X) - 1)], 1)
+ cand = (G[-1].unsqueeze(1) - dG @ al.unsqueeze(1)).squeeze(1).reshape(sh)
+ rc = (eps * blk.force(cand, xin)).norm()
+ if rc < r.norm(): # safeguarded acceptance
+ z = cand
+ continue
+ except Exception:
+ pass
+ z = g
+ return z.detach(), budget
+
+
def relax(blk, z, xin, steps, eps):
cstep = getattr(blk, '_cstep', None)
if cstep is not None and blk.fnoise == 0.0: # compiled pure-thick free-phase fast path
@@ -146,6 +179,15 @@ def relax(blk, z, xin, steps, eps):
return z.detach()
blk._sdpa = getattr(blk, 'sdpa', False) # fused attention for the pure-forward loop only
try:
+ if getattr(blk, 'fastfp', False) and steps >= 50 and blk.fnoise == 0.0:
+ zf, _ = anderson_relax(blk, z, xin, steps, eps)
+ return zf
+ k = getattr(blk, 'bf16polish', 0) # bf16 bulk + fp32 endpoint polish (last k steps)
+ if k and steps > k and blk.fnoise == 0.0:
+ with torch.no_grad(), torch.autocast('cuda', dtype=torch.bfloat16):
+ for _ in range(steps - k):
+ z = (z + eps * blk.force(z, xin)).float().detach()
+ steps = k
for _ in range(steps):
with torch.no_grad():
z = z + eps * blk.force(z, xin).detach()
@@ -447,6 +489,8 @@ def main():
ap.add_argument('--holofast', action='store_true') # exact halved-jvp track (1.55x nudged phase; parity = FD noise floor)
ap.add_argument('--sdpa', action='store_true') # fused flash attention in the no_grad relax loop
ap.add_argument('--holoavg', action='store_true') # trend-aware stop + plateau-avg track (gate: 0.913->0.936 @t2sel160)
+ ap.add_argument('--fastfp', action='store_true') # Anderson-accelerated free phase (pure-speed opt-in; alters resreg semantics)
+ ap.add_argument('--bf16polish', type=int, default=0) # bf16 bulk relax + fp32 last-K polish (0=off; gate before use)
ap.add_argument('--rt_final', type=float, default=0.0) # anneal res_target to this (0=off), 25%-75% of run
ap.add_argument('--nudge_brake', type=float, default=0.0) # kappa: anchor spring during nudge (Tikhonov adjoint)
ap.add_argument('--init_ckpt', type=str, default='') # warm-start weights from a saved ckpt
@@ -524,6 +568,8 @@ def main():
blk.holofast = cfg.holofast
blk.sdpa = cfg.sdpa
blk.holoavg = cfg.holoavg
+ blk.fastfp = cfg.fastfp
+ blk.bf16polish = cfg.bf16polish
blk.nbrake = cfg.nudge_brake
blk.qknorm = cfg.qknorm
if cfg.resinit != 1.0: # near-identity block at init (contractive) -> stable big-width start