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- 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 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
"
|
| 362 |
-
"
|
| 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(
|
|
|
|
| 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 =
|
| 463 |
-
"
|
| 464 |
-
"
|
| 465 |
-
" check=False)\n",
|
| 466 |
" print(f\"[{tag}] rc={rc} wall={(time.time() - t0) / 60:.1f} min\")\n",
|
| 467 |
" if rc != 0:\n",
|
| 468 |
-
"
|
| 469 |
-
"
|
|
|
|
|
|
|
|
|
|
| 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
|
| 706 |
-
"
|
| 707 |
-
"
|
| 708 |
-
"
|
| 709 |
-
"
|
| 710 |
-
"
|
| 711 |
-
"
|
| 712 |
-
"
|
| 713 |
-
"
|
| 714 |
-
"
|
| 715 |
-
"
|
| 716 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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
|
| 727 |
-
"
|
| 728 |
-
"
|
| 729 |
-
"
|
| 730 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
"
|
| 872 |
-
"
|
| 873 |
-
"
|
| 874 |
-
"
|
| 875 |
-
"
|
| 876 |
-
"
|
| 877 |
-
"
|
|
|
|
|
|
|
| 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 |
-
"
|
| 891 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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",
|