dragonlimited commited on
Commit
e6f0ced
·
verified ·
1 Parent(s): 546e98c

Upload notebook.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. notebook.py +108 -438
notebook.py CHANGED
@@ -6,457 +6,127 @@ app = marimo.App(width="medium", auto_download=["html"])
6
 
7
  @app.cell
8
  def _():
9
- # =============================================================== #
10
- # A) DragonCode 方案Ainfra: imports, auth, helpers, data source
11
- # =============================================================== #
12
- # 規則:完全跳過 DragonCode-Tokenized-Pretrain(視為垃圾);全部 token
13
- # streaming FineWeb-Edu -> SlimPajama -> The-Pile;不下載完整檔案到本機。
14
- import os, sys, time, json, math, shutil, tempfile, random, logging
15
- from dataclasses import dataclass, field, asdict
16
- from collections import deque
17
- from typing import Optional
18
- import numpy as np
19
- import torch
20
- import torch.nn.functional as F
21
-
22
- # ---- auth (source from env; never hard-coded, to avoid leaking on a
23
- # public repo). Set HF_TOKEN in your Molab env before running: either
24
- # export it in the environment, or uncomment the next line and paste
25
- # your own token. ------------------------------------------------ #
26
- DRAGON_HF_TOKEN = os.environ.get("HF_TOKEN", "") or ""
27
- os.environ["HF_TOKEN"] = DRAGON_HF_TOKEN
28
- os.environ["HF_HOME"] = "/home/marimo/.cache/huggingface"
29
- if not DRAGON_HF_TOKEN:
30
- print("⚠️ 請先設定 HF_TOKEN 環境變數(例如 os.environ['HF_TOKEN']='hf_...')再執行。")
31
- print(" 未設定 token 無法 load dataset / push checkpoint HF。")
32
-
33
- TOKENIZER_REPO = "bigcode/starcoder2-3b"
34
- VOCAB_SIZE = 49152
35
- MAX_SEQ_LEN = 2048
36
-
37
- logger = logging.getLogger("dragoncode")
38
- if not logger.handlers:
39
- _h = logging.StreamHandler()
40
- _h.setFormatter(logging.Formatter("%(asctime)s [%(levelname)s] %(message)s"))
41
- logger.addHandler(_h)
42
- logger.setLevel(logging.INFO)
43
-
44
- # ---- HF helpers ------------------------------------------------------- #
45
- def _hf_api():
46
- from huggingface_hub import HfApi
47
- return HfApi(token=DRAGON_HF_TOKEN)
48
-
49
- def _run_with_retry(fn, tries=8, base_wait=4.0, max_wait=120.0, label="op"):
50
- last = None
51
- for attempt in range(1, tries + 1):
52
- try:
53
- return fn()
54
- except Exception as e:
55
- last = e
56
- wait = min(base_wait * (2 ** (attempt - 1)), max_wait)
57
- logger.warning("[%s] %d/%d failed: %s — retry in %.0fs", label, attempt, tries, e, wait)
58
- time.sleep(wait)
59
- raise RuntimeError(f"[{label}] failed after {tries} attempts: {last}")
60
-
61
- def _seed_everything(seed):
62
- random.seed(seed); np.random.seed(seed)
63
- torch.manual_seed(seed); torch.cuda.manual_seed_all(seed)
64
-
65
- # ---- tokenizer -------------------------------------------------------- #
66
- _tok = None
67
- def _get_tokenizer():
68
- global _tok
69
- if _tok is not None:
70
- return _tok
71
- from transformers import AutoTokenizer
72
- _tok = AutoTokenizer.from_pretrained(TOKENIZER_REPO, token=DRAGON_HF_TOKEN, trust_remote_code=True)
73
- if _tok.pad_token is None:
74
- _tok.pad_token = _tok.eos_token
75
- if _tok.pad_token_id is None:
76
- _tok.pad_token_id = _tok.eos_token_id
77
- logger.info("Tokenizer %s (vocab=%d)", TOKENIZER_REPO, _tok.vocab_size)
78
- return _tok
79
-
80
- # ---- model / tier registry -------------------------------------------- #
81
- def _build_model_config(hidden, layers, ffn, heads, kv_heads=None, name="DragonCode-150M"):
82
- from transformers import LlamaConfig
83
- return LlamaConfig(
84
- vocab_size=VOCAB_SIZE, hidden_size=hidden, intermediate_size=ffn,
85
- num_hidden_layers=layers, num_attention_heads=heads,
86
- num_key_value_heads=kv_heads or heads, max_position_embeddings=MAX_SEQ_LEN,
87
- rope_theta=10000.0, rms_norm_eps=1e-5, tie_word_embeddings=False,
88
- hidden_act="silu", _name_or_path=f"DragonLimited/{name}",
89
- )
90
-
91
- @dataclass
92
- class TierSpec:
93
- name: str; size_str: str; hidden: int; layers: int; ffn: int
94
- heads: int; kv_heads: Optional[int]; chinchilla_tokens: int
95
-
96
- # Chinchilla 20x 鎖死: 150M->3.0B, 387M->7.74B, 787M->15.74B, 1.2B->24B, 2.4B->48B
97
- def _tier_specs():
98
- return {
99
- "150M": TierSpec("DragonCode-150M", "150M", 768, 12, 3072, 12, None, 3_000_000_000),
100
- "387M": TierSpec("DragonCode-387M", "387M", 1024, 22, 4096, 16, None, 7_740_000_000),
101
- "787M": TierSpec("DragonCode-787M", "787M", 1280, 30, 5120, 16, 16, 15_740_000_000),
102
- "1.2B": TierSpec("DragonCode-1.2B", "1.2B", 1536, 34, 6144, 24, 24, 24_000_000_000),
103
- "2.4B": TierSpec("DragonCode-2.4B", "2.4B", 2048, 38, 8192, 32, 32, 48_000_000_000),
104
- }
105
-
106
- def _hf_repos():
107
- return {
108
- "150M": "DragonLimited/DragonCode-150M",
109
- "387M": "DragonLimited/DragonCode-387M",
110
- "787M": "DragonLimited/DragonCode-787M",
111
- "1.2B": "DragonLimited/DragonCode-1.2B",
112
- "2.4B": "DragonLimited/DragonCode-2.4B",
113
- "family": "DragonLimited/DragonCode-Family",
114
- }
115
-
116
- # ---- 方案A data source: 純外部 streaming,絕不讀 Tokenized-Pretrain ---- #
117
- DATA_SOURCES = [ # strict fallback 優先序
118
- "HuggingFaceFW/fineweb-edu",
119
- "cerebras/SlimPajama-627B",
120
- "EleutherAI/the_pile",
121
- ]
122
-
123
- def _tokenize_string(text, tok):
124
- ids = tok.encode(text)
125
- if hasattr(ids, "ids"):
126
- ids = ids.ids
127
- return list(ids)
128
-
129
- class StreamingCorpus:
130
- """純外部 HF streaming 數據源(方案A)。單向前向 pass,唔讀 Tokenized repo。"""
131
- def __init__(self, token, seq_len, budget_tokens, offset_tokens=0):
132
- self.token = token; self.seq = seq_len; self.budget = budget_tokens
133
- self.off = offset_tokens; self.data_used = 0
134
-
135
- def __iter__(self):
136
- from datasets import load_dataset
137
- buf = deque(); cursor = self.off; need = self.budget
138
- for src in DATA_SOURCES:
139
- if cursor >= need:
140
- return
141
- try:
142
- ds = load_dataset(src, split="train", streaming=True, token=self.token)
143
- logger.info("Streaming %s (cursor=%d budget=%d)", src, cursor, need)
144
- except Exception as e:
145
- logger.warning("source %s failed (%s); next", src, repr(e)); continue
146
- try:
147
- for row in ds:
148
- txt = row.get("text") or ""
149
- for v in _tokenize_string(txt, _get_tokenizer()):
150
- cursor += 1
151
- if cursor <= self.off:
152
- continue
153
- buf.append(int(v))
154
- while len(buf) >= self.seq:
155
- window = [buf.popleft() for _ in range(self.seq)]
156
- self.data_used = cursor
157
- yield torch.tensor(window, dtype=torch.long), cursor
158
- if cursor >= need:
159
- return
160
- except Exception as e:
161
- logger.warning("source %s mid-stream (%s); next", src, repr(e)); continue
162
- logger.warning("All external sources exhausted at cursor %d (budget %d)", cursor, need)
163
-
164
- def _make_batches(gen, batch_size, seq_len):
165
- batch = []
166
- for token_tensor, tok_cursor in gen:
167
- batch.append(token_tensor)
168
- if len(batch) == batch_size:
169
- x = torch.stack(batch)[:, :-1].contiguous(); y = torch.stack(batch)[:, 1:].contiguous()
170
- yield x, y, tok_cursor, True; batch = []
171
- if batch:
172
- x = torch.stack(batch)[:, :-1].contiguous(); y = torch.stack(batch)[:, 1:].contiguous()
173
- yield x, y, tok_cursor, False
174
-
175
-
176
- return (
177
- DRAGON_HF_TOKEN,
178
- MAX_SEQ_LEN,
179
- StreamingCorpus,
180
- json,
181
- logger,
182
- math,
183
- os,
184
- shutil,
185
- tempfile,
186
- time,
187
- torch,
188
- )
189
-
190
-
191
- @app.cell
192
- def _(DRAGON_HF_TOKEN, json, logger, os, shutil, tempfile, torch):
193
- # =============================================================== #
194
- # B) DragonCode 方案A — HF checkpoint push / resume
195
- # =============================================================== #
196
- # checkpoint 直接推送至該 tier 嘅 HF public model repo;中斷後 resume
197
- # 由 HF 拉取,完全唔依賴 Molab 本地儲存。
198
-
199
- class _TrainState:
200
- def __init__(self, step=0, tokens_seen=0, epoch=0, global_seed=0,
201
- best_val_loss=float("inf"), metadata=None):
202
- self.step = step; self.tokens_seen = tokens_seen; self.epoch = epoch
203
- self.global_seed = global_seed; self.best_val_loss = best_val_loss
204
- self.metadata = metadata or {}
205
- def to_dict(self):
206
- return {"step": self.step, "tokens_seen": self.tokens_seen,
207
- "epoch": self.epoch, "global_seed": self.global_seed,
208
- "best_val_loss": self.best_val_loss, "metadata": self.metadata}
209
-
210
-
211
- def _find_latest_hf_checkpoint(repo):
212
- from huggingface_hub import list_repo_commits, hf_hub_download
213
- try:
214
- commits = _run_with_retry(lambda: list_repo_commits(repo, token=DRAGON_HF_TOKEN), label="list-ckpt")
215
- except Exception as e:
216
- logger.warning("list commits %s: %s", repo, e); return None
217
- for c in commits:
218
- sha = c.commit_id
219
- try:
220
- tree = _hf_api().repo_info(repo, revision=sha, repo_type="model").siblings
221
- names = [t.rfilename for t in tree]
222
- if "train_state.json" in names:
223
- st = hf_hub_download(repo, "train_state.json", revision=sha, token=DRAGON_HF_TOKEN)
224
- with open(st) as f: state = json.load(f)
225
- return sha, state
226
- except Exception:
227
- continue
228
- return None
229
-
230
-
231
- def _push_checkpoint_hf(repo, ckpt_paths, commit_message, size_cls):
232
- api = _hf_api(); api.create_repo(repo, repo_type="model", exist_ok=True, private=False)
233
- tmpdir = tempfile.mkdtemp(prefix="dc_ck_")
234
- dst = os.path.join(tmpdir, "checkpoints", f"DragonCode-{size_cls}")
235
- for name, src in ckpt_paths.items():
236
- if os.path.isdir(src):
237
- shutil.copytree(src, os.path.join(dst, name), dirs_exist_ok=True)
238
- else:
239
- os.makedirs(os.path.dirname(os.path.join(dst, name)), exist_ok=True)
240
- shutil.copy(src, os.path.join(dst, name))
241
- def _upload():
242
- api.upload_folder(folder_path=os.path.join(tmpdir, "checkpoints"), repo_id=repo,
243
- repo_type="model", commit_message=commit_message,
244
- allow_duplicate_filename=True)
245
- _run_with_retry(_upload, label="push-ckpt", tries=6)
246
- shutil.rmtree(tmpdir, ignore_errors=True)
247
- logger.info("Pushed checkpoint -> %s (%s)", repo, commit_message)
248
-
249
-
250
- def _load_local_ckpt(path, model, optimizer, scheduler):
251
- ck = torch.load(path, map_location="cpu", weights_only=False)
252
- if model is not None: model.load_state_dict(ck["model"])
253
- if optimizer is not None and ck.get("optimizer") is not None: optimizer.load_state_dict(ck["optimizer"])
254
- if scheduler is not None and ck.get("lr_scheduler") is not None: scheduler.load_state_dict(ck["lr_scheduler"])
255
- return ck
256
-
257
-
258
- return
259
-
260
-
261
- @app.cell
262
- def _(
263
- DRAGON_HF_TOKEN,
264
- MAX_SEQ_LEN,
265
- StreamingCorpus,
266
- json,
267
- logger,
268
- math,
269
- os,
270
- shutil,
271
- tempfile,
272
- time,
273
- torch,
274
- ):
275
- # =============================================================== #
276
- # C) DragonCode 方案A — pretrain 主迴圈(主執行緒,無後台thread)
277
- # =============================================================== #
278
- # 全部 CPU/GPU 繁重邏輯喺 Notebook Cell 主執行緒循序執行(Molab 合規);
279
- # 不開 daemon / 後台業務 thread。
280
-
281
- def _lr_warmup(step, warm, total):
282
- if step < warm: return step / max(1.0, warm)
283
- return max(0.0, 1.0 - (step - warm) / max(1, total - warm))
284
-
285
-
286
- def _try_resume(model, optimizer, scheduler, kwargs, repo, size_cls, step, tokens_seen, dev):
287
- if not kwargs.get("resume", True):
288
- return model, optimizer, scheduler, step, tokens_seen, 0
289
- local_dir = kwargs.get("local_ckpt_dir", "/home/marimo/DragonCode/checkpoints")
290
- ck = os.path.join(local_dir, f"DragonCode-{size_cls}", "checkpoint-latest.pt")
291
- loaded = False
292
- if os.path.exists(ck):
293
- logger.info("Resume LOCAL %s", ck)
294
- data = _load_local_ckpt(ck, model, optimizer, scheduler)
295
- st = data["train_state"]; step = st["step"]; tokens_seen = st["tokens_seen"]
296
- loaded = True
297
- else:
298
- hit = _find_latest_hf_checkpoint(repo)
299
- if hit:
300
- sha, st = hit
301
- logger.info("Resume HF commit %s (step=%s tokens=%s)", sha, st.get("step"), st.get("tokens_seen"))
302
- tmp = tempfile.mkdtemp(prefix="dc_rs_")
303
- from huggingface_hub import snapshot_download
304
- _run_with_retry(lambda: snapshot_download(repo, revision=sha, token=DRAGON_HF_TOKEN, local_dir=tmp),
305
- label="snap-resume")
306
- ck = os.path.join(tmp, "checkpoints", f"DragonCode-{size_cls}", "checkpoint-latest.pt")
307
- if os.path.exists(ck):
308
- data = _load_local_ckpt(ck, model, optimizer, scheduler)
309
- stt = data["train_state"]; step = stt["step"]; tokens_seen = stt["tokens_seen"]
310
- loaded = True
311
- shutil.rmtree(tmp, ignore_errors=True)
312
- else:
313
- logger.info("No checkpoint found; starting fresh (%s)", kwargs.get("tier_name", "?"))
314
- if loaded:
315
- _seed_everything(kwargs.get("seed", 42) + step)
316
- return model, optimizer, scheduler, step, tokens_seen, tokens_seen
317
-
318
-
319
- def _save_and_push(model, optimizer, scheduler, step, tokens_seen, epoch, seed, kwargs, repo, size_cls, tier):
320
- local_dir = kwargs.get("local_ckpt_dir", "/home/marimo/DragonCode/checkpoints")
321
- cdir = os.path.join(local_dir, f"DragonCode-{size_cls}"); os.makedirs(cdir, exist_ok=True)
322
- ckpt_path = os.path.join(cdir, "checkpoint-latest.pt")
323
- st = _TrainState(step=step, tokens_seen=tokens_seen, epoch=epoch, global_seed=seed,
324
- best_val_loss=float("inf"), metadata={"tier": tier.size_cls, "name": tier.name})
325
- torch.save({"model": model.state_dict(), "optimizer": optimizer.state_dict(),
326
- "lr_scheduler": scheduler.state_dict(), "train_state": st.to_dict(),
327
- "format": "dragoncode-checkpoint-v1"}, ckpt_path)
328
- sj = os.path.join(cdir, "train_state.json")
329
- with open(sj, "w") as f: json.dump(st.to_dict(), f, indent=2)
330
- _push_checkpoint_hf(repo, {"checkpoint-latest.pt": ckpt_path, "train_state.json": sj},
331
- f"[{tier.name}] checkpoint step={step} tokens={tokens_seen:,}", size_cls)
332
- logger.info("Saved+push step=%d tokens=%d", step, tokens_seen)
333
-
334
-
335
- def train_pretrain(tier, kwargs):
336
- """主執行緒訓練單一 tier 至 Chinchilla 預算(純外部 streaming)。"""
337
- torch.backends.cuda.matmul.allow_tf32 = False
338
- torch.backends.cudnn.allow_tf32 = False
339
- dev = kwargs["device"]; seed = kwargs.get("seed", 42)
340
- seq_len = kwargs.get("seq_len", MAX_SEQ_LEN); batch_size = kwargs.get("batch_size", 8)
341
- grad_acc = kwargs.get("grad_accum", 1); lr = kwargs.get("lr", 3e-4)
342
- warmup_frac = kwargs.get("warmup_frac", 0.01); max_grad_norm = kwargs.get("max_grad_norm", 1.0)
343
- save_every = kwargs.get("save_every_steps", 2000); log_every = kwargs.get("log_every", 50)
344
- size_cls = tier.size_str; repo = kwargs["hf_repo"]; token_budget = tier.chinchilla_tokens
345
- _seed_everything(seed); _get_tokenizer()
346
-
347
- from transformers import LlamaConfig, LlamaForCausalLM
348
- cfg = _build_model_config(tier.hidden, tier.layers, tier.ffn, tier.heads, tier.kv_heads, name=tier.name)
349
- cfg.attn_implementation = "flash_attention_2"
350
- model = LlamaForCausalLM(cfg).to(dev).to(torch.bfloat16)
351
- n_params = sum(p.numel() for p in model.parameters())
352
- logger.info("Pretrain %s on %s — %.1fM params, budget %d tokens", tier.name, dev, n_params/1e6, token_budget)
353
-
354
- optimizer = torch.optim.AdamW(model.parameters(), lr=lr, betas=(0.9, 0.95), weight_decay=0.1, fused=True)
355
- tokens_per_step_eff = batch_size * grad_acc * (seq_len - 1)
356
- total_steps_est = math.ceil(token_budget / tokens_per_step_eff)
357
- scheduler = torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda=lambda s: _lr_warmup(s, warmup_frac * total_steps_est, total_steps_est))
358
-
359
- # 方案A:純外部 streaming
360
- src = StreamingCorpus(DRAGON_HF_TOKEN, seq_len, token_budget, offset_tokens=0)
361
- logger.info("數據源[方案A]: 跳過 DragonCode-Tokenized-Pretrain; 全部 token 流式讀取 FineWeb-Edu → SlimPajama → The-Pile. Budget=%d", token_budget)
362
-
363
- step = 0; tokens_seen = 0; epoch = 0
364
- model, optimizer, scheduler, step, tokens_seen, offset_toks = _try_resume(
365
- model, optimizer, scheduler, kwargs, repo, size_cls, step, tokens_seen, dev)
366
- if offset_toks:
367
- src.off = offset_toks
368
- logger.info("Resume offset=%d tokens(純外部流,不含舊shard)", offset_toks)
369
-
370
- model.train(); gen = _make_batches(iter(src), batch_size, seq_len)
371
- prog_start = time.time()
372
- while tokens_seen < token_budget:
373
- local_steps = 0
374
- for x, y, tok_cursor, is_full in gen:
375
- x = x.to(dev); y = y.to(dev)
376
- out = model(x, labels=y); loss = out.loss / grad_acc; loss.backward()
377
- local_steps += 1
378
- tokens_seen = min(tok_cursor, token_budget)
379
- cond = (is_full and (step + 1) % grad_acc == 0) or (not is_full)
380
- if cond:
381
- torch.nn.utils.clip_grad_norm_(model.parameters(), max_grad_norm)
382
- optimizer.step(); scheduler.step(); optimizer.zero_grad(set_to_none=True)
383
- step += 1
384
- if step % log_every == 0 and step > 0:
385
- el = time.time() - prog_start; tps = tokens_seen / max(el, 1e-9)
386
- logger.info("[%s] step=%d tokens=%d/%d (%.2f%%) loss=%.4f lr=%.2e tps=%.0f",
387
- tier.name, step, tokens_seen, token_budget,
388
- 100.0 * tokens_seen / token_budget, out.loss.item() * grad_acc,
389
- scheduler.get_last_lr()[0], tps)
390
- if step % save_every == 0 and step > 0:
391
- _save_and_push(model, optimizer, scheduler, step, tokens_seen, epoch, seed, kwargs, repo, size_cls, tier)
392
- if tokens_seen >= token_budget: break
393
- if local_steps > 10_000_000: break
394
- if tokens_seen < token_budget:
395
- logger.warning("All 方案A external sources exhausted at token %d (budget %d) — stop %s.",
396
- tokens_seen, token_budget, tier.name)
397
- break
398
- _save_and_push(model, optimizer, scheduler, step, tokens_seen, epoch, seed, kwargs, repo, size_cls, tier)
399
- logger.info("PRETRAIN DONE %s: %d/%d tokens", tier.name, tokens_seen, token_budget)
400
- return {"model": model, "step": step, "tokens_seen": tokens_seen}
401
-
402
 
