AbstractPhil commited on
Commit
283127c
·
verified ·
1 Parent(s): 02253aa

CELL 1 rewritten as an INCREMENTAL materializer: the fused set is ~160GB and the campaign needs ~9k rows — shards visited in sha256(name) order one at a time, gated+deduped+slimmed into the pool, source deleted per shard, hard stop at TRAIN_TARGET+EVAL_N (8192+512). Download bounded to ~10GB instead of the corpus. Split logic executed green against a real shard.

Browse files
Files changed (1) hide show
  1. colab/anima_closeout.ipynb +107 -93
colab/anima_closeout.ipynb CHANGED
@@ -171,126 +171,138 @@
171
  "execution_count": null,
172
  "outputs": [],
173
  "source": [
174
- "# \u2550\u2550\u2550 CELL 1 \u2014 materialize the gated held-out split + write TOMLs \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n",
175
- "# Row pipeline, exactly the campaign record:\n",
176
- "# AUDIT GATE (pod2/dexp011:98-105): a row passes when its age_audit/audit\n",
177
- "# value contains \"approved\" or \"pass\" (case-insensitive); gated rows are\n",
178
- "# counted and reported loudly.\n",
179
- "# DEDUP by id (first occurrence wins) \u2014 guards the stray rank0.part00\n",
180
- "# shard alongside the shard_r0_* series.\n",
181
- "# CAPTION = caption_joycaption or prompt_fused fallback (dexp011:154),\n",
182
- "# materialized as a `caption` column so the fork reads one key.\n",
183
- "# SPLIT: sha256(id) ascending; first EVAL_N surviving rows are eval.\n",
184
- "import hashlib, json\n",
 
 
 
 
 
185
  "import pyarrow as pa\n",
186
  "import pyarrow.parquet as pq\n",
187
  "from huggingface_hub import hf_hub_download\n",
188
  "\n",
189
- "EVAL_N = 512\n",
 
 
 
 
190
  "TRAIN_DIR = DATA / \"train\"; TRAIN_DIR.mkdir(exist_ok=True)\n",
191
  "EVAL_PARQUET = DATA / \"eval.parquet\"\n",
192
  "MANIFEST = DATA / \"split_manifest.json\"\n",
 
193
  "\n",
194
- "def _passes_gate(row_get):\n",
195
- " vals = [str(row_get(c)) for c in (\"age_audit\", \"audit\")\n",
196
- " if row_get(c) is not None]\n",
197
  " return (not vals) or any((\"approved\" in v.lower() or \"pass\" in v.lower())\n",
198
  " for v in vals)\n",
199
  "\n",
200
  "if not MANIFEST.exists():\n",
201
- " _paths = [hf_hub_download(ANIMA[\"DATASET\"], sh, repo_type=\"dataset\")\n",
202
- " for sh in ANIMA[\"SHARDS\"]]\n",
203
- "\n",
204
- " # pass 1: gate + dedup + rank survivors by sha256(id)\n",
205
- " _key_cols = [c for c in (\"id\", \"caption_joycaption\", \"prompt_fused\",\n",
206
- " \"age_audit\", \"audit\")\n",
207
- " if True]\n",
208
- " seen_ids, ranked = set(), []\n",
209
  " n_seen = n_gated = n_dup = 0\n",
210
- " for si, pth in enumerate(_paths):\n",
211
- " pf = pq.ParquetFile(pth)\n",
212
- " avail = [c for c in _key_cols if c in pf.schema_arrow.names]\n",
213
- " ri = 0\n",
214
- " for batch in pf.iter_batches(batch_size=256, columns=avail):\n",
215
- " cols = {c: batch.column(c) for c in avail}\n",
 
 
 
 
 
 
 
 
 
 
 
 
 
216
  " for j in range(batch.num_rows):\n",
 
 
217
  " n_seen += 1\n",
218
- " get = lambda c: (cols[c][j].as_py() if c in cols else None)\n",
219
- " rid = str(get(\"id\"))\n",
220
  " if not _passes_gate(get):\n",
221
  " n_gated += 1\n",
222
- " elif rid in seen_ids:\n",
 
 
223
  " n_dup += 1\n",
224
- " else:\n",
225
- " seen_ids.add(rid)\n",
226
- " ranked.append((hashlib.sha256(rid.encode()).hexdigest(),\n",
227
- " si, ri, rid))\n",
228
- " ri += 1\n",
229
- " ranked.sort()\n",
230
- " assert len(ranked) > 4 * EVAL_N, (\n",
231
- " f\"only {len(ranked)} rows survive the audit gate \"\n",
232
- " f\"(saw {n_seen}, gated {n_gated}, dup {n_dup}) \u2014 inspect before \"\n",
233
- " \"training on so little\")\n",
234
- " eval_set = {(si, ri) for _h, si, ri, _k in ranked[:EVAL_N]}\n",
235
- " keep_set = {(si, ri) for _h, si, ri, _k in ranked}\n",
236
- "\n",
237
- " # pass 2: route rows, appending the derived caption column\n",
238
- " ew = tw = None\n",
239
- " for si, pth in enumerate(_paths):\n",
240
- " pf = pq.ParquetFile(pth)\n",
241
- " names = pf.schema_arrow.names\n",
242
- " ri = 0\n",
243
- " for batch in pf.iter_batches(batch_size=64):\n",
244
- " tbl = pa.Table.from_batches([batch])\n",
245
- " jc = tbl.column(\"caption_joycaption\")\n",
246
- " pfu = (tbl.column(\"prompt_fused\")\n",
247
- " if \"prompt_fused\" in names else None)\n",
248
- " caps, kmask, emask = [], [], []\n",
249
- " for j in range(tbl.num_rows):\n",
250
- " c = jc[j].as_py() or (pfu[j].as_py() if pfu is not None\n",
251
- " else None) or \"\"\n",
252
- " caps.append(str(c))\n",
253
- " kmask.append((si, ri + j) in keep_set)\n",
254
- " emask.append((si, ri + j) in eval_set)\n",
255
- " ri += tbl.num_rows\n",
256
- " tbl = tbl.append_column(\"caption\", pa.array(caps))\n",
257
- " esub = tbl.filter(pa.array(emask))\n",
258
- " tsub = tbl.filter(pa.array([k and not e for k, e\n",
259
- " in zip(kmask, emask)]))\n",
260
- " if esub.num_rows:\n",
261
- " if ew is None:\n",
262
- " ew = pq.ParquetWriter(EVAL_PARQUET, esub.schema)\n",
263
- " ew.write_table(esub)\n",
264
- " if tsub.num_rows:\n",
265
- " if tw is None:\n",
266
- " tw = pq.ParquetWriter(TRAIN_DIR / \"train.parquet\",\n",
267
- " tsub.schema)\n",
268
- " tw.write_table(tsub)\n",
269
- " for w in (ew, tw):\n",
270
- " if w:\n",
271
- " w.close()\n",
272
  " MANIFEST.write_text(json.dumps(\n",
273
- " {\"dataset\": ANIMA[\"DATASET\"], \"rows_seen\": n_seen,\n",
274
- " \"gated_out\": n_gated, \"duplicate_ids\": n_dup,\n",
275
- " \"rows_kept\": len(ranked), \"eval_n\": EVAL_N,\n",
276
- " \"eval_ids\": [k for _h, _s, _r, k in ranked[:EVAL_N]],\n",
 
 
277
  " \"caption_rule\": \"caption_joycaption or prompt_fused fallback \"\n",
278
  " \"(dexp011:154; cond = caption_joycaption nl77)\",\n",
279
  " \"gate_rule\": \"age_audit/audit must contain approved|pass \"\n",
280
  " \"(dexp011:98-105)\",\n",
281
- " \"split_rule\": \"sha256(id) ascending; first EVAL_N are eval\"},\n",
 
282
  " indent=1))\n",
283
- " print(f\"split: seen {n_seen} -> gated {n_gated}, dup {n_dup}, kept \"\n",
284
- " f\"{len(ranked)} = {len(ranked) - EVAL_N} train + {EVAL_N} eval\")\n",
 
285
  "else:\n",
286
  " _m = json.loads(MANIFEST.read_text())\n",
287
- " print(f\"split already materialized: kept {_m['rows_kept']} \"\n",
288
- " f\"(gated {_m['gated_out']}, dup {_m['duplicate_ids']})\")\n",
289
  "\n",
290
  "# -- dataset TOMLs (fused recipe: derived caption column) -----------------\n",
291
- "_wh = (\"image_width_column = 'image_width'\\n\"\n",
292
- " \"image_height_column = 'image_height'\\n\") if ANIMA[\"HAS_WH\"] else \"\"\n",
293
- "\n",
294
  "def _dataset_toml(files):\n",
295
  " return f\"\"\"# generated by anima_closeout.ipynb\n",
296
  "resolutions = [512]\n",
@@ -305,7 +317,9 @@
305
  "type = 'parquet'\n",
306
  "parquet_files = '{files}'\n",
307
  "image_column = 'image'\n",
308
- "{_wh}caption_column = 'caption'\n",
 
 
309
  "caption_type = 'text'\n",
310
  "num_repeats = 1\n",
311
  "skip_empty_caption = true\n",
 
171
  "execution_count": null,
172
  "outputs": [],
173
  "source": [
174
+ "# \u2550\u2550\u2550 CELL 1 \u2014 materialize the gated split INCREMENTALLY \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n",
175
+ "# The fused dataset is ~160GB across 200+ shards; the campaign needs ~9k\n",
176
+ "# rows. So: NEVER download the corpus. Shards are visited in sha256(name)\n",
177
+ "# order (deterministic, free of curation-order bias), one at a time; each\n",
178
+ "# is gated + deduped + slimmed into the pool, then its source file is\n",
179
+ "# DELETED; we stop the moment the row target is met. Disk stays bounded at\n",
180
+ "# roughly one source shard + the materialized output.\n",
181
+ "#\n",
182
+ "# Row rules, verbatim from the campaign record:\n",
183
+ "# AUDIT GATE (pod2/dexp011:98-105): age_audit/audit must contain\n",
184
+ "# \"approved\" or \"pass\" (case-insensitive); gated rows counted loudly.\n",
185
+ "# CAPTION = caption_joycaption or prompt_fused fallback (dexp011:154;\n",
186
+ "# cond = \"caption_joycaption nl77\"), materialized as `caption`.\n",
187
+ "# DEDUP by id (first occurrence wins).\n",
188
+ "# SPLIT: within the pool, sha256(id) ascending; first EVAL_N are eval.\n",
189
+ "import hashlib, json, os, shutil\n",
190
  "import pyarrow as pa\n",
191
  "import pyarrow.parquet as pq\n",
192
  "from huggingface_hub import hf_hub_download\n",
193
  "\n",
194
+ "TRAIN_TARGET = 8192 # ~2.7x exp004's criticized 2978; 10k steps @ mbs8\n",
195
+ "EVAL_N = 512 # = 80k samples ~= 9 epochs over this pool\n",
196
+ "KEEP_COLS = [\"id\", \"image\", \"image_width\", \"image_height\",\n",
197
+ " \"caption\", \"fused_json\", \"age_audit\"] # slim rows only\n",
198
+ "\n",
199
  "TRAIN_DIR = DATA / \"train\"; TRAIN_DIR.mkdir(exist_ok=True)\n",
200
  "EVAL_PARQUET = DATA / \"eval.parquet\"\n",
201
  "MANIFEST = DATA / \"split_manifest.json\"\n",
202
+ "SRC = DATA / \"src\"; SRC.mkdir(exist_ok=True)\n",
203
  "\n",
204
+ "def _passes_gate(val_of):\n",
205
+ " vals = [str(val_of(c)) for c in (\"age_audit\", \"audit\")\n",
206
+ " if val_of(c) is not None]\n",
207
  " return (not vals) or any((\"approved\" in v.lower() or \"pass\" in v.lower())\n",
208
  " for v in vals)\n",
209
  "\n",
210
  "if not MANIFEST.exists():\n",
211
+ " # deterministic pseudo-random shard order \u2014 never curation order\n",
212
+ " shard_order = sorted(\n",
213
+ " ANIMA[\"SHARDS\"],\n",
214
+ " key=lambda n: hashlib.sha256(n.encode()).hexdigest())\n",
215
+ "\n",
216
+ " pool = [] # slim row dicts\n",
217
+ " seen_ids = set()\n",
 
218
  " n_seen = n_gated = n_dup = 0\n",
219
+ " shards_used = []\n",
220
+ " target = TRAIN_TARGET + EVAL_N\n",
221
+ "\n",
222
+ " for sh in shard_order:\n",
223
+ " if len(pool) >= target:\n",
224
+ " break\n",
225
+ " local = hf_hub_download(ANIMA[\"DATASET\"], sh, repo_type=\"dataset\",\n",
226
+ " local_dir=str(SRC))\n",
227
+ " pf = pq.ParquetFile(local)\n",
228
+ " names = pf.schema_arrow.names\n",
229
+ " cols = [c for c in (\"id\", \"image\", \"image_width\", \"image_height\",\n",
230
+ " \"caption_joycaption\", \"prompt_fused\",\n",
231
+ " \"fused_json\", \"age_audit\", \"audit\")\n",
232
+ " if c in names]\n",
233
+ " for batch in pf.iter_batches(batch_size=32, columns=cols):\n",
234
+ " if len(pool) >= target:\n",
235
+ " break\n",
236
+ " data = {c: batch.column(c) for c in\n",
237
+ " (set(cols) & set(batch.schema.names))}\n",
238
  " for j in range(batch.num_rows):\n",
239
+ " if len(pool) >= target:\n",
240
+ " break\n",
241
  " n_seen += 1\n",
242
+ " get = lambda c: (data[c][j].as_py() if c in data else None)\n",
 
243
  " if not _passes_gate(get):\n",
244
  " n_gated += 1\n",
245
+ " continue\n",
246
+ " rid = str(get(\"id\"))\n",
247
+ " if rid in seen_ids:\n",
248
  " n_dup += 1\n",
249
+ " continue\n",
250
+ " cap = get(\"caption_joycaption\") or get(\"prompt_fused\") or \"\"\n",
251
+ " if not str(cap).strip():\n",
252
+ " n_gated += 1 # empty caption: unusable row\n",
253
+ " continue\n",
254
+ " seen_ids.add(rid)\n",
255
+ " pool.append({\n",
256
+ " \"id\": rid, \"image\": get(\"image\"),\n",
257
+ " \"image_width\": get(\"image_width\"),\n",
258
+ " \"image_height\": get(\"image_height\"),\n",
259
+ " \"caption\": str(cap),\n",
260
+ " \"fused_json\": str(get(\"fused_json\") or \"\"),\n",
261
+ " \"age_audit\": str(get(\"age_audit\") or \"\")})\n",
262
+ " shards_used.append(sh)\n",
263
+ " shutil.rmtree(SRC, ignore_errors=True) # bound the disk\n",
264
+ " SRC.mkdir(exist_ok=True)\n",
265
+ " print(f\"[split] {sh}: pool {len(pool)}/{target} \"\n",
266
+ " f\"(seen {n_seen}, gated {n_gated}, dup {n_dup})\", flush=True)\n",
267
+ "\n",
268
+ " assert len(pool) >= target, (\n",
269
+ " f\"exhausted ALL shards with only {len(pool)} usable rows \"\n",
270
+ " f\"(target {target}) \u2014 inspect the gate before training\")\n",
271
+ "\n",
272
+ " # split within the pool: sha256(id) ascending, first EVAL_N are eval\n",
273
+ " pool.sort(key=lambda r: hashlib.sha256(r[\"id\"].encode()).hexdigest())\n",
274
+ " eval_rows, train_rows = pool[:EVAL_N], pool[EVAL_N:target]\n",
275
+ "\n",
276
+ " def _write(rows, path):\n",
277
+ " tbl = pa.table({c: [r[c] for r in rows] for c in KEEP_COLS})\n",
278
+ " pq.write_table(tbl, path)\n",
279
+ " return tbl.num_rows\n",
280
+ "\n",
281
+ " ne = _write(eval_rows, EVAL_PARQUET)\n",
282
+ " nt = _write(train_rows, TRAIN_DIR / \"train.parquet\")\n",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
283
  " MANIFEST.write_text(json.dumps(\n",
284
+ " {\"dataset\": ANIMA[\"DATASET\"],\n",
285
+ " \"shard_order\": \"sha256(shard_name) ascending\",\n",
286
+ " \"shards_used\": shards_used, \"rows_seen\": n_seen,\n",
287
+ " \"gated_or_empty\": n_gated, \"duplicate_ids\": n_dup,\n",
288
+ " \"train_rows\": nt, \"eval_n\": ne,\n",
289
+ " \"eval_ids\": [r[\"id\"] for r in eval_rows],\n",
290
  " \"caption_rule\": \"caption_joycaption or prompt_fused fallback \"\n",
291
  " \"(dexp011:154; cond = caption_joycaption nl77)\",\n",
292
  " \"gate_rule\": \"age_audit/audit must contain approved|pass \"\n",
293
  " \"(dexp011:98-105)\",\n",
294
+ " \"split_rule\": \"sha256(id) ascending within the pool; first \"\n",
295
+ " \"EVAL_N are eval\"},\n",
296
  " indent=1))\n",
297
+ " print(f\"split DONE: {nt} train + {ne} eval from \"\n",
298
+ " f\"{len(shards_used)}/{len(ANIMA['SHARDS'])} shards \"\n",
299
+ " f\"(seen {n_seen}, gated/empty {n_gated}, dup {n_dup})\")\n",
300
  "else:\n",
301
  " _m = json.loads(MANIFEST.read_text())\n",
302
+ " print(f\"split already materialized: {_m['train_rows']} train + \"\n",
303
+ " f\"{_m['eval_n']} eval from {len(_m['shards_used'])} shards\")\n",
304
  "\n",
305
  "# -- dataset TOMLs (fused recipe: derived caption column) -----------------\n",
 
 
 
306
  "def _dataset_toml(files):\n",
307
  " return f\"\"\"# generated by anima_closeout.ipynb\n",
308
  "resolutions = [512]\n",
 
317
  "type = 'parquet'\n",
318
  "parquet_files = '{files}'\n",
319
  "image_column = 'image'\n",
320
+ "image_width_column = 'image_width'\n",
321
+ "image_height_column = 'image_height'\n",
322
+ "caption_column = 'caption'\n",
323
  "caption_type = 'text'\n",
324
  "num_repeats = 1\n",
325
  "skip_empty_caption = true\n",