faz9_recur: --sweep (k zorluk taramasi, GAP-vs-k trendi = asil GO/NO-GO kaniti)
Browse files- code/kod/faz9_recur.py +44 -14
code/kod/faz9_recur.py
CHANGED
|
@@ -171,17 +171,15 @@ class FixedDepthLM(nn.Module):
|
|
| 171 |
return self.lm_head(rms_norm(h, self.norm_f))
|
| 172 |
|
| 173 |
|
| 174 |
-
def
|
|
|
|
| 175 |
P, C = 1, 1
|
| 176 |
cfg = tiny_cfg(d_model=d_model, vocab_size=n_keys + 1)
|
| 177 |
rec = RecurrentDepthLM(cfg, n_prelude=P, n_coda=C, core_attn=True, prenorm_core=False, block_attn=fast).to(device)
|
| 178 |
fix = FixedDepthLM(cfg, n_layers=P + 1 + C, all_attn=fast).to(device)
|
| 179 |
-
print(f"[compare] görev: {k}-hop / {n_keys} anahtar | device={device} | steps={steps} | fast={fast}")
|
| 180 |
-
print(f" param: recurrent {_params(rec)/1e6:.3f}M | fixed {_params(fix)/1e6:.3f}M (eşit olmalı)")
|
| 181 |
|
| 182 |
def train(model, recurrent):
|
| 183 |
-
opt = torch.optim.AdamW(model.parameters(), lr=lr)
|
| 184 |
-
model.train()
|
| 185 |
for s in range(steps):
|
| 186 |
ids, tgt = gen_khop(batch, n_keys, k, device)
|
| 187 |
R = int(torch.randint(2, 13, (1,))) if recurrent else 1
|
|
@@ -189,8 +187,8 @@ def compare(device="cpu", n_keys=12, k=4, steps=2000, batch=64, d_model=128, lr=
|
|
| 189 |
loss = F.cross_entropy(last, tgt)
|
| 190 |
opt.zero_grad(); loss.backward()
|
| 191 |
torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0); opt.step()
|
| 192 |
-
if s % max(1, steps //
|
| 193 |
-
print(f" {'REC' if recurrent else 'FIX'} step {s:>4} loss {loss.item():.3f}")
|
| 194 |
|
| 195 |
@torch.no_grad()
|
| 196 |
def acc(model, recurrent, R=8, n=1000):
|
|
@@ -198,17 +196,44 @@ def compare(device="cpu", n_keys=12, k=4, steps=2000, batch=64, d_model=128, lr=
|
|
| 198 |
last = (model(ids, R=R) if recurrent else model(ids))[:, -1]
|
| 199 |
return (last.argmax(-1) == tgt).float().mean().item()
|
| 200 |
|
| 201 |
-
|
| 202 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 203 |
rnd = 1.0 / n_keys
|
| 204 |
-
print(f"\n[SONUÇ] (random={rnd:.3f}
|
| 205 |
-
print(f" FIXED (depth
|
| 206 |
print(f" RECURRENT test-zamanı R ölçekleme:")
|
| 207 |
-
for R
|
| 208 |
-
print(f" R={R:>2} → acc {
|
|
|
|
| 209 |
print(" GO sinyali: recurrent fixed'i geçer VE R↑ ile acc↑ (özellikle R≥k).")
|
| 210 |
|
| 211 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 212 |
def main():
|
| 213 |
ap = argparse.ArgumentParser()
|
| 214 |
ap.add_argument("--smoke", action="store_true", help="CPU mekanik smoke (Faz A)")
|
|
@@ -219,13 +244,18 @@ def main():
|
|
| 219 |
ap.add_argument("--steps", type=int, default=2000)
|
| 220 |
ap.add_argument("--d_model", type=int, default=128)
|
| 221 |
ap.add_argument("--fast", action="store_true", help="tüm bloklar attention (Mamba token-loop yok → ~30× hızlı; k-hop için uygun)")
|
|
|
|
|
|
|
| 222 |
args = ap.parse_args()
|
| 223 |
if args.smoke:
|
| 224 |
smoke()
|
|
|
|
|
|
|
|
|
|
| 225 |
elif args.compare:
|
| 226 |
compare(device=args.device, n_keys=args.n_keys, k=args.k, steps=args.steps, d_model=args.d_model, fast=args.fast)
|
| 227 |
else:
|
| 228 |
-
print("kullanım: python faz9_recur.py --smoke | --compare [--device cuda --
|
| 229 |
|
| 230 |
|
| 231 |
if __name__ == "__main__":
|
|
|
|
| 171 |
return self.lm_head(rms_norm(h, self.norm_f))
|
| 172 |
|
| 173 |
|
| 174 |
+
def _train_eval(device, n_keys, k, steps, batch, d_model, lr, fast, verbose=True):
|
| 175 |
+
"""Tek k için param-eşit fixed+recurrent eğit → (fix_acc, {R:rec_acc}, n_param)."""
|
| 176 |
P, C = 1, 1
|
| 177 |
cfg = tiny_cfg(d_model=d_model, vocab_size=n_keys + 1)
|
| 178 |
rec = RecurrentDepthLM(cfg, n_prelude=P, n_coda=C, core_attn=True, prenorm_core=False, block_attn=fast).to(device)
|
| 179 |
fix = FixedDepthLM(cfg, n_layers=P + 1 + C, all_attn=fast).to(device)
|
|
|
|
|
|
|
| 180 |
|
| 181 |
def train(model, recurrent):
|
| 182 |
+
opt = torch.optim.AdamW(model.parameters(), lr=lr); model.train()
|
|
|
|
| 183 |
for s in range(steps):
|
| 184 |
ids, tgt = gen_khop(batch, n_keys, k, device)
|
| 185 |
R = int(torch.randint(2, 13, (1,))) if recurrent else 1
|
|
|
|
| 187 |
loss = F.cross_entropy(last, tgt)
|
| 188 |
opt.zero_grad(); loss.backward()
|
| 189 |
torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0); opt.step()
|
| 190 |
+
if verbose and s % max(1, steps // 4) == 0:
|
| 191 |
+
print(f" {'REC' if recurrent else 'FIX'} k={k} step {s:>4} loss {loss.item():.3f}")
|
| 192 |
|
| 193 |
@torch.no_grad()
|
| 194 |
def acc(model, recurrent, R=8, n=1000):
|
|
|
|
| 196 |
last = (model(ids, R=R) if recurrent else model(ids))[:, -1]
|
| 197 |
return (last.argmax(-1) == tgt).float().mean().item()
|
| 198 |
|
| 199 |
+
train(fix, False); train(rec, True)
|
| 200 |
+
rec_by_R = {R: acc(rec, True, R=R) for R in (1, 2, 4, 8, 16)}
|
| 201 |
+
return acc(fix, False), rec_by_R, _params(rec)
|
| 202 |
+
|
| 203 |
+
|
| 204 |
+
def compare(device="cpu", n_keys=12, k=4, steps=2000, batch=64, d_model=128, lr=1e-3, fast=False):
|
| 205 |
+
print(f"[compare] görev: {k}-hop / {n_keys} anahtar | device={device} | steps={steps} | fast={fast}")
|
| 206 |
+
fa, rec, npar = _train_eval(device, n_keys, k, steps, batch, d_model, lr, fast)
|
| 207 |
rnd = 1.0 / n_keys
|
| 208 |
+
print(f"\n[SONUÇ] param ~{npar/1e6:.3f}M (eşit) | random={rnd:.3f}")
|
| 209 |
+
print(f" FIXED (depth 3) acc = {fa:.3f}")
|
| 210 |
print(f" RECURRENT test-zamanı R ölçekleme:")
|
| 211 |
+
for R, a in rec.items():
|
| 212 |
+
print(f" R={R:>2} → acc {a:.3f}")
|
| 213 |
+
print(f" GAP (rec_best − fixed) = {max(rec.values()) - fa:+.3f}")
|
| 214 |
print(" GO sinyali: recurrent fixed'i geçer VE R↑ ile acc↑ (özellikle R≥k).")
|
| 215 |
|
| 216 |
|
| 217 |
+
def sweep(device="cpu", n_keys=12, ks=(2, 4, 6), steps=2000, batch=64, d_model=128, lr=1e-3, fast=True):
|
| 218 |
+
"""ZORLUK TARAMASI: GAP (rec−fixed) k ile büyüyor mu = recursion derinlikle değer kazanıyor mu."""
|
| 219 |
+
rnd = 1.0 / n_keys
|
| 220 |
+
print(f"[sweep] k={list(ks)} / {n_keys} anahtar | device={device} | steps={steps} | fast={fast} | random={rnd:.3f}\n")
|
| 221 |
+
rows = []
|
| 222 |
+
for k in ks:
|
| 223 |
+
fa, rec, npar = _train_eval(device, n_keys, k, steps, batch, d_model, lr, fast, verbose=False)
|
| 224 |
+
bR = max(rec, key=rec.get); gap = rec[bR] - fa
|
| 225 |
+
rows.append((k, fa, rec, bR, gap))
|
| 226 |
+
print(f" k={k}: FIX {fa:.3f} | REC R1={rec[1]:.2f} R4={rec[4]:.2f} R8={rec[8]:.2f} R16={rec[16]:.2f} "
|
| 227 |
+
f"| best@R{bR}={rec[bR]:.3f} | GAP {gap:+.3f}")
|
| 228 |
+
print(f"\n[ÖZET] GAP (rec_best − fixed) — k arttıkça büyümeli (random={rnd:.3f}):")
|
| 229 |
+
for k, fa, rec, bR, gap in rows:
|
| 230 |
+
print(f" k={k}: GAP {gap:+.3f} {'#' * max(0, int(gap * 60))}")
|
| 231 |
+
gaps = [r[4] for r in rows]
|
| 232 |
+
grow = all(gaps[i] <= gaps[i + 1] + 1e-9 for i in range(len(gaps) - 1)) and gaps[-1] > 0.05
|
| 233 |
+
print(f"\n → GAP k ile {'✅ ARTIYOR = GO (recursion derinlikle değer kazanıyor)' if grow else '⚠️ ARTMIYOR/karışık = zayıf sinyal'}")
|
| 234 |
+
print(" → Ayrıca zor k'da REC acc ~R≥k civarında sıçramalı (daha çok düşünme = daha çok hop).")
|
| 235 |
+
|
| 236 |
+
|
| 237 |
def main():
|
| 238 |
ap = argparse.ArgumentParser()
|
| 239 |
ap.add_argument("--smoke", action="store_true", help="CPU mekanik smoke (Faz A)")
|
|
|
|
| 244 |
ap.add_argument("--steps", type=int, default=2000)
|
| 245 |
ap.add_argument("--d_model", type=int, default=128)
|
| 246 |
ap.add_argument("--fast", action="store_true", help="tüm bloklar attention (Mamba token-loop yok → ~30× hızlı; k-hop için uygun)")
|
| 247 |
+
ap.add_argument("--sweep", action="store_true", help="Faz B zorluk taraması: k=2/4/6 GAP trendi (asıl GO/NO-GO)")
|
| 248 |
+
ap.add_argument("--ks", default="2,4,6", help="sweep k değerleri (virgülle, örn. 2,4,6)")
|
| 249 |
args = ap.parse_args()
|
| 250 |
if args.smoke:
|
| 251 |
smoke()
|
| 252 |
+
elif args.sweep:
|
| 253 |
+
ks = tuple(int(x) for x in args.ks.split(","))
|
| 254 |
+
sweep(device=args.device, n_keys=args.n_keys, ks=ks, steps=args.steps, d_model=args.d_model, fast=args.fast)
|
| 255 |
elif args.compare:
|
| 256 |
compare(device=args.device, n_keys=args.n_keys, k=args.k, steps=args.steps, d_model=args.d_model, fast=args.fast)
|
| 257 |
else:
|
| 258 |
+
print("kullanım: python faz9_recur.py --smoke | --compare | --sweep [--device cuda --n_keys 12 --steps 3000 --fast]")
|
| 259 |
|
| 260 |
|
| 261 |
if __name__ == "__main__":
|