403
- return (train_pretrain,)
404
 
405
 
406
  @app.cell
407
- def _(DRAGON_HF_TOKEN, torch, train_pretrain):
408
- # =============================================================== #
409
- # D) DragonCode 方案A runner:偵測下一個未完成 tier
410
- # =============================================================== #
411
-
412
- TIER_ORDER = ["150M", "387M", "787M", "1.2B", "2.4B"]
413
-
414
-
415
- def hf_has_model(repo):
416
- from huggingface_hub import list_repo_files
417
- try:
418
- files = list_repo_files(repo, repo_type="model", token=DRAGON_HF_TOKEN)
419
- return any("config.json" in f or f.endswith(".safetensors") for f in files)
420
- except Exception:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
421
  return False
 
 
422
 
 
423
 
424
- def next_tier():
425
- for t in TIER_ORDER:
426
- if not hf_has_model(_hf_repos()[t]):
427
- return t
428
- return None
429
 
430
-
431
- def run_pipeline(tier=None, device="cuda", dry_run=False):
432
- """喺主執行緒訓練下一個未完成 tier(或指定 tier)。"""
433
- if tier is None:
434
- tier = next_tier()
435
- if tier is None:
436
- print("[RUN] 所有 tier 都已有公開 weights。無需再做。")
437
- return {"tier": None, "tokens_seen": None}
438
- spec = _tier_specs()[tier]
439
- kwargs = dict(tier_name=spec.name, hf_repo=_hf_repos()[tier], device=device, seed=42)
440
- print(f"[RUN] PRETRAIN {spec.name} — budget {spec.chinchilla_tokens/1e9:.2f}B tokens (方案A外部streaming)")
441
- if dry_run:
442
- print("[RUN] dry_run:", spec.name); return {"tier": tier, "tokens_seen": 0}
443
- out = train_pretrain(spec, kwargs)
444
- print(f"[RUN] PRETRAIN {tier} DONE: tokens_seen={out['tokens_seen']}")
445
- torch.cuda.empty_cache()
446
- return {"tier": tier, "tokens_seen": out["tokens_seen"]}
 
 
 
