Upload build/build_mix.py with huggingface_hub
Browse files- build/build_mix.py +58 -3
build/build_mix.py
CHANGED
|
@@ -375,23 +375,59 @@ def stage(args, st, tokenizer):
|
|
| 375 |
|
| 376 |
# --------------------------------------------------------------------- merge
|
| 377 |
def merge(args, st, tokenizer):
|
| 378 |
-
"""Interleave staged documents proportionally to each source's staged token total.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 379 |
vocab = tokenizer.get_vocab_size()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 380 |
streams = []
|
| 381 |
for src in SOURCES:
|
| 382 |
key = src_key(src)
|
| 383 |
rec = st.d["staged"].get(key)
|
| 384 |
if not rec or not rec.get("shards"):
|
| 385 |
continue
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 386 |
weight = rec.get("tokens") or sum(s["tokens"] for s in rec["shards"])
|
|
|
|
| 387 |
if weight <= 0:
|
|
|
|
| 388 |
continue
|
| 389 |
iters = [iter_shard_docs(os.path.join(st.root, s["file"])) for s in rec["shards"]]
|
| 390 |
|
| 391 |
-
def gen(its=iters):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 392 |
for it in its:
|
| 393 |
for d in it:
|
| 394 |
-
|
|
|
|
|
|
|
| 395 |
|
| 396 |
streams.append({"key": key, "weight": float(weight), "credit": 0.0, "it": gen(iters),
|
| 397 |
"pending": None, "emitted_tokens": 0, "exhausted": False})
|
|
@@ -520,6 +556,9 @@ def main():
|
|
| 520 |
"empty string disables sync")
|
| 521 |
ap.add_argument("--stage-only", action="store_true")
|
| 522 |
ap.add_argument("--merge-only", action="store_true")
|
|
|
|
|
|
|
|
|
|
| 523 |
args = ap.parse_args()
|
| 524 |
|
| 525 |
if args.only:
|
|
@@ -608,6 +647,22 @@ def main():
|
|
| 608 |
default=0),
|
| 609 |
"seconds": round(time.monotonic() - t0, 1),
|
| 610 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 611 |
with open(os.path.join(args.root, "manifest.json"), "w") as f:
|
| 612 |
json.dump(manifest, f, indent=1)
|
| 613 |
# Nothing may be printed between the JSON and its END marker: the caller parses this span with
|
|
|
|
| 375 |
|
| 376 |
# --------------------------------------------------------------------- merge
|
| 377 |
def merge(args, st, tokenizer):
|
| 378 |
+
"""Interleave staged documents proportionally to each source's staged token total.
|
| 379 |
+
|
| 380 |
+
--exclude-dir applies per-source uint8 masks written by audit_contamination --write-filter: a 1 byte
|
| 381 |
+
means "this document's 13-grams appear in a benchmark train/validation/dev split, do not emit it"
|
| 382 |
+
(§3.3). Masks are indexed by document ordinal within the source, which is stable because both the
|
| 383 |
+
audit and the merge replay the source's own record.json shard order.
|
| 384 |
+
"""
|
| 385 |
vocab = tokenizer.get_vocab_size()
|
| 386 |
+
masks, dropped = {}, {}
|
| 387 |
+
if args.exclude_dir:
|
| 388 |
+
fj = os.path.join(args.exclude_dir, "filter.json")
|
| 389 |
+
if not os.path.exists(fj):
|
| 390 |
+
print(f"FATAL: --exclude-dir {args.exclude_dir} contains no filter.json", flush=True)
|
| 391 |
+
sys.exit(5)
|
| 392 |
+
dropped = json.load(open(fj)).get("sources", {})
|
| 393 |
+
for key in sorted(os.listdir(args.exclude_dir)):
|
| 394 |
+
if key.endswith(".u8"):
|
| 395 |
+
with open(os.path.join(args.exclude_dir, key), "rb") as fh:
|
| 396 |
+
masks[key[:-3]] = fh.read()
|
| 397 |
+
print(f"exclude: {len(masks)} mask(s), "
|
| 398 |
+
f"{sum(len(m) for m in masks.values()):,} docs covered, "
|
| 399 |
+
f"{sum(int(v.get('dropped_docs', 0)) for v in dropped.values()):,} flagged", flush=True)
|
| 400 |
streams = []
|
| 401 |
for src in SOURCES:
|
| 402 |
key = src_key(src)
|
| 403 |
rec = st.d["staged"].get(key)
|
| 404 |
if not rec or not rec.get("shards"):
|
| 405 |
continue
|
| 406 |
+
staged_docs = sum(int(s.get("docs", 0)) for s in rec["shards"])
|
| 407 |
+
m = masks.get(key)
|
| 408 |
+
if m is not None and len(m) != staged_docs:
|
| 409 |
+
# A short mask would silently keep exactly the documents the audit did not reach.
|
| 410 |
+
print(f"FATAL: mask for {key} covers {len(m)} docs but {staged_docs} are staged", flush=True)
|
| 411 |
+
sys.exit(5)
|
| 412 |
weight = rec.get("tokens") or sum(s["tokens"] for s in rec["shards"])
|
| 413 |
+
weight = weight - int((dropped.get(key) or {}).get("dropped_tokens", 0))
|
| 414 |
if weight <= 0:
|
| 415 |
+
print(f" {key}: fully excluded, dropped from the merge", flush=True)
|
| 416 |
continue
|
| 417 |
iters = [iter_shard_docs(os.path.join(st.root, s["file"])) for s in rec["shards"]]
|
| 418 |
|
| 419 |
+
def gen(its=iters, m=m):
|
| 420 |
+
if m is None:
|
| 421 |
+
for it in its:
|
| 422 |
+
for d in it:
|
| 423 |
+
yield d
|
| 424 |
+
return
|
| 425 |
+
i = 0
|
| 426 |
for it in its:
|
| 427 |
for d in it:
|
| 428 |
+
if not m[i]:
|
| 429 |
+
yield d
|
| 430 |
+
i += 1
|
| 431 |
|
| 432 |
streams.append({"key": key, "weight": float(weight), "credit": 0.0, "it": gen(iters),
|
| 433 |
"pending": None, "emitted_tokens": 0, "exhausted": False})
|
|
|
|
| 556 |
"empty string disables sync")
|
| 557 |
ap.add_argument("--stage-only", action="store_true")
|
| 558 |
ap.add_argument("--merge-only", action="store_true")
|
| 559 |
+
ap.add_argument("--exclude-dir", default="",
|
| 560 |
+
help="directory of per-source <key>.u8 contamination masks + filter.json written by "
|
| 561 |
+
"audit_contamination --write-filter; documents flagged there are not merged (§3.3)")
|
| 562 |
args = ap.parse_args()
|
| 563 |
|
| 564 |
if args.only:
|
|
|
|
| 647 |
default=0),
|
| 648 |
"seconds": round(time.monotonic() - t0, 1),
|
| 649 |
}
|
| 650 |
+
if args.exclude_dir:
|
| 651 |
+
# Provenance: a filtered mix is only reproducible if the exclusion set travels with it, so the
|
| 652 |
+
# counts go in the manifest and the mask bytes go in mixroot/filter/ (publish_mix ships them).
|
| 653 |
+
try:
|
| 654 |
+
fj = json.load(open(os.path.join(args.exclude_dir, "filter.json")))
|
| 655 |
+
manifest["contamination_filter"] = {
|
| 656 |
+
"criterion": fj.get("criterion"), "k": fj.get("k"),
|
| 657 |
+
"docs_dropped": sum(int(v.get("dropped_docs", 0)) for v in fj["sources"].values()),
|
| 658 |
+
"tokens_dropped": sum(int(v.get("dropped_tokens", 0) or 0)
|
| 659 |
+
for v in fj["sources"].values()),
|
| 660 |
+
"per_source": {k2: {"docs": v2.get("dropped_docs"),
|
| 661 |
+
"tokens": v2.get("dropped_tokens")}
|
| 662 |
+
for k2, v2 in fj["sources"].items()}}
|
| 663 |
+
except Exception as e:
|
| 664 |
+
print(f"FATAL: --exclude-dir set but filter.json unreadable: {e}", flush=True)
|
| 665 |
+
sys.exit(5)
|
| 666 |
with open(os.path.join(args.root, "manifest.json"), "w") as f:
|
| 667 |
json.dump(manifest, f, indent=1)
|
| 668 |
# Nothing may be printed between the JSON and its END marker: the caller parses this span with
|