Upload dblock training helper
Browse files- dblocks_train.py +432 -0
dblocks_train.py
ADDED
|
@@ -0,0 +1,432 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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
|
| 9 |
+
import random
|
| 10 |
+
import time
|
| 11 |
+
from collections import defaultdict
|
| 12 |
+
import numpy as np
|
| 13 |
+
import torch
|
| 14 |
+
import torch.nn as nn
|
| 15 |
+
import torch.nn.functional as F
|
| 16 |
+
import torch.utils.checkpoint as _ck
|
| 17 |
+
from fused_ce import fused_ce
|
| 18 |
+
|
| 19 |
+
SD = 0.5
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def _profile_active(state, args):
|
| 25 |
+
limit = int(getattr(args, "profile_steps", 0) or 0)
|
| 26 |
+
return limit > 0 and int(state.get("profile_n", 0)) < limit
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def _profile_add(state, name, seconds):
|
| 30 |
+
if seconds is None:
|
| 31 |
+
return
|
| 32 |
+
prof = state.setdefault("profile_times", defaultdict(float))
|
| 33 |
+
prof[name] += float(seconds)
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def _profile_tic(enabled):
|
| 37 |
+
if not enabled:
|
| 38 |
+
return None
|
| 39 |
+
if torch.cuda.is_available():
|
| 40 |
+
torch.cuda.synchronize()
|
| 41 |
+
return time.perf_counter()
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
def _profile_toc(state, name, start):
|
| 45 |
+
if start is None:
|
| 46 |
+
return
|
| 47 |
+
if torch.cuda.is_available():
|
| 48 |
+
torch.cuda.synchronize()
|
| 49 |
+
_profile_add(state, name, time.perf_counter() - start)
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def _profile_step_done(state, args):
|
| 53 |
+
limit = int(getattr(args, "profile_steps", 0) or 0)
|
| 54 |
+
if limit <= 0:
|
| 55 |
+
return
|
| 56 |
+
n_prev = int(state.get("profile_n", 0))
|
| 57 |
+
if n_prev >= limit:
|
| 58 |
+
return
|
| 59 |
+
state["profile_n"] = n_prev + 1
|
| 60 |
+
n = int(state["profile_n"])
|
| 61 |
+
log_every = max(1, int(getattr(args, "profile_log_every", 25) or 25))
|
| 62 |
+
if n % log_every != 0 and n != limit:
|
| 63 |
+
return
|
| 64 |
+
times = state.get("profile_times", {})
|
| 65 |
+
keys = [
|
| 66 |
+
"data_stream", "tensor", "setup",
|
| 67 |
+
"ar_forward", "ar_ce", "ar_backward",
|
| 68 |
+
"sat_forward", "sat_ce", "sat_backward",
|
| 69 |
+
"nat_forward", "nat_ce", "nat_backward",
|
| 70 |
+
"opt_step", "step_total",
|
| 71 |
+
]
|
| 72 |
+
parts = []
|
| 73 |
+
for key in keys:
|
| 74 |
+
val = float(times.get(key, 0.0)) * 1000.0 / max(1, n)
|
| 75 |
+
if val > 0.01:
|
| 76 |
+
parts.append(f"{key}={val:.2f}ms")
|
| 77 |
+
print(f"[profile] n={n}/{limit} avg " + " ".join(parts), flush=True)
|
| 78 |
+
|
| 79 |
+
def _cdf(x):
|
| 80 |
+
return 0.5 * (1 + math.erf(x / math.sqrt(2)))
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
def _ppf(p):
|
| 84 |
+
return float(torch.erfinv(torch.tensor(2 * p - 1.0)) * math.sqrt(2))
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
def _block_sigmas(B, smin=0.002, smax=80.0, pm=-1.2, ps=1.2):
|
| 88 |
+
a, b = _cdf((math.log(smin) - pm) / ps), _cdf((math.log(smax) - pm) / ps)
|
| 89 |
+
return [float(np.exp(pm + ps * _ppf(a + (b - a) * (i / B)))) for i in range(B + 1)]
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
def _edm_pre(s):
|
| 93 |
+
s = s[:, None, None]
|
| 94 |
+
return SD**2 / (s**2 + SD**2), s * SD / (s**2 + SD**2) ** 0.5, 1 / (s**2 + SD**2) ** 0.5
|
| 95 |
+
|
| 96 |
+
|
| 97 |
+
def _edm_w(s, wmax=5.0):
|
| 98 |
+
return float(((s**2 + SD**2) / (s * SD) ** 2).clamp(max=wmax).mean())
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
def _dblock_init(core, args):
|
| 102 |
+
B = int(getattr(args, "dblock_blocks", 4))
|
| 103 |
+
L = len(core.blocks)
|
| 104 |
+
sp = max(1, L // B)
|
| 105 |
+
asg = [list(range(i * sp, (i + 1) * sp)) for i in range(B)]
|
| 106 |
+
asg[-1] = list(range((B - 1) * sp, L))
|
| 107 |
+
bsig = _block_sigmas(B)
|
| 108 |
+
schedule = getattr(args, "dblock_schedule", "loss_balanced")
|
| 109 |
+
print(f"[dblock] DiffusionBlocks mode: {L} layers -> {B} blocks {asg}")
|
| 110 |
+
print(f"[dblock] schedule={schedule} sigma boundaries: {[round(x, 3) for x in bsig]}")
|
| 111 |
+
return {
|
| 112 |
+
"B": B,
|
| 113 |
+
"assign": asg,
|
| 114 |
+
"bsig": bsig,
|
| 115 |
+
"step": 0,
|
| 116 |
+
"counts": [0 for _ in range(B)],
|
| 117 |
+
"loss_ema": [None for _ in range(B)],
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
def _choose_block(state, args):
|
| 122 |
+
B = state["B"]
|
| 123 |
+
schedule = str(getattr(args, "dblock_schedule", "loss_balanced") or "loss_balanced").lower()
|
| 124 |
+
step = int(state.get("step", 0))
|
| 125 |
+
counts = state.setdefault("counts", [0 for _ in range(B)])
|
| 126 |
+
emas = state.setdefault("loss_ema", [None for _ in range(B)])
|
| 127 |
+
if schedule == "random":
|
| 128 |
+
return random.randrange(B)
|
| 129 |
+
if schedule == "roundrobin":
|
| 130 |
+
return step % B
|
| 131 |
+
explore = float(getattr(args, "dblock_explore", 0.05))
|
| 132 |
+
warmup = int(getattr(args, "dblock_warmup_steps", max(8, B * 2)))
|
| 133 |
+
if step < warmup or any(c == 0 for c in counts):
|
| 134 |
+
return min(range(B), key=lambda i: (counts[i], i))
|
| 135 |
+
if explore > 0.0 and random.random() < explore:
|
| 136 |
+
return min(range(B), key=lambda i: (counts[i], i))
|
| 137 |
+
return max(range(B), key=lambda i: (-1.0 if emas[i] is None else emas[i], -counts[i]))
|
| 138 |
+
|
| 139 |
+
|
| 140 |
+
def _sample_sigma(ids, lo, hi, args, state):
|
| 141 |
+
cur_step = int(state.get("step", 0))
|
| 142 |
+
curriculum = int(getattr(args, "dblock_sigma_curriculum_steps", 0))
|
| 143 |
+
if curriculum > 0:
|
| 144 |
+
frac = min(1.0, max(0.05, (cur_step + 1) / float(curriculum)))
|
| 145 |
+
hi = lo * ((hi / max(lo, 1e-8)) ** frac)
|
| 146 |
+
sig_np = np.exp(
|
| 147 |
+
np.random.uniform(
|
| 148 |
+
math.log(max(lo, 1e-4)),
|
| 149 |
+
math.log(max(hi, lo + 1e-4)),
|
| 150 |
+
ids.size(0),
|
| 151 |
+
).astype("float32")
|
| 152 |
+
)
|
| 153 |
+
return torch.from_numpy(sig_np).to(ids.device)
|
| 154 |
+
|
| 155 |
+
|
| 156 |
+
def _maybe_log(state, args, bi, layers, ar_val, sat_val, nat_val, total_val, peak_alloc, peak_reserved, objective=None):
|
| 157 |
+
log_every = int(getattr(args, "dblock_log_every", 50))
|
| 158 |
+
step = int(state.get("step", 0))
|
| 159 |
+
if log_every <= 0 or step % log_every != 0:
|
| 160 |
+
return
|
| 161 |
+
counts = ",".join(str(x) for x in state.get("counts", []))
|
| 162 |
+
emas = ",".join("nan" if x is None else f"{x:.2f}" for x in state.get("loss_ema", []))
|
| 163 |
+
mem = ""
|
| 164 |
+
if peak_alloc is not None:
|
| 165 |
+
mem = f" peak_alloc={peak_alloc:.2f}GB peak_reserved={peak_reserved:.2f}GB"
|
| 166 |
+
print(
|
| 167 |
+
f"[dblock] step={step} block={bi} obj={objective or 'mixed'} layers={layers} "
|
| 168 |
+
f"loss={total_val:.3f} ar={ar_val:.3f} sat={sat_val:.3f} nat={nat_val:.3f} "
|
| 169 |
+
f"counts=[{counts}] ema=[{emas}]{mem}",
|
| 170 |
+
flush=True,
|
| 171 |
+
)
|
| 172 |
+
|
| 173 |
+
|
| 174 |
+
def _update_stats(state, bi, loss_value):
|
| 175 |
+
B = state["B"]
|
| 176 |
+
counts = state.setdefault("counts", [0 for _ in range(B)])
|
| 177 |
+
emas = state.setdefault("loss_ema", [None for _ in range(B)])
|
| 178 |
+
counts[bi] += 1
|
| 179 |
+
prev = emas[bi]
|
| 180 |
+
beta = 0.96
|
| 181 |
+
emas[bi] = float(loss_value) if prev is None else beta * float(prev) + (1.0 - beta) * float(loss_value)
|
| 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):
|
| 232 |
+
max_tokens = int(max_tokens or 0)
|
| 233 |
+
if max_tokens <= 0:
|
| 234 |
+
return hidden.contiguous(), targets.contiguous(), int(targets.numel()), int(targets.numel())
|
| 235 |
+
flat_targets = targets.reshape(-1)
|
| 236 |
+
total = int(flat_targets.numel())
|
| 237 |
+
if total <= max_tokens:
|
| 238 |
+
return hidden.contiguous(), targets.contiguous(), total, total
|
| 239 |
+
# With-replacement sampling avoids building a full randperm each step; the sampled
|
| 240 |
+
# mean remains an unbiased estimator of the dense token CE mean.
|
| 241 |
+
idx = torch.randint(total, (max_tokens,), device=targets.device)
|
| 242 |
+
flat_hidden = hidden.reshape(total, hidden.size(-1))
|
| 243 |
+
return flat_hidden.index_select(0, idx).contiguous(), flat_targets.index_select(0, idx).contiguous(), int(max_tokens), total
|
| 244 |
+
|
| 245 |
+
|
| 246 |
+
def _choose_objectives(state, args, ar_weight, sat_weight, nat_weight, do_sat_periodic, do_nat_periodic):
|
| 247 |
+
mode = str(getattr(args, "dblock_objective_mode", "periodic") or "periodic").lower()
|
| 248 |
+
if mode != "stochastic":
|
| 249 |
+
return ar_weight > 0.0, sat_weight > 0.0 and do_sat_periodic, nat_weight > 0.0 and do_nat_periodic, "periodic"
|
| 250 |
+
choices = []
|
| 251 |
+
probs = []
|
| 252 |
+
if ar_weight > 0.0:
|
| 253 |
+
choices.append("ar")
|
| 254 |
+
probs.append(max(0.0, float(getattr(args, "dblock_ar_prob", 0.80))))
|
| 255 |
+
if sat_weight > 0.0 and not getattr(args, "ar_only", False):
|
| 256 |
+
choices.append("sat")
|
| 257 |
+
probs.append(max(0.0, float(getattr(args, "dblock_sat_prob", 0.10))))
|
| 258 |
+
if nat_weight > 0.0 and not getattr(args, "ar_only", False):
|
| 259 |
+
choices.append("nat")
|
| 260 |
+
probs.append(max(0.0, float(getattr(args, "dblock_nat_prob", 0.10))))
|
| 261 |
+
if not choices:
|
| 262 |
+
return False, False, False, "none"
|
| 263 |
+
total = sum(probs)
|
| 264 |
+
if total <= 0.0:
|
| 265 |
+
probs = [1.0 / len(choices) for _ in choices]
|
| 266 |
+
else:
|
| 267 |
+
probs = [p / total for p in probs]
|
| 268 |
+
picked = random.choices(choices, weights=probs, k=1)[0]
|
| 269 |
+
return picked == "ar", picked == "sat", picked == "nat", picked
|
| 270 |
+
|
| 271 |
+
|
| 272 |
+
def _dblock_step(core, ar_h, sat_h, nat_h, opt, scaler, args, ids, state):
|
| 273 |
+
import nB300_agillm4 as M
|
| 274 |
+
|
| 275 |
+
prof = _profile_active(state, args)
|
| 276 |
+
_step_t = _profile_tic(prof)
|
| 277 |
+
if torch.cuda.is_available():
|
| 278 |
+
torch.cuda.reset_peak_memory_stats()
|
| 279 |
+
|
| 280 |
+
_setup_t = _profile_tic(prof)
|
| 281 |
+
B = state["B"]
|
| 282 |
+
asg = state["assign"]
|
| 283 |
+
bs = state["bsig"]
|
| 284 |
+
T = ids.size(1)
|
| 285 |
+
use_layer_checkpoint = bool(getattr(args, "grad_checkpoint", False))
|
| 286 |
+
bi = _choose_block(state, args)
|
| 287 |
+
lo, hi = sorted([bs[bi], bs[bi + 1]])
|
| 288 |
+
layers = asg[bi]
|
| 289 |
+
sig = _sample_sigma(ids, lo, hi, args, state)
|
| 290 |
+
cs, co, ci = _edm_pre(sig)
|
| 291 |
+
w = _edm_w(sig, float(getattr(args, "dblock_edm_wmax", 5.0)))
|
| 292 |
+
SATB = M.SAT_BLOCK
|
| 293 |
+
ar_weight = float(getattr(args, "dblock_ar_weight", 1.0))
|
| 294 |
+
sat_weight = float(getattr(args, "dblock_sat_weight", 1.0))
|
| 295 |
+
nat_weight = float(getattr(args, "dblock_nat_weight", 1.0)) * float(getattr(args, "nat_loss_weight", 1.0))
|
| 296 |
+
do_sat_periodic = (not getattr(args, "ar_only", False)) and (
|
| 297 |
+
int(getattr(args, "sat_every", 1)) <= 1 or ((int(state.get("step", 0)) + 1) % int(getattr(args, "sat_every", 1)) == 0)
|
| 298 |
+
)
|
| 299 |
+
do_nat_periodic = (
|
| 300 |
+
nat_h is not None
|
| 301 |
+
and (not getattr(args, "ar_only", False))
|
| 302 |
+
and int(getattr(args, "nat_every", 1)) > 0
|
| 303 |
+
and (
|
| 304 |
+
int(getattr(args, "nat_every", 1)) <= 1
|
| 305 |
+
or ((int(state.get("step", 0)) + 1) % int(getattr(args, "nat_every", 1)) == 0)
|
| 306 |
+
)
|
| 307 |
+
)
|
| 308 |
+
run_ar, run_sat, run_nat, objective = _choose_objectives(
|
| 309 |
+
state, args, ar_weight, sat_weight, nat_weight, do_sat_periodic, do_nat_periodic
|
| 310 |
+
)
|
| 311 |
+
_profile_toc(state, "setup", _setup_t)
|
| 312 |
+
|
| 313 |
+
ar_val = 0.0
|
| 314 |
+
sat_val = 0.0
|
| 315 |
+
nat_val = 0.0
|
| 316 |
+
|
| 317 |
+
if run_ar:
|
| 318 |
+
causal = M.causal_mask(T, structured=M.use_structured_masks(args))
|
| 319 |
+
_t = _profile_tic(prof)
|
| 320 |
+
with M.amp(args.amp):
|
| 321 |
+
emb = core.emb(ids)
|
| 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)
|
| 329 |
+
ar_hidden, ar_targets, ar_used, ar_total = _sample_token_loss_inputs(
|
| 330 |
+
Dn[:, :-1], ids[:, 1:], int(getattr(args, "dblock_ar_loss_tokens", 0))
|
| 331 |
+
)
|
| 332 |
+
ar = ar_weight * w * fused_ce(ar_hidden, ar_h.proj.weight, ar_targets)
|
| 333 |
+
ar_val = float(ar.detach())
|
| 334 |
+
_profile_toc(state, "ar_ce", _t)
|
| 335 |
+
_t = _profile_tic(prof)
|
| 336 |
+
scaler.scale(ar).backward()
|
| 337 |
+
_profile_toc(state, "ar_backward", _t)
|
| 338 |
+
del causal, emb, zt, h, Dn, ar_hidden, ar_targets, ar, ar_used, ar_total
|
| 339 |
+
|
| 340 |
+
if run_sat:
|
| 341 |
+
smask = M.sat_mask(T, structured=M.use_structured_masks(args))
|
| 342 |
+
_t = _profile_tic(prof)
|
| 343 |
+
with M.amp(args.amp):
|
| 344 |
+
emb2 = core.emb(ids)
|
| 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)
|
| 352 |
+
_t = _profile_tic(prof)
|
| 353 |
+
sat_hidden, sat_targets, sat_used, sat_total = _sample_token_loss_inputs(
|
| 354 |
+
last, ids[:, 1 : SATB + 1], int(getattr(args, "dblock_sat_loss_tokens", 0))
|
| 355 |
+
)
|
| 356 |
+
with M.amp(args.amp):
|
| 357 |
+
satf = fused_ce(sat_hidden, sat_h.proj.weight, sat_targets)
|
| 358 |
+
satv = (
|
| 359 |
+
M.EMIT_LAMBDA
|
| 360 |
+
* F.cross_entropy(
|
| 361 |
+
sat_h.gate(Ds[:, 0].float()),
|
| 362 |
+
torch.ones(ids.size(0), dtype=torch.long, device=ids.device),
|
| 363 |
+
)
|
| 364 |
+
if sat_h.gate is not None
|
| 365 |
+
else 0.0
|
| 366 |
+
)
|
| 367 |
+
sat = sat_weight * w * (satf + satv)
|
| 368 |
+
_profile_toc(state, "sat_ce", _t)
|
| 369 |
+
sat_val = float(sat.detach())
|
| 370 |
+
_t = _profile_tic(prof)
|
| 371 |
+
scaler.scale(sat).backward()
|
| 372 |
+
_profile_toc(state, "sat_backward", _t)
|
| 373 |
+
del smask, emb2, zt2, h2, Ds, last, sat_hidden, sat_targets, satf, satv, sat
|
| 374 |
+
|
| 375 |
+
if run_nat:
|
| 376 |
+
ratio = min(max(float(getattr(args, "nat_mask_ratio", 0.5)), 0.05), 0.95)
|
| 377 |
+
nat_ids = M._nat_ids_for_training(ids, int(getattr(args, "nat_max_tokens", 0)))
|
| 378 |
+
_t = _profile_tic(prof)
|
| 379 |
+
with M.amp(args.amp):
|
| 380 |
+
nat_in = nat_ids.clone()
|
| 381 |
+
m = torch.rand(nat_ids.shape, device=nat_ids.device) < ratio
|
| 382 |
+
if not bool(m.any()):
|
| 383 |
+
m[..., -1] = True
|
| 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)
|
| 391 |
+
nat_hidden = Dnat[m]
|
| 392 |
+
nat_targets = nat_ids[m]
|
| 393 |
+
nat_hidden, nat_targets, nat_used, nat_total = _sample_token_loss_inputs(
|
| 394 |
+
nat_hidden.unsqueeze(0), nat_targets.unsqueeze(0), int(getattr(args, "dblock_nat_loss_tokens", 0))
|
| 395 |
+
)
|
| 396 |
+
nat = nat_weight * fused_ce(nat_hidden, nat_h.proj.weight, nat_targets)
|
| 397 |
+
nat_val = float(nat.detach())
|
| 398 |
+
_profile_toc(state, "nat_ce", _t)
|
| 399 |
+
_t = _profile_tic(prof)
|
| 400 |
+
scaler.scale(nat).backward()
|
| 401 |
+
_profile_toc(state, "nat_backward", _t)
|
| 402 |
+
del nat_ids, nat_in, m, hn, Dnat, nat_hidden, nat_targets, nat, nat_used, nat_total
|
| 403 |
+
|
| 404 |
+
total_val = ar_val + sat_val + nat_val
|
| 405 |
+
if not math.isfinite(total_val):
|
| 406 |
+
opt.zero_grad(set_to_none=True)
|
| 407 |
+
if torch.cuda.is_available():
|
| 408 |
+
torch.cuda.empty_cache()
|
| 409 |
+
print(f"[dblock] non-finite loss {total_val}; skipped optimizer step", flush=True)
|
| 410 |
+
_profile_toc(state, "step_total", _step_t)
|
| 411 |
+
_profile_step_done(state, args)
|
| 412 |
+
_update_stats(state, bi, total_val)
|
| 413 |
+
return total_val
|
| 414 |
+
|
| 415 |
+
_t = _profile_tic(prof)
|
| 416 |
+
scaler.unscale_(opt)
|
| 417 |
+
nn.utils.clip_grad_norm_([p for g in opt.param_groups for p in g["params"]], 1.0)
|
| 418 |
+
scaler.step(opt)
|
| 419 |
+
scaler.update()
|
| 420 |
+
opt.zero_grad(set_to_none=True)
|
| 421 |
+
_profile_toc(state, "opt_step", _t)
|
| 422 |
+
|
| 423 |
+
peak_alloc = None
|
| 424 |
+
peak_reserved = None
|
| 425 |
+
if torch.cuda.is_available():
|
| 426 |
+
peak_alloc = torch.cuda.max_memory_allocated() / (1024**3)
|
| 427 |
+
peak_reserved = torch.cuda.max_memory_reserved() / (1024**3)
|
| 428 |
+
_profile_toc(state, "step_total", _step_t)
|
| 429 |
+
_profile_step_done(state, args)
|
| 430 |
+
_update_stats(state, bi, total_val)
|
| 431 |
+
_maybe_log(state, args, bi, layers, ar_val, sat_val, nat_val, total_val, peak_alloc, peak_reserved, objective=objective)
|
| 432 |
+
return total_val
|