diff options
| author | Yuren Hao <yurenh2@illinois.edu> | 2026-08-05 08:18:11 -0500 |
|---|---|---|
| committer | Yuren Hao <yurenh2@illinois.edu> | 2026-08-05 08:18:11 -0500 |
| commit | 68ac1f9d1fa8944a216964479e49e813de6370ac (patch) | |
| tree | 3a5aedebe30df058079ddc123fe04b63c7f5b7e2 /ep_run | |
| parent | d0d1849e16127d4248bf5ef6c0bb1d6686aa9924 (diff) | |
偏置放大公理(用户08-06指出): 逐坐标归一化把持久小偏置放大成满幅漂移, sign全家同罪(否决只挡
方差不挡偏置); 曲率通道=偏置磁铁(E[s·ĝ]=βc+δ/β, 污染被1/β放大333×), 存活=两档|β|锁相分离;
评分表增第三轴=偏置放大系数, 器件电池预注册排序重排预测(per-matrix优雅退化/sign满幅/Dither翻身)。
附: --dump_grad探针+cautlion已实装。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FAPDWQ49M5Ye3NpTndTpn
Diffstat (limited to 'ep_run')
| -rw-r--r-- | ep_run/casc_eq_train.py | 19 | ||||
| -rw-r--r-- | ep_run/muon.py | 26 |
2 files changed, 42 insertions, 3 deletions
diff --git a/ep_run/casc_eq_train.py b/ep_run/casc_eq_train.py index 6a6865d..e29048c 100644 --- a/ep_run/casc_eq_train.py +++ b/ep_run/casc_eq_train.py @@ -22,7 +22,7 @@ ap.add_argument('--wandb_run', default='') ap.add_argument('--kmax', type=int, default=8) # adaptive fb rounds cap ap.add_argument('--noguard', action='store_true') # diagnosis: skip only non-finite grads ap.add_argument('--untie', action='store_true') # separate readout matrix (untied from tok) -ap.add_argument('--opt', choices=['adamw', 'muon', 'sgdm', 'lion', 'olion', 'adafactor', 'signline', 'conslion', 'ditherlion'], default='adamw') +ap.add_argument('--opt', choices=['adamw', 'muon', 'sgdm', 'lion', 'olion', 'adafactor', 'signline', 'conslion', 'ditherlion', 'cautlion'], default='adamw') ap.add_argument('--muon_lr', type=float, default=0.02) ap.add_argument('--tok_init', type=float, default=0.0) # >0: init tok/pos with this std (GPT-standard 0.02) ap.add_argument('--compile', action='store_true') # torch.compile each block (free speed where supported) @@ -61,6 +61,7 @@ ap.add_argument('--gen_new', type=int, default=120) ap.add_argument('--probe_dgspec', type=int, default=0) # >0: M1 spectroscopy, value = n batches; exits before training ap.add_argument('--probe_gains', default='1,2,4,8,16,32,64,128,256') ap.add_argument('--probe_f64', action='store_true') # fp64 states+model in the probe: the fp-floor decisive arm # >1: per-STEP log-uniform dgain_top in +ap.add_argument('--dump_grad', type=int, default=0) # >0: record per-step grad estimates + beta sign ap.add_argument('--dump_mom', type=int, default=0) # >0: record 3 Muon momentum matrices every step # for N steps -> runs/momdump_{tag}.pt, then exit # (EqOLion tracking-falsification input) @@ -344,7 +345,7 @@ if args.bf16: if args.untie: with torch.no_grad(): W_out.data = W_out.data.to(torch.bfloat16) print('[bf16] model cast to bfloat16 (E-accum + sigma stay fp32)', flush=True) -if args.opt in ('sgdm', 'lion', 'olion', 'adafactor', 'signline', 'conslion', 'ditherlion'): +if args.opt in ('sgdm', 'lion', 'olion', 'adafactor', 'signline', 'conslion', 'ditherlion', 'cautlion'): from muon import build_alt opt, sched = build_alt(args.opt, blocks, all_params, args.lr, args.warmup, total_steps=(args.steps if args.cosine else 0), lr_min_ratio=args.lr_min_ratio, @@ -1050,6 +1051,20 @@ for step in range(start_step, args.steps + 1): with torch.no_grad(): WSNAP['p'] = [p.detach().clone() for p in all_params] WSNAP['o'] = _clone_state(opt.state_dict()) + if args.dump_grad > 0 and args.opt == 'muon': + # per-step gradient ESTIMATES + the bsign coin, for the odd/even (curvature-channel) + # decomposition test: E[s*ghat] = beta*c. Captured BEFORE opt.step consumes grads. + om_ = opt.optimizers[0] + _m2 = om_.param_groups[0]['params'] + _s2 = [_m2[1], _m2[len(_m2) // 2], _m2[-1]] + if 'GDUMP' not in globals(): + GDUMP = {'shapes': [tuple(p.shape) for p in _s2], 'sign': [], 'traj': []} + GDUMP['sign'].append(1.0 if beta_t > 0 else -1.0) + GDUMP['traj'].append([p.grad.detach().float().cpu().clone() for p in _s2]) + if step >= args.dump_grad: + torch.save(GDUMP, f'runs/graddump_{args.tag}.pt') + print(f'[graddump] DONE {len(GDUMP["traj"])} steps -> runs/graddump_{args.tag}.pt', flush=True) + import sys; sys.exit(0) opt.step(); sched.step(); opt.zero_grad(set_to_none=True) if args.dump_mom > 0 and args.opt == 'muon': # per-step momentum trajectory for the EqOLion tracking falsification: three diff --git a/ep_run/muon.py b/ep_run/muon.py index e6c2692..1289620 100644 --- a/ep_run/muon.py +++ b/ep_run/muon.py @@ -176,7 +176,8 @@ def build_alt(opt_name, blocks, other_params, lr, warmup, total_steps=0, lr_min_ 'adafactor': lambda: Adafactor2D(mats, lr=lm, wd=wd), 'signline': lambda: SignLine(mats, lr=lm, wd=wd), 'conslion': lambda: ConsensusLion(mats, lr=lm, wd=wd), - 'ditherlion': lambda: DitherLion(mats, lr=lm, wd=wd)}[opt_name]() + 'ditherlion': lambda: DitherLion(mats, lr=lm, wd=wd), + 'cautlion': lambda: CautiousLion(mats, lr=lm, wd=wd)}[opt_name]() oa = torch.optim.AdamW(rest, lr=lr, weight_decay=1e-4) opts = [om, oa] if total_steps > 0: @@ -247,6 +248,29 @@ class ConsensusLion(torch.optim.Optimizer): p.add_(u, alpha=-g_['lr']) +class CautiousLion(torch.optim.Optimizer): + """C-Lion (Liang et al., arXiv:2411.16085, ICLR'26): Lion masked where the update sign + disagrees with the CURRENT gradient sign. The mandatory prior-art baseline for ConsensusLion; + the difference under test is instantaneous-gradient gating (this) vs filtered two-EMA gating.""" + def __init__(self, params, lr=3e-4, betas=(0.9, 0.99), wd=0.0): + super().__init__(params, dict(lr=lr, betas=betas, wd=wd)) + + @torch.no_grad() + def step(self, closure=None): + for g_ in self.param_groups: + b1, b2 = g_['betas'] + for p in g_['params']: + if p.grad is None: continue + st = self.state[p] + if 'm' not in st: st['m'] = torch.zeros_like(p) + m = st['m'] + u = (b1 * m + (1 - b1) * p.grad).sign_() + u = u * ((u * p.grad) > 0) + if g_['wd'] > 0: p.mul_(1 - g_['lr'] * g_['wd']) + p.add_(u, alpha=-g_['lr']) + m.mul_(b2).add_(p.grad, alpha=1 - b2) + + class DitherLion(torch.optim.Optimizer): """Lion with dithered sign: sign(m + tau*noise*rms(m)). Free substrate noise turns the hard sign into an unbiased soft-sign in expectation, letting small entries carry proportional |
