Cion-lab commited on
Commit
9e79358
·
verified ·
1 Parent(s): 7f57bf0

Upload build/build_mix.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. build/build_mix.py +48 -2
build/build_mix.py CHANGED
@@ -392,13 +392,20 @@ def merge(args, st, tokenizer):
392
  audit and the merge replay the source's own record.json shard order.
393
  """
394
  vocab = tokenizer.get_vocab_size()
395
- masks, dropped = {}, {}
396
  if args.exclude_dir:
397
  fj = os.path.join(args.exclude_dir, "filter.json")
398
  if not os.path.exists(fj):
399
  print(f"FATAL: --exclude-dir {args.exclude_dir} contains no filter.json", flush=True)
400
  sys.exit(5)
401
- dropped = json.load(open(fj)).get("sources", {})
 
 
 
 
 
 
 
402
  for key in sorted(os.listdir(args.exclude_dir)):
403
  if key.endswith(".u8"):
404
  with open(os.path.join(args.exclude_dir, key), "rb") as fh:
@@ -446,6 +453,42 @@ def merge(args, st, tokenizer):
446
  # silent success in this pipeline, so it is a failure and not a return.
447
  print("FATAL merge: nothing staged. Refusing to emit an empty mix.", flush=True)
448
  sys.exit(4)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
449
  total_w = sum(s["weight"] for s in streams)
450
  print(f"merge: {len(streams)} sources, "
451
  f"{sum(s['weight'] for s in streams) / 1e6:,.0f}M staged tokens", flush=True)
@@ -568,6 +611,9 @@ def main():
568
  ap.add_argument("--exclude-dir", default="",
569
  help="directory of per-source <key>.u8 contamination masks + filter.json written by "
570
  "audit_contamination --write-filter; documents flagged there are not merged (§3.3)")
 
 
 
571
  args = ap.parse_args()
572
 
573
  if args.only:
 
392
  audit and the merge replay the source's own record.json shard order.
393
  """
394
  vocab = tokenizer.get_vocab_size()
395
+ masks, dropped, filter_digest = {}, {}, None
396
  if args.exclude_dir:
397
  fj = os.path.join(args.exclude_dir, "filter.json")
398
  if not os.path.exists(fj):
399
  print(f"FATAL: --exclude-dir {args.exclude_dir} contains no filter.json", flush=True)
400
  sys.exit(5)
401
+ filter_digest = hashlib.sha256(open(fj, "rb").read()).hexdigest()
402
+ fj_obj = json.load(open(fj))
403
+ if not fj_obj.get("scanned_sources"):
404
+ print("FATAL: filter.json records no scanned_sources -- the audit that wrote it predates "
405
+ "the completeness field, so an unscanned source could be silently unfiltered. Re-run "
406
+ "audit_contamination --write-filter.", flush=True)
407
+ sys.exit(5)
408
+ dropped = fj_obj.get("sources", {})
409
  for key in sorted(os.listdir(args.exclude_dir)):
410
  if key.endswith(".u8"):
411
  with open(os.path.join(args.exclude_dir, key), "rb") as fh:
 
453
  # silent success in this pipeline, so it is a failure and not a return.
454
  print("FATAL merge: nothing staged. Refusing to emit an empty mix.", flush=True)
455
  sys.exit(4)
456
+ if args.exclude_dir:
457
+ # A missing mask must never mean "this source is clean" (review finding): it means the audit
458
+ # never scanned it, and the default behaviour would have been to merge every contaminated doc.
459
+ unscanned = [s["key"] for s in streams if s["key"] not in masks]
460
+ if unscanned:
461
+ print(f"FATAL merge: --exclude-dir has no mask for {unscanned}. Refusing to merge sources "
462
+ "the contamination audit did not read.", flush=True)
463
+ sys.exit(5)
464
+
465
+ # A re-merge is only correct if it starts from nothing. The loop below stops when merged_tokens()
466
+ # reaches the input total, so on a mixroot that already holds 141 shards it would emit ZERO new
467
+ # shards, exit 0, and let the manifest claim a filter that never happened (found in review while
468
+ # Gate 2c was running against exactly this path). Resume-after-a-kill stays legal -- it is the same
469
+ # inputs -- so the test is on a digest of the merge's inputs, not on whether shards exist.
470
+ digest = hashlib.sha256(json.dumps({
471
+ "streams": [[s["key"], round(s["weight"]) ] for s in streams], "seed": SHUFFLE_SEED,
472
+ "tokens_per_shard": TOKENS_PER_SHARD, "val_stride": VAL_STRIDE,
473
+ "filter": filter_digest}, sort_keys=True).encode()).hexdigest()
474
+ prior = st.d.get("merge_inputs")
475
+ if prior is not None and prior != digest and st.d["merged_shards"]:
476
+ if not (args.rebuild_merged or args.exclude_dir):
477
+ print("FATAL merge: the mix root already holds shards merged from DIFFERENT inputs "
478
+ f"(recorded {prior[:12]}, now {digest[:12]}). Continuing would be a silent no-op. "
479
+ "Pass --rebuild-merged to discard them deliberately.", flush=True)
480
+ sys.exit(6)
481
+ n_old = len(st.d["merged_shards"]) + len(st.d.get("val_shards", []))
482
+ for grp in ("merged_shards", "val_shards"):
483
+ for rec in st.d.get(grp, []):
484
+ p = os.path.join(st.root, rec["file"])
485
+ if os.path.exists(p):
486
+ os.remove(p)
487
+ st.d["merged_shards"] = []
488
+ st.d["val_shards"] = []
489
+ print(f"merge: inputs changed ({prior[:12]} -> {digest[:12]}); discarded {n_old} old shard(s) "
490
+ "and rebuilding from the staged sources", flush=True)
491
+ st.d["merge_inputs"] = digest
492
  total_w = sum(s["weight"] for s in streams)
493
  print(f"merge: {len(streams)} sources, "
494
  f"{sum(s['weight'] for s in streams) / 1e6:,.0f}M staged tokens", flush=True)
 
611
  ap.add_argument("--exclude-dir", default="",
612
  help="directory of per-source <key>.u8 contamination masks + filter.json written by "
613
  "audit_contamination --write-filter; documents flagged there are not merged (§3.3)")
614
+ ap.add_argument("--rebuild-merged", action="store_true",
615
+ help="discard shards already recorded in build_state.json before merging. Implied by "
616
+ "--exclude-dir, because a filter changes every shard's contents")
617
  args = ap.parse_args()
618
 
619
  if args.only: