AbstractPhil commited on
Commit
dae9733
·
verified ·
1 Parent(s): 5d2594b

anima_closeout v15: the val bed was reading the eval cache wrong in TWO ways. (1) text embeddings live in the AR-bucket dir (ar_frames_{ar}x{f}, dataset.py:485), not the size-bucket dir (cache_{ar}x{w}x{h}x{f}, :247) — hence 'found []'. (2) far worse: SizeBucketDataset SHUFFLES its metadata (:241-242) before caching latents while TE is cached unshuffled one level up, so pairing by row order marries each latent to someone else's caption and still yields plausible numbers. The bed now joins on image_spec — the key the fork itself joins on (:312) — and iterates in sorted spec order for run-to-run reproducibility. PROVEN on a synthetic cache written by the fork's OWN ParquetCache with the real shuffle: 24/24 rows correctly paired, while the old order-based read mismatched 23/24.

Browse files
Files changed (1) hide show
  1. colab/anima_closeout.ipynb +59 -29
colab/anima_closeout.ipynb CHANGED
@@ -954,19 +954,22 @@
954
  "DEV = \"cuda\"\n",
955
  "\n",
956
  "# -- read the fork's eval cache -------------------------------------------\n",
957
- "# Layout (utils/dataset.py + parquet_cache.py): {root}/cache_{bucket}/ holds\n",
958
- "# separate parquet caches \u2014 'latents' (models/base.py:247) and\n",
959
- "# 'text_embeddings_{i}' (cosmos_predict2.py:398: prompt_embeds/attn_mask/\n",
960
- "# t5_input_ids/t5_attn_mask; the live anima runs write i=1, so the TE dir\n",
961
- "# is DISCOVERED, not hardcoded; 'uncond_text_embeddings_*' is excluded).\n",
962
- "# Both map over the SAME shuffled metadata dataset and this campaign has\n",
963
- "# exactly one caption per image, so rows pair by order; the per-bucket\n",
964
- "# count assert guards that assumption.\n",
 
 
 
965
  "cache_root = CFG[\"eval_cache_dir\"]\n",
966
- "buckets = sorted(d for d in os.listdir(cache_root)\n",
967
- " if d.startswith(\"cache_\")\n",
968
- " and os.path.isdir(os.path.join(cache_root, d)))\n",
969
- "assert buckets, f\"no cache_* bucket dirs under {cache_root}\"\n",
970
  "\n",
971
  "def read_cache(d):\n",
972
  " shards = sorted(p for p in os.listdir(d)\n",
@@ -981,29 +984,56 @@
981
  " return torch.frombuffer(bytearray(raw),\n",
982
  " dtype=getattr(torch, dt)).reshape(shape)\n",
983
  "\n",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
984
  "LAT = [\"latents\"]\n",
985
  "TE = [\"prompt_embeds\", \"attn_mask\", \"t5_input_ids\", \"t5_attn_mask\"]\n",
986
  "rows = []\n",
987
- "for b in buckets:\n",
988
- " lt = read_cache(os.path.join(cache_root, b, \"latents\"))\n",
989
- " te_dirs = sorted(d for d in os.listdir(os.path.join(cache_root, b))\n",
990
- " if d.startswith(\"text_embeddings_\"))\n",
991
- " assert len(te_dirs) == 1, \\\n",
992
- " f\"{b}: expected exactly one text_embeddings_* cache, found {te_dirs}\"\n",
993
- " tt = read_cache(os.path.join(cache_root, b, te_dirs[0]))\n",
 
 
 
 
 
 
 
994
  " for c in LAT:\n",
995
- " assert c + \"__shape\" in lt[0].schema.names, (b, lt[0].schema.names)\n",
 
996
  " for c in TE:\n",
997
- " assert c + \"__shape\" in tt[0].schema.names, (b, tt[0].schema.names)\n",
998
- " lrows = [(t, j) for t in lt for j in range(t.num_rows)]\n",
999
- " trows = [(t, j) for t in tt for j in range(t.num_rows)]\n",
1000
- " assert len(lrows) == len(trows), \\\n",
1001
- " f\"{b}: latents {len(lrows)} != text {len(trows)} \u2014 pairing unsafe\"\n",
1002
- " for (ltb, lj), (ttb, tj) in zip(lrows, trows):\n",
1003
- " r = {c: decol(ltb, c, lj) for c in LAT}\n",
1004
- " r.update({c: decol(ttb, c, tj) for c in TE})\n",
 
 
 
1005
  " rows.append(r)\n",
1006
- "print(f\"eval cache rows: {len(rows)} from {len(buckets)} bucket dir(s)\",\n",
 
 
1007
  " flush=True)\n",
1008
  "rows = rows[:int(os.environ.get(\"VB_MAX_ROWS\", \"512\"))]\n",
1009
  "assert rows\n",
 
954
  "DEV = \"cuda\"\n",
955
  "\n",
956
  "# -- read the fork's eval cache -------------------------------------------\n",
