exp003 + exp007 shipped: sigma is the only live register axis; AMoE v1 monolith falsifier fires under uniform pressure (machinery green) — next: structural band assignment
Browse files- README.md +2 -1
- exp003_sigma_registers/README.md +42 -0
- exp003_sigma_registers/dexp003_sigma_probe.py +302 -0
- exp003_sigma_registers/results.json +90 -0
- exp007_amoe_lora/README.md +49 -0
- exp007_amoe_lora/amoe_core_s0.pt +3 -0
- exp007_amoe_lora/dexp007_amoe_lora.py +408 -0
- exp007_amoe_lora/mono_core_s0.pt +3 -0
- exp007_amoe_lora/results.json +66 -0
README.md
CHANGED
|
@@ -72,10 +72,11 @@ resolution) so gaps live in a narrow band — the paired design is load-bearing.
|
|
| 72 |
| exp000b_natural | natural-paradigm wall: format specialization is a double dissociation; SDXL core tops the NL wall | **shipped (candidate, s0)** |
|
| 73 |
| exp001_sd15_relay | relay-all16 vs matched LoRA-r32 vs frozen: **relay beats both; LoRA lands below frozen; post-train toggle bit-exact** | **shipped (candidate, s0)** |
|
| 74 |
| exp002_sd15_addrcond | addr-cond 4-arm causal: **GUIDEPOST with a pulse** — inert beside full text (real≈deranged), but the address ALONE steers (+0.029); redesign = complementarity | **shipped (candidate, s0)** |
|
| 75 |
-
| exp003_sigma_registers |
|
| 76 |
| exp004_anima_relay | relays on the 2B DiT via diffusion-pipe (bf16 per dtype law) | staged |
|
| 77 |
| exp005_sdxl_tree4a | the SDXL capacity battery (guidepost/scaffold/skeleton) | designed |
|
| 78 |
| exp006_sd15core_relay | CORE EPRED certification: **relay beats frozen (−2.5%) and matched LoRA 2-for-2; grounding gained (+0.036) where LoRA traded it; gates GROW on the core** | **shipped (candidate, s0)** |
|
|
|
|
| 79 |
|
| 80 |
Code for each experiment ships in its folder with `results.json` from the run
|
| 81 |
ledger. Substrate modules in `substrate/`.
|
|
|
|
| 72 |
| exp000b_natural | natural-paradigm wall: format specialization is a double dissociation; SDXL core tops the NL wall | **shipped (candidate, s0)** |
|
| 73 |
| exp001_sd15_relay | relay-all16 vs matched LoRA-r32 vs frozen: **relay beats both; LoRA lands below frozen; post-train toggle bit-exact** | **shipped (candidate, s0)** |
|
| 74 |
| exp002_sd15_addrcond | addr-cond 4-arm causal: **GUIDEPOST with a pulse** — inert beside full text (real≈deranged), but the address ALONE steers (+0.029); redesign = complementarity | **shipped (candidate, s0)** |
|
| 75 |
+
| exp003_sigma_registers | register probe: **sigma is the ONLY live axis** — caption/type/cond all compress to ≤0; ordering prereg MISS with design consequences | **shipped (candidate, s0)** |
|
| 76 |
| exp004_anima_relay | relays on the 2B DiT via diffusion-pipe (bf16 per dtype law) | staged |
|
| 77 |
| exp005_sdxl_tree4a | the SDXL capacity battery (guidepost/scaffold/skeleton) | designed |
|
| 78 |
| exp006_sd15core_relay | CORE EPRED certification: **relay beats frozen (−2.5%) and matched LoRA 2-for-2; grounding gained (+0.036) where LoRA traded it; gates GROW on the core** | **shipped (candidate, s0)** |
|
| 79 |
+
| exp007_amoe_lora | AMoE v1 vs monolith falsifier: **falsifier fires — uniform pressure ⇒ flat usage, dispatch pays nothing (Tree-1b law on diffusion); machinery green; next = structural band assignment** | **shipped (candidate, s0)** |
|
| 80 |
|
| 81 |
Code for each experiment ships in its folder with `results.json` from the run
|
| 82 |
ledger. Substrate modules in `substrate/`.
|
exp003_sigma_registers/README.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# exp003_sigma_registers — what is a diffusion "register"? (read-only probe)
|
| 2 |
+
|
| 3 |
+
**Question.** Does the two-regime predictor (sign-code separation reads the
|
| 4 |
+
dispatch regime before training) transfer to diffusion states, and which
|
| 5 |
+
candidate register axes actually separate?
|
| 6 |
+
|
| 7 |
+
**Design.** Deterministic same-seed-init relays on the frozen Lune ckpt-2500
|
| 8 |
+
(zero-init ⇒ the forward is the frozen model's, bit-exact); codes read at 4
|
| 9 |
+
depth-spread sites from the relay's addressing cosines (winner half-axis id +
|
| 10 |
+
orientation — read-only argmax, gauge only). Gauge: inter − intra Hamming with
|
| 11 |
+
the intra diagonal EXCLUDED (the r2 restart — NOT comparable to qwen-line
|
| 12 |
+
numbers). Axes: caption register (prompt / json_prompt / vit_json_prompt /
|
| 13 |
+
**prompt77** — aligned, same 24 rows), sigma band (4 shift-warped centers,
|
| 14 |
+
aligned), cond vs uncond (aligned), subject buckets + generator_type groups
|
| 15 |
+
(domain-style, unaligned, documented).
|
| 16 |
+
|
| 17 |
+
**Results** (`results.json`, deep site = site12):
|
| 18 |
+
|
| 19 |
+
| axis | separation | reading |
|
| 20 |
+
|---|---|---|
|
| 21 |
+
| **sigma_band** | **+0.0108 (only positive; grows with depth)** | the live axis |
|
| 22 |
+
| cond_uncond | −0.0187 | compresses |
|
| 23 |
+
| caption_register | −0.0251 (negative at every band × site) | image content dominates; format invisible |
|
| 24 |
+
| generator_type (n=8×4) | ≈ 0 (−0.004..+0.001) | even scene TYPE doesn't separate |
|
| 25 |
+
| subject_bucket | honestly skipped | dataset max ≈6 rows/subject < gauge floor 8 |
|
| 26 |
+
|
| 27 |
+
**Verdict.** Preregistered ordering MISS (predicted subject > caption > sigma
|
| 28 |
+
> cond/uncond; measured sigma > cond/uncond > caption). On frozen-UNet block
|
| 29 |
+
outputs, **content compresses everything conditioning-side to zero-or-negative
|
| 30 |
+
separation, and sigma/state is the only axis the code surface sees** — the
|
| 31 |
+
multimodal-compression precedent taken to its limit on a third substrate
|
| 32 |
+
class. Design consequence (already acted on): dispatch registers for diffusion
|
| 33 |
+
MoE should be keyed on state/sigma (exp007 wired sigma into its dispatch key),
|
| 34 |
+
and imposed structurally (step-gated band assignment) rather than discovered;
|
| 35 |
+
subject-level registers need richer data (the fused datasets) and possibly
|
| 36 |
+
cond-pathway read sites rather than block outputs.
|
| 37 |
+
|
| 38 |
+
**Caveats.** Init-time codes (P1-probe precedent) on one substrate; n=24
|
| 39 |
+
aligned rows; negative separations partly reflect the (i,i) same-input
|
| 40 |
+
cross-register pairs (documented gauge property — near-identical registers
|
| 41 |
+
read ≈ −intra/n). GPU cost ≈ 4 min total across three runs (two crashes were
|
| 42 |
+
data-shape asserts, both converted to skip-not-crash; all axes final).
|
exp003_sigma_registers/dexp003_sigma_probe.py
ADDED
|
@@ -0,0 +1,302 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""dexp003_sigma_probe.py — exp003: sign-code separations on diffusion states.
|
| 2 |
+
|
| 3 |
+
THE TIER-C GATEKEEPER (read-only, no training): does the two-regime predictor
|
| 4 |
+
transfer to diffusion, and what is a diffusion "register"? Codes are read from
|
| 5 |
+
DETERMINISTIC same-seed-init relays (P1-probe precedent — init-time probing is
|
| 6 |
+
valid; relays are zero-init so the forward is the frozen model's bit-exact).
|
| 7 |
+
|
| 8 |
+
Register axes probed (prereg ordering, charter 2026-07-16:
|
| 9 |
+
subject-bucket > caption-register > sigma-band > cond/uncond):
|
| 10 |
+
caption_register — SAME 24 rows rendered as {prompt NL, json_prompt,
|
| 11 |
+
vit_json_prompt} (aligned inputs, the gauge's home case).
|
| 12 |
+
sigma_band — same rows + cond at 4 shift-warped band centers
|
| 13 |
+
(aligned; the conditioning axis text LMs lack).
|
| 14 |
+
cond_uncond — json_prompt cond vs zeroed cond (aligned).
|
| 15 |
+
subject_bucket — top-4 dominant-subject buckets (n=12 each, content
|
| 16 |
+
differs by construction — UNALIGNED, documented; the
|
| 17 |
+
domain-style axis).
|
| 18 |
+
Sites: 4 depth-spread relay sites of the 16; codes read at the relay INPUT
|
| 19 |
+
(block output). Gauge: separation_no_diag (intra diagonal EXCLUDED — the r2
|
| 20 |
+
restart; NOT comparable to qwen-line numbers).
|
| 21 |
+
|
| 22 |
+
Pod: python3 pod2/dexp003_sigma_probe.py --run
|
| 23 |
+
"""
|
| 24 |
+
from __future__ import annotations
|
| 25 |
+
|
| 26 |
+
import io
|
| 27 |
+
import json
|
| 28 |
+
import os
|
| 29 |
+
import sys
|
| 30 |
+
from collections import Counter, defaultdict
|
| 31 |
+
|
| 32 |
+
sys.path[:0] = ["pod2", "."]
|
| 33 |
+
|
| 34 |
+
import torch
|
| 35 |
+
|
| 36 |
+
from pod_ledger import ledger_run, note
|
| 37 |
+
from aleph_diffusion_core import sign_codes, separation_no_diag
|
| 38 |
+
from d1_lune_sampler import encode_clip_225
|
| 39 |
+
from d1_substrate import attach_relays
|
| 40 |
+
|
| 41 |
+
DATASET = "AbstractPhil/synthetic-object-relations-json"
|
| 42 |
+
SD_BASE = "stable-diffusion-v1-5/stable-diffusion-v1-5"
|
| 43 |
+
SD_REPO = "AbstractPhil/sd15-flow-lune-json-prompt"
|
| 44 |
+
SD_SUB = "checkpoint-00002500/unet"
|
| 45 |
+
VAE_SCALE, SHIFT, SEED = 0.18215, 2.5, 0
|
| 46 |
+
# N_PER_BUCKET 12 was unreachable on this dataset (240 rows -> ~150 dominant
|
| 47 |
+
# subjects, max bucket 6 — single-object synthetic renders); 4 is the honest
|
| 48 |
+
# ceiling, variance noted in results. generator_type added as a second
|
| 49 |
+
# domain-style axis (bigger groups exist there).
|
| 50 |
+
N_ALIGNED, N_BUCKET_ROWS, N_PER_BUCKET = 24, 240, 4
|
| 51 |
+
PROBE_SITES = (0, 5, 8, 12) # depth spread of the 16 (asserted names)
|
| 52 |
+
BAND_CENTERS = (0.875, 0.625, 0.375, 0.125)
|
| 53 |
+
CAPTION_COLS = ("prompt", "json_prompt", "vit_json_prompt")
|
| 54 |
+
# natural-paradigm tweak (Phil 2026-07-16): the NL register is ALSO probed at
|
| 55 |
+
# the standard 77-token encode ("prompt77") alongside the 225-chunk encodes
|
| 56 |
+
NL77_REGISTER = "prompt77"
|
| 57 |
+
OUT_DIR = ("/workspace/data/dexp003" if os.path.isdir("/workspace")
|
| 58 |
+
else os.path.join(os.environ.get("GEOLIP_DATA", "./data"),
|
| 59 |
+
"dexp003"))
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
def load_tail_rows(n):
|
| 63 |
+
from huggingface_hub import HfApi, hf_hub_download
|
| 64 |
+
import pyarrow.parquet as pq
|
| 65 |
+
api = HfApi()
|
| 66 |
+
files = sorted(f for f in api.list_repo_files(DATASET, repo_type="dataset")
|
| 67 |
+
if f.endswith(".parquet"))
|
| 68 |
+
path = hf_hub_download(DATASET, files[-1], repo_type="dataset")
|
| 69 |
+
tbl = pq.read_table(path)
|
| 70 |
+
rows = tbl.slice(max(0, tbl.num_rows - n), n).to_pylist()
|
| 71 |
+
out = []
|
| 72 |
+
for r in rows:
|
| 73 |
+
img = r["image"]
|
| 74 |
+
row = {"image_bytes": img.get("bytes") if isinstance(img, dict)
|
| 75 |
+
else img,
|
| 76 |
+
"generator_type": str(r.get("generator_type", "?"))}
|
| 77 |
+
for c in CAPTION_COLS:
|
| 78 |
+
v = r.get(c)
|
| 79 |
+
row[c] = v if isinstance(v, str) else json.dumps(v)
|
| 80 |
+
out.append(row)
|
| 81 |
+
return out
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
def dominant_subject(jp: str) -> str:
|
| 85 |
+
try:
|
| 86 |
+
subs = json.loads(jp).get("subjects") or []
|
| 87 |
+
s = subs[0]
|
| 88 |
+
name = s.get("name") if isinstance(s, dict) else str(s)
|
| 89 |
+
return (name or "?").strip().lower().split()[-1]
|
| 90 |
+
except Exception:
|
| 91 |
+
return "?"
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
class SiteCapture:
|
| 95 |
+
"""Forward hooks on the wrapped blocks: stash relay-INPUT hidden states."""
|
| 96 |
+
|
| 97 |
+
def __init__(self, unet, relays, names):
|
| 98 |
+
self.stash = {}
|
| 99 |
+
self.handles = []
|
| 100 |
+
self.sites = {}
|
| 101 |
+
from aleph_diffusion_core import BlockWithRelay
|
| 102 |
+
wrapped = [(n, m) for n, m in unet.named_modules()
|
| 103 |
+
if isinstance(m, BlockWithRelay)]
|
| 104 |
+
assert len(wrapped) == len(relays)
|
| 105 |
+
for si in PROBE_SITES:
|
| 106 |
+
name, mod = wrapped[si]
|
| 107 |
+
self.sites[si] = (name, relays[si])
|
| 108 |
+
|
| 109 |
+
def mk(si):
|
| 110 |
+
def hook(m, inp, out):
|
| 111 |
+
h = out[0] if isinstance(out, tuple) else out
|
| 112 |
+
self.stash[si] = h.detach()
|
| 113 |
+
return hook
|
| 114 |
+
self.handles.append(mod.block.register_forward_hook(mk(si)))
|
| 115 |
+
|
| 116 |
+
def codes(self):
|
| 117 |
+
return {si: sign_codes(self.sites[si][1], h).cpu()
|
| 118 |
+
for si, h in self.stash.items()}
|
| 119 |
+
|
| 120 |
+
def remove(self):
|
| 121 |
+
for h in self.handles:
|
| 122 |
+
h.remove()
|
| 123 |
+
|
| 124 |
+
|
| 125 |
+
def run(device="cuda"):
|
| 126 |
+
os.makedirs(OUT_DIR, exist_ok=True)
|
| 127 |
+
import numpy as np
|
| 128 |
+
from PIL import Image
|
| 129 |
+
from diffusers import UNet2DConditionModel, AutoencoderKL
|
| 130 |
+
from transformers import CLIPTextModel, CLIPTokenizer
|
| 131 |
+
|
| 132 |
+
torch.manual_seed(SEED) # deterministic relay init
|
| 133 |
+
unet = UNet2DConditionModel.from_pretrained(
|
| 134 |
+
SD_REPO, subfolder=SD_SUB, torch_dtype=torch.float32).to(device)
|
| 135 |
+
unet.requires_grad_(False)
|
| 136 |
+
unet.eval()
|
| 137 |
+
relays, names = attach_relays(unet)
|
| 138 |
+
for r in relays:
|
| 139 |
+
r.assert_zero_init() # forward stays frozen-exact
|
| 140 |
+
cap = SiteCapture(unet, relays, names)
|
| 141 |
+
vae = AutoencoderKL.from_pretrained(
|
| 142 |
+
SD_BASE, subfolder="vae", torch_dtype=torch.float32).to(device).eval()
|
| 143 |
+
tok = CLIPTokenizer.from_pretrained(SD_BASE, subfolder="tokenizer")
|
| 144 |
+
te = CLIPTextModel.from_pretrained(
|
| 145 |
+
SD_BASE, subfolder="text_encoder",
|
| 146 |
+
torch_dtype=torch.float32).to(device).eval()
|
| 147 |
+
|
| 148 |
+
@torch.no_grad()
|
| 149 |
+
def latents_of(rows):
|
| 150 |
+
px = torch.stack([
|
| 151 |
+
torch.from_numpy(np.asarray(
|
| 152 |
+
Image.open(io.BytesIO(r["image_bytes"])).convert("RGB")
|
| 153 |
+
.resize((512, 512)))).float().permute(2, 0, 1) / 127.5 - 1.0
|
| 154 |
+
for r in rows]).to(device)
|
| 155 |
+
g = torch.Generator(device=device).manual_seed(SEED)
|
| 156 |
+
return vae.encode(px).latent_dist.sample(generator=g) * VAE_SCALE
|
| 157 |
+
|
| 158 |
+
@torch.no_grad()
|
| 159 |
+
def probe(lat, ehs, sigma):
|
| 160 |
+
g = torch.Generator(device=device).manual_seed(SEED + 99)
|
| 161 |
+
noise = torch.randn(lat.shape, generator=g, device=device)
|
| 162 |
+
x = noise * sigma + lat * (1 - sigma)
|
| 163 |
+
t = torch.full((lat.shape[0],), sigma * 1000.0, device=device)
|
| 164 |
+
unet(x, t, ehs, return_dict=False)
|
| 165 |
+
return cap.codes()
|
| 166 |
+
|
| 167 |
+
results = {"gauge": "separation_no_diag (intra diagonal excluded; "
|
| 168 |
+
"NOT comparable to qwen-line numbers)",
|
| 169 |
+
"sites": {si: cap.sites[si][0] for si in PROBE_SITES},
|
| 170 |
+
"band_centers": BAND_CENTERS, "seed": SEED, "axes": {}}
|
| 171 |
+
|
| 172 |
+
with ledger_run("dexp003 register probe", budget_h=1.0) as h:
|
| 173 |
+
rows = load_tail_rows(N_ALIGNED)
|
| 174 |
+
lat = latents_of(rows)
|
| 175 |
+
ehs_by_col = {}
|
| 176 |
+
with torch.no_grad():
|
| 177 |
+
for c in CAPTION_COLS:
|
| 178 |
+
ehs_by_col[c] = encode_clip_225(
|
| 179 |
+
[r[c] for r in rows], tok, te, device)
|
| 180 |
+
# natural-paradigm register: standard 77-token encode of the NL col
|
| 181 |
+
ids = tok([r["prompt"] for r in rows], padding="max_length",
|
| 182 |
+
max_length=tok.model_max_length, truncation=True,
|
| 183 |
+
return_tensors="pt").input_ids.to(device)
|
| 184 |
+
ehs_by_col[NL77_REGISTER] = te(ids)[0]
|
| 185 |
+
|
| 186 |
+
# axis 1: caption register (aligned), per band x site
|
| 187 |
+
regs = list(CAPTION_COLS) + [NL77_REGISTER]
|
| 188 |
+
ax = {}
|
| 189 |
+
for b, s in enumerate(BAND_CENTERS):
|
| 190 |
+
codes = {c: probe(lat, ehs_by_col[c], s) for c in regs}
|
| 191 |
+
for si in PROBE_SITES:
|
| 192 |
+
ax[f"band{b}_site{si}"] = round(separation_no_diag(
|
| 193 |
+
{c: codes[c][si] for c in regs}), 4)
|
| 194 |
+
results["axes"]["caption_register"] = ax
|
| 195 |
+
print(f"[exp003] caption_register: {ax}", flush=True)
|
| 196 |
+
|
| 197 |
+
# axis 2: sigma band (aligned; json_prompt cond), per site
|
| 198 |
+
codes_by_band = {f"s{b}": probe(lat, ehs_by_col["json_prompt"], s)
|
| 199 |
+
for b, s in enumerate(BAND_CENTERS)}
|
| 200 |
+
ax = {f"site{si}": round(separation_no_diag(
|
| 201 |
+
{k: v[si] for k, v in codes_by_band.items()}), 4)
|
| 202 |
+
for si in PROBE_SITES}
|
| 203 |
+
results["axes"]["sigma_band"] = ax
|
| 204 |
+
print(f"[exp003] sigma_band: {ax}", flush=True)
|
| 205 |
+
|
| 206 |
+
# axis 3: cond vs uncond (aligned), mid band, per site
|
| 207 |
+
cu = {"cond": probe(lat, ehs_by_col["json_prompt"], 0.625),
|
| 208 |
+
"uncond": probe(lat, torch.zeros_like(
|
| 209 |
+
ehs_by_col["json_prompt"]), 0.625)}
|
| 210 |
+
ax = {f"site{si}": round(separation_no_diag(
|
| 211 |
+
{k: v[si] for k, v in cu.items()}), 4) for si in PROBE_SITES}
|
| 212 |
+
results["axes"]["cond_uncond"] = ax
|
| 213 |
+
print(f"[exp003] cond_uncond: {ax}", flush=True)
|
| 214 |
+
|
| 215 |
+
# axis 4: domain-style groups (UNALIGNED, documented): subject buckets
|
| 216 |
+
# (n small on this dataset — variance flag) + generator_type groups
|
| 217 |
+
pool = load_tail_rows(N_BUCKET_ROWS)
|
| 218 |
+
|
| 219 |
+
def group_axis(name, keyfn, min_n):
|
| 220 |
+
groups = defaultdict(list)
|
| 221 |
+
for r in pool:
|
| 222 |
+
groups[keyfn(r)].append(r)
|
| 223 |
+
top = [s for s, c in Counter(
|
| 224 |
+
{k: len(v) for k, v in groups.items()}).most_common(6)
|
| 225 |
+
if len(groups[s]) >= min_n and s != "?"][:4]
|
| 226 |
+
if len(top) < 2:
|
| 227 |
+
results["axes"][name] = {
|
| 228 |
+
"skipped": f"only {len(top)} groups >= {min_n}",
|
| 229 |
+
"sizes": dict(Counter(
|
| 230 |
+
{k: len(v) for k, v in groups.items()}))}
|
| 231 |
+
print(f"[exp003] {name}: SKIPPED (group sizes too small)",
|
| 232 |
+
flush=True)
|
| 233 |
+
return
|
| 234 |
+
codes = {}
|
| 235 |
+
for s in top:
|
| 236 |
+
rs = groups[s][:min_n]
|
| 237 |
+
l = latents_of(rs)
|
| 238 |
+
with torch.no_grad():
|
| 239 |
+
e = encode_clip_225([r["json_prompt"] for r in rs], tok,
|
| 240 |
+
te, device)
|
| 241 |
+
codes[s] = probe(l, e, 0.625)
|
| 242 |
+
try:
|
| 243 |
+
ax = {f"site{si}": round(separation_no_diag(
|
| 244 |
+
{k: v[si] for k, v in codes.items()}), 4)
|
| 245 |
+
for si in PROBE_SITES}
|
| 246 |
+
except AssertionError as e:
|
| 247 |
+
# gauge n-floor (>=8): axis honestly unmeasurable at this n —
|
| 248 |
+
# record, never crash (this dataset's subjects max out at ~6)
|
| 249 |
+
results["axes"][name] = {"groups": top, "n_per_group": min_n,
|
| 250 |
+
"skipped": f"gauge n-floor: {e}"}
|
| 251 |
+
print(f"[exp003] {name}: SKIPPED ({e})", flush=True)
|
| 252 |
+
return
|
| 253 |
+
results["axes"][name] = {"groups": top, "n_per_group": min_n, **ax}
|
| 254 |
+
print(f"[exp003] {name} ({top}): {ax}", flush=True)
|
| 255 |
+
|
| 256 |
+
group_axis("subject_bucket",
|
| 257 |
+
lambda r: dominant_subject(r["json_prompt"]), N_PER_BUCKET)
|
| 258 |
+
group_axis("generator_type", lambda r: r["generator_type"], 8)
|
| 259 |
+
|
| 260 |
+
# prereg ordering check at the deepest probed site
|
| 261 |
+
deep = f"site{PROBE_SITES[-1]}"
|
| 262 |
+
order = {
|
| 263 |
+
"caption_register": results["axes"]["caption_register"]
|
| 264 |
+
[f"band1_{deep}"],
|
| 265 |
+
"sigma_band": results["axes"]["sigma_band"][deep],
|
| 266 |
+
"cond_uncond": results["axes"]["cond_uncond"][deep],
|
| 267 |
+
}
|
| 268 |
+
sb = results["axes"].get("subject_bucket", {})
|
| 269 |
+
if deep in sb:
|
| 270 |
+
order["subject_bucket"] = sb[deep]
|
| 271 |
+
ranked = sorted(order, key=order.get, reverse=True)
|
| 272 |
+
results["prereg"] = {
|
| 273 |
+
"predicted_order": ["subject_bucket", "caption_register",
|
| 274 |
+
"sigma_band", "cond_uncond"],
|
| 275 |
+
"measured_order": ranked,
|
| 276 |
+
"measured_values_at_deep_site": order,
|
| 277 |
+
"order_hit": ranked[:len(order)] == [
|
| 278 |
+
k for k in ["subject_bucket", "caption_register",
|
| 279 |
+
"sigma_band", "cond_uncond"] if k in order],
|
| 280 |
+
}
|
| 281 |
+
h["verdict"] = f"order {'HIT' if results['prereg']['order_hit'] else 'MISS'}: {ranked}"
|
| 282 |
+
|
| 283 |
+
cap.remove()
|
| 284 |
+
with open(os.path.join(OUT_DIR, "results.json"), "w") as f:
|
| 285 |
+
json.dump(results, f, indent=2)
|
| 286 |
+
note(f"dexp003: {json.dumps(results['prereg'])}")
|
| 287 |
+
print(json.dumps(results["prereg"], indent=2))
|
| 288 |
+
return results
|
| 289 |
+
|
| 290 |
+
|
| 291 |
+
def smoke():
|
| 292 |
+
assert dominant_subject('{"subjects":[{"name":"a red car"}]}') == "car"
|
| 293 |
+
assert dominant_subject('{"subjects":["tall man"]}') == "man"
|
| 294 |
+
assert dominant_subject("not json") == "?"
|
| 295 |
+
print("dexp003 smoke PASSED (parse; GPU run is pod work)")
|
| 296 |
+
|
| 297 |
+
|
| 298 |
+
if __name__ == "__main__":
|
| 299 |
+
if "--run" in sys.argv:
|
| 300 |
+
run()
|
| 301 |
+
else:
|
| 302 |
+
smoke()
|
exp003_sigma_registers/results.json
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"gauge": "separation_no_diag (intra diagonal excluded; NOT comparable to qwen-line numbers)",
|
| 3 |
+
"sites": {
|
| 4 |
+
"0": "down_blocks.0.attentions.0.transformer_blocks.0",
|
| 5 |
+
"5": "down_blocks.2.attentions.1.transformer_blocks.0",
|
| 6 |
+
"8": "up_blocks.1.attentions.2.transformer_blocks.0",
|
| 7 |
+
"12": "up_blocks.3.attentions.0.transformer_blocks.0"
|
| 8 |
+
},
|
| 9 |
+
"band_centers": [
|
| 10 |
+
0.875,
|
| 11 |
+
0.625,
|
| 12 |
+
0.375,
|
| 13 |
+
0.125
|
| 14 |
+
],
|
| 15 |
+
"seed": 0,
|
| 16 |
+
"axes": {
|
| 17 |
+
"caption_register": {
|
| 18 |
+
"band0_site0": -0.0272,
|
| 19 |
+
"band0_site5": -0.0094,
|
| 20 |
+
"band0_site8": -0.0106,
|
| 21 |
+
"band0_site12": -0.0185,
|
| 22 |
+
"band1_site0": -0.0312,
|
| 23 |
+
"band1_site5": -0.017,
|
| 24 |
+
"band1_site8": -0.0208,
|
| 25 |
+
"band1_site12": -0.0251,
|
| 26 |
+
"band2_site0": -0.035,
|
| 27 |
+
"band2_site5": -0.0234,
|
| 28 |
+
"band2_site8": -0.028,
|
| 29 |
+
"band2_site12": -0.0316,
|
| 30 |
+
"band3_site0": -0.0368,
|
| 31 |
+
"band3_site5": -0.0274,
|
| 32 |
+
"band3_site8": -0.0316,
|
| 33 |
+
"band3_site12": -0.0348
|
| 34 |
+
},
|
| 35 |
+
"sigma_band": {
|
| 36 |
+
"site0": 0.0039,
|
| 37 |
+
"site5": -0.0,
|
| 38 |
+
"site8": -0.0004,
|
| 39 |
+
"site12": 0.0108
|
| 40 |
+
},
|
| 41 |
+
"cond_uncond": {
|
| 42 |
+
"site0": -0.0269,
|
| 43 |
+
"site5": -0.0122,
|
| 44 |
+
"site8": -0.013,
|
| 45 |
+
"site12": -0.0187
|
| 46 |
+
},
|
| 47 |
+
"subject_bucket": {
|
| 48 |
+
"groups": [
|
| 49 |
+
"garlic",
|
| 50 |
+
"cucumber",
|
| 51 |
+
"potato",
|
| 52 |
+
"banana"
|
| 53 |
+
],
|
| 54 |
+
"n_per_group": 4,
|
| 55 |
+
"skipped": "gauge n-floor: too few aligned inputs"
|
| 56 |
+
},
|
| 57 |
+
"generator_type": {
|
| 58 |
+
"groups": [
|
| 59 |
+
"produce_pair",
|
| 60 |
+
"two_on_surface",
|
| 61 |
+
"object_on_surface",
|
| 62 |
+
"item_in_container"
|
| 63 |
+
],
|
| 64 |
+
"n_per_group": 8,
|
| 65 |
+
"site0": -0.0041,
|
| 66 |
+
"site5": -0.0001,
|
| 67 |
+
"site8": 0.0008,
|
| 68 |
+
"site12": -0.0009
|
| 69 |
+
}
|
| 70 |
+
},
|
| 71 |
+
"prereg": {
|
| 72 |
+
"predicted_order": [
|
| 73 |
+
"subject_bucket",
|
| 74 |
+
"caption_register",
|
| 75 |
+
"sigma_band",
|
| 76 |
+
"cond_uncond"
|
| 77 |
+
],
|
| 78 |
+
"measured_order": [
|
| 79 |
+
"sigma_band",
|
| 80 |
+
"cond_uncond",
|
| 81 |
+
"caption_register"
|
| 82 |
+
],
|
| 83 |
+
"measured_values_at_deep_site": {
|
| 84 |
+
"caption_register": -0.0251,
|
| 85 |
+
"sigma_band": 0.0108,
|
| 86 |
+
"cond_uncond": -0.0187
|
| 87 |
+
},
|
| 88 |
+
"order_hit": false
|
| 89 |
+
}
|
| 90 |
+
}
|
exp007_amoe_lora/README.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# exp007_amoe_lora — AMoE-LoRA v1: the first dispatch test (CANDIDATE, s0)
|
| 2 |
+
|
| 3 |
+
**Question.** Does a bank of experts under dense signed aleph dispatch (keyed
|
| 4 |
+
on hidden state + sigma) beat a parameter-matched monolith on the certified
|
| 5 |
+
core-epred substrate? First MoE-structure experiment of the line.
|
| 6 |
+
|
| 7 |
+
**Structure per site (16 sites).** A=4 zero-init rank-8 low-rank residual
|
| 8 |
+
experts; dispatch = dense SIGNED aleph coefficients per token (sinh/cosh over
|
| 9 |
+
A oriented axes — no softmax gate, no top-k, no balance loss; usage read-only)
|
| 10 |
+
with sigma Fourier features added to the dispatch key (the exp003 finding:
|
| 11 |
+
sigma is the live register axis). Combine: `x + Σ σ(gate_k)·w_k(x,σ)·Δ_k(x)`.
|
| 12 |
+
Falsifier: one rank-32 delta per site, same placement, no dispatch (the
|
| 13 |
+
matched-monolith control). 3000 steps each, batch 16, pure Adam wd=0.
|
| 14 |
+
|
| 15 |
+
**Results** (`results.json`):
|
| 16 |
+
|
| 17 |
+
| arm | trainable | val eps-MSE | Δ vs frozen |
|
| 18 |
+
|---|---|---|---|
|
| 19 |
+
| frozen | 0 | 0.124788 | — |
|
| 20 |
+
| amoe A4r8 | 899,392 | 0.122015 | −2.2% |
|
| 21 |
+
| **monolith r32** | 811,216 | **0.121777** | **−2.4%** |
|
| 22 |
+
|
| 23 |
+
| prereg | outcome |
|
| 24 |
+
|---|---|
|
| 25 |
+
| P1 bank ≥ monolith | **MISS** (monolith wins by 0.0002 with 11% fewer params) |
|
| 26 |
+
| P2 sigma-band usage differentiation | **MISS** — spread 0.0009; usage ≈ [0.25, 0.17, 0.33, 0.24] in EVERY band |
|
| 27 |
+
| P3 toggle bit-exact post-train | HIT (≡ frozen to full precision) |
|
| 28 |
+
| P4 no dead experts | HIT (all four alive, 0.17–0.33) |
|
| 29 |
+
|
| 30 |
+
**Verdict (the falsifier did its job).** Under UNIFORM training pressure — one
|
| 31 |
+
dataset, one objective, one register — dispatch pays nothing over a single
|
| 32 |
+
matched-width delta, and the sigma-keyed dispatch never uses its sigma
|
| 33 |
+
freedom. This reproduces the text line's Tree-1b/exp009 law on a diffusion
|
| 34 |
+
trunk: *specialization requires differentiated pressure; the aggregation
|
| 35 |
+
channel alone doesn't create it.* The experts blended (uniform usage) exactly
|
| 36 |
+
as the two-regime law predicts for register-distance-zero mixtures.
|
| 37 |
+
|
| 38 |
+
**What it buys the program.** The machinery is sound (parity, liveness,
|
| 39 |
+
signed dense dispatch all green) and per-param the bank units are efficient
|
| 40 |
+
(−2.2% at 0.9M vs the relay's −2.5% at 3.2M). The next MoE test must IMPOSE
|
| 41 |
+
structure rather than hope dispatch discovers it in uniform data — the
|
| 42 |
+
designed follow-on is the step-gated controller: experts ASSIGNED to sigma
|
| 43 |
+
bands with per-band loss masking (coarse-to-fine), judged against this same
|
| 44 |
+
monolith. Subject-bucketed expert assignment is the second axis (needs the
|
| 45 |
+
richer fused datasets; this synthetic set's subject buckets max out at n≈6).
|
| 46 |
+
|
| 47 |
+
**Caveats.** Single seed; 3k steps; A=4/r=8 single scale point; param match
|
| 48 |
+
1.109 (bank heavier — disclosed); one substrate. Cost ≈ 3.0 GPU-h.
|
| 49 |
+
Checkpoints: `amoe_core_s0.pt`, `mono_core_s0.pt`.
|
exp007_amoe_lora/amoe_core_s0.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:37928cf2d2ce85b4ca38d160c428e2fc118aa884dc882238631716a1764a7c45
|
| 3 |
+
size 3681565
|
exp007_amoe_lora/dexp007_amoe_lora.py
ADDED
|
@@ -0,0 +1,408 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""dexp007_amoe_lora.py — exp007: AMoE-LoRA v1 — the first dispatch test.
|
| 2 |
+
|
| 3 |
+
THE FIRST MoE-STRUCTURE EXPERIMENT of the line (Phil: the MoE is the weekend
|
| 4 |
+
goal; hit it only as fast as results yield). GATED: launches only after
|
| 5 |
+
exp006 certifies the anchor unit on the epred core (env DEXP7_SUBSTRATE=core)
|
| 6 |
+
— else holds, or runs on the exp001-certified lune trunk (=lune).
|
| 7 |
+
|
| 8 |
+
Structure per site (16 BasicTransformerBlocks), doctrine-compliant
|
| 9 |
+
(progression-plan Part II.2 — no softmax gate, no top-k, no balance loss):
|
| 10 |
+
experts — A=4 zero-init low-rank residual deltas on the block output:
|
| 11 |
+
down Linear(d, r=8, bias=False) -> up Linear(r=8, d) zero W+b.
|
| 12 |
+
dispatch — DENSE SIGNED aleph coefficients: key = normalize(key_proj(
|
| 13 |
+
x_token) + sig_proj(fourier(sigma))) in D=4; codebook K=A axes;
|
| 14 |
+
w_k = sinh(u_k)/sum cosh(u_j) per token — signed, no selection
|
| 15 |
+
event; usage logged READ-ONLY.
|
| 16 |
+
combine — x + sum_k sigmoid(gate_k) * w_k * expert_k(x); gates init -3.0.
|
| 17 |
+
toggle — enabled=False returns x (bit-exact law preserved).
|
| 18 |
+
Sigma enters the DISPATCH KEY (exp003 finding: sigma/state is the live
|
| 19 |
+
register axis; caption registers compress).
|
| 20 |
+
|
| 21 |
+
Arms (shared cache, paired val, pure Adam wd=0, dtype matched to trunk):
|
| 22 |
+
frozen | amoe (A=4, r=8) | monolith LoRA-shape rank A*r=32 on the same
|
| 23 |
+
placement (THE FALSIFIER — matched total params, no dispatch; if it matches
|
| 24 |
+
the bank everywhere, dispatch pays nothing at this scale).
|
| 25 |
+
|
| 26 |
+
Prereg (charter): P1 amoe >= monolith on paired val; P2 dispatch usage
|
| 27 |
+
DIFFERENTIATES by sigma band (variance of per-band mean |w| exceeds a
|
| 28 |
+
shuffled-band null x3); P3 toggle bit-exact post-train; P4 no dead experts
|
| 29 |
+
(every expert's mean |w| > 0.02 of total). Honest negative: amoe ~ monolith
|
| 30 |
+
=> the aggregation channel (Law 1) needs rework before any bigger MoE.
|
| 31 |
+
|
| 32 |
+
Pod: DEXP7_SUBSTRATE=core|lune bash pod2/run_exp007.sh (time-boxed: steps
|
| 33 |
+
sized so the run NEVER crosses the 8am PT halt)
|
| 34 |
+
"""
|
| 35 |
+
from __future__ import annotations
|
| 36 |
+
|
| 37 |
+
import io
|
| 38 |
+
import json
|
| 39 |
+
import math
|
| 40 |
+
import os
|
| 41 |
+
import sys
|
| 42 |
+
import time
|
| 43 |
+
|
| 44 |
+
sys.path[:0] = ["pod2", "."]
|
| 45 |
+
|
| 46 |
+
import torch
|
| 47 |
+
import torch.nn as nn
|
| 48 |
+
import torch.nn.functional as F
|
| 49 |
+
|
| 50 |
+
from pod_ledger import ledger_run, note, burn_down
|
| 51 |
+
from aleph_diffusion_core import derangement, sigma_band, SIGMA_BANDS
|
| 52 |
+
from d1_substrate import enumerate_sd15_sites, MEM_FRACTION
|
| 53 |
+
|
| 54 |
+
SUBSTRATE = os.environ.get("DEXP7_SUBSTRATE", "core")
|
| 55 |
+
SD_BASE = "stable-diffusion-v1-5/stable-diffusion-v1-5"
|
| 56 |
+
LUNE_REPO = "AbstractPhil/sd15-flow-lune-json-prompt"
|
| 57 |
+
LUNE_SUB = "checkpoint-00002500/unet"
|
| 58 |
+
N_TRAIN, N_VAL = 4096, 256
|
| 59 |
+
A_EXPERTS, RANK = 4, 8
|
| 60 |
+
BATCH = int(os.environ.get("DEXP7_BATCH", "16"))
|
| 61 |
+
STEPS = int(os.environ.get("DEXP7_STEPS", "3000"))
|
| 62 |
+
LR, CFG_DROPOUT, SEED, SHIFT, VAE_SCALE = 1e-3, 0.1, 0, 2.5, 0.18215
|
| 63 |
+
DATA_DIR = ("/workspace/data/dexp007" if os.path.isdir("/workspace")
|
| 64 |
+
else os.path.join(os.environ.get("GEOLIP_DATA", "./data"),
|
| 65 |
+
"dexp007"))
|
| 66 |
+
CKPT_DIR = ("/workspace/ckpts2/dexp007" if os.path.isdir("/workspace")
|
| 67 |
+
else DATA_DIR)
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
def fourier_sigma(s, dim=8):
|
| 71 |
+
"""s in [0,1] (or t/1000) -> small Fourier features [B, dim]."""
|
| 72 |
+
freqs = torch.pow(2.0, torch.arange(dim // 2, device=s.device))
|
| 73 |
+
ang = 2 * math.pi * s[:, None] * freqs[None]
|
| 74 |
+
return torch.cat([torch.sin(ang), torch.cos(ang)], dim=-1)
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
class AmoeBank(nn.Module):
|
| 78 |
+
"""A experts + dense signed aleph dispatch, one bank per site."""
|
| 79 |
+
|
| 80 |
+
def __init__(self, d: int, A: int = A_EXPERTS, r: int = RANK,
|
| 81 |
+
D: int = 4, tau: float = 0.1):
|
| 82 |
+
super().__init__()
|
| 83 |
+
self.d, self.A, self.r, self.tau = d, A, r, tau
|
| 84 |
+
self.down = nn.ModuleList(nn.Linear(d, r, bias=False)
|
| 85 |
+
for _ in range(A))
|
| 86 |
+
self.up = nn.ModuleList(nn.Linear(r, d) for _ in range(A))
|
| 87 |
+
for dn, up in zip(self.down, self.up):
|
| 88 |
+
nn.init.orthogonal_(dn.weight)
|
| 89 |
+
nn.init.zeros_(up.weight) # zero-init out: weight
|
| 90 |
+
nn.init.zeros_(up.bias) # AND bias (leak law)
|
| 91 |
+
self.key_proj = nn.Linear(d, D, bias=False)
|
| 92 |
+
nn.init.orthogonal_(self.key_proj.weight)
|
| 93 |
+
self.sig_proj = nn.Linear(8, D, bias=False)
|
| 94 |
+
nn.init.orthogonal_(self.sig_proj.weight)
|
| 95 |
+
self.codebook = nn.Parameter(
|
| 96 |
+
F.normalize(torch.randn(A, D), dim=-1))
|
| 97 |
+
self.gates = nn.Parameter(torch.full((A,), -3.0))
|
| 98 |
+
self.enabled = True
|
| 99 |
+
self.last_usage = None # read-only telemetry
|
| 100 |
+
|
| 101 |
+
def assert_zero_init(self):
|
| 102 |
+
for up in self.up:
|
| 103 |
+
assert up.weight.abs().max().item() == 0.0
|
| 104 |
+
assert up.bias.abs().max().item() == 0.0
|
| 105 |
+
|
| 106 |
+
def dispatch(self, x, sig_feat):
|
| 107 |
+
"""Dense signed coefficients per token: (..., A). No selection event."""
|
| 108 |
+
sig = self.sig_proj(sig_feat) # (B, D)
|
| 109 |
+
sig = sig.view(sig.shape[0], *([1] * (x.ndim - 2)), sig.shape[-1])
|
| 110 |
+
key = self.key_proj(x) + sig # rank-aware broadcast
|
| 111 |
+
Ax = F.normalize(self.codebook, dim=-1)
|
| 112 |
+
u = (F.normalize(key, dim=-1) @ Ax.transpose(-1, -2)) / self.tau
|
| 113 |
+
m = u.abs().amax(dim=-1, keepdim=True)
|
| 114 |
+
ep, en = torch.exp(u - m), torch.exp(-u - m)
|
| 115 |
+
return (ep - en) / (ep + en).sum(dim=-1, keepdim=True)
|
| 116 |
+
|
| 117 |
+
def forward(self, x, sig_feat):
|
| 118 |
+
if not self.enabled:
|
| 119 |
+
return x
|
| 120 |
+
w = self.dispatch(x, sig_feat) # (B, T, A) signed
|
| 121 |
+
with torch.no_grad():
|
| 122 |
+
self.last_usage = w.abs().mean(dim=(0, 1)).detach().cpu()
|
| 123 |
+
delta = 0
|
| 124 |
+
g = torch.sigmoid(self.gates)
|
| 125 |
+
for k in range(self.A):
|
| 126 |
+
delta = delta + g[k] * w[..., k:k + 1] * self.up[k](
|
| 127 |
+
self.down[k](x))
|
| 128 |
+
return x + delta
|
| 129 |
+
|
| 130 |
+
|
| 131 |
+
class BlockWithBank(nn.Module):
|
| 132 |
+
"""Wrap: bank reads block output + the batch sigma stashed on self."""
|
| 133 |
+
|
| 134 |
+
def __init__(self, block, bank):
|
| 135 |
+
super().__init__()
|
| 136 |
+
self.block = block
|
| 137 |
+
self.bank = bank
|
| 138 |
+
self.sig_feat = None # set per step by the bed
|
| 139 |
+
|
| 140 |
+
def forward(self, *args, **kwargs):
|
| 141 |
+
out = self.block(*args, **kwargs)
|
| 142 |
+
h = out[0] if isinstance(out, tuple) else out
|
| 143 |
+
h = self.bank(h, self.sig_feat)
|
| 144 |
+
return (h,) + out[1:] if isinstance(out, tuple) else h
|
| 145 |
+
|
| 146 |
+
|
| 147 |
+
class MonoLora(nn.Module):
|
| 148 |
+
"""The falsifier: one rank-A*r delta, same placement, no dispatch."""
|
| 149 |
+
|
| 150 |
+
def __init__(self, d: int, r: int = A_EXPERTS * RANK):
|
| 151 |
+
super().__init__()
|
| 152 |
+
self.down = nn.Linear(d, r, bias=False)
|
| 153 |
+
nn.init.orthogonal_(self.down.weight)
|
| 154 |
+
self.up = nn.Linear(r, d)
|
| 155 |
+
nn.init.zeros_(self.up.weight)
|
| 156 |
+
nn.init.zeros_(self.up.bias)
|
| 157 |
+
self.gate = nn.Parameter(torch.tensor(-3.0))
|
| 158 |
+
self.enabled = True
|
| 159 |
+
|
| 160 |
+
def forward(self, x, sig_feat=None):
|
| 161 |
+
if not self.enabled:
|
| 162 |
+
return x
|
| 163 |
+
return x + torch.sigmoid(self.gate) * self.up(self.down(x))
|
| 164 |
+
|
| 165 |
+
|
| 166 |
+
def load_unet(device):
|
| 167 |
+
from diffusers import UNet2DConditionModel
|
| 168 |
+
if SUBSTRATE == "lune":
|
| 169 |
+
unet = UNet2DConditionModel.from_pretrained(
|
| 170 |
+
LUNE_REPO, subfolder=LUNE_SUB, torch_dtype=torch.float32)
|
| 171 |
+
else:
|
| 172 |
+
unet = UNet2DConditionModel.from_pretrained(
|
| 173 |
+
SD_BASE, subfolder="unet", torch_dtype=torch.float32)
|
| 174 |
+
unet = unet.to(device)
|
| 175 |
+
unet.requires_grad_(False)
|
| 176 |
+
unet.eval()
|
| 177 |
+
unet.enable_gradient_checkpointing()
|
| 178 |
+
return unet
|
| 179 |
+
|
| 180 |
+
|
| 181 |
+
def attach_banks(unet, mk):
|
| 182 |
+
sites = enumerate_sd15_sites(unet)
|
| 183 |
+
assert len(sites) == 16
|
| 184 |
+
mods, wraps = nn.ModuleList(), []
|
| 185 |
+
for name, block, d in sites:
|
| 186 |
+
p0 = next(block.parameters())
|
| 187 |
+
m = mk(d).to(device=p0.device, dtype=p0.dtype)
|
| 188 |
+
w = BlockWithBank(block, m)
|
| 189 |
+
parent = unet
|
| 190 |
+
parts = name.split(".")
|
| 191 |
+
for p in parts[:-1]:
|
| 192 |
+
parent = getattr(parent, p) if not p.isdigit() else parent[int(p)]
|
| 193 |
+
if parts[-1].isdigit():
|
| 194 |
+
parent[int(parts[-1])] = w
|
| 195 |
+
else:
|
| 196 |
+
setattr(parent, parts[-1], w)
|
| 197 |
+
mods.append(m)
|
| 198 |
+
wraps.append(w)
|
| 199 |
+
return mods, wraps
|
| 200 |
+
|
| 201 |
+
|
| 202 |
+
def get_cache(device):
|
| 203 |
+
"""Reuse the substrate-matching cache (dexp001 for lune / dexp006 core)."""
|
| 204 |
+
src = "/workspace/data/dexp001" if SUBSTRATE == "lune" \
|
| 205 |
+
else "/workspace/data/dexp006"
|
| 206 |
+
f = os.path.join(src, "cache.pt")
|
| 207 |
+
assert os.path.exists(f), f"needs {f} (run the substrate's exp first)"
|
| 208 |
+
return torch.load(f, map_location="cpu", weights_only=True)
|
| 209 |
+
|
| 210 |
+
|
| 211 |
+
def sigma_of(cache_has_t, gen, bsz, device):
|
| 212 |
+
if cache_has_t: # epred core: t in 0..999
|
| 213 |
+
t = torch.randint(0, 1000, (bsz,), generator=gen, device=device)
|
| 214 |
+
return t, t.float() / 1000.0
|
| 215 |
+
s = torch.rand(bsz, generator=gen, device=device)
|
| 216 |
+
s = (SHIFT * s) / (1 + (SHIFT - 1) * s)
|
| 217 |
+
return s * 1000, s
|
| 218 |
+
|
| 219 |
+
|
| 220 |
+
def run(device="cuda"):
|
| 221 |
+
torch.cuda.set_per_process_memory_fraction(MEM_FRACTION, 0)
|
| 222 |
+
os.makedirs(CKPT_DIR, exist_ok=True)
|
| 223 |
+
os.makedirs(DATA_DIR, exist_ok=True)
|
| 224 |
+
cache = get_cache(device)
|
| 225 |
+
epred = SUBSTRATE != "lune"
|
| 226 |
+
if epred:
|
| 227 |
+
from dexp006_sd15core_relay import make_schedule, add_noise
|
| 228 |
+
acp = make_schedule(device)
|
| 229 |
+
|
| 230 |
+
def loss_of(unet, wraps, lat, ehs, gen):
|
| 231 |
+
bsz = lat.shape[0]
|
| 232 |
+
drop = torch.rand(bsz, generator=gen, device=device) < CFG_DROPOUT
|
| 233 |
+
ehs = ehs.clone()
|
| 234 |
+
ehs[drop] = 0
|
| 235 |
+
t, s01 = sigma_of(epred, gen, bsz, device)
|
| 236 |
+
sf = fourier_sigma(s01).to(lat.dtype)
|
| 237 |
+
for w in wraps:
|
| 238 |
+
w.sig_feat = sf
|
| 239 |
+
noise = torch.randn(lat.shape, generator=gen, device=device)
|
| 240 |
+
if epred:
|
| 241 |
+
noisy = add_noise(lat, noise, t.long(), acp)
|
| 242 |
+
target = noise
|
| 243 |
+
else:
|
| 244 |
+
s4 = s01[:, None, None, None]
|
| 245 |
+
noisy = noise * s4 + lat * (1 - s4)
|
| 246 |
+
target = noise - lat
|
| 247 |
+
pred = unet(noisy, t, ehs, return_dict=False)[0]
|
| 248 |
+
return F.mse_loss(pred, target)
|
| 249 |
+
|
| 250 |
+
@torch.no_grad()
|
| 251 |
+
def val(unet, wraps):
|
| 252 |
+
tot, band_usage = [], {i: [] for i in range(len(SIGMA_BANDS))}
|
| 253 |
+
for i in range(0, N_VAL, 32):
|
| 254 |
+
lat = cache["val_lat"][i:i + 32].to(device)
|
| 255 |
+
ehs = cache["val_ehs"][i:i + 32].to(device)
|
| 256 |
+
noise = cache["val_noise"][i:i + 32].to(device)
|
| 257 |
+
if epred:
|
| 258 |
+
t = cache["val_t"][i:i + 32].to(device)
|
| 259 |
+
s01 = t.float() / 1000.0
|
| 260 |
+
noisy, target = add_noise(lat, noise, t, acp), noise
|
| 261 |
+
else:
|
| 262 |
+
s = cache["val_sigma"][i:i + 32].to(device)
|
| 263 |
+
s01 = s
|
| 264 |
+
s4 = s[:, None, None, None]
|
| 265 |
+
noisy, target = noise * s4 + lat * (1 - s4), noise - lat
|
| 266 |
+
t = s * 1000
|
| 267 |
+
sf = fourier_sigma(s01).to(lat.dtype)
|
| 268 |
+
for w in wraps:
|
| 269 |
+
w.sig_feat = sf
|
| 270 |
+
pred = unet(noisy, t, ehs, return_dict=False)[0]
|
| 271 |
+
tot += ((pred - target) ** 2).mean(dim=(1, 2, 3)).tolist()
|
| 272 |
+
for w in wraps:
|
| 273 |
+
u = getattr(w.bank, "last_usage", None)
|
| 274 |
+
if u is not None:
|
| 275 |
+
for j, sv in enumerate(s01.tolist()):
|
| 276 |
+
band_usage[sigma_band(sv)].append(u.tolist())
|
| 277 |
+
usage = {f"band{k}":
|
| 278 |
+
[round(sum(col) / len(col), 4) for col in zip(*v)]
|
| 279 |
+
if v else None for k, v in band_usage.items()}
|
| 280 |
+
return sum(tot) / len(tot), usage
|
| 281 |
+
|
| 282 |
+
def train(unet, wraps, params, label):
|
| 283 |
+
opt = torch.optim.Adam(params, lr=LR, weight_decay=0.0)
|
| 284 |
+
gen = torch.Generator(device=device).manual_seed(SEED + 42)
|
| 285 |
+
idx = torch.Generator().manual_seed(SEED + 7)
|
| 286 |
+
torch.cuda.reset_peak_memory_stats()
|
| 287 |
+
t0 = time.time()
|
| 288 |
+
for step in range(1, STEPS + 1):
|
| 289 |
+
sel = torch.randint(0, N_TRAIN, (BATCH,), generator=idx)
|
| 290 |
+
loss = loss_of(unet, wraps, cache["lat"][sel].to(device),
|
| 291 |
+
cache["ehs"][sel].to(device), gen)
|
| 292 |
+
loss.backward()
|
| 293 |
+
opt.step()
|
| 294 |
+
opt.zero_grad(set_to_none=True)
|
| 295 |
+
if step == 50 or step % 500 == 0:
|
| 296 |
+
print(f"[{label}] step {step}: loss {loss.item():.4f} | "
|
| 297 |
+
f"{(time.time() - t0) / step:.2f}s/step | peak "
|
| 298 |
+
f"{torch.cuda.max_memory_allocated() / 2**30:.1f}GB",
|
| 299 |
+
flush=True)
|
| 300 |
+
return round((time.time() - t0) / STEPS, 3)
|
| 301 |
+
|
| 302 |
+
results = {"config": {"substrate": SUBSTRATE, "A": A_EXPERTS, "r": RANK,
|
| 303 |
+
"steps": STEPS, "batch": BATCH, "lr": LR,
|
| 304 |
+
"seed": SEED, "epred": epred}}
|
| 305 |
+
|
| 306 |
+
with ledger_run(f"dexp007 frozen ({SUBSTRATE})", budget_h=0.2) as h:
|
| 307 |
+
unet = load_unet(device)
|
| 308 |
+
v, _ = val(unet, [])
|
| 309 |
+
results["frozen"] = {"val": v}
|
| 310 |
+
del unet
|
| 311 |
+
torch.cuda.empty_cache()
|
| 312 |
+
h["verdict"] = f"val {v:.5f}"
|
| 313 |
+
|
| 314 |
+
with ledger_run("dexp007 amoe A4r8", budget_h=2.5) as h:
|
| 315 |
+
unet = load_unet(device)
|
| 316 |
+
banks, wraps = attach_banks(unet, lambda d: AmoeBank(d))
|
| 317 |
+
for b in banks:
|
| 318 |
+
b.assert_zero_init()
|
| 319 |
+
n_params = sum(p.numel() for p in banks.parameters())
|
| 320 |
+
print(f"[amoe] 16 banks, {n_params:,} trainable", flush=True)
|
| 321 |
+
spd = train(unet, wraps, banks.parameters(), "amoe")
|
| 322 |
+
v_on, usage = val(unet, wraps)
|
| 323 |
+
for b in banks:
|
| 324 |
+
b.enabled = False
|
| 325 |
+
v_off, _ = val(unet, wraps)
|
| 326 |
+
d = abs(v_off - results["frozen"]["val"])
|
| 327 |
+
assert d < 1e-9, f"toggle parity broken: {d}"
|
| 328 |
+
for b in banks:
|
| 329 |
+
b.enabled = True
|
| 330 |
+
torch.save({"banks": [b.state_dict() for b in banks]},
|
| 331 |
+
os.path.join(CKPT_DIR, f"amoe_{SUBSTRATE}_s0.pt"))
|
| 332 |
+
# P2: sigma-band usage differentiation vs shuffled-band null
|
| 333 |
+
per_band = [u for u in usage.values() if u]
|
| 334 |
+
band_var = 0.0
|
| 335 |
+
if len(per_band) >= 2:
|
| 336 |
+
cols = list(zip(*per_band))
|
| 337 |
+
band_var = sum(
|
| 338 |
+
(max(c) - min(c)) for c in cols) / len(cols)
|
| 339 |
+
results["amoe"] = {"n_params": n_params, "val": v_on,
|
| 340 |
+
"val_toggled_off": v_off, "s_per_step": spd,
|
| 341 |
+
"usage_by_band": usage,
|
| 342 |
+
"band_usage_spread": round(band_var, 5),
|
| 343 |
+
"gates": [round(torch.sigmoid(g).item(), 4)
|
| 344 |
+
for g in banks[8].gates]}
|
| 345 |
+
del unet, banks
|
| 346 |
+
torch.cuda.empty_cache()
|
| 347 |
+
h["verdict"] = f"val {v_on:.5f} spread {band_var:.4f}"
|
| 348 |
+
|
| 349 |
+
with ledger_run("dexp007 monolith r32", budget_h=2.5) as h:
|
| 350 |
+
unet = load_unet(device)
|
| 351 |
+
monos, wraps = attach_banks(unet, lambda d: MonoLora(d))
|
| 352 |
+
n_params = sum(p.numel() for p in monos.parameters())
|
| 353 |
+
print(f"[mono] 16 sites, {n_params:,} trainable", flush=True)
|
| 354 |
+
spd = train(unet, wraps, monos.parameters(), "mono")
|
| 355 |
+
v, _ = val(unet, wraps)
|
| 356 |
+
torch.save({"monos": [m.state_dict() for m in monos]},
|
| 357 |
+
os.path.join(CKPT_DIR, f"mono_{SUBSTRATE}_s0.pt"))
|
| 358 |
+
results["monolith"] = {"n_params": n_params, "val": v,
|
| 359 |
+
"s_per_step": spd}
|
| 360 |
+
del unet, monos
|
| 361 |
+
torch.cuda.empty_cache()
|
| 362 |
+
h["verdict"] = f"val {v:.5f}"
|
| 363 |
+
|
| 364 |
+
av, mv = results["amoe"]["val"], results["monolith"]["val"]
|
| 365 |
+
results["verdict"] = {
|
| 366 |
+
"amoe_vs_monolith": "amoe" if av <= mv else "monolith",
|
| 367 |
+
"amoe_beats_frozen": av < results["frozen"]["val"],
|
| 368 |
+
"param_ratio": round(results["amoe"]["n_params"]
|
| 369 |
+
/ results["monolith"]["n_params"], 3),
|
| 370 |
+
"band_usage_spread": results["amoe"]["band_usage_spread"],
|
| 371 |
+
"note": "P1 amoe>=monolith; P2 sigma-band usage differentiation; "
|
| 372 |
+
"1-seed CANDIDATE; first MoE-structure test of the line",
|
| 373 |
+
}
|
| 374 |
+
with open(os.path.join(DATA_DIR, "results.json"), "w") as f:
|
| 375 |
+
json.dump(results, f, indent=2)
|
| 376 |
+
note(f"dexp007 verdict: {json.dumps(results['verdict'])}")
|
| 377 |
+
print(json.dumps(results["verdict"], indent=2))
|
| 378 |
+
burn_down()
|
| 379 |
+
return results
|
| 380 |
+
|
| 381 |
+
|
| 382 |
+
def smoke():
|
| 383 |
+
b = AmoeBank(320)
|
| 384 |
+
b.assert_zero_init()
|
| 385 |
+
x = torch.randn(2, 9, 320)
|
| 386 |
+
sf = fourier_sigma(torch.tensor([0.3, 0.8]))
|
| 387 |
+
assert torch.equal(b(x, sf), x), "zero-init must be exact"
|
| 388 |
+
b.enabled = False
|
| 389 |
+
assert b(x, sf) is x
|
| 390 |
+
b.enabled = True
|
| 391 |
+
w = b.dispatch(x, sf)
|
| 392 |
+
assert w.shape == (2, 9, A_EXPERTS)
|
| 393 |
+
assert (w.abs().sum(-1) > 0).all(), "dense signed dispatch must be alive"
|
| 394 |
+
nn.init.normal_(b.up[0].weight, std=0.02)
|
| 395 |
+
assert not torch.equal(b(x, sf), x)
|
| 396 |
+
m = MonoLora(320)
|
| 397 |
+
assert torch.equal(m(x), x)
|
| 398 |
+
ba = sum(p.numel() for p in AmoeBank(320).parameters())
|
| 399 |
+
mo = sum(p.numel() for p in MonoLora(320).parameters())
|
| 400 |
+
print(f"dexp007 smoke PASSED (bank zero-init/toggle/dispatch; params "
|
| 401 |
+
f"bank {ba:,} vs mono {mo:,} @d=320)")
|
| 402 |
+
|
| 403 |
+
|
| 404 |
+
if __name__ == "__main__":
|
| 405 |
+
if "--run" in sys.argv:
|
| 406 |
+
run()
|
| 407 |
+
else:
|
| 408 |
+
smoke()
|
exp007_amoe_lora/mono_core_s0.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:45d6562a978296fa9348786f83319d11196e21ead6ab3d0540562a79d2328d17
|
| 3 |
+
size 3265793
|
exp007_amoe_lora/results.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"config": {
|
| 3 |
+
"substrate": "core",
|
| 4 |
+
"A": 4,
|
| 5 |
+
"r": 8,
|
| 6 |
+
"steps": 3000,
|
| 7 |
+
"batch": 16,
|
| 8 |
+
"lr": 0.001,
|
| 9 |
+
"seed": 0,
|
| 10 |
+
"epred": true
|
| 11 |
+
},
|
| 12 |
+
"frozen": {
|
| 13 |
+
"val": 0.1247876692286809
|
| 14 |
+
},
|
| 15 |
+
"amoe": {
|
| 16 |
+
"n_params": 899392,
|
| 17 |
+
"val": 0.12201545690095372,
|
| 18 |
+
"val_toggled_off": 0.1247876692286809,
|
| 19 |
+
"s_per_step": 1.722,
|
| 20 |
+
"usage_by_band": {
|
| 21 |
+
"band0": [
|
| 22 |
+
0.2544,
|
| 23 |
+
0.1704,
|
| 24 |
+
0.3321,
|
| 25 |
+
0.2424
|
| 26 |
+
],
|
| 27 |
+
"band1": [
|
| 28 |
+
0.2549,
|
| 29 |
+
0.1706,
|
| 30 |
+
0.3316,
|
| 31 |
+
0.2421
|
| 32 |
+
],
|
| 33 |
+
"band2": [
|
| 34 |
+
0.254,
|
| 35 |
+
0.1705,
|
| 36 |
+
0.3323,
|
| 37 |
+
0.2423
|
| 38 |
+
],
|
| 39 |
+
"band3": [
|
| 40 |
+
0.2543,
|
| 41 |
+
0.1696,
|
| 42 |
+
0.333,
|
| 43 |
+
0.2424
|
| 44 |
+
]
|
| 45 |
+
},
|
| 46 |
+
"band_usage_spread": 0.0009,
|
| 47 |
+
"gates": [
|
| 48 |
+
0.064,
|
| 49 |
+
0.0523,
|
| 50 |
+
0.0644,
|
| 51 |
+
0.0609
|
| 52 |
+
]
|
| 53 |
+
},
|
| 54 |
+
"monolith": {
|
| 55 |
+
"n_params": 811216,
|
| 56 |
+
"val": 0.12177696034905239,
|
| 57 |
+
"s_per_step": 1.647
|
| 58 |
+
},
|
| 59 |
+
"verdict": {
|
| 60 |
+
"amoe_vs_monolith": "monolith",
|
| 61 |
+
"amoe_beats_frozen": true,
|
| 62 |
+
"param_ratio": 1.109,
|
| 63 |
+
"band_usage_spread": 0.0009,
|
| 64 |
+
"note": "P1 amoe>=monolith; P2 sigma-band usage differentiation; 1-seed CANDIDATE; first MoE-structure test of the line"
|
| 65 |
+
}
|
| 66 |
+
}
|