Scott/Codex commited on
Commit
9c90574
·
1 Parent(s): aa3d8cc

Tune DBlock backward-math speed line

Browse files
README.md CHANGED
@@ -94,3 +94,6 @@ Quality target update 2026-05-29: Scott clarified the previous AGILLM run was ro
94
 
95
 
96
  License: Apache-2.0 (matching the upstream method).
 
 
 
 
94
 
95
 
96
  License: Apache-2.0 (matching the upstream method).
97
+
98
+ Backward-math speed update 2026-05-29: live profiling confirmed the expensive path is AR transformer backward/recompute, not fused CE, data loading, or optimizer step. A clean context/batch sweep found B6/L1024 gives the best raw throughput among quality-preserving candidates (6144 tokens/step, ~3.3k tok/s profiler math) while keeping a 1024-token context. A second objective-mix sweep tested a harder experimental path: reducing full causal AR steps from 85% to 70% and moving the probability mass to SAT/NAT (`--dblock_ar_prob 0.70 --dblock_sat_prob 0.15 --dblock_nat_prob 0.15`). Clean profiler math reached ~3440 tok/s, and the live relaunch now uses B6/L1024 + ar70. The relaunch script intentionally unsets `PYTORCH_CUDA_ALLOC_CONF` because the previous expandable-segments allocator reserved ~23 GB and caused memory-pressure slowdown on this shape; without it, the live line returns to ~15.1 GB tensor peak / ~16.5-17.4 GB observed VRAM. This is experimental by design: it trades some AR-step density for faster multi-objective DBlock training while preserving checkpoint warm start and the 55 tokens/param target.
99
+
dblocks_train.py CHANGED
@@ -182,21 +182,50 @@ def _update_stats(state, bi, loss_value):
182
  state["step"] = int(state.get("step", 0)) + 1
183
 
184
 
185
- def _run_block(block, x, mask, use_checkpoint):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186
  if use_checkpoint:
187
  return _ck.checkpoint(lambda y, block=block: block(y, mask), x, use_reentrant=False)
 
 
 
188
  return block(x, mask)
189
 
190
 
191
- def _dblock_checkpoint_this_layer(args, base_enabled, layer_pos):
192
  if not base_enabled:
193
  return False
 
 
 
 
 
194
  stride = int(getattr(args, "dblock_checkpoint_stride", 1) or 1)
195
  if stride <= 0:
196
  return False
197
  if stride == 1:
198
  return True
199
- return (int(layer_pos) % stride) == 0
200
 
201
 
202
  def _sample_token_loss_inputs(hidden, targets, max_tokens):
@@ -293,7 +322,7 @@ def _dblock_step(core, ar_h, sat_h, nat_h, opt, scaler, args, ids, state):
293
  zt = emb + sig[:, None, None] * torch.randn_like(emb)
294
  h = ci * zt
295
  for lpos, li in enumerate(layers):
296
- h = _run_block(core.blocks[li], h, causal, _dblock_checkpoint_this_layer(args, use_layer_checkpoint, lpos))
297
  Dn = core.ln(cs * zt + co * h)
298
  _profile_toc(state, "ar_forward", _t)
299
  _t = _profile_tic(prof)
@@ -316,7 +345,7 @@ def _dblock_step(core, ar_h, sat_h, nat_h, opt, scaler, args, ids, state):
316
  zt2 = emb2 + sig[:, None, None] * torch.randn_like(emb2)
317
  h2 = ci * zt2
318
  for lpos, li in enumerate(layers):
319
- h2 = _run_block(core.blocks[li], h2, smask, _dblock_checkpoint_this_layer(args, use_layer_checkpoint, lpos))
320
  Ds = core.ln(cs * zt2 + co * h2)
321
  last = Ds[:, -SATB:]
322
  _profile_toc(state, "sat_forward", _t)
@@ -355,7 +384,7 @@ def _dblock_step(core, ar_h, sat_h, nat_h, opt, scaler, args, ids, state):
355
  nat_in[m] = M.BLANK
356
  hn = core.emb(nat_in)
357
  for lpos, li in enumerate(layers):
358
- hn = _run_block(core.blocks[li], hn, None, _dblock_checkpoint_this_layer(args, use_layer_checkpoint, lpos))
359
  Dnat = core.ln(hn)
360
  _profile_toc(state, "nat_forward", _t)
361
  _t = _profile_tic(prof)
 
182
  state["step"] = int(state.get("step", 0)) + 1
183
 
184
 
185
+ def _activation_offload_enabled(args):
186
+ return bool(getattr(args, "dblock_activation_offload", False)) and torch.cuda.is_available()
187
+
188
+
189
+ def _activation_offload_hooks(args):
190
+ min_bytes = int(float(getattr(args, "dblock_activation_offload_min_mb", 1.0) or 1.0) * 1024 * 1024)
191
+
192
+ def pack(t):
193
+ if not torch.is_tensor(t) or not t.is_cuda or not t.is_floating_point() or t.numel() * t.element_size() < min_bytes:
194
+ return t
195
+ return ("cpu_offload", t.device, t.detach().to("cpu", non_blocking=True))
196
+
197
+ def unpack(x):
198
+ if isinstance(x, tuple) and len(x) == 3 and x[0] == "cpu_offload":
199
+ _, dev, cpu_t = x
200
+ return cpu_t.to(dev, non_blocking=True)
201
+ return x
202
+
203
+ return torch.autograd.graph.saved_tensors_hooks(pack, unpack)
204
+
205
+
206
+ def _run_block(block, x, mask, use_checkpoint, args=None):
207
  if use_checkpoint:
208
  return _ck.checkpoint(lambda y, block=block: block(y, mask), x, use_reentrant=False)
209
+ if args is not None and _activation_offload_enabled(args):
210
+ with _activation_offload_hooks(args):
211
+ return block(x, mask)
212
  return block(x, mask)
213
 
214
 
215
+ def _dblock_checkpoint_this_layer(args, base_enabled, layer_pos, layer_count=None):
216
  if not base_enabled:
217
  return False
218
+ pos = int(layer_pos)
219
+ count = int(layer_count or 0)
220
+ skip_tail = max(0, int(getattr(args, "dblock_checkpoint_skip_tail", 0) or 0))
221
+ if skip_tail > 0 and count > 0 and pos >= max(0, count - skip_tail):
222
+ return False
223
  stride = int(getattr(args, "dblock_checkpoint_stride", 1) or 1)
224
  if stride <= 0:
225
  return False
226
  if stride == 1:
227
  return True
228
+ return (pos % stride) == 0
229
 
230
 
231
  def _sample_token_loss_inputs(hidden, targets, max_tokens):
 
322
  zt = emb + sig[:, None, None] * torch.randn_like(emb)
323
  h = ci * zt
324
  for lpos, li in enumerate(layers):
325
+ h = _run_block(core.blocks[li], h, causal, _dblock_checkpoint_this_layer(args, use_layer_checkpoint, lpos, len(layers)), args)
326
  Dn = core.ln(cs * zt + co * h)
327
  _profile_toc(state, "ar_forward", _t)
328
  _t = _profile_tic(prof)
 
345
  zt2 = emb2 + sig[:, None, None] * torch.randn_like(emb2)
346
  h2 = ci * zt2
347
  for lpos, li in enumerate(layers):
348
+ h2 = _run_block(core.blocks[li], h2, smask, _dblock_checkpoint_this_layer(args, use_layer_checkpoint, lpos, len(layers)), args)
349
  Ds = core.ln(cs * zt2 + co * h2)
350
  last = Ds[:, -SATB:]
351
  _profile_toc(state, "sat_forward", _t)
 
384
  nat_in[m] = M.BLANK
385
  hn = core.emb(nat_in)
386
  for lpos, li in enumerate(layers):
387
+ hn = _run_block(core.blocks[li], hn, None, _dblock_checkpoint_this_layer(args, use_layer_checkpoint, lpos, len(layers)), args)
388
  Dnat = core.ln(hn)
389
  _profile_toc(state, "nat_forward", _t)
390
  _t = _profile_tic(prof)
nB300_agillm4_vram_dblock.py CHANGED
@@ -3039,6 +3039,12 @@ def main():
3039
  help="Print DBlock block/loss/VRAM diagnostics every N DBlock steps; 0 disables.")
3040
  tr.add_argument("--dblock_checkpoint_stride", type=int, default=1,
3041
  help="With --grad_checkpoint in --dblock mode, checkpoint one layer every N selected block layers; 1=all layers, 2=alternate, 0=off.")
 
 
 
 
 
 
3042
  tr.add_argument("--dblock_sigma_curriculum_steps", type=int, default=2000,
3043
  help="Warm sigma ranges from easy to full span over this many DBlock steps; 0 disables.")
3044
  tr.add_argument("--dblock_edm_wmax", type=float, default=5.0,
 
3039
  help="Print DBlock block/loss/VRAM diagnostics every N DBlock steps; 0 disables.")
3040
  tr.add_argument("--dblock_checkpoint_stride", type=int, default=1,
3041
  help="With --grad_checkpoint in --dblock mode, checkpoint one layer every N selected block layers; 1=all layers, 2=alternate, 0=off.")
3042
+ tr.add_argument("--dblock_checkpoint_skip_tail", type=int, default=0,
3043
+ help="Experimental DBlock speed knob: do not checkpoint this many final layers in the selected block, reducing backward recompute at higher VRAM cost.")
3044
+ tr.add_argument("--dblock_activation_offload", action="store_true",
3045
+ help="Experimental DBlock speed knob: for non-checkpointed block layers, offload saved backward tensors to CPU RAM instead of recomputing.")
3046
+ tr.add_argument("--dblock_activation_offload_min_mb", type=float, default=1.0,
3047
+ help="Minimum CUDA tensor size in MB to offload under --dblock_activation_offload.")
3048
  tr.add_argument("--dblock_sigma_curriculum_steps", type=int, default=2000,
3049
  help="Warm sigma ranges from easy to full span over this many DBlock steps; 0 disables.")
