AbstractPhil commited on
Commit
165c0dc
·
verified ·
1 Parent(s): 015802c

anima_closeout v7: (1) rc no longer masked — the deepspeed|tee pipeline returned TEE's exit code, so the smoke's ~24s death printed rc=0; Python is now the tee and any failure (rc!=0 OR no run dir) dumps the log tail into the cell. (2) CRITICAL: train+eval dataset TOMLs shared the fork's default parquet cache root ('local_parquet' constant) — eval would clobber train's metadata/latents and the loop would silently train on the 512 eval rows; now explicit distinct path= roots under dp_cache/. (3) width_column/height_column (the real fork keys; image_*_column variants were silently ignored). (4) val bed reads the fork's REAL cache layout: per-bucket paired latents/text_embeddings_0 caches. Source-verified against the fork + exp004's as-run TOMLs by 4-agent audit.

Browse files
Files changed (1) hide show
  1. colab/anima_closeout.ipynb +97 -39
colab/anima_closeout.ipynb CHANGED
@@ -344,7 +344,14 @@
344
  " f\"{_m['eval_n']} eval from {len(_m['shards_used'])} shards\")\n",
345
  "\n",
346
  "# -- dataset TOMLs (fused recipe: derived caption column) -----------------\n",
347
- "def _dataset_toml(files):\n",
 
 
 
 
 
 
 
348
  " return f\"\"\"# generated by anima_closeout.ipynb\n",
349
  "resolutions = [512]\n",
350
  "enable_ar_bucket = true\n",
@@ -356,10 +363,11 @@
356
  "\n",
357
  "[[directory]]\n",
358
  "type = 'parquet'\n",
 
359
  "parquet_files = '{files}'\n",
360
  "image_column = 'image'\n",
361
- "image_width_column = 'image_width'\n",
362
- "image_height_column = 'image_height'\n",
363
  "caption_column = 'caption'\n",
364
  "caption_type = 'text'\n",
365
  "num_repeats = 1\n",
@@ -367,8 +375,9 @@
367
  "\"\"\"\n",
368
  "\n",
369
  "(TOMLS / \"dataset_train.toml\").write_text(\n",
370
- " _dataset_toml(f\"{TRAIN_DIR}/*.parquet\"))\n",
371
- "(TOMLS / \"dataset_eval.toml\").write_text(_dataset_toml(str(EVAL_PARQUET)))\n",
 
372
  "# -- training TOMLs per arm -----------------------------------------------\n",
373
  "_AP = WORK / \"models\" / \"anima\" / \"split_files\"\n",
374
  "\n",
@@ -455,18 +464,42 @@
455
  "\n",
456
  "HUB_REPO = \"AbstractPhil/geolip-aleph-diffusion\"\n",
457
  "\n",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
458
  "def run_arm(tag, resume=False):\n",
459
  " log = RUNS / f\"{tag}.log\"\n",
460
- " flags = \"--resume_from_checkpoint\" if resume else \"\"\n",
461
  " t0 = time.time()\n",
462
- " rc = sh(f\"cd {FORK} && NCCL_P2P_DISABLE=1 NCCL_IB_DISABLE=1 \"\n",
463
- " f\"deepspeed --num_gpus=1 train.py --deepspeed \"\n",
464
- " f\"--config {ARMS[tag]} {flags} 2>&1 | tee -a {log}\",\n",
465
- " check=False)\n",
466
  " print(f\"[{tag}] rc={rc} wall={(time.time() - t0) / 60:.1f} min\")\n",
467
  " if rc != 0:\n",
468
- " raise RuntimeError(f\"{tag} failed \u2014 read {log}\")\n",
469
- " return newest_save(tag)\n",
 
 
 
470
  "\n",
471
  "def latest_run_dir(tag):\n",
472
  " run_dirs = sorted(glob.glob(str(RUNS / tag / \"*\")))\n",
@@ -702,18 +735,24 @@
702
  "QUANTILES = [0.1, 0.3, 0.5, 0.7, 0.9]\n",
703
  "DEV = \"cuda\"\n",
704
  "\n",
705
- "# -- read the fork's eval cache (schema discovered loudly) ----------------\n",
706
- "cache_dir = CFG[\"eval_cache_dir\"]\n",
707
- "shard_files = sorted(f for f in os.listdir(cache_dir)\n",
708
- " if f.endswith(\".parquet\"))\n",
709
- "assert shard_files, f\"no cache shards under {cache_dir}\"\n",
710
- "schema = pq.read_schema(os.path.join(cache_dir, shard_files[0]))\n",
711
- "print(\"cache columns:\", schema.names, flush=True)\n",
712
- "NEEDED = [\"latents\", \"prompt_embeds\", \"attn_mask\", \"t5_input_ids\",\n",
713
- " \"t5_attn_mask\"]\n",
714
- "for c in NEEDED:\n",
715
- " assert c in schema.names or c + \"__shape\" in schema.names, \\\n",
716
- " f\"cache lacks column {c} \u2014 inspect the printed schema\"\n",
 
 
 
 
 
 
717
  "\n",
