item 24 pre-registered: d=1 retry with loop-only band-LoRA r=16 (4.8M params, whole band, k=0 bit-exact); trainer/eval gain --bandlora; smoke-tested train+eval
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -630,3 +630,28 @@ chapter closes as scored in item 22; the loop program's live paths
|
||||
are state-side (rung-2 band-LoRA / wider merge, E2-N hardening,
|
||||
coarse-target auxiliary supervision matched to the medium) or the
|
||||
hybrid (A2), not longer/denser pause-chains.
|
||||
|
||||
24. **E2-L d=1 with a trainable band: loop-only band-LoRA
|
||||
(pre-registered 2026-07-17 ~00:30, before running; Nils: "can we
|
||||
unfreeze the entire band and try this again?").** Item 23 located
|
||||
the constraint in the carried state's per-position transformation;
|
||||
this is the state-side attack. Full unfreeze rejected in design
|
||||
(642M params vs 427 examples, and it would break the frozen-model
|
||||
guarantee); instead LoopLoRA (lora_band.py, built for the rung-2
|
||||
design): rank-16 deltas on q/v/down of EVERY band layer (L14-30,
|
||||
uniform scale 1.0, 4.8M params), active ONLY during band re-runs —
|
||||
initial forward and k=0 stay bit-exact by construction. Otherwise
|
||||
identical to item-22 d=1: front-first deletion, 10 pauses/step,
|
||||
warm-start rung-A e400 (adapter lr 3e-4; fresh LoRA lr 1e-3, B
|
||||
zero-init so step-0 matches item 22 exactly), 200 steps, seed 0.
|
||||
Eval n=256: 0:0 (sanity, must equal base), 2:12, 2:16; e200.
|
||||
Decision rule (same bands as item 23, vs d=1's 31.6): >=+5
|
||||
(>36.6) = band expressivity was binding -> escalate (rank 64, all
|
||||
projections, or full-band rung ladder); within +-5 = the medium
|
||||
verdict stands even with a trainable band -> internalization line
|
||||
CLOSED, program pivots (A2 / E2-N / coarse-aux / divergence
|
||||
batch). Prediction, honest: mild gain but under threshold (~33-36)
|
||||
— the microscopy says the board's failure mode is WHAT it carries,
|
||||
not how flexibly it transforms it; but this is the experiment the
|
||||
'wider state' hypothesis deserves before the line closes. Job:
|
||||
scripts/jobs/zzz_p_rungb_blr.sh.
|
||||
|
||||
@@ -36,11 +36,25 @@ def main():
|
||||
ap.add_argument("--batch", type=int, default=8)
|
||||
ap.add_argument("--feedforward", action="store_true")
|
||||
ap.add_argument("--max-new", type=int, default=160)
|
||||
ap.add_argument("--bandlora", default=None, metavar="LORA_PT",
|
||||
help="load a lora_*_e*.pt loop-only band-LoRA checkpoint")
|
||||
args = ap.parse_args()
|
||||
|
||||
model, tok = load_model(dtype=torch.bfloat16)
|
||||
tok.padding_side = "left"
|
||||
looper = BandLooper(model)
|
||||
if args.bandlora:
|
||||
from lora_band import inject_band_lora
|
||||
ck = torch.load(args.bandlora, map_location="cuda")
|
||||
scales = {l: 1.0 for l in ck["band"]}
|
||||
ps = inject_band_lora(looper.tm, ck["band"][0], scales,
|
||||
rank=ck["rank"])
|
||||
assert len(ps) == len(ck["tensors"]), (len(ps), len(ck["tensors"]))
|
||||
for pr, t in zip(ps, ck["tensors"]):
|
||||
pr.data = t.cuda()
|
||||
print(f"band-lora loaded: {args.bandlora} "
|
||||
f"(r={ck['rank']}, layers {ck['band'][0]}-{ck['band'][-1]})",
|
||||
flush=True)
|
||||
adapter = MergeAdapter(
|
||||
d=model.config.get_text_config().hidden_size).cuda()
|
||||
adapter.load_state_dict(torch.load(args.adapter, map_location="cuda"))
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# gpuq-in: results-loop/star_data.json results-loop/gsm_cot_data.json results-loop/adapter_carrycot_e400.pt
|
||||
# gpuq-out: results-loop/eval_gsm_carrycot_b1_blr16.json results-loop/train_carrycot_b1_blr16_log.json results-loop/adapter_carrycot_b1_blr16_*.pt results-loop/lora_carrycot_b1_blr16_*.pt
|
||||
git pull origin main -q 2>/dev/null
|
||||
P=/home/nils/jspace/.venv/bin/python
|
||||
export JLENS_MODEL=google/gemma-4-E2B-it LOOP_OUT=/home/nils/jspace/results-loop
|
||||
cd /home/nils/jspace/scripts
|
||||
$P train_carry_cot.py --drop-steps 1 --warm-start $LOOP_OUT/adapter_carrycot_e400.pt \
|
||||
--steps 200 --lr 3e-4 --bandlora 16 --lora-lr 1e-3
|
||||
$P eval_carry_cot.py --adapter $LOOP_OUT/adapter_carrycot_b1_blr16_e200.pt \
|
||||
--bandlora $LOOP_OUT/lora_carrycot_b1_blr16_e200.pt \
|
||||
--tag gsm_carrycot_b1_blr16 --grid 0:0,2:12,2:16 --n 256
|
||||
@@ -53,10 +53,16 @@ ap.add_argument("--steps", type=int, default=STEPS)
|
||||
ap.add_argument("--lr", type=float, default=LR)
|
||||
ap.add_argument("--tag-suffix", default="",
|
||||
help="appended to TAG (distinguish control variants)")
|
||||
ap.add_argument("--bandlora", type=int, default=0, metavar="RANK",
|
||||
help="item 24: loop-only LoRA (lora_band.LoopLoRA) on every "
|
||||
"band layer, uniform scale 1.0 — active only during "
|
||||
"band re-runs, k=0 stays bit-exact")
|
||||
ap.add_argument("--lora-lr", type=float, default=1e-3)
|
||||
ARGS = ap.parse_args()
|
||||
STEPS, LR = ARGS.steps, ARGS.lr
|
||||
TAG = ("carrycot_ff" if ARGS.feedforward else "carrycot") + (
|
||||
f"_b{ARGS.drop_steps}" if ARGS.drop_steps else "") + (
|
||||
f"_blr{ARGS.bandlora}" if ARGS.bandlora else "") + (
|
||||
f"_ln{ARGS.lensnoise.replace(',', '_')}" if ARGS.lensnoise else "") + (
|
||||
f"_s{ARGS.seed}" if ARGS.seed else "") + ARGS.tag_suffix
|
||||
|
||||
@@ -186,7 +192,25 @@ def main():
|
||||
(adapter.base if ARGS.lensnoise else adapter).load_state_dict(
|
||||
torch.load(ARGS.warm_start, map_location="cuda"))
|
||||
print(f"warm-started from {ARGS.warm_start}", flush=True)
|
||||
opt = torch.optim.AdamW(adapter.parameters(), lr=LR, weight_decay=0.01)
|
||||
lora_params, lora_band_layers = [], []
|
||||
if ARGS.bandlora:
|
||||
from lora_band import inject_band_lora
|
||||
from loop_common import BAND
|
||||
lora_band_layers = list(range(BAND[0], BAND[1] + 1))
|
||||
scales = {l: 1.0 for l in lora_band_layers}
|
||||
lora_params = inject_band_lora(looper.tm, BAND[0], scales,
|
||||
rank=ARGS.bandlora)
|
||||
for p in lora_params:
|
||||
p.data = p.data.cuda()
|
||||
print(f"band-lora r={ARGS.bandlora}: "
|
||||
f"{sum(p.numel() for p in lora_params)/1e6:.1f}M params, "
|
||||
f"layers {lora_band_layers[0]}-{lora_band_layers[-1]}, "
|
||||
f"lr={ARGS.lora_lr}", flush=True)
|
||||
groups = [{"params": list(adapter.parameters()), "lr": LR, "base": LR}]
|
||||
if lora_params:
|
||||
groups.append({"params": lora_params, "lr": ARGS.lora_lr,
|
||||
"base": ARGS.lora_lr})
|
||||
opt = torch.optim.AdamW(groups, weight_decay=0.01)
|
||||
|
||||
keep = [it for it in data
|
||||
if len(tok(it["question"])["input_ids"])
|
||||
@@ -211,7 +235,7 @@ def main():
|
||||
p = P_BY_LABEL[lbl]
|
||||
ids, msk, lab, plens = build_batch(tok, batch, p)
|
||||
for g in opt.param_groups:
|
||||
g["lr"] = lr_at(step)
|
||||
g["lr"] = g["base"] * lr_at(step) / LR
|
||||
logits = carry_logits(looper, adapter, ids, msk, plens, K_PREFILL,
|
||||
use_checkpoint=True,
|
||||
feedforward=ARGS.feedforward)
|
||||
@@ -219,7 +243,8 @@ def main():
|
||||
lab[:, 1:].flatten(), ignore_index=-100)
|
||||
opt.zero_grad(set_to_none=True)
|
||||
loss.backward()
|
||||
torch.nn.utils.clip_grad_norm_(adapter.parameters(), 1.0)
|
||||
torch.nn.utils.clip_grad_norm_(
|
||||
list(adapter.parameters()) + lora_params, 1.0)
|
||||
opt.step()
|
||||
log.append({"step": step, "loss": loss.item()})
|
||||
if step % 10 == 0:
|
||||
@@ -235,6 +260,11 @@ def main():
|
||||
adapter.noise_on = True
|
||||
sd = (adapter.base if ARGS.lensnoise else adapter).state_dict()
|
||||
torch.save(sd, OUT / f"adapter_{TAG}_e{step+1}.pt")
|
||||
if lora_params:
|
||||
torch.save({"rank": ARGS.bandlora, "band": lora_band_layers,
|
||||
"tensors": [p.detach().cpu()
|
||||
for p in lora_params]},
|
||||
OUT / f"lora_{TAG}_e{step+1}.pt")
|
||||
json.dump(log, open(OUT / f"train_{TAG}_log.json", "w"))
|
||||
print("done", flush=True)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user