3050
  tr.add_argument("--dblock_edm_wmax", type=float, default=5.0,
relaunch_agillm4_dblock_sg2.sh CHANGED
@@ -4,20 +4,20 @@ 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=sublinear
9
  [ -f /root/.cache/huggingface/token ] && { export HF_TOKEN="$(tr -d '\r\n' </root/.cache/huggingface/token)"; export HUGGING_FACE_HUB_TOKEN="$HF_TOKEN"; }
10
  SAVE_DIR=/workspace/agillm4_4090_ckpts
11
  TOKEN_PARAM_RATIO="${TOKEN_PARAM_RATIO:-55}"
12
  CKPT="$(ls -1t "$SAVE_DIR"/pretrain_step*.pt 2>/dev/null | head -1)"
13
  exec >> /workspace/agillm4_floor_train.log 2>&1
14
- echo "RELAUNCH_AGILLM4_DBLOCK_SG2 $(date -u +%Y-%m-%dT%H:%M:%SZ) resume=$CKPT (quality ratio55 + batch4 + sublinear v2)"
15
  exec python -u nB300_agillm4.py train --preset agillm4_floor --resume "$CKPT" \
16
  --dblock --dblock_blocks 4 --dblock_schedule loss_balanced --dblock_warmup_steps 16 \
17
  --dblock_sigma_curriculum_steps 2000 --dblock_log_every 25 --dblock_objective_mode stochastic \
18
- --dblock_ar_prob 0.85 --dblock_sat_prob 0.075 --dblock_nat_prob 0.075 \
19
  --dblock_ar_loss_tokens 512 --dblock_sat_loss_tokens 0 --dblock_nat_loss_tokens 512 \
20
- --tie_weights --batch_size 4 --block 1280 --amp --attn_backend sublinear \
21
  --sublinear_window 128 --sublinear_stride 128 --sublinear_max_anchors 128 --sublinear_chunk 128 \
22
  --sublinear_sinks 4 --sublinear_recent_anchors 64 --no-sublinear_pooled_landmarks \
23
  --grad_checkpoint --dblock_checkpoint_stride 1 --optimizer paged_adamw8bit --sat_every 4 --nat_every 4 --nat_max_tokens 768 --nat_mask_ratio 0.5 \
 
4
  cd /workspace/agillm-4
5
  export TOKENIZERS_PARALLELISM=false
6
  export TOKENIZER_ID="${TOKENIZER_ID:-deepseek-ai/DeepSeek-V4-Pro}"
7
+ unset PYTORCH_CUDA_ALLOC_CONF # B6/L1024 ar70: avoid near-full allocator reservation slowdown
8
  export AGILLM_ATTN_BACKEND=sublinear
9
  [ -f /root/.cache/huggingface/token ] && { export HF_TOKEN="$(tr -d '\r\n' </root/.cache/huggingface/token)"; export HUGGING_FACE_HUB_TOKEN="$HF_TOKEN"; }
10
  SAVE_DIR=/workspace/agillm4_4090_ckpts
11
  TOKEN_PARAM_RATIO="${TOKEN_PARAM_RATIO:-55}"
12
  CKPT="$(ls -1t "$SAVE_DIR"/pretrain_step*.pt 2>/dev/null | head -1)"
13
  exec >> /workspace/agillm4_floor_train.log 2>&1
14
+ echo "RELAUNCH_AGILLM4_DBLOCK_SG2 $(date -u +%Y-%m-%dT%H:%M:%SZ) resume=$CKPT (quality ratio55 + B6/L1024 + ar70 backward-math + sublinear v2)"
15
  exec python -u nB300_agillm4.py train --preset agillm4_floor --resume "$CKPT" \
16
  --dblock --dblock_blocks 4 --dblock_schedule loss_balanced --dblock_warmup_steps 16 \
17
  --dblock_sigma_curriculum_steps 2000 --dblock_log_every 25 --dblock_objective_mode stochastic \
18
+ --dblock_ar_prob 0.70 --dblock_sat_prob 0.15 --dblock_nat_prob 0.15 \
19
  --dblock_ar_loss_tokens 512 --dblock_sat_loss_tokens 0 --dblock_nat_loss_tokens 512 \
20
+ --tie_weights --batch_size 6 --block 1024 --amp --attn_backend sublinear \
21
  --sublinear_window 128 --sublinear_stride 128 --sublinear_max_anchors 128 --sublinear_chunk 128 \
22
  --sublinear_sinks 4 --sublinear_recent_anchors 64 --no-sublinear_pooled_landmarks \
23
  --grad_checkpoint --dblock_checkpoint_stride 1 --optimizer paged_adamw8bit --sat_every 4 --nat_every 4 --nat_max_tokens 768 --nat_mask_ratio 0.5 \