718
  "def decol(tbl, name, j):\n",
719
  " raw = tbl.column(name)[j].as_py()\n",
@@ -722,14 +761,27 @@
722
  " return torch.frombuffer(bytearray(raw),\n",
723
  " dtype=getattr(torch, dt)).reshape(shape)\n",
724
  "\n",
 
 
725
  "rows = []\n",
726
- "for sf in shard_files:\n",
727
- " tbl = pq.read_table(os.path.join(cache_dir, sf))\n",
728
- " for j in range(tbl.num_rows):\n",
729
- " rows.append({c: decol(tbl, c, j) for c in NEEDED\n",
730
- " if c + \"__shape\" in schema.names})\n",
 
 
 
 
 
 
 
 
 
 
 
 
731
  "rows = rows[:int(os.environ.get(\"VB_MAX_ROWS\", \"512\"))]\n",
732
- "print(f\"eval cache rows used: {len(rows)}\", flush=True)\n",
733
  "assert rows\n",
734
  "\n",
735
  "# -- pipeline (frozen trunk); adapters swapped per arm --------------------\n",
@@ -868,13 +920,15 @@
868
  "except ImportError:\n",
869
  " import tomli as tomllib\n",
870
  "\n",
871
- "_pq_files = glob.glob(str(DATA / \"**\" / \"*.parquet\"), recursive=True)\n",
872
- "_cache_dirs = sorted({str(Path(f).parent) for f in _pq_files\n",
873
- " if \"cache\" in f.lower() and \"eval\" in f.lower()})\n",
874
- "print(\"eval cache candidates:\", _cache_dirs)\n",
875
- "assert _cache_dirs, (\"no eval cache found under DATA \u2014 inspect the tree, \"\n",
876
- " \"set EVAL_CACHE manually, re-run\")\n",
877
- "EVAL_CACHE = _cache_dirs[0]\n",
 
 
878
  "\n",
879
  "_full = tomllib.loads(ARMS[\"e004b_relay_s0\"].read_text())\n",
880
  "_model = {k: v for k, v in _full[\"model\"].items()\n",
@@ -887,8 +941,12 @@
887
  " config.update(out=str(outp), eval_cache_dir=EVAL_CACHE,\n",
888
  " model_cfg=_model_cfg)\n",
889
  " cfgp.write_text(json.dumps(config, indent=1))\n",
890
- " sh(f\"cd {FORK} && VB_CONFIG={cfgp} python {WORK}/val_bed.py \"\n",
891
- " f\"2>&1 | tee {RUNS}/{out_name}.log\")\n",
 
 
 
 
892
  " return json.loads(outp.read_text())\n",
893
  "\n",
894
  "def _pt(saves, tag):\n",
 
344
  " f\"{_m['eval_n']} eval from {len(_m['shards_used'])} shards\")\n",
345
  "\n",
346
  "# -- dataset TOMLs (fused recipe: derived caption column) -----------------\n",
347
+ "# `path` = the latent/TE cache root, and it MUST differ between train and\n",
348
+ "# eval: for type='parquet' the fork's default root is the CONSTANT\n",
349
+ "# 'local_parquet' (utils/dataset.py:1014-1015), so without explicit paths\n",
350
+ "# the eval dataset overwrites the train dataset's grouped metadata and\n",
351
+ "# clears its latents mid-run \u2014 the train loop then silently loads the 512\n",
352
+ "# EVAL rows. Key names per the fork + exp004's as-run dataset TOML:\n",
353
+ "# width_column/height_column (image_*_column variants are silently ignored).\n",
354
+ "def _dataset_toml(files, cache_path):\n",
355
  " return f\"\"\"# generated by anima_closeout.ipynb\n",
356
  "resolutions = [512]\n",
357
  "enable_ar_bucket = true\n",
 
363
  "\n",
364
  "[[directory]]\n",
365
  "type = 'parquet'\n",
366
+ "path = '{cache_path}'\n",
367
  "parquet_files = '{files}'\n",
368
  "image_column = 'image'\n",
369
+ "width_column = 'image_width'\n",
370
+ "height_column = 'image_height'\n",
371
  "caption_column = 'caption'\n",
372
  "caption_type = 'text'\n",
373
  "num_repeats = 1\n",
 
