Scott/Codex commited on
Commit
5c319bd
·
1 Parent(s): 4d8ed2f

Fold VRAM-first dblock mode into AGILLM4

Browse files
README.md CHANGED
@@ -37,6 +37,14 @@ whose released code is ViT/classification only.
37
  | 4096 | 11.08 GB | 8.68 GB |
38
  | 8192 | 22.11 GB | 19.37 GB |
39
 
 
 
 
 
 
 
 
 
40
  ## Honest findings
41
  - DiffusionBlocks and gradient-checkpointing are **substitutes** for activation
42
  memory; with checkpointing on, the 28->7 layer saving is only ~1.1-1.3x.
@@ -44,8 +52,11 @@ whose released code is ViT/classification only.
44
  - The long-context ceiling (16k+) is **attention-bound**, so the next lever is the
45
  sublinear attention backend, not more block/CE work.
46
 
47
- Status: validated research prototype. The official AGILLM-4 training line remains the
48
- proven AR/SAT/NAT end-to-end trainer; these wins (tied heads, fused-CE, sublinear
49
- attention) are intended to be folded into it for long context.
 
 
 
50
 
51
  License: Apache-2.0 (matching the upstream method).
 
37
  | 4096 | 11.08 GB | 8.68 GB |
38
  | 8192 | 22.11 GB | 19.37 GB |
39
 
40
+ ## Official-line integration snapshot (2026-05-29)
41
+ - `nB300_agillm4_vram_dblock.py` is the patched official trainer snapshot from the Vast box.
42
+ - `dblocks_train.py` is the folded-in low-VRAM training step used by `--dblock`.
43
+ - `relaunch_agillm4_dblock.sh` restarts the official line with `--dblock --tie_weights --attn_backend sublinear`.
44
+ - `--tie_weights` now means AR, SAT, and NAT share the embedding projection tensor. This drops the live parameter count from 1,213,418,242 to 716,595,202.
45
+ - Old untied checkpoint head matrices are intentionally skipped under tied mode; core weights still warm-start and the optimizer can rebuild.
46
+ - SAT now uses fused vocab-streaming CE in the dblock path, and the dblock step releases AR/SAT activations before moving to the next objective.
47
+
48
  ## Honest findings
49
  - DiffusionBlocks and gradient-checkpointing are **substitutes** for activation
50
  memory; with checkpointing on, the 28->7 layer saving is only ~1.1-1.3x.
 
52
  - The long-context ceiling (16k+) is **attention-bound**, so the next lever is the
53
  sublinear attention backend, not more block/CE work.
54
 
55
+ Status update 2026-05-29: Scott chose the VRAM-first route. The official AGILLM-4
56
+ training line is now the DiffusionBlocks mode folded into `nB300_agillm4.py`, with
57
+ `--dblock --tie_weights --attn_backend sublinear`. Checkpoint compatibility is best-effort
58
+ only: old untied AR/SAT/NAT head tensors are skipped when tied heads are active, and the
59
+ optimizer state is allowed to reset. The priority is lower VRAM over preserving every
60
+ old training assumption.
61
 
62
  License: Apache-2.0 (matching the upstream method).