447
 
448
 
449
- return (run_pipeline,)
450
 
451
 
452
  @app.cell
453
- def _(run_pipeline):
454
- # =============================================================== #
455
- # E) DragonCode 方案A 手動啟動 cell
456
- # =============================================================== #
457
- # 請手動點擊呢個 cell 嘅 Run () 開始 150M 預訓練。
458
- # 若中斷,重新 Run 即由 HF checkpoint resume(唔依賴 Molab 本地)。
459
- run_pipeline(device="cuda")
460
 
461
  return
462
 
 
6
 
7
  @app.cell
8
  def _():
9
+ # ===================================================================== #
10
+ # DragonCode LLM Family production notebook (thin wrapper)
11
+ # (c) 2026 Dragon Limited. All rights reserved.
12
+ #
13
+ # This notebook is a THIN LAUNCHER over scripts/run_dragoncode.py.
14
+ # The single source of truth for training logic lives in
15
+ # ~/DragonCode/scripts/*.py (NOT duplicated in cells).
16
+ #
17
+ # Industrial-standard guarantees enforced by the scripts:
18
+ # * 100% code-domain data — codeparrot/codeparrot-clean +
19
+ # open-r1/codeforces-cots (permissive licenses only). NO generic web.
20
+ # * 4 training bugs fixed: grad-accum dead-loop (local_steps counter),
21
+ # lr=0 (token-progress schedule), bytes JSON serialization (base64),
22
+ # allow_duplicate_filename (removed for hf_hub 1.24.0).
23
+ # * resume-aware + idempotent stage markers (never restart from zero).
24
+ # ===================================================================== #
25
+ import os, sys, subprocess, json, time
26
+
27
+ SCRIPT_DIR = os.path.expanduser("~/DragonCode/scripts")
28
+ CONFIG_DIR = os.path.expanduser("~/DragonCode/configs")
29
+ LOG_DIR = os.path.expanduser("~/DragonCode/logs")
30
+
31
+ # Auth: the scripts force the "dragonlimited" account token internally, so
32
+ # we only need to make sure the box has *some* HF_TOKEN exported.
33
+ os.environ.setdefault("HF_TOKEN", os.environ.get("HF_TOKEN", ""))
34
+ os.environ["HF_HOME"] = os.path.expanduser("~/.cache/huggingface")
35
+
36
+ # 5-model tier order (Chinchilla-optimal, 20 tokens/param).
37
+ TIER_ORDER = ["150M", "387M", "787M", "1.2B", "2.4B"]
38
+ CHINCHILLA = {
39
+ "150M": 3_000_000_000,
40
+ "387M": 7_740_000_000,
41
+ "787M": 15_740_000_000,
42
+ "1.2B": 24_000_000_000,
43
+ "2.4B": 48_000_000_000,
44
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
 
46
+ return (SCRIPT_DIR, CONFIG_DIR, LOG_DIR, TIER_ORDER, CHINCHILLA, os, subprocess, time)
47
 
48
 
49
  @app.cell
50
+ def _(SCRIPT_DIR, CONFIG_DIR, LOG_DIR, os, subprocess, time):
51
+ # ===================================================================== #
52
+ # Stage runnerdelegates every stage to scripts/run_dragoncode.py
53
+ # (the single source of truth). Stages per tier (domain-only 12-step):
54
+ # pretrain → sft → dpo → golf → merge → verify → gguf
55
+ # 150M/387M: pretrain only. 2.4B: no DPO this cycle.
56
+ # ===================================================================== #
57
+ TIER_STAGES = {
58
+ "150M": ["pretrain"],
59
+ "387M": ["pretrain"],
60
+ "787M": ["pretrain", "sft", "dpo", "golf", "merge", "verify", "gguf"],
61
+ "1.2B": ["pretrain", "sft", "dpo", "golf", "merge", "verify", "gguf"],
62
+ "2.4B": ["pretrain", "sft", "golf", "merge", "verify", "gguf"],
63
+ }
64
+
65
+ def _run(args, logfile):
66
+ """Run a CLI stage, streaming stdout to its own log file (tail-friendly)."""
67
+ os.makedirs(LOG_DIR, exist_ok=True)
68
+ with open(logfile, "a") as lf:
69
+ lf.write(f"\n=== {time.strftime('%Y-%m-%dT%H:%M:%SZ')} {' '.join(args)} ===\n")
70
+ lf.flush()
71
+ proc = subprocess.Popen(
72
+ args, cwd=SCRIPT_DIR,
73
+ stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
74
+ text=True, bufsize=1,
75
+ )
76
+ assert proc.stdout is not None
77
+ for line in proc.stdout:
78
+ lf.write(line); lf.flush()
79
+ print(line, end="", flush=True)
80
+ rc = proc.wait()
81
+ return rc
82
+
83
+ def run_stage(tier, stage):
84
+ script = f"dragoncode_{stage}.py"
85
+ config = os.path.join(CONFIG_DIR, f"DragonCode-{tier}.yaml")
86
+ cmd = [sys.executable, script, "--tier", tier, "--config", config]
87
+ logfile = os.path.join(LOG_DIR, f"DragonCode-{tier}-{stage}.log")
88
+ print(f"\n[DRIVE] {tier}/{stage} -> {' '.join(cmd)}", flush=True)
89
+ rc = _run(cmd, logfile)
90
+ if rc != 0:
91
+ print(f"[DRIVE] {tier}/{stage} FAILED rc={rc} (see {logfile})", flush=True)
92
  return False
93
+ print(f"[DRIVE] {tier}/{stage} OK", flush=True)
94
+ return True
95
 
96
+ return (TIER_STAGES, run_stage)
97
 
 
 
 
 
 
98
 
99
+ @app.cell
100
+ def _(TIER_ORDER, TIER_STAGES, run_stage, time):
101
+ # ===================================================================== #
102
+ # Full pipeline sequential, resume-safe, single epoch per tier.
103
+ # Unique stop condition: user interrupt. No early-exit, no auto-exit.
104
+ # ===================================================================== #
105
+ def run_all():
106
+ for tier in TIER_ORDER:
107
+ for stage in TIER_STAGES[tier]:
108
+ ok = run_stage(tier, stage)
109
+ attempt = 0
110
+ while not ok and attempt < 3:
111
+ attempt += 1
112
+ time.sleep(8)
113
+ print(f"[DRIVE] {tier}/{stage} retry {attempt}/3", flush=True)
114
+ ok = run_stage(tier, stage)
115
+ if not ok:
116
+ print(f"[DRIVE] {tier}/{stage} failed after retries — stopping pipeline", flush=True)
117
+ return
118
+ print("[DRIVE] All 5 models complete.", flush=True)
119
 
120
 
121
+ return (run_all,)
122
 
123
 
124
  @app.cell
125
+ def _(run_all):
126
+ # ===================================================================== #
127
+ # LAUNCH press Run (▶) on this cell to train all 5 models end to end.
128
+ # ===================================================================== #
129
+ run_all()
 
 
130
 
131
  return
132