375
  "\"\"\"\n",
376
  "\n",
377
  "(TOMLS / \"dataset_train.toml\").write_text(\n",
378
+ " _dataset_toml(f\"{TRAIN_DIR}/*.parquet\", WORK / \"dp_cache\" / \"train\"))\n",
379
+ "(TOMLS / \"dataset_eval.toml\").write_text(\n",
380
+ " _dataset_toml(str(EVAL_PARQUET), WORK / \"dp_cache\" / \"heldout\"))\n",
381
  "# -- training TOMLs per arm -----------------------------------------------\n",
382
  "_AP = WORK / \"models\" / \"anima\" / \"split_files\"\n",
383
  "\n",
 
464
  "\n",
465
  "HUB_REPO = \"AbstractPhil/geolip-aleph-diffusion\"\n",
466
  "\n",
467
+ "def _die(tag, log, why):\n",
468
+ " tail = \"\".join(\n",
469
+ " log.read_text(errors=\"replace\").splitlines(keepends=True)[-60:]) \\\n",
470
+ " if log.exists() else \"(no log written)\"\n",
471
+ " raise RuntimeError(f\"{tag}: {why}\\n--- last 60 lines of {log} ---\\n\"\n",
472
+ " f\"{tail}\")\n",
473
+ "\n",
474
+ "def sh_tee(cmd, log):\n",
475
+ " # NO shell pipe to tee: a pipeline returns TEE's rc, so a dead train\n",
476
+ " # reported rc=0 (the smoke's exact failure). Python is the tee \u2014 the\n",
477
+ " # child's rc is real, output streams live AND lands in the log.\n",
478
+ " print(f\"$ {cmd}\")\n",
479
+ " with open(log, \"a\") as lf:\n",
480
+ " proc = subprocess.Popen(cmd, shell=True, executable=\"/bin/bash\",\n",
481
+ " stdout=subprocess.PIPE,\n",
482
+ " stderr=subprocess.STDOUT,\n",
483
+ " text=True, bufsize=1)\n",
484
+ " for line in proc.stdout:\n",
485
+ " print(line, end=\"\", flush=True)\n",
486
+ " lf.write(line)\n",
487
+ " return proc.wait()\n",
488
+ "\n",
489
  "def run_arm(tag, resume=False):\n",
490
  " log = RUNS / f\"{tag}.log\"\n",
491
+ " flags = \" --resume_from_checkpoint\" if resume else \"\"\n",
492
  " t0 = time.time()\n",
493
+ " rc = sh_tee(f\"cd {FORK} && NCCL_P2P_DISABLE=1 NCCL_IB_DISABLE=1 \"\n",
494
+ " f\"deepspeed --num_gpus=1 train.py --deepspeed \"\n",
495
+ " f\"--config {ARMS[tag]}{flags}\", log)\n",
 
496
  " print(f\"[{tag}] rc={rc} wall={(time.time() - t0) / 60:.1f} min\")\n",
497
  " if rc != 0:\n",
498
+ " _die(tag, log, f\"train exited rc={rc}\")\n",
499
+ " try:\n",
500
+ " return newest_save(tag) # rc=0 but no run/save dir is ALSO death\n",
501
+ " except AssertionError as e:\n",
502
+ " _die(tag, log, str(e))\n",
503
  "\n",
504
  "def latest_run_dir(tag):\n",
505
  " run_dirs = sorted(glob.glob(str(RUNS / tag / \"*\")))\n",
 
735
  "QUANTILES = [0.1, 0.3, 0.5, 0.7, 0.9]\n",
736
  "DEV = \"cuda\"\n",
737
  "\n",
738
+ "# -- read the fork's eval cache -------------------------------------------\n",
739
+ "# Layout (utils/dataset.py + parquet_cache.py): {root}/cache_{bucket}/ holds\n",
740
+ "# TWO separate parquet caches \u2014 'latents' (models/base.py:247) and\n",
741
+ "# 'text_embeddings_0' (cosmos_predict2.py:398: prompt_embeds/attn_mask/\n",
742
+ "# t5_input_ids/t5_attn_mask). Both map over the SAME shuffled metadata\n",
743
+ "# dataset and this campaign has exactly one caption per image, so rows pair\n",
744
+ "# by order; the per-bucket count assert guards that assumption.\n",
745
+ "cache_root = CFG[\"eval_cache_dir\"]\n",
746
+ "buckets = sorted(d for d in os.listdir(cache_root)\n",
747
+ " if d.startswith(\"cache_\")\n",
748
+ " and os.path.isdir(os.path.join(cache_root, d)))\n",
749
+ "assert buckets, f\"no cache_* bucket dirs under {cache_root}\"\n",
750
+ "\n",
751
+ "def read_cache(d):\n",
752
+ " shards = sorted(p for p in os.listdir(d)\n",
753
+ " if p.startswith(\"shard_\") and p.endswith(\".parquet\"))\n",
754
+ " assert shards, f\"no shards under {d}\"\n",
755
+ " return [pq.read_table(os.path.join(d, p)) for p in shards]\n",
756
  "\n",
