SeaWolf-AI commited on
Commit
4162dd3
Β·
verified Β·
1 Parent(s): 9323f1a

Upload training/launcher_v2b_multi.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. training/launcher_v2b_multi.py +361 -0
training/launcher_v2b_multi.py ADDED
@@ -0,0 +1,361 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ AETHER-2B-7Attn Phase 1.6 v2b β€” Continued Pretraining
5
+ =======================================================
6
+ Resume: step_0455000 (6.59B model, 59.8B tokens done)
7
+ Data: 132B pool (phase15_mix 90B + tokenized_v2 42.5B, weighted)
8
+ Goal: annealing on high-quality data β†’ 132B chinchilla total
9
+ Infra: multi node 2x8 B200 (CID=5352+5353, 16 GPU)
10
+ LR: cosine annealing 5e-5 β†’ 5e-6 over 324K steps (~85B new tokens)
11
+ Log: /NHNHOME/WORKSPACE/0426030036_A/aether_1b_7attn_v3/logs/launcher_v2b.log
12
+ """
13
+
14
+ import math, os, sys, time, signal, json, logging
15
+ from collections import deque
16
+ from functools import partial
17
+ from pathlib import Path
18
+
19
+ import numpy as np
20
+ import torch
21
+ import torch.distributed as dist
22
+ import torch.distributed.checkpoint as dcp
23
+ from torch.distributed.checkpoint import FileSystemReader, FileSystemWriter
24
+ from torch.distributed.fsdp import (
25
+ FullyShardedDataParallel as FSDP,
26
+ MixedPrecision, ShardingStrategy, BackwardPrefetch,
27
+ StateDictType, ShardedStateDictConfig, ShardedOptimStateDictConfig,
28
+ )
29
+ from torch.distributed.fsdp.wrap import transformer_auto_wrap_policy
30
+
31
+ # ── paths ────────────────────────────────────────────────────────────────────
32
+ BASE = "/NHNHOME/WORKSPACE/0426030036_A/aether_1b_7attn_v3"
33
+ V2_ROOT = "/NHNHOME/WORKSPACE/0426030036_A/aether-recovered/aether-v2-current"
34
+ RESUME_CKPT = f"{BASE}/runs/v2b_phase16/ckpt/step_0001905"
35
+ OUTPUT_DIR = f"{BASE}/runs/v2b_multi_phase16"
36
+ CKPT_DIR = f"{OUTPUT_DIR}/ckpt"
37
+ LOG_FILE = f"{BASE}/logs/launcher_v2b_multi.log"
38
+ KILL_SWITCH = "/NHNHOME/STOP_TRAINING_V2B_MULTI"
39
+
40
+ sys.path.insert(0, V2_ROOT)
41
+ sys.path.insert(0, V2_ROOT + "/scripts")
42
+
43
+ from aether_pkg.configuration_aether_v2_7way import AETHERV27wayConfig
44
+ from aether_pkg.modeling_aether_v2_7way import (
45
+ AETHERV27wayForCausalLM as AETHERForCausalLM,
46
+ AETHERV27wayDecoderLayer as AETHERDecoderLayer,
47
+ )
48
+ from scripts.mini_config import mini_cfg
49
+
50
+ # ── hyper params ─────────────────────────────────────────────────────────────
51
+ SEQ_LEN = 4096
52
+ MICRO_BATCH = 1
53
+ GRAD_ACCUM = 8
54
+ TOTAL_STEPS = 162000 # ~85B new tokens
55
+ LR_PEAK = 5e-5
56
+ LR_MIN = 5e-6
57
+ WARMUP = 0 # already warmed up at step 1905
58
+ GRAD_CLIP = 1.0
59
+ SAVE_EVERY = 5000
60
+ CKPT_KEEP = 4
61
+ LOG_EVERY = 50
62
+ EMBED_LR_MULT = 0.1
63
+ LWD_DECAY = 0.97
64
+
65
+ # ── data pool ────────────────────────────────────────────────────────────────
66
+ # (path, sampling_weight) β€” higher weight = more often sampled
67
+ DATA_POOL = [
68
+ (f"{BASE}/../aether_phase15/tokenized/phase15_mix_90b.bin", 1.0),
69
+ (f"{BASE}/../aether_phase15/tokenized_v2/eng_fineweb_edu.bin", 2.0),
70
+ (f"{BASE}/../aether_phase15/tokenized_v2/syn_cosmopedia.bin", 2.0),
71
+ (f"{BASE}/../aether_phase15/tokenized_v2/math_finemath.bin", 3.5),
72
+ (f"{BASE}/../aether_phase15/tokenized_v2/math_owm.bin", 3.5),
73
+ (f"{BASE}/../aether_phase15/tokenized_v2/code_opc.bin", 2.5),
74
+ (f"{BASE}/../aether_phase15/tokenized_v2/kor_webtext.bin", 2.0),
75
+ (f"{BASE}/../aether_phase15/tokenized_v2/kor_synth.bin", 2.0),
76
+ ]
77
+
78
+ # ── NCCL / env ───────────────────────────────────────────────────────────────
79
+ os.environ.setdefault("NCCL_TIMEOUT", "3600")
80
+ os.environ.setdefault("TORCH_NCCL_ASYNC_ERROR_HANDLING", "1")
81
+ os.environ.setdefault("PYTORCH_CUDA_ALLOC_CONF", "expandable_segments:True")
82
+
83
+ # ── distributed init ─────────────────────────────────────────────────────────
84
+ dist.init_process_group(backend="nccl")
85
+ local_rank = int(os.environ["LOCAL_RANK"])
86
+ rank = dist.get_rank()
87
+ world_size = dist.get_world_size()
88
+ torch.cuda.set_device(local_rank)
89
+ device = torch.device(f"cuda:{local_rank}")
90
+ is_main = rank == 0
91
+
92
+ def barrier():
93
+ dist.barrier()
94
+
95
+ # ── logging ──────────────────────────────────────────────────────────────────
96
+ Path(LOG_FILE).parent.mkdir(parents=True, exist_ok=True)
97
+ handlers = [logging.StreamHandler(sys.stdout)]
98
+ if is_main:
99
+ handlers.append(logging.FileHandler(LOG_FILE, mode="a"))
100
+ logging.basicConfig(
101
+ level=logging.INFO,
102
+ format="[%(asctime)s][r%(process)d] %(message)s",
103
+ datefmt="%Y-%m-%d %H:%M:%S",
104
+ handlers=handlers,
105
+ )
106
+ logger = logging.getLogger(__name__)
107
+ def log(msg):
108
+ if is_main: logger.info(msg)
109
+
110
+ # ── signal ───────────────────────────────────────────────────────────────────
111
+ shutdown_req = False
112
+ def _handler(sig, frame):
113
+ global shutdown_req
114
+ log(f"[signal] {sig} β†’ graceful shutdown")
115
+ shutdown_req = True
116
+ signal.signal(signal.SIGTERM, _handler)
117
+ signal.signal(signal.SIGINT, _handler)
118
+
119
+ # ═══════════════════════════════════════════════════════════════════════════
120
+ log("=" * 68)
121
+ log("AETHER-2B-7Attn Phase 1.6 v2b β€” Continued Pretraining")
122
+ log(f" resume ckpt : {RESUME_CKPT}")
123
+ log(f" output : {OUTPUT_DIR}")
124
+ log(f" log : {LOG_FILE}")
125
+ log(f" world_size : {world_size}")
126
+ log(f" LR : {LR_PEAK} β†’ {LR_MIN} warmup={WARMUP}")
127
+ log(f" steps : {TOTAL_STEPS} (~{TOTAL_STEPS*MICRO_BATCH*GRAD_ACCUM*SEQ_LEN*world_size/1e9:.1f}B tok)")
128
+ log("=" * 68)
129
+ barrier()
130
+
131
+ # ── [1] build model ───────────────────────────────────────────────────────────
132
+ log("[1/5] Building model (mini_cfg, bf16)...")
133
+ cfg = mini_cfg
134
+ cfg.max_position_embeddings = SEQ_LEN
135
+ cfg.use_cache = False
136
+ t0 = time.time()
137
+ model = AETHERForCausalLM(cfg).to(device=device, dtype=torch.bfloat16)
138
+ n_params = sum(p.numel() for p in model.parameters())
139
+ log(f" {n_params/1e9:.3f}B params ({time.time()-t0:.1f}s)")
140
+ barrier()
141
+
142
+ # ── [2] FSDP wrap ─────────────────────────────────────────────────────────────
143
+ log("[2/5] FSDP wrap...")
144
+ strategy = ShardingStrategy.FULL_SHARD if world_size > 1 else ShardingStrategy.NO_SHARD
145
+ model = FSDP(
146
+ model,
147
+ sharding_strategy=strategy,
148
+ mixed_precision=MixedPrecision(
149
+ param_dtype=torch.bfloat16,
150
+ reduce_dtype=torch.bfloat16,
151
+ buffer_dtype=torch.bfloat16,
152
+ ),
153
+ auto_wrap_policy=partial(transformer_auto_wrap_policy,
154
+ transformer_layer_cls={AETHERDecoderLayer}),
155
+ backward_prefetch=BackwardPrefetch.BACKWARD_PRE,
156
+ forward_prefetch=True,
157
+ use_orig_params=True,
158
+ device_id=local_rank,
159
+ )
160
+ log(f" strategy={strategy.name}")
161
+ barrier()
162
+
163
+ # ── [3] optimizer ─────────────────────────────────────────────────────────────
164
+ log("[3/5] Building optimizer (AdamW + LWD)...")
165
+ from collections import defaultdict
166
+ used = set()
167
+ groups = []
168
+
169
+ # embedding (low LR, no WD)
170
+ emb_p = [(n,p) for n,p in model.named_parameters()
171
+ if "embed" in n.lower() and p.requires_grad]
172
+ if emb_p:
173
+ groups.append({"params":[p for _,p in emb_p], "lr": LR_PEAK*EMBED_LR_MULT,
174
+ "weight_decay":0.0, "name":"embed"})
175
+ used.update(id(p) for _,p in emb_p)
176
+
177
+ # scalars / alphas (no WD)
178
+ sc_p = [(n,p) for n,p in model.named_parameters()
179
+ if id(p) not in used and p.requires_grad and ("_alpha" in n or p.dim() < 2)]
180
+ if sc_p:
181
+ groups.append({"params":[p for _,p in sc_p], "lr": LR_PEAK,
182
+ "weight_decay":0.0, "name":"scalars"})
183
+ used.update(id(p) for _,p in sc_p)
184
+
185
+ # body β€” layer-wise LR decay
186
+ layer_buckets = defaultdict(list)
187
+ other_p = []
188
+ for n, p in model.named_parameters():
189
+ if id(p) in used or not p.requires_grad: continue
190
+ parts = n.split(".")
191
+ lidx = None
192
+ for i, part in enumerate(parts):
193
+ if part == "layers" and i+1 < len(parts) and parts[i+1].isdigit():
194
+ lidx = int(parts[i+1]); break
195
+ (layer_buckets[lidx] if lidx is not None else other_p).append(p)
196
+ used.add(id(p))
197
+ for lidx in sorted(layer_buckets):
198
+ scale = LWD_DECAY ** (cfg.num_hidden_layers - 1 - lidx)
199
+ groups.append({"params": layer_buckets[lidx], "lr": LR_PEAK*scale,
200
+ "weight_decay":0.1, "name":f"layer_{lidx}"})
201
+ if other_p:
202
+ groups.append({"params":other_p, "lr":LR_PEAK, "weight_decay":0.1, "name":"misc"})
203
+
204
+ optimizer = torch.optim.AdamW(groups, betas=(0.9, 0.95), eps=1e-8)
205
+ log(f" param groups: {len(groups)}")
206
+ barrier()
207
+
208
+ # ── [4] resume from step_0455000 ─────────────────────────────────────────────
209
+ RESUME_STEP = 1905 # world_size 8->16: model only load
210
+ log(f"[4/5] Loading DCP checkpoint: {RESUME_CKPT} (model-only, optimizer fresh for 16-GPU)")
211
+ t0 = time.time()
212
+ with FSDP.state_dict_type(
213
+ model,
214
+ StateDictType.SHARDED_STATE_DICT,
215
+ ShardedStateDictConfig(offload_to_cpu=True),
216
+ ShardedOptimStateDictConfig(offload_to_cpu=True),
217
+ ):
218
+ state = {"model": model.state_dict()}
219
+ dcp.load(state, storage_reader=FileSystemReader(RESUME_CKPT))
220
+ model.load_state_dict(state["model"])
221
+ log(f" loaded in {time.time()-t0:.1f}s (optimizer fresh init)")
222
+ barrier()
223
+
224
+ # ── [5] data pool ────────────────────────────────────────────────────────────
225
+ log("[5/5] Loading multi-file data pool...")
226
+ arrs, probs_raw = [], []
227
+ for path_rel, wt in DATA_POOL:
228
+ path = str(Path(path_rel).resolve())
229
+ if not Path(path).exists():
230
+ log(f" SKIP: {Path(path).name}")
231
+ continue
232
+ n_tok = Path(path).stat().st_size // 4
233
+ arr = np.memmap(path, dtype=np.uint32, mode="r")
234
+ arrs.append(arr)
235
+ probs_raw.append(wt * n_tok)
236
+ log(f" {Path(path).name}: {n_tok/1e9:.2f}B tok w={wt}")
237
+ total_w = sum(probs_raw)
238
+ probs = [w/total_w for w in probs_raw]
239
+ log(f" files={len(arrs)} effective={total_w/1e9:.1f}B weighted-tok")
240
+
241
+ rng = np.random.default_rng(seed=42 + rank)
242
+
243
+ def sample_batch():
244
+ fi = rng.choice(len(arrs), size=MICRO_BATCH, p=probs)
245
+ out = np.zeros((MICRO_BATCH, SEQ_LEN+1), dtype=np.int64)
246
+ for i, f in enumerate(fi):
247
+ arr = arrs[f]
248
+ mx = len(arr) - SEQ_LEN - 1
249
+ if mx <= 0: continue
250
+ s = rng.integers(0, mx)
251
+ out[i] = arr[s:s+SEQ_LEN+1].astype(np.int64)
252
+ return torch.from_numpy(out)
253
+
254
+ # ── LR schedule (cosine annealing) ───────────────────────────────────────────
255
+ def cosine_lr(step):
256
+ if step < WARMUP:
257
+ return LR_PEAK * (step + 1) / WARMUP
258
+ t = (step - WARMUP) / max(TOTAL_STEPS - WARMUP, 1)
259
+ return LR_MIN + 0.5 * (LR_PEAK - LR_MIN) * (1 + math.cos(math.pi * t))
260
+
261
+ def apply_lr(step):
262
+ base = cosine_lr(step)
263
+ for g in groups:
264
+ name = g.get("name","")
265
+ if name == "embed":
266
+ g["lr"] = base * EMBED_LR_MULT
267
+ elif name.startswith("layer_"):
268
+ lidx = int(name.split("_")[1])
269
+ scale = LWD_DECAY ** (cfg.num_hidden_layers - 1 - lidx)
270
+ g["lr"] = base * scale
271
+ else:
272
+ g["lr"] = base
273
+ return base
274
+
275
+ # ── checkpoint helpers ───────────────────────────────────────────────────────
276
+ Path(CKPT_DIR).mkdir(parents=True, exist_ok=True)
277
+ Path(OUTPUT_DIR).mkdir(parents=True, exist_ok=True)
278
+
279
+ def save_ckpt(step):
280
+ barrier()
281
+ path = Path(CKPT_DIR) / f"step_{step:07d}"
282
+ path.mkdir(parents=True, exist_ok=True)
283
+ with FSDP.state_dict_type(
284
+ model, StateDictType.SHARDED_STATE_DICT,
285
+ ShardedStateDictConfig(offload_to_cpu=True),
286
+ ShardedOptimStateDictConfig(offload_to_cpu=True),
287
+ ):
288
+ state = {"model": model.state_dict(),
289
+ "optimizer": FSDP.optim_state_dict(model, optimizer),
290
+ "step": step}
291
+ dcp.save(state, storage_writer=FileSystemWriter(str(path)))
292
+ if is_main:
293
+ with open(path/"meta.json","w") as f:
294
+ json.dump({"step":step}, f)
295
+ existing = sorted([d for d in Path(CKPT_DIR).iterdir()
296
+ if d.is_dir() and d.name.startswith("step_")])
297
+ for old in existing[:-CKPT_KEEP]:
298
+ import shutil; shutil.rmtree(old, ignore_errors=True)
299
+ log(f" [ckpt] saved step_{step:07d}")
300
+ barrier()
301
+
302
+ # ═══════════════════════ Training loop ═══════════════════════════════════════
303
+ log("=" * 68)
304
+ log(f"Starting Phase 1.6 v2b training (step 1 β†’ {TOTAL_STEPS})")
305
+ log("=" * 68)
306
+
307
+ t_log = time.time()
308
+ tok_log = 0
309
+ loss_acc = 0.0
310
+ tok_per_step = MICRO_BATCH * GRAD_ACCUM * SEQ_LEN * world_size
311
+ total_tok_b = 60.3 # tokens done so far in B (Phase 1 + v2b step 1905)
312
+
313
+ for step in range(RESUME_STEP + 1, TOTAL_STEPS + 1):
314
+ if Path(KILL_SWITCH).exists():
315
+ log(f" [kill] {KILL_SWITCH} β†’ save+exit")
316
+ save_ckpt(step); dist.destroy_process_group(); sys.exit(0)
317
+ if shutdown_req:
318
+ log(f" [shutdown] step {step} β†’ save+exit")
319
+ save_ckpt(step); dist.destroy_process_group(); sys.exit(0)
320
+
321
+ lr = apply_lr(step)
322
+ optimizer.zero_grad(set_to_none=True)
323
+
324
+ step_loss = 0.0
325
+ for _ in range(GRAD_ACCUM):
326
+ batch = sample_batch().to(device, non_blocking=True)
327
+ inp = batch[:, :-1].contiguous()
328
+ with torch.amp.autocast("cuda", dtype=torch.bfloat16):
329
+ out = model(input_ids=inp, labels=inp.clone(),
330
+ output_router_logits=True)
331
+ loss = out.loss / GRAD_ACCUM
332
+ if out.aux_loss is not None:
333
+ loss = loss + 0.001 * out.aux_loss / GRAD_ACCUM
334
+ loss.backward()
335
+ step_loss += loss.item() * GRAD_ACCUM
336
+
337
+ torch.nn.utils.clip_grad_norm_(model.parameters(), GRAD_CLIP)
338
+ optimizer.step()
339
+
340
+ tok_log += tok_per_step
341
+ loss_acc += step_loss
342
+
343
+ if math.isnan(step_loss) or math.isinf(step_loss):
344
+ log(f" [NaN/Inf] step={step} loss={step_loss:.4f} β†’ ABORT")
345
+ save_ckpt(step); dist.destroy_process_group(); sys.exit(1)
346
+
347
+ if step % LOG_EVERY == 0 and is_main:
348
+ elapsed = time.time() - t_log
349
+ tps = tok_log / elapsed
350
+ total_tok_b += tok_per_step * LOG_EVERY / 1e9
351
+ log(f" [step {step:7d}/{TOTAL_STEPS}] "
352
+ f"loss={loss_acc/LOG_EVERY:.4f} lr={lr:.2e} "
353
+ f"tps={tps:.0f} total={total_tok_b:.1f}B tok")
354
+ loss_acc = 0.0; tok_log = 0; t_log = time.time()
355
+
356
+ if step % SAVE_EVERY == 0:
357
+ save_ckpt(step)
358
+
359
+ save_ckpt(TOTAL_STEPS)
360
+ log("=== Phase 1.6 v2b COMPLETE ===")
361
+ dist.destroy_process_group()