dblocks_train.py ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """DiffusionBlocks training mode folded into AGILLM-4 (gated by --dblock).
2
+
3
+ Block-wise EDM denoising on the real Encoder blocks, supervising AR + SAT(fixed+var)
4
+ + NAT each step on ONE block, with grad-checkpointed layers and fused vocab-streaming
5
+ CE. Reuses the live data stream / optimizer / checkpointing of nB300_agillm4.
6
+ Lazy-imports nB300 inside functions to avoid a circular import.
7
+ """
8
+ import math, random, numpy as np, torch, torch.nn as nn, torch.nn.functional as F
9
+ import torch.utils.checkpoint as _ck
10
+ from fused_ce import fused_ce
11
+ SD=0.5
12
+ def _cdf(x): return 0.5*(1+math.erf(x/math.sqrt(2)))
13
+ def _ppf(p): return float(torch.erfinv(torch.tensor(2*p-1.0))*math.sqrt(2))
14
+ def _block_sigmas(B,smin=0.002,smax=80.0,pm=-1.2,ps=1.2):
15
+ a,b=_cdf((math.log(smin)-pm)/ps),_cdf((math.log(smax)-pm)/ps)
16
+ return [float(np.exp(pm+ps*_ppf(a+(b-a)*(i/B)))) for i in range(B+1)]
17
+ def _edm_pre(s): s=s[:,None,None]; return SD**2/(s**2+SD**2), s*SD/(s**2+SD**2)**0.5, 1/(s**2+SD**2)**0.5
18
+ def _edm_w(s,wmax=5.0): return float(((s**2+SD**2)/(s*SD)**2).clamp(max=wmax).mean())
19
+
20
+ def _dblock_init(core, args):
21
+ B=int(getattr(args,"dblock_blocks",4)); L=len(core.blocks); sp=max(1,L//B)
22
+ asg=[list(range(i*sp,(i+1)*sp)) for i in range(B)]; asg[-1]=list(range((B-1)*sp,L))
23
+ print(f"[dblock] DiffusionBlocks mode: {L} layers -> {B} blocks {asg}")
24
+ print(f"[dblock] equi-prob sigma boundaries: {[round(x,3) for x in _block_sigmas(B)]}")
25
+ return {"B":B,"assign":asg,"bsig":_block_sigmas(B)}
26
+
27
+ def _dblock_step(core, ar_h, sat_h, nat_h, opt, scaler, args, ids, state):
28
+ import nB300_agillm4 as M
29
+ B=state["B"]; asg=state["assign"]; bs=state["bsig"]; T=ids.size(1)
30
+ bi=random.randrange(B); lo,hi=sorted([bs[bi],bs[bi+1]]); layers=asg[bi]
31
+ sig=torch.from_numpy(np.exp(np.random.uniform(math.log(max(lo,1e-4)),math.log(hi),ids.size(0))).astype("float32")).to(ids.device)
32
+ cs,co,ci=_edm_pre(sig); w=_edm_w(sig); SATB=M.SAT_BLOCK
33
+ # ---- AR: causal diffusion denoise ----
34
+ with M.amp(args.amp):
35
+ emb=core.emb(ids); zt=emb+sig[:,None,None]*torch.randn_like(emb); h=ci*zt
36
+ for li in layers: h=_ck.checkpoint(core.blocks[li], h, M.causal_mask(T), use_reentrant=False)
37
+ Dn=core.ln(cs*zt+co*h)
38
+ ar=w*fused_ce(Dn[:,:-1].contiguous(), ar_h.proj.weight, ids[:,1:].contiguous())
39
+ scaler.scale(ar).backward()
40
+ ar_val=float(ar.detach())
41
+ del emb, zt, h, Dn, ar
42
+ # ---- SAT: block-causal diffusion; fixed proj + variable gate ----
43
+ with M.amp(args.amp):
44
+ emb2=core.emb(ids); zt2=emb2+sig[:,None,None]*torch.randn_like(emb2); h2=ci*zt2
45
+ for li in layers: h2=_ck.checkpoint(core.blocks[li], h2, M.sat_mask(T), use_reentrant=False)
46
+ Ds=core.ln(cs*zt2+co*h2); last=Ds[:,-SATB:]
47
+ satf=fused_ce(last.contiguous(), sat_h.proj.weight, ids[:,1:SATB+1].contiguous())
48
+ satv=(M.EMIT_LAMBDA*F.cross_entropy(sat_h.gate(Ds[:,0].float()), torch.ones(ids.size(0),dtype=torch.long,device=ids.device))) if sat_h.gate is not None else 0.0
49
+ sat=w*(satf+satv)
50
+ scaler.scale(sat).backward()
51
+ sat_val=float(sat.detach())
52
+ del emb2, zt2, h2, Ds, last, satf, satv, sat
53
+ # ---- NAT: bidirectional mask-predict ----
54
+ nat_val=0.0
55
+ if nat_h is not None:
56
+ ratio=min(max(float(getattr(args,"nat_mask_ratio",0.5)),0.05),0.95)
57
+ with M.amp(args.amp):
58
+ nat_ids=ids.clone(); m=torch.rand(ids.shape,device=ids.device)<ratio
59
+ if not bool(m.any()): m[...,-1]=True
60
+ nat_ids[m]=M.BLANK; hn=core.emb(nat_ids)
61
+ for li in layers: hn=_ck.checkpoint(core.blocks[li], hn, None, use_reentrant=False)
62
+ Dnat=core.ln(hn)
63
+ nat=fused_ce(Dnat[m], nat_h.proj.weight, ids[m]); scaler.scale(nat).backward(); nat_val=float(nat.detach()); del nat_ids, m, hn, Dnat, nat
64
+ scaler.unscale_(opt)
65
+ nn.utils.clip_grad_norm_([p for g in opt.param_groups for p in g["params"]],1.0)
66
+ scaler.step(opt); scaler.update(); opt.zero_grad(set_to_none=True)
67
+ return ar_val+sat_val+nat_val
nB300_agillm4_vram_dblock.py ADDED
The diff for this file is too large to render. See raw diff
 
relaunch_agillm4_dblock.sh ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+ # OFFICIAL LINE: DiffusionBlocks block-wise denoising (low VRAM). Resumes newest ckpt.
3
+ set -Eeuo pipefail
4
+ cd /workspace/agillm-4
5
+ export TOKENIZERS_PARALLELISM=false
6
+ export TOKENIZER_ID="${TOKENIZER_ID:-deepseek-ai/DeepSeek-V4-Pro}"
7
+ export PYTORCH_CUDA_ALLOC_CONF=max_split_size_mb:512,expandable_segments:True
8
+ export AGILLM_ATTN_BACKEND="${AGILLM_ATTN_BACKEND:-sublinear}"
9
+ if [ -f /root/.cache/huggingface/token ]; then export HF_TOKEN="$(tr -d '\r\n' </root/.cache/huggingface/token)"; export HUGGING_FACE_HUB_TOKEN="$HF_TOKEN"; fi
10
+ SAVE_DIR=/workspace/agillm4_4090_ckpts
11
+ CKPT="$(ls -1t "$SAVE_DIR"/pretrain_step*.pt 2>/dev/null | head -1)"
12
+ [ -n "$CKPT" ] || { echo "no ckpt" >&2; exit 1; }
13
+ exec >> /workspace/agillm4_floor_train.log 2>&1
14
+ echo "RELAUNCH_AGILLM4_DBLOCK $(date -u +%Y-%m-%dT%H:%M:%SZ) resume=$CKPT --dblock blocks=${AGILLM4_DBLOCKS:-4} tie_weights=1 attn=${AGILLM_ATTN_BACKEND}"
15
+ exec python -u nB300_agillm4.py train --preset agillm4_floor --resume "$CKPT" \
16
+ --dblock --dblock_blocks "${AGILLM4_DBLOCKS:-4}" --tie_weights \
17
+ --batch_size 1 --block "${AGILLM4_BLOCK:-1280}" --amp --attn_backend "${AGILLM_ATTN_BACKEND}" --grad_checkpoint \
18
+ --optimizer paged_adamw8bit --sat_every 1 --nat_every 1 --nat_max_tokens 768 --nat_mask_ratio 0.5 \
19
+ --token_param_ratio 100 --save_dir "$SAVE_DIR" \
20
+ --save_every_sec 86400 --delta_every_steps 25000 --delta_max_keep 1 --max_ckpts 1