957
+ "# LAYOUT (utils/dataset.py) and the trap inside it:\n",
958
+ "# {root}/cache_{ar}x{w}x{h}x{f}/latents/ SizeBucketDataset (:247)\n",
959
+ "# {root}/ar_frames_{ar}x{f}/text_embeddings_N/ ARBucketDataset (:485)\n",
960
+ "# Latents are cached from metadata that SizeBucketDataset SHUFFLES first\n",
961
+ "# (:241-242); text embeddings are cached one level up, at the AR bucket,\n",
962
+ "# unshuffled. So latent row i and TE row i are DIFFERENT images \u2014 pairing\n",
963
+ "# by row order would silently hand every latent someone else's caption and\n",
964
+ "# still produce plausible numbers. Both caches carry image_spec\n",
965
+ "# (parquet_cache.image_specs()), which is the key the fork itself joins on\n",
966
+ "# (dataset.py:312), so we join on image_spec and iterate in sorted spec\n",
967
+ "# order, which also makes the bed reproducible run-to-run.\n",
968
  "cache_root = CFG[\"eval_cache_dir\"]\n",
969
+ "size_dirs = sorted(d for d in os.listdir(cache_root)\n",
970
+ " if d.startswith(\"cache_\")\n",
971
+ " and os.path.isdir(os.path.join(cache_root, d)))\n",
972
+ "assert size_dirs, f\"no cache_* size-bucket dirs under {cache_root}\"\n",
973
  "\n",
974
  "def read_cache(d):\n",
975
  " shards = sorted(p for p in os.listdir(d)\n",
 
984
  " return torch.frombuffer(bytearray(raw),\n",
985
  " dtype=getattr(torch, dt)).reshape(shape)\n",
986
  "\n",
987
+ "def by_spec(tables, what):\n",
988
+ " \"\"\"{image_spec tuple: (table, row)} \u2014 tuples are JSON-encoded by the\n",
989
+ " cache writer (parquet_cache.py:_encode_row), so accept either form.\"\"\"\n",
990
+ " out = {}\n",
991
+ " for t in tables:\n",
992
+ " names = t.schema.names\n",
993
+ " col = (\"image_spec__json\" if \"image_spec__json\" in names else\n",
994
+ " (\"image_spec\" if \"image_spec\" in names else None))\n",
995
+ " assert col, f\"{what} cache carries no image_spec column: {names[:8]}\"\n",
996
+ " for j, v in enumerate(t.column(col).to_pylist()):\n",
997
+ " s = tuple(json.loads(v)) if isinstance(v, str) else tuple(v)\n",
998
+ " out.setdefault(s, (t, j))\n",
999
+ " return out\n",
1000
+ "\n",
1001
  "LAT = [\"latents\"]\n",
1002
  "TE = [\"prompt_embeds\", \"attn_mask\", \"t5_input_ids\", \"t5_attn_mask\"]\n",
1003
  "rows = []\n",
1004
+ "for sd in size_dirs:\n",
1005
+ " parts = sd[len(\"cache_\"):].split(\"x\") # {ar}x{w}x{h}x{frames}\n",
1006
+ " ar_dir = os.path.join(cache_root, f\"ar_frames_{parts[0]}x{parts[-1]}\")\n",
1007
+ " assert os.path.isdir(ar_dir), (\n",
1008
+ " f\"{sd}: expected AR-bucket dir {ar_dir} \u2014 text embeddings are \"\n",
1009
+ " \"cached per AR bucket, not per size bucket\")\n",
1010
+ " te_names = sorted(d for d in os.listdir(ar_dir)\n",
1011
+ " if d.startswith(\"text_embeddings_\"))\n",
1012
+ " assert len(te_names) == 1, \\\n",
1013
+ " f\"{ar_dir}: expected one text_embeddings_* cache, found {te_names}\"\n",
1014
+ " lat = by_spec(read_cache(os.path.join(cache_root, sd, \"latents\")),\n",
1015
+ " \"latents\")\n",
1016
+ " te = by_spec(read_cache(os.path.join(ar_dir, te_names[0])),\n",
1017
+ " \"text embedding\")\n",
1018
  " for c in LAT:\n",
1019
+ " _s = next(iter(lat.values()))[0].schema.names\n",
1020
+ " assert c + \"__shape\" in _s, (sd, _s[:8])\n",
1021
  " for c in TE:\n",
1022
+ " _s = next(iter(te.values()))[0].schema.names\n",
1023
+ " assert c + \"__shape\" in _s, (ar_dir, _s[:8])\n",
1024
+ " _missing = [s for s in lat if s not in te]\n",
1025
+ " assert not _missing, (\n",
1026
+ " f\"{sd}: {len(_missing)} latents have no text embedding for their \"\n",
1027
+ " f\"image_spec (e.g. {_missing[:1]}) \u2014 caches are out of sync\")\n",
1028
+ " for s in sorted(lat):\n",
1029
+ " lt, lj = lat[s]\n",
1030
+ " tt, tj = te[s]\n",
1031
+ " r = {c: decol(lt, c, lj) for c in LAT}\n",
1032
+ " r.update({c: decol(tt, c, tj) for c in TE})\n",
1033
  " rows.append(r)\n",
1034
+ " print(f\" {sd}: {len(lat)} rows joined on image_spec \"\n",
1035
+ " f\"(AR pool {len(te)})\", flush=True)\n",
1036
+ "print(f\"eval cache rows: {len(rows)} from {len(size_dirs)} size bucket(s)\",\n",
1037
  " flush=True)\n",
1038
  "rows = rows[:int(os.environ.get(\"VB_MAX_ROWS\", \"512\"))]\n",
1039
  "assert rows\n",