AbstractPhil commited on
Commit
c5e5e50
·
verified ·
1 Parent(s): 42ed8a8

exp015 shipped: address-as-key falsified with corrected instruments (zero routing excess, zero match advantage) - the dispatch-key form closes; TE+AMOE joint training is the open form

Browse files
README.md CHANGED
@@ -82,6 +82,7 @@ resolution) so gaps live in a narrow band — the paired design is load-bearing.
82
  | exp009_bandroles | role objectives: **directional hit 4/4 but noise-adjacent — frequency reweighting too collinear; needs qualitatively different supervision + generation-side gauges (exp010)** | **shipped (2 seeds + rejudge)** |
83
  | exp010_controller | **StepGatedSampler ships**: controller lifts grounding +0.089 over frozen; monotonic lesion ladder; HIGH lesion 14x LP-dominant (coarse-to-fine confirmed in image space); eps-trained HIGH band concentrates (diversity = open training goal) | **shipped (candidate)** |
84
  | exp011a_fused_multiband | multiband on REAL fused data: **adapters pay 2-3x more; structural story replicates (3/3 surgical, monolith edge persists); blob targets built 100% after a schema lesson** | **shipped (candidate, s0; s1 running)** |
 
85
  | exp014_te_dispatch | router-solidifier v1: **honest negative** — state keys already route by prompt; raw-flattened address kills routing (the known high-D disease geometry); null-design lesson → v2 | **shipped (candidate, s0; s1 running)** |
86
  | exp013_blob_flow | **CONDITIONING HYPOTHESIS CONFIRMED**: same blob coupling, ~200x the eps effect on the flow substrate (−5.9% vs +0.03%); blob supervision belongs on flow/v-pred trunks | **shipped (candidate, s0; s1 running)** |
87
 
 
82
  | exp009_bandroles | role objectives: **directional hit 4/4 but noise-adjacent — frequency reweighting too collinear; needs qualitatively different supervision + generation-side gauges (exp010)** | **shipped (2 seeds + rejudge)** |
83
  | exp010_controller | **StepGatedSampler ships**: controller lifts grounding +0.089 over frozen; monotonic lesion ladder; HIGH lesion 14x LP-dominant (coarse-to-fine confirmed in image space); eps-trained HIGH band concentrates (diversity = open training goal) | **shipped (candidate)** |
84
  | exp011a_fused_multiband | multiband on REAL fused data: **adapters pay 2-3x more; structural story replicates (3/3 surgical, monolith edge persists); blob targets built 100% after a schema lesson** | **shipped (candidate, s0; s1 running)** |
85
+ | exp015_router_v2 | corrected router test: **address-as-key FALSIFIED** (routing excess 2.5e-06 over constant-key null; match advantage −0.0); open form = TE+AMOE joint training | **shipped (candidate, s0)** |
86
  | exp014_te_dispatch | router-solidifier v1: **honest negative** — state keys already route by prompt; raw-flattened address kills routing (the known high-D disease geometry); null-design lesson → v2 | **shipped (candidate, s0; s1 running)** |
87
  | exp013_blob_flow | **CONDITIONING HYPOTHESIS CONFIRMED**: same blob coupling, ~200x the eps effect on the flow substrate (−5.9% vs +0.03%); blob supervision belongs on flow/v-pred trunks | **shipped (candidate, s0; s1 running)** |
88
 