757
  "def decol(tbl, name, j):\n",
758
  " raw = tbl.column(name)[j].as_py()\n",
 
761
  " return torch.frombuffer(bytearray(raw),\n",
762
  " dtype=getattr(torch, dt)).reshape(shape)\n",
763
  "\n",
764
+ "LAT = [\"latents\"]\n",
765
+ "TE = [\"prompt_embeds\", \"attn_mask\", \"t5_input_ids\", \"t5_attn_mask\"]\n",
766
  "rows = []\n",
767
+ "for b in buckets:\n",
768
+ " lt = read_cache(os.path.join(cache_root, b, \"latents\"))\n",
769
+ " tt = read_cache(os.path.join(cache_root, b, \"text_embeddings_0\"))\n",
770
+ " for c in LAT:\n",
771
+ " assert c + \"__shape\" in lt[0].schema.names, (b, lt[0].schema.names)\n",
772
+ " for c in TE:\n",
773
+ " assert c + \"__shape\" in tt[0].schema.names, (b, tt[0].schema.names)\n",
774
+ " lrows = [(t, j) for t in lt for j in range(t.num_rows)]\n",
775
+ " trows = [(t, j) for t in tt for j in range(t.num_rows)]\n",
776
+ " assert len(lrows) == len(trows), \\\n",
777
+ " f\"{b}: latents {len(lrows)} != text {len(trows)} \u2014 pairing unsafe\"\n",
778
+ " for (ltb, lj), (ttb, tj) in zip(lrows, trows):\n",
779
+ " r = {c: decol(ltb, c, lj) for c in LAT}\n",
780
+ " r.update({c: decol(ttb, c, tj) for c in TE})\n",
781
+ " rows.append(r)\n",
782
+ "print(f\"eval cache rows: {len(rows)} from {len(buckets)} bucket dir(s)\",\n",
783
+ " flush=True)\n",
784
  "rows = rows[:int(os.environ.get(\"VB_MAX_ROWS\", \"512\"))]\n",
 
785
  "assert rows\n",
786
  "\n",
787
  "# -- pipeline (frozen trunk); adapters swapped per arm --------------------\n",
 
920
  "except ImportError:\n",
921
  " import tomli as tomllib\n",
922
  "\n",
923
+ "# deterministic: the eval dataset TOML pins path = dp_cache/heldout, and\n",
924
+ "# the fork caches under {path}/cache/{model_name} with model_name 'anima'\n",
925
+ "# (cosmos_predict2.py:254 renames the pipeline when llm_path is a file)\n",
926
+ "EVAL_CACHE = str(WORK / \"dp_cache\" / \"heldout\" / \"cache\" / \"anima\")\n",
927
+ "_buckets = sorted(glob.glob(str(Path(EVAL_CACHE) / \"cache_*\")))\n",
928
+ "assert _buckets, (f\"no cache_* bucket dirs under {EVAL_CACHE} \u2014 the arms \"\n",
929
+ " \"must have run (they build the eval cache) before the bed\")\n",
930
+ "print(\"eval cache:\", EVAL_CACHE,\n",
931
+ " \"| buckets:\", [Path(b).name for b in _buckets])\n",
932
  "\n",
933
  "_full = tomllib.loads(ARMS[\"e004b_relay_s0\"].read_text())\n",
934
  "_model = {k: v for k, v in _full[\"model\"].items()\n",
 
941
  " config.update(out=str(outp), eval_cache_dir=EVAL_CACHE,\n",
942
  " model_cfg=_model_cfg)\n",
943
  " cfgp.write_text(json.dumps(config, indent=1))\n",
944
+ " _blog = RUNS / f\"{out_name}.log\"\n",
945
+ " rc = sh_tee(f\"cd {FORK} && VB_CONFIG={cfgp} python {WORK}/val_bed.py\",\n",
946
+ " _blog)\n",
947
+ " if rc != 0 or not outp.exists():\n",
948
+ " _die(out_name, _blog, f\"val bed rc={rc}, results \"\n",
949
+ " f\"{'missing' if not outp.exists() else 'present'}\")\n",
950
  " return json.loads(outp.read_text())\n",
951
  "\n",
952
  "def _pt(saves, tag):\n",