mini-beatrix-3/code: re-cut at amoe-lora 0.2.11 (9bae609: the compiled adapter chain's recompile budget and shape gate) + the stop / install / relaunch / guard scripts of the 2026-09-28 relaunch at 122,000; the pod's mission file as running
Browse files- mini-beatrix-3/code/README.md +26 -5
- mini-beatrix-3/code/amoe-lora/src/amoe/__init__.py +24 -24
- mini-beatrix-3/code/amoe-lora/src/amoe/core/adapter.py +254 -210
- mini-beatrix-3/code/pod/compile_guard.sh +35 -0
- mini-beatrix-3/code/pod/go_relaunch_0211.sh +16 -0
- mini-beatrix-3/code/pod/install_0211.sh +15 -0
- mini-beatrix-3/code/pod/mission.json +1 -1
- mini-beatrix-3/code/pod/relaunch_3arms.sh +55 -0
- mini-beatrix-3/code/pod/stop_at_checkpoint.sh +37 -0
- mini-beatrix-3/code/requirements.txt +3 -3
mini-beatrix-3/code/README.md
CHANGED
|
@@ -1,17 +1,23 @@
|
|
| 1 |
# mini-beatrix-3 — the training code, pinned to the commits that train it
|
| 2 |
|
| 3 |
-
This folder is a verbatim snapshot of the two libraries and the pod files behind the `mini-beatrix-3` run,
|
| 4 |
-
2026-09-27
|
| 5 |
-
the
|
|
|
|
| 6 |
|
| 7 |
| part | what it is | where it comes from |
|
| 8 |
|---|---|---|
|
| 9 |
| `alephllm/` | the model, the trainer, the data plane, the instruments, the arm program and the mission loop (`geolip.alephllm`, version 0.10.5) | [github.com/AbstractEyes/alephllm](https://github.com/AbstractEyes/alephllm) @ `e8b7440` |
|
| 10 |
-
| `amoe-lora/` | the arm library: the relay adapters, attach / detach / mask handles, recompute-in-backward, the compiled adapter chain, the anchor file format (`amoe.__version__` 0.2.
|
| 11 |
| `pod/mission.json` | the mission file: the craft, the data plane, the stage arms, the knobs; the trainer re-reads the refreshable keys at every phase boundary | the pod, as running |
|
| 12 |
| `pod/launch_mission.sh` | the launch: `torchrun` data-parallel over every card on the machine, resume-first | the pod |
|
| 13 |
| `pod/relaunch_106000.sh` | the one-command relaunch used on 2026-09-27: sets the knobs, checks the installed versions, launches, restarts the sidecar, prints the proving log lines | the pod |
|
| 14 |
| `pod/stop_at_106000.sh` | a clean manual stop at a 2,000-step checkpoint (the resume state is exactly that checkpoint) | the pod |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
| `pod/arm_anchor_sidecar.py` | ships every attached stage arm as a safetensors anchor at each checkpoint (the trainer's own boundary anchors ship at phase ends) | the pod |
|
| 16 |
| `pod/write_mission_json.py` | how the mission file was written from the pre-flight screens' verdicts | the pod |
|
| 17 |
| `pod/env.sh` | the shell environment (the token comes from the container's own environment; nothing secret is in the file) | the pod |
|
|
@@ -39,7 +45,7 @@ the pod files are the launch, resume, stop and shipping scripts as they run on t
|
|
| 39 |
| `arm_spec_certified` | a gate: a phase that attaches an arm opens only when this is true; setting it false ends the session cleanly at the next boundary | true |
|
| 40 |
| `abstain_chunks` | abstention (quiet-term) chunks per step; `null` = one per task chunk (16 of 16); an integer = that many, each scaled so the term's weight per step is unchanged | 4 since step 106,000 |
|
| 41 |
| `adapter_recompute` | the arms' intermediates are recomputed in the backward instead of kept (about 0.3 GB per arm instead of 3 GB at this shape) | true since 106,000 |
|
| 42 |
-
| `adapter_compile` | the per-block adapter chain runs through `torch.compile` with inductor's precision-cast emulation (the plain compile produced a non-finite backward on the address stage) | true since 106,000 |
|
| 43 |
| `minted_lexicon` | the curriculum's word pool for the rule-chain stages (216 minted words), its share of stage 3 and the pair rate | see the file |
|
| 44 |
| `head_birth` | how the aleph head is born (`revival_birth` fits it to the first batch at step 0) | `revival_birth` |
|
| 45 |
| `l6_ledger` | the in-run guard certification record (the rank-collapse guard halts the run on its own when certified) | `v3_preflight/l6_guards/...` |
|
|
@@ -63,3 +69,18 @@ sd = load_file("arms/s1_perspective_step106000.safetensors") # keys blocks.<bl
|
|
| 63 |
|
| 64 |
Anchors before 2026-09-25 were converted in place from a torch-serialised form to real safetensors; `load_anchor` reads
|
| 65 |
either form by content.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
# mini-beatrix-3 — the training code, pinned to the commits that train it
|
| 2 |
|
| 3 |
+
This folder is a verbatim snapshot of the two libraries and the pod files behind the `mini-beatrix-3` run, first taken
|
| 4 |
+
on 2026-09-27 at step ~106,600 of 245,670 and re-cut on 2026-09-28 at step 122,000 when the arm library moved to 0.2.11
|
| 5 |
+
(the section on the compiled chain below). The libraries are copies of their public GitHub commits; the pod files are the
|
| 6 |
+
launch, resume, stop, install and shipping scripts as they run on the training machine.
|
| 7 |
|
| 8 |
| part | what it is | where it comes from |
|
| 9 |
|---|---|---|
|
| 10 |
| `alephllm/` | the model, the trainer, the data plane, the instruments, the arm program and the mission loop (`geolip.alephllm`, version 0.10.5) | [github.com/AbstractEyes/alephllm](https://github.com/AbstractEyes/alephllm) @ `e8b7440` |
|
| 11 |
+
| `amoe-lora/` | the arm library: the relay adapters, attach / detach / mask handles, recompute-in-backward, the compiled adapter chain, the anchor file format (`amoe.__version__` 0.2.11; its `pyproject.toml` still says 0.10.0) | [github.com/AbstractEyes/amoe-lora](https://github.com/AbstractEyes/amoe-lora) @ `9bae609` (branch `experimental`; `f3db5d4` = 0.2.10 trained steps 106,000 to 122,000) |
|
| 12 |
| `pod/mission.json` | the mission file: the craft, the data plane, the stage arms, the knobs; the trainer re-reads the refreshable keys at every phase boundary | the pod, as running |
|
| 13 |
| `pod/launch_mission.sh` | the launch: `torchrun` data-parallel over every card on the machine, resume-first | the pod |
|
| 14 |
| `pod/relaunch_106000.sh` | the one-command relaunch used on 2026-09-27: sets the knobs, checks the installed versions, launches, restarts the sidecar, prints the proving log lines | the pod |
|
| 15 |
| `pod/stop_at_106000.sh` | a clean manual stop at a 2,000-step checkpoint (the resume state is exactly that checkpoint) | the pod |
|
| 16 |
+
| `pod/stop_at_checkpoint.sh` | the same stop generalized to any checkpoint step (used at 122,000 on 2026-09-28) | the pod |
|
| 17 |
+
| `pod/install_0211.sh` | installs the arm library at the pinned 0.2.11 commit and reads the versions back; refuses while a trainer is alive | the pod |
|
| 18 |
+
| `pod/relaunch_3arms.sh` | the relaunch used on 2026-09-28: the running form, the version gate, the proving log lines, the recompile-warning count | the pod |
|
| 19 |
+
| `pod/go_relaunch_0211.sh` | stop at a named checkpoint, install, relaunch, each stage gated on the previous one's report line | the pod |
|
| 20 |
+
| `pod/compile_guard.sh` | polls the log for torch's recompile-limit warning (the sign of the compiled chain falling back to eager) and arms the stop-and-relaunch at the next checkpoint | the pod |
|
| 21 |
| `pod/arm_anchor_sidecar.py` | ships every attached stage arm as a safetensors anchor at each checkpoint (the trainer's own boundary anchors ship at phase ends) | the pod |
|
| 22 |
| `pod/write_mission_json.py` | how the mission file was written from the pre-flight screens' verdicts | the pod |
|
| 23 |
| `pod/env.sh` | the shell environment (the token comes from the container's own environment; nothing secret is in the file) | the pod |
|
|
|
|
| 45 |
| `arm_spec_certified` | a gate: a phase that attaches an arm opens only when this is true; setting it false ends the session cleanly at the next boundary | true |
|
| 46 |
| `abstain_chunks` | abstention (quiet-term) chunks per step; `null` = one per task chunk (16 of 16); an integer = that many, each scaled so the term's weight per step is unchanged | 4 since step 106,000 |
|
| 47 |
| `adapter_recompute` | the arms' intermediates are recomputed in the backward instead of kept (about 0.3 GB per arm instead of 3 GB at this shape) | true since 106,000 |
|
| 48 |
+
| `adapter_compile` | the per-block adapter chain runs through `torch.compile` with inductor's precision-cast emulation (the plain compile produced a non-finite backward on the address stage); since 0.2.11 the library also raises torch's recompile budget and routes only the training shapes through the compiled chain (the section below) | true since 106,000 |
|
| 49 |
| `minted_lexicon` | the curriculum's word pool for the rule-chain stages (216 minted words), its share of stage 3 and the pair rate | see the file |
|
| 50 |
| `head_birth` | how the aleph head is born (`revival_birth` fits it to the first batch at step 0) | `revival_birth` |
|
| 51 |
| `l6_ledger` | the in-run guard certification record (the rank-collapse guard halts the run on its own when certified) | `v3_preflight/l6_guards/...` |
|
|
|
|
| 69 |
|
| 70 |
Anchors before 2026-09-25 were converted in place from a torch-serialised form to real safetensors; `load_anchor` reads
|
| 71 |
either form by content.
|
| 72 |
+
|
| 73 |
+
## The compiled chain and its recompile budget (0.2.11)
|
| 74 |
+
|
| 75 |
+
The adapter chain is compiled with static shapes, so every distinct (mask pattern, input shape) pair is one entry in torch's
|
| 76 |
+
compile cache for that function. Torch's default budget is 8 recompiles per function, and when it is exceeded torch does
|
| 77 |
+
not run that one call eagerly: it marks the function to bypass the compiler for the rest of the process, with a single
|
| 78 |
+
warning line. The stage 2 boundary evaluation fed the armed model probe prompts of many different lengths, spent that budget
|
| 79 |
+
in seconds, and from the stage 3 attach on every step ran the arms eager (10.5 s per step at three arms instead of about
|
| 80 |
+
7.5) until the run was stopped at 122,000 and relaunched on 0.2.11. The fix lives in the library, not in a launch flag:
|
| 81 |
+
`compiled_chain()` raises the budget (64 per function, 4,096 accumulated) before the first compile, and `chain_for(h)`
|
| 82 |
+
routes only the first two distinct (batch, length) shapes seen through the compiled chain, every other shape through the
|
| 83 |
+
eager chain, which is the same function. The unit test `tests/test_compiled_chain_gate.py` in the GitHub repository stacks
|
| 84 |
+
three arms, runs the training shape armed and with each member masked, then forty prompt lengths, with torch configured
|
| 85 |
+
to raise on any budget hit. `pod/compile_guard.sh` watches the log for the warning and arms a stop-and-relaunch if it ever
|
| 86 |
+
returns.
|
mini-beatrix-3/code/amoe-lora/src/amoe/__init__.py
CHANGED
|
@@ -1,24 +1,24 @@
|
|
| 1 |
-
"""amoe — aleph mixture-of-experts adapters (train/attach/align/detach).
|
| 2 |
-
|
| 3 |
-
The productized adapter system from the geolip-aleph research line.
|
| 4 |
-
"LoRA-style" refers to the attach/detach usage pattern, not the math:
|
| 5 |
-
these are aleph-addressed patch heads, not low-rank matrices.
|
| 6 |
-
"""
|
| 7 |
-
from .core.adapter import AdapterSpec, RelayPatchwork, BlockWithAdapter
|
| 8 |
-
from .core.address import AlephAddress
|
| 9 |
-
from .core.dispatch import AnchorDispatch, BlockWithDispatch, set_mask
|
| 10 |
-
from .io.checkpoint import (AnchorCheckpoint, DispatchCheckpoint,
|
| 11 |
-
load_anchor, load_dispatch,
|
| 12 |
-
import_legacy_keys)
|
| 13 |
-
from .runtime.attach import attach, detach, AttachHandle
|
| 14 |
-
from .train.config import TrainConfig, AlignConfig
|
| 15 |
-
from .train.trainer import train
|
| 16 |
-
from .train.aligner import align
|
| 17 |
-
from .train.quiet import QuietSpec, kl_abstain, quiet_step
|
| 18 |
-
from . import laws
|
| 19 |
-
|
| 20 |
-
__version__ = "0.2.
|
| 21 |
-
|
| 22 |
-
# The diffusion subsystem (amoe.diffusion) is imported lazily — its verbs
|
| 23 |
-
# live under `import amoe.diffusion as ad`. Core is pure torch; diffusers
|
| 24 |
-
# is only touched by bindings/samplers/data that need it.
|
|
|
|
| 1 |
+
"""amoe — aleph mixture-of-experts adapters (train/attach/align/detach).
|
| 2 |
+
|
| 3 |
+
The productized adapter system from the geolip-aleph research line.
|
| 4 |
+
"LoRA-style" refers to the attach/detach usage pattern, not the math:
|
| 5 |
+
these are aleph-addressed patch heads, not low-rank matrices.
|
| 6 |
+
"""
|
| 7 |
+
from .core.adapter import AdapterSpec, RelayPatchwork, BlockWithAdapter
|
| 8 |
+
from .core.address import AlephAddress
|
| 9 |
+
from .core.dispatch import AnchorDispatch, BlockWithDispatch, set_mask
|
| 10 |
+
from .io.checkpoint import (AnchorCheckpoint, DispatchCheckpoint,
|
| 11 |
+
load_anchor, load_dispatch,
|
| 12 |
+
import_legacy_keys)
|
| 13 |
+
from .runtime.attach import attach, detach, AttachHandle
|
| 14 |
+
from .train.config import TrainConfig, AlignConfig
|
| 15 |
+
from .train.trainer import train
|
| 16 |
+
from .train.aligner import align
|
| 17 |
+
from .train.quiet import QuietSpec, kl_abstain, quiet_step
|
| 18 |
+
from . import laws
|
| 19 |
+
|
| 20 |
+
__version__ = "0.2.11"
|
| 21 |
+
|
| 22 |
+
# The diffusion subsystem (amoe.diffusion) is imported lazily — its verbs
|
| 23 |
+
# live under `import amoe.diffusion as ad`. Core is pure torch; diffusers
|
| 24 |
+
# is only touched by bindings/samplers/data that need it.
|
mini-beatrix-3/code/amoe-lora/src/amoe/core/adapter.py
CHANGED
|
@@ -1,210 +1,254 @@
|
|
| 1 |
-
"""RelayPatchwork adapter + the hybrid-safe block wrapper.
|
| 2 |
-
|
| 3 |
-
The certified geometry (16 slots x D=4 through a 64-atom aleph address,
|
| 4 |
-
squared-ReLU patch head, sigmoid gate initialized at -3): ~261k params
|
| 5 |
-
at d=1024. Output head zero-initialized so a fresh anchor is inert
|
| 6 |
-
(modulo the documented LayerNorm-bias leak).
|
| 7 |
-
|
| 8 |
-
BlockWithAdapter carries an `enabled` switch: when False, the forward
|
| 9 |
-
returns the block output untouched — the single-anchor half of the
|
| 10 |
-
toggle law. It also carries a `recompute` switch (0.2.7): when True,
|
| 11 |
-
the adapter's intermediates are not kept for the backward pass but
|
| 12 |
-
recomputed from the block output when the backward reaches them
|
| 13 |
-
(torch.utils.checkpoint, non-reentrant). Same math, one extra adapter
|
| 14 |
-
forward per backward, a fraction of the activation memory: at d=1024
|
| 15 |
-
on 4096-token rows the kept intermediates run ~96 MB per block per
|
| 16 |
-
adapter per two-row micro-batch, which is what walls a 32-block trunk
|
| 17 |
-
with several stacked arms on a 32 GB card. A stack of wrappers on one
|
| 18 |
-
block recomputes as one chain (0.2.8), keeping one residual copy per
|
| 19 |
-
block for the whole stack.
|
| 20 |
-
"""
|
| 21 |
-
from __future__ import annotations
|
| 22 |
-
|
| 23 |
-
import contextlib
|
| 24 |
-
from dataclasses import dataclass
|
| 25 |
-
|
| 26 |
-
import torch
|
| 27 |
-
import torch.nn as nn
|
| 28 |
-
import torch.nn.functional as F
|
| 29 |
-
from torch.utils.checkpoint import checkpoint
|
| 30 |
-
|
| 31 |
-
from .address import AlephAddress
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
@dataclass
|
| 35 |
-
class AdapterSpec:
|
| 36 |
-
n_slots: int = 16
|
| 37 |
-
K: int = 64
|
| 38 |
-
D: int = 4
|
| 39 |
-
tau: float = 0.1
|
| 40 |
-
hidden: int = 178
|
| 41 |
-
gate_init: float = -3.0
|
| 42 |
-
zero_init_head: bool = True
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
class SquaredReLU(nn.Module):
|
| 46 |
-
def forward(self, x):
|
| 47 |
-
return F.relu(x) ** 2
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
class RelayPatchwork(nn.Module):
|
| 51 |
-
def __init__(self, d: int, spec: AdapterSpec | None = None):
|
| 52 |
-
super().__init__()
|
| 53 |
-
s = spec or AdapterSpec()
|
| 54 |
-
self.spec = s
|
| 55 |
-
self.n_slots = s.n_slots
|
| 56 |
-
self.proj = nn.Linear(d, s.n_slots * s.D, bias=False)
|
| 57 |
-
nn.init.orthogonal_(self.proj.weight)
|
| 58 |
-
self.addr = AlephAddress(s.K, s.D, s.tau)
|
| 59 |
-
self.consume = nn.Sequential(
|
| 60 |
-
nn.Linear(s.n_slots * s.D, s.hidden), SquaredReLU(),
|
| 61 |
-
nn.LayerNorm(s.hidden), nn.Linear(s.hidden, d))
|
| 62 |
-
if s.zero_init_head:
|
| 63 |
-
nn.init.zeros_(self.consume[-1].weight)
|
| 64 |
-
self.gate = nn.Parameter(torch.tensor(float(s.gate_init)))
|
| 65 |
-
|
| 66 |
-
def forward(self, x):
|
| 67 |
-
B, n, _ = x.shape
|
| 68 |
-
slots = self.proj(x).view(B, n, self.n_slots, self.spec.D)
|
| 69 |
-
feats = self.addr.m_hat(slots).reshape(B, n, -1)
|
| 70 |
-
return x + torch.sigmoid(self.gate) * self.consume(feats)
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
def _apply_chain(h, *adapters):
|
| 74 |
-
for a in adapters:
|
| 75 |
-
h = a(h)
|
| 76 |
-
return h
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
def _autocast_uncached(device_type: str):
|
| 80 |
-
"""The active autocast region re-entered with its weight-cast cache OFF
|
| 81 |
-
(0.2.10), for the checkpointed chain. Autocast caches the low-precision
|
| 82 |
-
copies of parameters it casts; when an earlier pass inside the same
|
| 83 |
-
autocast region (a no_grad pass with a member masked, as the abstention
|
| 84 |
-
term runs) already cast a member's weights, the recorded forward of the
|
| 85 |
-
checkpointed chain holds no cast ops for them, while the recompute,
|
| 86 |
-
which re-enters autocast fresh, records the casts, and the checkpoint's
|
| 87 |
-
operator-list check fails ('different metadata'; torch 2.8). With the
|
| 88 |
-
cache off inside the chain both passes record the same ops. The cost is
|
| 89 |
-
one bf16 cast of each live adapter's weights per block call."""
|
| 90 |
-
try:
|
| 91 |
-
enabled = torch.is_autocast_enabled(device_type)
|
| 92 |
-
except TypeError: # older signature: cuda only
|
| 93 |
-
enabled = device_type == "cuda" and torch.is_autocast_enabled()
|
| 94 |
-
if not enabled:
|
| 95 |
-
return contextlib.nullcontext()
|
| 96 |
-
try:
|
| 97 |
-
dtype = torch.get_autocast_dtype(device_type)
|
| 98 |
-
except (TypeError, AttributeError):
|
| 99 |
-
dtype = torch.get_autocast_gpu_dtype() if device_type == "cuda" else torch.bfloat16
|
| 100 |
-
return torch.autocast(device_type=device_type, dtype=dtype, cache_enabled=False)
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
# The compiled chain (0.2.9). The aleph address's compiled backward is
|
| 104 |
-
# non-finite under bf16 autocast unless inductor rounds its fused
|
| 105 |
-
# intermediates to bf16 the way eager does (measured 2026-09: of the
|
| 106 |
-
# adapter's stages compiled alone, only addr.m_hat fails; pure fp32 and
|
| 107 |
-
# emulated casts are clean), so the switch below is set when the chain
|
| 108 |
-
# is first compiled. It is process-global; set it False before the first
|
| 109 |
-
# compile to opt out (not recommended for bf16 training).
|
| 110 |
-
COMPILE_EMULATE_CASTS = True
|
| 111 |
-
COMPILE_MODE = "default" # reduce-overhead (CUDA graphs) fails inside a checkpointed chain
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
|
| 180 |
-
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
|
| 188 |
-
|
| 189 |
-
|
| 190 |
-
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
|
| 195 |
-
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
|
| 206 |
-
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
|
| 210 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""RelayPatchwork adapter + the hybrid-safe block wrapper.
|
| 2 |
+
|
| 3 |
+
The certified geometry (16 slots x D=4 through a 64-atom aleph address,
|
| 4 |
+
squared-ReLU patch head, sigmoid gate initialized at -3): ~261k params
|
| 5 |
+
at d=1024. Output head zero-initialized so a fresh anchor is inert
|
| 6 |
+
(modulo the documented LayerNorm-bias leak).
|
| 7 |
+
|
| 8 |
+
BlockWithAdapter carries an `enabled` switch: when False, the forward
|
| 9 |
+
returns the block output untouched — the single-anchor half of the
|
| 10 |
+
toggle law. It also carries a `recompute` switch (0.2.7): when True,
|
| 11 |
+
the adapter's intermediates are not kept for the backward pass but
|
| 12 |
+
recomputed from the block output when the backward reaches them
|
| 13 |
+
(torch.utils.checkpoint, non-reentrant). Same math, one extra adapter
|
| 14 |
+
forward per backward, a fraction of the activation memory: at d=1024
|
| 15 |
+
on 4096-token rows the kept intermediates run ~96 MB per block per
|
| 16 |
+
adapter per two-row micro-batch, which is what walls a 32-block trunk
|
| 17 |
+
with several stacked arms on a 32 GB card. A stack of wrappers on one
|
| 18 |
+
block recomputes as one chain (0.2.8), keeping one residual copy per
|
| 19 |
+
block for the whole stack.
|
| 20 |
+
"""
|
| 21 |
+
from __future__ import annotations
|
| 22 |
+
|
| 23 |
+
import contextlib
|
| 24 |
+
from dataclasses import dataclass
|
| 25 |
+
|
| 26 |
+
import torch
|
| 27 |
+
import torch.nn as nn
|
| 28 |
+
import torch.nn.functional as F
|
| 29 |
+
from torch.utils.checkpoint import checkpoint
|
| 30 |
+
|
| 31 |
+
from .address import AlephAddress
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
@dataclass
|
| 35 |
+
class AdapterSpec:
|
| 36 |
+
n_slots: int = 16
|
| 37 |
+
K: int = 64
|
| 38 |
+
D: int = 4
|
| 39 |
+
tau: float = 0.1
|
| 40 |
+
hidden: int = 178
|
| 41 |
+
gate_init: float = -3.0
|
| 42 |
+
zero_init_head: bool = True
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
class SquaredReLU(nn.Module):
|
| 46 |
+
def forward(self, x):
|
| 47 |
+
return F.relu(x) ** 2
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
class RelayPatchwork(nn.Module):
|
| 51 |
+
def __init__(self, d: int, spec: AdapterSpec | None = None):
|
| 52 |
+
super().__init__()
|
| 53 |
+
s = spec or AdapterSpec()
|
| 54 |
+
self.spec = s
|
| 55 |
+
self.n_slots = s.n_slots
|
| 56 |
+
self.proj = nn.Linear(d, s.n_slots * s.D, bias=False)
|
| 57 |
+
nn.init.orthogonal_(self.proj.weight)
|
| 58 |
+
self.addr = AlephAddress(s.K, s.D, s.tau)
|
| 59 |
+
self.consume = nn.Sequential(
|
| 60 |
+
nn.Linear(s.n_slots * s.D, s.hidden), SquaredReLU(),
|
| 61 |
+
nn.LayerNorm(s.hidden), nn.Linear(s.hidden, d))
|
| 62 |
+
if s.zero_init_head:
|
| 63 |
+
nn.init.zeros_(self.consume[-1].weight)
|
| 64 |
+
self.gate = nn.Parameter(torch.tensor(float(s.gate_init)))
|
| 65 |
+
|
| 66 |
+
def forward(self, x):
|
| 67 |
+
B, n, _ = x.shape
|
| 68 |
+
slots = self.proj(x).view(B, n, self.n_slots, self.spec.D)
|
| 69 |
+
feats = self.addr.m_hat(slots).reshape(B, n, -1)
|
| 70 |
+
return x + torch.sigmoid(self.gate) * self.consume(feats)
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
def _apply_chain(h, *adapters):
|
| 74 |
+
for a in adapters:
|
| 75 |
+
h = a(h)
|
| 76 |
+
return h
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
def _autocast_uncached(device_type: str):
|
| 80 |
+
"""The active autocast region re-entered with its weight-cast cache OFF
|
| 81 |
+
(0.2.10), for the checkpointed chain. Autocast caches the low-precision
|
| 82 |
+
copies of parameters it casts; when an earlier pass inside the same
|
| 83 |
+
autocast region (a no_grad pass with a member masked, as the abstention
|
| 84 |
+
term runs) already cast a member's weights, the recorded forward of the
|
| 85 |
+
checkpointed chain holds no cast ops for them, while the recompute,
|
| 86 |
+
which re-enters autocast fresh, records the casts, and the checkpoint's
|
| 87 |
+
operator-list check fails ('different metadata'; torch 2.8). With the
|
| 88 |
+
cache off inside the chain both passes record the same ops. The cost is
|
| 89 |
+
one bf16 cast of each live adapter's weights per block call."""
|
| 90 |
+
try:
|
| 91 |
+
enabled = torch.is_autocast_enabled(device_type)
|
| 92 |
+
except TypeError: # older signature: cuda only
|
| 93 |
+
enabled = device_type == "cuda" and torch.is_autocast_enabled()
|
| 94 |
+
if not enabled:
|
| 95 |
+
return contextlib.nullcontext()
|
| 96 |
+
try:
|
| 97 |
+
dtype = torch.get_autocast_dtype(device_type)
|
| 98 |
+
except (TypeError, AttributeError):
|
| 99 |
+
dtype = torch.get_autocast_gpu_dtype() if device_type == "cuda" else torch.bfloat16
|
| 100 |
+
return torch.autocast(device_type=device_type, dtype=dtype, cache_enabled=False)
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
# The compiled chain (0.2.9). The aleph address's compiled backward is
|
| 104 |
+
# non-finite under bf16 autocast unless inductor rounds its fused
|
| 105 |
+
# intermediates to bf16 the way eager does (measured 2026-09: of the
|
| 106 |
+
# adapter's stages compiled alone, only addr.m_hat fails; pure fp32 and
|
| 107 |
+
# emulated casts are clean), so the switch below is set when the chain
|
| 108 |
+
# is first compiled. It is process-global; set it False before the first
|
| 109 |
+
# compile to opt out (not recommended for bf16 training).
|
| 110 |
+
COMPILE_EMULATE_CASTS = True
|
| 111 |
+
COMPILE_MODE = "default" # reduce-overhead (CUDA graphs) fails inside a checkpointed chain
|
| 112 |
+
# The recompile budget and the shape gate (0.2.11). The chain is compiled
|
| 113 |
+
# static (dynamic=False), so every (mask pattern x input shape) pair is one
|
| 114 |
+
# cache entry of `_apply_chain`, and when torch's per-code recompile limit
|
| 115 |
+
# (8 by default) is exceeded dynamo does not merely run that call eagerly:
|
| 116 |
+
# it marks the code object SKIP and the chain runs eager for the rest of the
|
| 117 |
+
# process, with a single warning. An evaluation that feeds the armed model
|
| 118 |
+
# short inputs of many lengths (probe items, chat documents) spends that
|
| 119 |
+
# budget in seconds. Two guards: the dynamo limits are raised to the floors
|
| 120 |
+
# below when the chain is first compiled, and only the first
|
| 121 |
+
# COMPILE_MAX_SHAPES distinct (batch, length) shapes are routed through the
|
| 122 |
+
# compiled chain; any other shape runs the eager chain (exact; the compile's
|
| 123 |
+
# gain is in the training shape, which is the first shape a training run
|
| 124 |
+
# presents). The budget then holds the mask patterns of the training shapes
|
| 125 |
+
# only (m + 1 per shape at m arms).
|
| 126 |
+
COMPILE_RECOMPILE_LIMIT = 64
|
| 127 |
+
COMPILE_ACCUMULATED_LIMIT = 4096
|
| 128 |
+
COMPILE_MAX_SHAPES = 2
|
| 129 |
+
_COMPILED_CHAIN = None
|
| 130 |
+
_COMPILED_SHAPES: set = set()
|
| 131 |
+
|
| 132 |
+
|
| 133 |
+
def _raise_dynamo_limits():
|
| 134 |
+
import torch._dynamo.config as dc
|
| 135 |
+
for names, floor in ((("recompile_limit", "cache_size_limit"),
|
| 136 |
+
COMPILE_RECOMPILE_LIMIT),
|
| 137 |
+
(("accumulated_recompile_limit",
|
| 138 |
+
"accumulated_cache_size_limit"),
|
| 139 |
+
COMPILE_ACCUMULATED_LIMIT)):
|
| 140 |
+
for name in names: # 2.8 carries both spellings; older torch one
|
| 141 |
+
if hasattr(dc, name):
|
| 142 |
+
setattr(dc, name, max(int(getattr(dc, name)), int(floor)))
|
| 143 |
+
|
| 144 |
+
|
| 145 |
+
def compiled_chain():
|
| 146 |
+
global _COMPILED_CHAIN
|
| 147 |
+
if _COMPILED_CHAIN is None:
|
| 148 |
+
if COMPILE_EMULATE_CASTS:
|
| 149 |
+
import torch._inductor.config as ic
|
| 150 |
+
ic.emulate_precision_casts = True
|
| 151 |
+
_raise_dynamo_limits()
|
| 152 |
+
_COMPILED_CHAIN = torch.compile(_apply_chain, dynamic=False,
|
| 153 |
+
mode=COMPILE_MODE)
|
| 154 |
+
return _COMPILED_CHAIN
|
| 155 |
+
|
| 156 |
+
|
| 157 |
+
def chain_for(h):
|
| 158 |
+
"""The chain to run on an input of h's shape (0.2.11): the compiled
|
| 159 |
+
chain for the first COMPILE_MAX_SHAPES distinct (batch, length) shapes
|
| 160 |
+
seen, the eager chain for every other shape."""
|
| 161 |
+
key = (int(h.shape[0]), int(h.shape[1]))
|
| 162 |
+
if key in _COMPILED_SHAPES:
|
| 163 |
+
return compiled_chain()
|
| 164 |
+
if len(_COMPILED_SHAPES) < COMPILE_MAX_SHAPES:
|
| 165 |
+
_COMPILED_SHAPES.add(key)
|
| 166 |
+
return compiled_chain()
|
| 167 |
+
return _apply_chain
|
| 168 |
+
|
| 169 |
+
|
| 170 |
+
class BlockWithAdapter(nn.Module):
|
| 171 |
+
"""Wraps one decoder block; hybrid-safe (tuple or tensor output).
|
| 172 |
+
|
| 173 |
+
`recompute=True` (0.2.7) routes the adapter call through a
|
| 174 |
+
non-reentrant checkpoint whenever autograd is recording: the slot
|
| 175 |
+
projection, the address features and the consume MLP's hidden
|
| 176 |
+
activations are dropped after the forward and rebuilt from the block
|
| 177 |
+
output during the backward. The head is deterministic and
|
| 178 |
+
dropout-free, so the RNG state is not snapshotted (no device sync per
|
| 179 |
+
call) and the recomputed values are the values the forward produced.
|
| 180 |
+
Inference paths (no_grad, prefill, step) never checkpoint.
|
| 181 |
+
|
| 182 |
+
Stacked wrappers (0.2.8; an arm attached over an arm nests a wrapper
|
| 183 |
+
around a wrapper) recompute as ONE chain: the outermost wrapper with
|
| 184 |
+
recompute on runs the core block once and applies every enabled
|
| 185 |
+
adapter of the stack, innermost first, inside a single checkpoint, so
|
| 186 |
+
one residual copy per block is kept for the whole stack instead of
|
| 187 |
+
one per adapter. Each wrapper's `enabled` switch is read where it
|
| 188 |
+
sits, so masks behave exactly as in the kept path.
|
| 189 |
+
|
| 190 |
+
`compile_chain=True` (0.2.9) runs that same chain through
|
| 191 |
+
torch.compile (default mode, one graph per mask pattern, shared by
|
| 192 |
+
every block since the adapters enter as arguments), with or without
|
| 193 |
+
the recompute; see COMPILE_EMULATE_CASTS above for the precision
|
| 194 |
+
switch it needs. The compiled and the eager chain agree to bf16
|
| 195 |
+
rounding, not bit for bit: a training run that switches it on owes a
|
| 196 |
+
gradient census on its own card first.
|
| 197 |
+
"""
|
| 198 |
+
|
| 199 |
+
def __init__(self, block: nn.Module, adapter: RelayPatchwork,
|
| 200 |
+
recompute: bool = False, compile_chain: bool = False):
|
| 201 |
+
super().__init__()
|
| 202 |
+
self.block = block
|
| 203 |
+
self.adapter = adapter
|
| 204 |
+
self.enabled = True
|
| 205 |
+
self.recompute = bool(recompute)
|
| 206 |
+
self.compile_chain = bool(compile_chain)
|
| 207 |
+
|
| 208 |
+
def stack(self):
|
| 209 |
+
"""(wrappers innermost first, the core block) of the stack this
|
| 210 |
+
wrapper tops."""
|
| 211 |
+
wraps, core = [], self
|
| 212 |
+
while isinstance(core, BlockWithAdapter):
|
| 213 |
+
wraps.append(core)
|
| 214 |
+
core = core.block
|
| 215 |
+
wraps.reverse()
|
| 216 |
+
return wraps, core
|
| 217 |
+
|
| 218 |
+
def forward(self, *args, **kwargs):
|
| 219 |
+
if self.compile_chain or (self.recompute and torch.is_grad_enabled()):
|
| 220 |
+
wraps, core = self.stack()
|
| 221 |
+
out = core(*args, **kwargs)
|
| 222 |
+
live = [w.adapter for w in wraps if w.enabled]
|
| 223 |
+
if not live:
|
| 224 |
+
return out
|
| 225 |
+
h = out[0] if isinstance(out, tuple) else out
|
| 226 |
+
fn = chain_for(h) if self.compile_chain else _apply_chain
|
| 227 |
+
if self.recompute and torch.is_grad_enabled():
|
| 228 |
+
with _autocast_uncached(h.device.type):
|
| 229 |
+
y = checkpoint(fn, h, *live, use_reentrant=False,
|
| 230 |
+
preserve_rng_state=False)
|
| 231 |
+
else:
|
| 232 |
+
y = fn(h, *live)
|
| 233 |
+
return (y,) + out[1:] if isinstance(out, tuple) else y
|
| 234 |
+
out = self.block(*args, **kwargs)
|
| 235 |
+
if not self.enabled:
|
| 236 |
+
return out
|
| 237 |
+
if isinstance(out, tuple):
|
| 238 |
+
return (self.adapter(out[0]),) + out[1:]
|
| 239 |
+
return self.adapter(out)
|
| 240 |
+
|
| 241 |
+
# Incremental-decode passthroughs (trunks with a cached decode path,
|
| 242 |
+
# e.g. AlephLM prefill/step). The patch head is position-wise, so
|
| 243 |
+
# applying it to the single new position is exact.
|
| 244 |
+
def prefill(self, *args, **kwargs):
|
| 245 |
+
out, cache = self.block.prefill(*args, **kwargs)
|
| 246 |
+
return (self.adapter(out) if self.enabled else out), cache
|
| 247 |
+
|
| 248 |
+
def step(self, *args, **kwargs):
|
| 249 |
+
out = self.block.step(*args, **kwargs)
|
| 250 |
+
if not self.enabled:
|
| 251 |
+
return out
|
| 252 |
+
if isinstance(out, tuple):
|
| 253 |
+
return (self.adapter(out[0]),) + out[1:]
|
| 254 |
+
return self.adapter(out)
|
mini-beatrix-3/code/pod/compile_guard.sh
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
# THE COMPILED-CHAIN GUARD (the standing rule: the run never continues on the eager chain). Polls the mission log every 2 min for
|
| 3 |
+
# the dynamo recompile-limit warning (the signature of the chain falling back to eager) written after this guard's start and for a
|
| 4 |
+
# trainer that runs slower than the eager line; on either, it writes an alert file, logs it, and arms go_relaunch_0211.sh for the
|
| 5 |
+
# next 2,000-step checkpoint (stop, reinstall 0.2.11, relaunch compiled) unless a go sequence is already running. Bounded by hours.
|
| 6 |
+
# Usage: setsid nohup bash /root/v3/tools/compile_guard.sh [hours=48] > /root/v3/logs/compile_guard.out 2>&1 < /dev/null &
|
| 7 |
+
HOURS="${1:-48}"
|
| 8 |
+
LOG=/root/v3/logs/mission.log
|
| 9 |
+
OUT=/root/v3/logs/compile_guard.log
|
| 10 |
+
ALERT=/root/v3/logs/COMPILED_CHAIN_LOST
|
| 11 |
+
EAGER_LINE=9.8 # s/step: the compiled three-arm pace is ~8.7, the eager 10.4-10.8; later stages raise both, so the line is re-read from the log's own history
|
| 12 |
+
log() { echo "[guard $(date -u '+%H:%M:%SZ')] $*" >> "$OUT"; }
|
| 13 |
+
START_BYTES=$(stat -c %s "$LOG")
|
| 14 |
+
log "armed for $HOURS h from byte $START_BYTES of the mission log"
|
| 15 |
+
END=$(( $(date +%s) + HOURS * 3600 ))
|
| 16 |
+
while [ "$(date +%s)" -lt "$END" ]; do
|
| 17 |
+
sleep 120
|
| 18 |
+
NOW_BYTES=$(stat -c %s "$LOG")
|
| 19 |
+
if [ "$NOW_BYTES" -lt "$START_BYTES" ]; then START_BYTES=0; fi
|
| 20 |
+
N=$(tail -c +$((START_BYTES + 1)) "$LOG" | grep -ac "recompile_limit")
|
| 21 |
+
if [ "$N" -gt 0 ]; then
|
| 22 |
+
if [ -f "$ALERT" ]; then continue; fi
|
| 23 |
+
date -u +%FT%TZ > "$ALERT"
|
| 24 |
+
log "ALERT: $N recompile-limit warning(s) since the guard's start: the chain has fallen back to eager"
|
| 25 |
+
tail -c +$((START_BYTES + 1)) "$LOG" | grep -a "recompile_limit" | head -n 3 | cut -c1-200 >> "$OUT"
|
| 26 |
+
if [ "$(pgrep -fc 'go_relaunch_021[1]')" != "0" ]; then log "a go sequence is already running; not arming another"; continue; fi
|
| 27 |
+
STEP=$(tail -c 1500 "$LOG" | tr "\r" "\n" | grep -aoE "[0-9]+/245670" | tail -n 1 | cut -d/ -f1)
|
| 28 |
+
NEXT=$(( (STEP / 2000 + 1) * 2000 ))
|
| 29 |
+
NEXTC=$(printf "%'d" "$NEXT")
|
| 30 |
+
log "arming the stop + reinstall + relaunch at the next checkpoint $NEXTC (the standing rule: never eager)"
|
| 31 |
+
setsid nohup bash /root/v3/tools/go_relaunch_0211.sh "$NEXTC" 0 > /root/v3/logs/go_relaunch_0211.out 2>&1 < /dev/null &
|
| 32 |
+
disown
|
| 33 |
+
fi
|
| 34 |
+
done
|
| 35 |
+
log "guard window ended"
|
mini-beatrix-3/code/pod/go_relaunch_0211.sh
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
# THE WHOLE SEQUENCE: stop at the named checkpoint -> install amoe-lora 0.2.11 -> relaunch (the running form).
|
| 3 |
+
# Usage: setsid nohup bash /root/v3/tools/go_relaunch_0211.sh <step, e.g. 119,496> [ships expected, default 3] > /root/v3/logs/go_relaunch_0211.out 2>&1 &
|
| 4 |
+
STEP="${1:?step with commas}"
|
| 5 |
+
SHIPS="${2:-3}"
|
| 6 |
+
OUT=/root/v3/logs/go_relaunch_0211.log
|
| 7 |
+
log() { echo "[go $(date -u '+%H:%M:%SZ')] $*" | tee -a "$OUT"; }
|
| 8 |
+
log "armed for the $STEP checkpoint"
|
| 9 |
+
bash /root/v3/tools/stop_at_checkpoint.sh "$STEP" "$SHIPS"
|
| 10 |
+
if ! grep -aq "STOPPED" "/root/v3/logs/stop_${STEP//,/}.log" 2>/dev/null; then log "ERROR: the stop did not report STOPPED; nothing installed, nothing launched"; exit 2; fi
|
| 11 |
+
log "stopped; installing"
|
| 12 |
+
bash /root/v3/tools/install_0211.sh
|
| 13 |
+
if ! grep -aq "INSTALLED" /root/v3/logs/install_0211.log 2>/dev/null; then log "ERROR: the install did not report INSTALLED; nothing launched"; exit 3; fi
|
| 14 |
+
log "installed; relaunching"
|
| 15 |
+
bash /root/v3/tools/relaunch_3arms.sh 1 1 4
|
| 16 |
+
log "done: $(tail -n 1 /root/v3/logs/relaunch_3arms.log)"
|
mini-beatrix-3/code/pod/install_0211.sh
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
# INSTALL amoe-lora 0.2.11 (the compiled chain's recompile budget + shape gate; commit 9bae609 on experimental) into /root/venv.
|
| 3 |
+
# Refuses while a trainer process is alive. alephllm stays at 0.10.5 (e8b7440). Reads the versions back.
|
| 4 |
+
OUT=/root/v3/logs/install_0211.log
|
| 5 |
+
log() { echo "[install $(date -u '+%H:%M:%SZ')] $*" | tee -a "$OUT"; }
|
| 6 |
+
LEFT=$(ps -eo cmd | grep -E "torch.distributed.run|geolip.alephllm.train.mission" | grep -v grep | wc -l)
|
| 7 |
+
if [ "$LEFT" != "0" ]; then log "REFUSED: $LEFT trainer processes alive"; exit 3; fi
|
| 8 |
+
SHA=9bae60922c83f5af242c5516fa369b9232afd2f3
|
| 9 |
+
log "installing amoe-lora 0.2.11 ($SHA)"
|
| 10 |
+
/root/venv/bin/pip install --no-deps --force-reinstall -q "git+https://github.com/AbstractEyes/amoe-lora@$SHA" >> "$OUT" 2>&1 && log "amoe-lora installed" || { log "amoe-lora install FAILED"; exit 4; }
|
| 11 |
+
echo "$SHA" > /root/v3/amoe_ref.txt
|
| 12 |
+
V=$(/root/venv/bin/python -c 'import amoe, geolip.alephllm as a; print(amoe.__version__, a.__version__)' 2>&1 | tail -n 1)
|
| 13 |
+
log "versions read back: amoe-lora / alephllm = $V"
|
| 14 |
+
case "$V" in "0.2.11 0.10.5") log "INSTALLED";; *) log "ERROR: expected 0.2.11 0.10.5"; exit 5;; esac
|
| 15 |
+
/root/venv/bin/python -c 'from amoe.core import adapter as A; print("gate constants:", A.COMPILE_RECOMPILE_LIMIT, A.COMPILE_ACCUMULATED_LIMIT, A.COMPILE_MAX_SHAPES)' | tee -a "$OUT"
|
mini-beatrix-3/code/pod/mission.json
CHANGED
|
@@ -82,5 +82,5 @@
|
|
| 82 |
"adapter_recompute": true,
|
| 83 |
"adapter_compile": true,
|
| 84 |
"abstain_chunks": 4,
|
| 85 |
-
"_note": "the mission file as it runs on the pod at the time of this snapshot (2026-09-
|
| 86 |
}
|
|
|
|
| 82 |
"adapter_recompute": true,
|
| 83 |
"adapter_compile": true,
|
| 84 |
"abstain_chunks": 4,
|
| 85 |
+
"_note": "the mission file as it runs on the pod at the time of this snapshot (2026-09-28 UTC): resumed from the 122,000 checkpoint on amoe-lora 0.2.11 with adapter_recompute, adapter_compile and abstain_chunks=4 set; the trainer re-reads the refreshable keys at every phase boundary"
|
| 86 |
}
|
mini-beatrix-3/code/pod/relaunch_3arms.sh
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
# THE RELAUNCH ON amoe-lora 0.2.11 (the 106,000 relaunch form generalized). Usage: bash relaunch_3arms.sh [recompute:0|1] [compile:0|1] [abstain_chunks:int|none]
|
| 3 |
+
# Defaults = the running form (recompute on, the compiled chain on, 4 abstention chunks). Keeps arm_spec_certified true, refuses if a
|
| 4 |
+
# trainer process is alive or a card holds memory or the installed libraries are not 0.2.11 / 0.10.5, launches launch_mission.sh (a
|
| 5 |
+
# resume-first launch: the resume state of the stop), restarts the arm sidecar, and prints the proving lines: versions, the attach
|
| 6 |
+
# lines with 'recompute on, compile on', the 'N abstention chunks per step' line, the first steps, the cards.
|
| 7 |
+
RECOMPUTE="${1:-1}"
|
| 8 |
+
COMPILE="${2:-1}"
|
| 9 |
+
ABST="${3:-4}"
|
| 10 |
+
OUT=/root/v3/logs/relaunch_3arms.log
|
| 11 |
+
log() { echo "[relaunch $(date -u '+%H:%M:%SZ')] $*" | tee -a "$OUT"; }
|
| 12 |
+
LEFT=$(ps -eo cmd | grep -E "torch.distributed.run|geolip.alephllm.train.mission" | grep -v grep | wc -l)
|
| 13 |
+
if [ "$LEFT" != "0" ]; then log "REFUSED: $LEFT trainer processes alive"; exit 3; fi
|
| 14 |
+
BUSY=$(nvidia-smi --query-gpu=memory.used --format=csv,noheader,nounits | awk '$1 > 2000' | wc -l)
|
| 15 |
+
if [ "$BUSY" != "0" ]; then log "REFUSED: a card still holds memory"; nvidia-smi --query-gpu=index,memory.used --format=csv,noheader | tee -a "$OUT"; exit 4; fi
|
| 16 |
+
V=$(/root/venv/bin/python -c 'import amoe, geolip.alephllm as a; print(amoe.__version__, a.__version__)' 2>&1 | tail -n 1)
|
| 17 |
+
log "installed: amoe-lora / alephllm = $V"
|
| 18 |
+
case "$V" in "0.2.11 0.10.5") ;; *) log "REFUSED: expected 0.2.11 0.10.5 (the compiled chain's recompile budget + shape gate)"; exit 5;; esac
|
| 19 |
+
RESUME=$(/root/venv/bin/python -c 'import torch; s = torch.load("/root/v3/runs/mission/mini-beatrix-3/resume/latest.pt", map_location="cpu", weights_only=False); print(s.get("step", "?"))' 2>/dev/null | tail -n 1)
|
| 20 |
+
log "resume state step: $RESUME"
|
| 21 |
+
cp /root/v3/mission.json "/root/v3/mission.json.bak_relaunch_$(date -u +%m%d_%H%M)"
|
| 22 |
+
/root/venv/bin/python - "$RECOMPUTE" "$COMPILE" "$ABST" "$RESUME" <<'PYEOF'
|
| 23 |
+
import json, os, sys
|
| 24 |
+
p = "/root/v3/mission.json"
|
| 25 |
+
C = json.load(open(p))
|
| 26 |
+
C["adapter_recompute"] = bool(int(sys.argv[1]))
|
| 27 |
+
C["adapter_compile"] = bool(int(sys.argv[2]))
|
| 28 |
+
C["abstain_chunks"] = None if sys.argv[3].lower() in ("none", "null", "") else int(sys.argv[3])
|
| 29 |
+
C["arm_spec_certified"] = True
|
| 30 |
+
C["_halt_note"] = ("relaunched from the %s resume state on amoe-lora 0.2.11 after the compiled chain fell back to eager at the stage 2 close "
|
| 31 |
+
"(dynamo's recompile limit hit by the boundary evaluation's variable-length inputs); the form unchanged: recompute + the "
|
| 32 |
+
"compiled chain + 4 abstention chunks; arm_spec_certified true" % sys.argv[4])
|
| 33 |
+
tmp = p + ".tmp"
|
| 34 |
+
json.dump(C, open(tmp, "w"), indent=2)
|
| 35 |
+
os.replace(tmp, p)
|
| 36 |
+
print("mission.json:", {k: C[k] for k in ("adapter_recompute", "adapter_compile", "abstain_chunks", "arm_spec_certified", "micro_batch", "grad_accum")})
|
| 37 |
+
PYEOF
|
| 38 |
+
log "launching"
|
| 39 |
+
cd /root/v3 || exit 9
|
| 40 |
+
bash /root/v3/launch_mission.sh | tee -a "$OUT"
|
| 41 |
+
for i in $(seq 1 90); do
|
| 42 |
+
if tr "\r" "\n" < /root/v3/logs/mission.log | tail -n 400 | grep -aq "\[train\] stage arms"; then break; fi
|
| 43 |
+
sleep 10
|
| 44 |
+
done
|
| 45 |
+
tr "\r" "\n" < /root/v3/logs/mission.log | tail -n 400 | grep -aE "\[mission\] alephllm|\[arms\] attached|\[arms\] restored|\[resume\]|\[train\] phase|\[train\] stage arms|Traceback|Error" | tail -n 14 | cut -c1-200 | tee -a "$OUT"
|
| 46 |
+
export $(tr "\0" "\n" < /proc/$(pgrep -f "geolip.alephllm.train.mission" | head -n 1)/environ | grep "^HF_TOKEN=")
|
| 47 |
+
nohup /root/venv/bin/python tools/arm_anchor_sidecar.py --poll 120 >> logs/arm_sidecar.out 2>&1 < /dev/null &
|
| 48 |
+
disown
|
| 49 |
+
sleep 2
|
| 50 |
+
log "sidecar pid $(pgrep -f 'python.*arm_anchor_sidecar.py' | tail -n 1) restarted"
|
| 51 |
+
sleep 240
|
| 52 |
+
log "steps after 4 min: $(tail -c 1500 /root/v3/logs/mission.log | tr "\r" "\n" | grep -aE "s/step" | tail -n 1 | cut -c1-100)"
|
| 53 |
+
log "recompile-limit warnings in the log since the launch: $(tail -c 300000 /root/v3/logs/mission.log | grep -ac 'recompile_limit')"
|
| 54 |
+
log "cards: $(nvidia-smi --query-gpu=index,memory.used --format=csv,noheader | tr '\n' ';')"
|
| 55 |
+
log "RELAUNCHED"
|
mini-beatrix-3/code/pod/stop_at_checkpoint.sh
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
# THE MANUAL STOP AT A CHECKPOINT (the 106,000 recipe of 2026-09-26, generalized). Usage: bash stop_at_checkpoint.sh <step, e.g. 119,496> [ships expected, default 3]
|
| 3 |
+
# Waits for the trainer's checkpoint line for that step (a full resume state, saved AND uploaded), then for the sidecar's arm ships
|
| 4 |
+
# from that state (one per attached arm; cap 6 min), then kills the torchrun tree while the loop is back in plain compute (no writes
|
| 5 |
+
# in flight): the resume lands exactly at that step and only the seconds after it are lost. The two-rank KeyboardInterrupt path is
|
| 6 |
+
# NOT used: torchrun treats a worker's exit as a failure and SIGTERMs the other mid-save.
|
| 7 |
+
STEP="${1:?step with commas, e.g. 119,496}"
|
| 8 |
+
SHIPS="${2:-3}"
|
| 9 |
+
LOG=/root/v3/logs/mission.log
|
| 10 |
+
SLOG=/root/v3/logs/arm_sidecar.log
|
| 11 |
+
OUT="/root/v3/logs/stop_${STEP//,/}.log"
|
| 12 |
+
log() { echo "[stop $(date -u '+%H:%M:%SZ')] $*" >> "$OUT"; }
|
| 13 |
+
log "armed: waiting for the [ckpt] step $STEP line ($SHIPS sidecar ships expected)"
|
| 14 |
+
for i in $(seq 1 2160); do
|
| 15 |
+
if tr "\r" "\n" < "$LOG" | grep -aq "\[ckpt\] step $STEP:.*saved & uploaded"; then break; fi
|
| 16 |
+
sleep 10
|
| 17 |
+
done
|
| 18 |
+
if ! tr "\r" "\n" < "$LOG" | grep -aq "\[ckpt\] step $STEP:.*saved & uploaded"; then log "ERROR: no checkpoint line within 6 h; nothing done"; exit 2; fi
|
| 19 |
+
log "checkpoint line seen: $(tr "\r" "\n" < "$LOG" | grep -a "\[ckpt\] step $STEP:" | tail -n 1 | cut -c1-140)"
|
| 20 |
+
for i in $(seq 1 36); do
|
| 21 |
+
n=$(grep -ac "step $STEP: shipped" "$SLOG")
|
| 22 |
+
if [ "$n" -ge "$SHIPS" ]; then break; fi
|
| 23 |
+
sleep 10
|
| 24 |
+
done
|
| 25 |
+
log "sidecar ships for $STEP: $(grep -ac "step $STEP: shipped" "$SLOG") ($SHIPS expected)"
|
| 26 |
+
sleep 20
|
| 27 |
+
LAST=$(tail -c 1500 "$LOG" | tr "\r" "\n" | grep -aE "s/step" | tail -n 1 | cut -c1-100)
|
| 28 |
+
log "last bar line before the kill: $LAST"
|
| 29 |
+
PIDS=$(ps -eo pid,cmd | grep -E "torch.distributed.run|geolip.alephllm.train.mission" | grep -v grep | awk '{print $1}' | tr "\n" " ")
|
| 30 |
+
log "killing the torchrun tree: $PIDS"
|
| 31 |
+
kill -9 $PIDS 2>/dev/null
|
| 32 |
+
sleep 5
|
| 33 |
+
LEFT=$(ps -eo pid,cmd | grep -E "torch.distributed.run|geolip.alephllm.train.mission" | grep -v grep | wc -l)
|
| 34 |
+
log "processes left: $LEFT; cards: $(nvidia-smi --query-gpu=index,memory.used --format=csv,noheader | tr "\n" ";")"
|
| 35 |
+
for SPID in $(pgrep -f "python.*arm_anchor_sidecar.py"); do kill "$SPID" 2>/dev/null; log "sidecar $SPID stopped (the relaunch restarts it)"; done
|
| 36 |
+
log "resume state: $(ls -la --time-style=+%H:%M:%S /root/v3/runs/mission/mini-beatrix-3/resume/latest.pt | awk '{print $5, $6}')"
|
| 37 |
+
log "STOPPED at the $STEP point"
|
mini-beatrix-3/code/requirements.txt
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
# the pod's environment for the mini-beatrix-3 mission (2026-09-
|
| 2 |
torch==2.8.0
|
| 3 |
torchvision==0.23.0
|
| 4 |
torchaudio==2.8.0
|
|
@@ -8,6 +8,6 @@ huggingface_hub==1.32.0
|
|
| 8 |
datasets==5.0.1
|
| 9 |
numpy==2.1.2
|
| 10 |
pyarrow==25.0.1
|
| 11 |
-
# the two libraries, pinned to the commits that
|
| 12 |
-
# pip install --no-deps 'git+https://github.com/AbstractEyes/amoe-lora@
|
| 13 |
# pip install --no-deps 'git+https://github.com/AbstractEyes/alephllm@e8b7440' # geolip.alephllm 0.10.5
|
|
|
|
| 1 |
+
# the pod's environment for the mini-beatrix-3 mission (2026-09-28); CUDA 12.8 wheels
|
| 2 |
torch==2.8.0
|
| 3 |
torchvision==0.23.0
|
| 4 |
torchaudio==2.8.0
|
|
|
|
| 8 |
datasets==5.0.1
|
| 9 |
numpy==2.1.2
|
| 10 |
pyarrow==25.0.1
|
| 11 |
+
# the two libraries, pinned to the commits that train this run (the snapshots in this folder are these commits):
|
| 12 |
+
# pip install --no-deps 'git+https://github.com/AbstractEyes/amoe-lora@9bae609' # amoe 0.2.11 (0.2.10 @f3db5d4 trained steps 106,000-122,000)
|
| 13 |
# pip install --no-deps 'git+https://github.com/AbstractEyes/alephllm@e8b7440' # geolip.alephllm 0.10.5
|