exp015_router_v2/README.md ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # exp015_router_v2 — the corrected router test: address-as-key FALSIFIED
2
+ # (CANDIDATE, s0 — the window's final training run)
3
+
4
+ **Fixes applied from exp014's instrument findings:** the address enters as
5
+ 32 slots → shared 128→4 projection → per-slot dense signed aleph
6
+ coefficients → MEAN composition (low-D before addressing — the text line's
7
+ cure for the high-D flattening disease); null = REPEATED KEY (constant
8
+ address for all prompts — isolates text-specific routing from state-driven
9
+ variance); plus a matched-vs-mismatched key val delta (the correctness
10
+ gauge v1 lacked).
11
+
12
+ **Results** (`results.json`, flow trunk, fused cache):
13
+
14
+ | arm | val | usage-var (real) | usage-var (repeated null) | match advantage |
15
+ |---|---|---|---|---|
16
+ | state_sigma (control) | **0.57310** | 1.36e-02 | — | — |
17
+ | mhat_addr (v2) | 0.57491 | 1.13e-02 | 1.13e-02 | **−0.0** |
18
+
19
+ **Verdict.** Routing excess over the constant-key null: **2.5e-06 — zero.**
20
+ Matched and mismatched address keys produce identical val. With correct
21
+ geometry AND correct instruments, the frozen text address contributes no
22
+ prompt-specific routing on this substrate at this scale; all per-prompt
23
+ usage structure is state-driven (consistent with exp014's finding that the
24
+ hidden-state key already routes by prompt). Two-experiment closure of the
25
+ dispatch-key form of the router-solidifier idea; the open form is the full
26
+ TE+AMOE joint-training collective (docket), where the text encoder learns
27
+ THROUGH the diffusion loss rather than entering as a frozen key.
28
+
29
+ **Caveats.** s0; one substrate (lune flow), one scale (A=4); the fused
30
+ captions are stylistically homogeneous (fashion photography) — a
31
+ low-text-diversity regime; a multi-domain caption mixture is the one
32
+ remaining escape hatch for the frozen-key form.
exp015_router_v2/dexp015_router_v2.py ADDED
@@ -0,0 +1,287 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """dexp015_router_v2.py — exp015: ROUTER v2 — the M-hat-bottlenecked address
2
+ key + the corrected null (exp014's two instrument findings applied).
3
+
4
+ v1 failures fixed: (1) the raw-flattened [32*128] address killed routing
5
+ (high-D disease geometry) -> v2 reads the address AS 32 SLOTS, projects each
6
+ slot 128->4 (orthogonal, shared) BEFORE addressing, takes per-slot dense
7
+ signed aleph coefficients against the bank codebook, and MEAN-COMPOSES over
8
+ slots (the aleph's own order-insensitive composition rule) — low-D before
9
+ addressing, per the text line's cure. (2) the shuffled-key null measured
10
+ diversity, not correctness -> v2 null = REPEATED KEY (every prompt gets
11
+ row-0's address; any residual per-prompt usage variance is state-driven).
12
+
13
+ Arms: state_sigma (control = v1's winner) | mhat_addr (v2). Judged: common
14
+ flow-MSE; HIGH-band blob gauge; per-prompt usage variance with the REPEATED
15
+ null; matched-vs-mismatched key val delta (the correctness gauge v1 lacked).
16
+ Prereg: P1 mhat_addr routing variance > 3x its REPEATED null EXCESS over
17
+ state-driven variance; P2 common val >= control - 0.5%; P3 toggle.
18
+
19
+ Pod: bash pod2/run_exp015.sh
20
+ """
21
+ from __future__ import annotations
22
+
23
+ import json
24
+ import os
25
+ import sys
26
+ import time
27
+
28
+ sys.path[:0] = ["pod2", "."]
29
+
30
+ import torch
31
+ import torch.nn as nn
32
+ import torch.nn.functional as F
33
+
34
+ from pod_ledger import ledger_run, note, burn_down
35
+ from d1_substrate import MEM_FRACTION
36
+ from aleph_diffusion_core import derangement
37
+ from dexp013_blob_flow import load_lune, blob_lp_err
38
+ from dexp009_bandroles import lp
39
+ from dexp014_te_dispatch import (TeDispatchBank, Wrap, attach_banks,
40
+ build_text_feats, fourier_sigma,
41
+ N_TRAIN, N_VAL, SHIFT)
42
+
43
+ BATCH = int(os.environ.get("DEXP15_BATCH", "16"))
44
+ STEPS = int(os.environ.get("DEXP15_STEPS", "3000"))
45
+ SEED = int(os.environ.get("DEXP15_SEED", "0"))
46
+ LR, CFG_DROPOUT = 1e-3, 0.1
47
+ D11 = ("/workspace/data/dexp011" if os.path.isdir("/workspace")
48
+ else "./data/dexp011")
49
+ D14 = ("/workspace/data/dexp014" if os.path.isdir("/workspace")
50
+ else "./data/dexp014")
51
+ DATA_DIR = ("/workspace/data/dexp015" if os.path.isdir("/workspace")
52
+ else "./data/dexp015")
53
+ CKPT_DIR = ("/workspace/ckpts2/dexp015" if os.path.isdir("/workspace")
54
+ else DATA_DIR)
55
+
56
+
57
+ class MhatAddrBank(TeDispatchBank):
58
+ """v2: address read as 32 slots -> shared 128->4 projection -> per-slot
59
+ signed aleph vs the bank codebook -> MEAN composition over slots."""
60
+
61
+ def __init__(self, d: int, **kw):
62
+ super().__init__(d, txt_dim=0, **kw)
63
+ self.slot_proj = nn.Linear(128, 4, bias=False)
64
+ nn.init.orthogonal_(self.slot_proj.weight)
65
+ self.addr_mix = nn.Parameter(torch.tensor(0.0)) # sigmoid=0.5 mix
66
+
67
+ def addr_weights(self, addr_flat):
68
+ slots = addr_flat.view(addr_flat.shape[0], 32, 128)
69
+ keys = self.slot_proj(slots) # (B, 32, 4)
70
+ A = F.normalize(self.codebook, dim=-1)
71
+ u = (F.normalize(keys, dim=-1) @ A.transpose(-1, -2)) / self.tau
72
+ m = u.abs().amax(dim=-1, keepdim=True)
73
+ ep, en = torch.exp(u - m), torch.exp(-u - m)
74
+ w = (ep - en) / (ep + en).sum(dim=-1, keepdim=True) # (B, 32, A)
75
+ return w.mean(dim=1) # mean composition
76
+
77
+ def forward(self, x, sig_feat, txt_feat=None):
78
+ if not self.enabled:
79
+ return x
80
+ w_state = self.dispatch(x, sig_feat, None) # (..., A)
81
+ if txt_feat is not None:
82
+ wa = self.addr_weights(txt_feat) # (B, A)
83
+ wa = wa.view(wa.shape[0], *([1] * (x.ndim - 2)), self.A)
84
+ mix = torch.sigmoid(self.addr_mix)
85
+ w = (1 - mix) * w_state + mix * wa
86
+ else:
87
+ w = w_state
88
+ with torch.no_grad():
89
+ self.last_usage = w.abs().mean(dim=tuple(
90
+ range(1, w.ndim - 1))).detach().cpu()
91
+ g = torch.sigmoid(self.gates)
92
+ delta = 0
93
+ for k in range(self.A):
94
+ delta = delta + g[k] * w[..., k:k + 1] * self.up[k](
95
+ self.down[k](x))
96
+ return x + delta
97
+
98
+
99
+ def run(device="cuda"):
100
+ torch.cuda.set_per_process_memory_fraction(MEM_FRACTION, 0)
101
+ os.makedirs(CKPT_DIR, exist_ok=True)
102
+ os.makedirs(DATA_DIR, exist_ok=True)
103
+ cache = torch.load(os.path.join(D11, "cache.pt"), map_location="cpu",
104
+ weights_only=True)
105
+ tf = torch.load(os.path.join(D14, "textfeats.pt"), map_location="cpu",
106
+ weights_only=True)
107
+ u = torch.linspace(0.02, 0.98, N_VAL)
108
+ val_sigma = (SHIFT * u) / (1 + (SHIFT - 1) * u)
109
+ ARMS = {"state_sigma": (TeDispatchBank, None),
110
+ "mhat_addr": (MhatAddrBank, "addr")}
111
+
112
+ def attach_v2(unet, cls):
113
+ from d1_substrate import enumerate_sd15_sites
114
+ sites = enumerate_sd15_sites(unet)
115
+ mods, wraps = nn.ModuleList(), []
116
+ for name, block, d in sites:
117
+ p0 = next(block.parameters())
118
+ m = (cls(d, txt_dim=0) if cls is TeDispatchBank
119
+ else cls(d)).to(device=p0.device, dtype=p0.dtype)
120
+ w = Wrap(block, m)
121
+ parent = unet
122
+ parts = name.split(".")
123
+ for p in parts[:-1]:
124
+ parent = getattr(parent, p) if not p.isdigit() \
125
+ else parent[int(p)]
126
+ if parts[-1].isdigit():
127
+ parent[int(parts[-1])] = w
128
+ else:
129
+ setattr(parent, parts[-1], w)
130
+ mods.append(m)
131
+ wraps.append(w)
132
+ return mods, wraps
133
+
134
+ def txt_of(kind, sel, repeat=False, mismatch=None):
135
+ if kind is None:
136
+ return None
137
+ t = tf[kind]
138
+ if repeat:
139
+ return t[0:1].expand(len(sel), -1).float().to(device)
140
+ if mismatch is not None:
141
+ return t[mismatch].float().to(device)
142
+ return t[sel].float().to(device)
143
+
144
+ def loss_of(unet, wraps, lat, ehs, gen):
145
+ bsz = lat.shape[0]
146
+ drop = torch.rand(bsz, generator=gen, device=device) < CFG_DROPOUT
147
+ ehs = ehs.clone()
148
+ ehs[drop] = 0
149
+ s = torch.rand(bsz, generator=gen, device=device)
150
+ s = (SHIFT * s) / (1 + (SHIFT - 1) * s)
151
+ noise = torch.randn(lat.shape, generator=gen, device=device)
152
+ s4 = s[:, None, None, None]
153
+ x_t, v = noise * s4 + lat * (1 - s4), noise - lat
154
+ for wr in wraps:
155
+ wr.sig_feat = fourier_sigma(s)
156
+ pred = unet(x_t, s * 1000, ehs, return_dict=False)[0]
157
+ return F.mse_loss(pred, v)
158
+
159
+ @torch.no_grad()
160
+ def val(unet, wraps, kind, mode="real"):
161
+ tot, blob_high, usages = [], [], []
162
+ perm = derangement(N_VAL, seed=SEED + 3)
163
+ for i in range(0, N_VAL, 32):
164
+ lat = cache["val_lat"][i:i + 32].to(device)
165
+ ehs = cache["val_ehs"][i:i + 32].to(device)
166
+ noise = cache["val_noise"][i:i + 32].to(device)
167
+ blob = cache["val_blob"][i:i + 32].float().to(device)
168
+ s = val_sigma[i:i + 32].to(device)
169
+ sel = torch.arange(N_TRAIN + i, N_TRAIN + i + lat.shape[0])
170
+ txt = txt_of(kind, sel, repeat=(mode == "repeat"),
171
+ mismatch=(N_TRAIN + perm[i:i + lat.shape[0]])
172
+ if mode == "mismatch" else None)
173
+ sf = fourier_sigma(s)
174
+ for wr in wraps:
175
+ wr.sig_feat = sf
176
+ wr.txt_feat = txt
177
+ s4 = s[:, None, None, None]
178
+ x_t, v = noise * s4 + lat * (1 - s4), noise - lat
179
+ pred = unet(x_t, s * 1000, ehs, return_dict=False)[0]
180
+ tot += ((pred - v) ** 2).mean(dim=(1, 2, 3)).tolist()
181
+ bg = blob_lp_err(x_t - s4 * pred, lat, blob)
182
+ for j, sv in enumerate(s.tolist()):
183
+ if sv > 0.75:
184
+ blob_high.append(bg[j].item())
185
+ for wr in wraps[8:9]:
186
+ if wr.bank.last_usage is not None:
187
+ usages.append(wr.bank.last_usage)
188
+ uvar = float(torch.cat(usages).var(dim=0).mean()) if usages else 0
189
+ return (sum(tot) / len(tot),
190
+ round(sum(blob_high) / max(len(blob_high), 1), 6),
191
+ round(uvar, 8))
192
+
193
+ results = {"config": {"steps": STEPS, "batch": BATCH, "seed": SEED}}
194
+ with ledger_run(f"dexp015 frozen s{SEED}", budget_h=0.2) as h:
195
+ unet = load_lune(device)
196
+ v, bg, _ = val(unet, [], None)
197
+ results["frozen"] = {"val": v, "blob_high": bg}
198
+ del unet
199
+ torch.cuda.empty_cache()
200
+ h["verdict"] = f"val {v:.5f}"
201
+
202
+ for arm, (cls, kind) in ARMS.items():
203
+ with ledger_run(f"dexp015 {arm} s{SEED}", budget_h=2.2) as h:
204
+ unet = load_lune(device)
205
+ mods, wraps = attach_v2(unet, cls)
206
+ for m in mods:
207
+ m.assert_zero_init()
208
+ opt = torch.optim.Adam(mods.parameters(), lr=LR,
209
+ weight_decay=0.0)
210
+ gen = torch.Generator(device=device).manual_seed(SEED + 42)
211
+ idx = torch.Generator().manual_seed(SEED + 7)
212
+ t0 = time.time()
213
+ for step in range(1, STEPS + 1):
214
+ sel = torch.randint(0, N_TRAIN, (BATCH,), generator=idx)
215
+ for wr in wraps:
216
+ wr.txt_feat = txt_of(kind, sel)
217
+ loss = loss_of(unet, wraps, cache["lat"][sel].to(device),
218
+ cache["ehs"][sel].to(device), gen)
219
+ loss.backward()
220
+ opt.step()
221
+ opt.zero_grad(set_to_none=True)
222
+ if step == 50 or step % 500 == 0:
223
+ print(f"[{arm}] step {step}: loss {loss.item():.4f} | "
224
+ f"{(time.time() - t0) / step:.2f}s/step",
225
+ flush=True)
226
+ v, bg, uvar = val(unet, wraps, kind)
227
+ entry = {"val": v, "blob_high": bg, "uvar_real": uvar}
228
+ if kind:
229
+ _, _, uvar_rep = val(unet, wraps, kind, mode="repeat")
230
+ v_mis, _, _ = val(unet, wraps, kind, mode="mismatch")
231
+ entry.update({"uvar_repeated_null": uvar_rep,
232
+ "val_mismatched_key": v_mis,
233
+ "match_advantage": round(v_mis - v, 6)})
234
+ for m in mods:
235
+ m.enabled = False
236
+ v_off, _, _ = val(unet, wraps, kind)
237
+ d = abs(v_off - results["frozen"]["val"])
238
+ assert d < 1e-9, f"toggle parity broken: {d}"
239
+ for m in mods:
240
+ m.enabled = True
241
+ torch.save({"mods": [m.state_dict() for m in mods]},
242
+ os.path.join(CKPT_DIR, f"{arm}_s{SEED}.pt"))
243
+ results[arm] = entry
244
+ del unet, mods
245
+ torch.cuda.empty_cache()
246
+ h["verdict"] = f"val {v:.5f}"
247
+
248
+ ma, ss = results["mhat_addr"], results["state_sigma"]
249
+ excess = ma["uvar_real"] - ma["uvar_repeated_null"]
250
+ results["verdict"] = {
251
+ "P1_routing_excess_over_repeated_null": round(excess, 8),
252
+ "P1_hit": excess > 2 * ma["uvar_repeated_null"],
253
+ "P2_val_vs_control": {"mhat": ma["val"], "state_sigma": ss["val"],
254
+ "ok": ma["val"] <= ss["val"] * 1.005},
255
+ "match_advantage_val": ma.get("match_advantage"),
256
+ "note": "router v2 (M-hat slots, mean composition, repeated null); "
257
+ "1-seed CANDIDATE",
258
+ }
259
+ with open(os.path.join(DATA_DIR, "results.json" if SEED == 0
260
+ else f"results_s{SEED}.json"), "w") as f:
261
+ json.dump(results, f, indent=2)
262
+ note(f"dexp015: {json.dumps(results['verdict'])}")
263
+ print(json.dumps(results["verdict"], indent=2))
264
+ burn_down()
265
+ return results
266
+
267
+
268
+ def smoke():
269
+ b = MhatAddrBank(320)
270
+ b.assert_zero_init()
271
+ x = torch.randn(2, 9, 320)
272
+ sf = fourier_sigma(torch.tensor([0.3, 0.8]))
273
+ addr = torch.randn(2, 32 * 128)
274
+ assert torch.equal(b(x, sf, addr), x), "zero-init must be exact"
275
+ w = b.addr_weights(addr)
276
+ w2 = b.addr_weights(torch.randn(2, 32 * 128))
277
+ assert w.shape == (2, 4) and not torch.equal(w, w2)
278
+ assert torch.equal(b(x, sf, None), x)
279
+ print("dexp015 smoke PASSED (M-hat slot key, mean composition, "
280
+ "zero-init/toggle)")
281
+
282
+
283
+ if __name__ == "__main__":
284
+ if "--run" in sys.argv:
285
+ run()
286
+ else:
287
+ smoke()
exp015_router_v2/results.json ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "config": {
3
+ "steps": 3000,
4
+ "batch": 16,
5
+ "seed": 0
6
+ },
7
+ "frozen": {
8
+ "val": 0.6298933834768832,
9
+ "blob_high": 0.184471
10
+ },
11
+ "state_sigma": {
12
+ "val": 0.5730983872199431,
13
+ "blob_high": 0.126756,
14
+ "uvar_real": 0.01355188
15
+ },
16
+ "mhat_addr": {
17
+ "val": 0.5749124474241398,
18
+ "blob_high": 0.128959,
19
+ "uvar_real": 0.01133719,
20
+ "uvar_repeated_null": 0.01133466,
21
+ "val_mismatched_key": 0.5749121565022506,
22
+ "match_advantage": -0.0
23
+ },
24
+ "verdict": {
25
+ "P1_routing_excess_over_repeated_null": 2.53e-06,
26
+ "P1_hit": false,
27
+ "P2_val_vs_control": {
28
+ "mhat": 0.5749124474241398,
29
+ "state_sigma": 0.5730983872199431,
30
+ "ok": true
31
+ },
32
+ "match_advantage_val": -0.0,
33
+ "note": "router v2 (M-hat slots, mean composition, repeated null); 1-seed CANDIDATE"
34
+ }
35
+ }