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

Upload build/audit_contamination.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. build/audit_contamination.py +69 -14
build/audit_contamination.py CHANGED
@@ -28,6 +28,7 @@
28
  # Read-only over the mix. CPU session. No credentials in this file.
29
 
30
  import argparse
 
31
  import json
32
  import os
33
  import struct
@@ -93,6 +94,17 @@ def window_hashes(ids, k=K):
93
  return h
94
 
95
 
 
 
 
 
 
 
 
 
 
 
 
96
  def flatten(v, out):
97
  if isinstance(v, str):
98
  out.append(v)
@@ -212,8 +224,8 @@ def build_reference(tk, max_items_per_split):
212
  else datasets.load_dataset(repo, split=sp, streaming=True))
213
  n, g = ingest(tk, ds, max_items_per_split)
214
  except Exception as e:
215
- errors[ckey] = f"{type(e).__name__}: {str(e)[:140]}"
216
- print(f" ref {ckey}: UNREADABLE {type(e).__name__}: {str(e)[:80]}", flush=True)
217
  continue
218
  if want and n < int(0.9 * want):
219
  print(f" ref {ckey}: {n} of {want} rows via datasets -> rows-API fallback",
@@ -270,20 +282,23 @@ def per_task_counts(bits):
270
  return [int((bits & np.uint16(1 << ti)).astype(np.uint16).sum()) for ti in range(len(REFS))]
271
 
272
 
273
- def scan_docs(ref, refmask, docs):
274
  """Fold an iterator of (ordinal_within_source, raw_bytes) into counts.
275
 
276
  The ordinal is the only identity a document ever gets here: a filter pass can drop it by index later
277
  without anything in this process knowing what it said. `hit_docs_over_half` is the column that decides
278
  interpretation -- contamination by verbatim inclusion shows up as documents whose grams are *mostly*
279
  matched, while one shared boilerplate sentence shows up as a single gram in a handful of documents.
 
 
280
  """
281
  import time
282
  import hashlib
283
  t0 = time.time()
284
  s = {"docs": 0, "tokens": 0, "grams": 0, "hit_docs": 0, "hits": 0, "hit_docs_over_half": 0,
285
  "hit_tokens": 0, "dup_docs": 0, "dup_tokens": 0, "per_task": [0] * len(REFS), "ordinals": []}
286
- seen = set()
 
287
  names = [t[0] for t in REFS]
288
  for idx, raw in docs:
289
  b = bytes(raw)
@@ -381,7 +396,9 @@ def main():
381
  json.dump(srv, open(os.path.join(a.ref_cache, "srv.json"), "w"))
382
  print(f"reference cached under {a.ref_cache}", flush=True)
383
  tasks_covered = sorted({k.split("::")[0] for k, v in refcounts.items()
384
- if v >= MIN_ITEMS_PER_SPLIT})
 
 
385
  print(f"reference: {ref.size:,} grams, {len(tasks_covered)}/8 tasks covered, "
386
  f"{len(errors)} loader problems", flush=True)
387
 
@@ -397,7 +414,13 @@ def main():
397
  for key in sorted(os.listdir(stage_root)):
398
  sd = os.path.join(stage_root, key)
399
  rd = os.path.join(sd, "record.json")
400
- if not os.path.isdir(sd) or not os.path.exists(rd):
 
 
 
 
 
 
401
  continue
402
  rec = json.load(open(rd))
403
  paths = [os.path.join(a.root, s["file"]) for s in rec.get("shards", [])]
@@ -424,15 +447,25 @@ def main():
424
  docs = grams_seen = mix_tokens = hit_docs = hit_docs_over_half = 0
425
  dup_docs = dup_tokens = 0
426
  missing = []
 
 
427
  if os.path.exists(man_path):
428
  man = json.load(open(man_path))
 
 
 
 
 
 
 
 
429
  for rec in man["shards"]:
430
  p = os.path.join(a.root, rec["file"])
431
  if not os.path.exists(p):
432
  # A shard not on disk is unmeasured, not clean (E-017's shape).
433
  missing.append(rec["file"])
434
  continue
435
- s = scan_docs(ref, refmask, doc_stream(BM, [p]))
436
  docs += s["docs"]
437
  mix_tokens += s["tokens"]
438
  grams_seen += s["grams"]
@@ -442,21 +475,35 @@ def main():
442
  dup_tokens += s["dup_tokens"]
443
  for n, c in s["per_task_named"].items():
444
  hits[n] = hits.get(n, 0) + c
445
- total_overlap = sum(hits.values())
446
- print(f" mix: {docs:,} docs, {grams_seen:,} grams, {total_overlap:,} hits in {hit_docs:,} docs "
447
- f"({hit_docs_over_half:,} majority-hit)", flush=True)
 
 
 
 
 
 
 
 
 
 
 
 
448
  else:
449
  total_overlap = 0
450
  print(f"no manifest at {a.root}: merged mix not scanned", flush=True)
451
 
452
- expected_fp = grams_seen * int(np.unique(ref).size) / float(1 << 64)
 
453
  noise_allow = max(10.0, 10.0 * expected_fp)
454
  per_task_named = {t[0]: hits.get(t[0], 0) for t in REFS}
455
 
456
  if a.write_filter:
457
  os.makedirs(a.write_filter, exist_ok=True)
458
  summary = {"k": K, "criterion": "any 13-gram of the document appears in a reference "
459
- "train/validation/dev split", "sources": {}}
 
460
  for key, (ord_sorted, n_docs) in masks.items():
461
  m = np.zeros(n_docs, dtype=np.uint8)
462
  if ord_sorted.size:
@@ -488,6 +535,11 @@ def main():
488
  "mix_grams_audited": grams_seen,
489
  "mix_documents_with_any_hit": hit_docs,
490
  "mix_documents_majority_hit": hit_docs_over_half,
 
 
 
 
 
491
  "overlap_by_task": per_task_named,
492
  "overlap_total": total_overlap,
493
  "by_source": by_source,
@@ -504,8 +556,11 @@ def main():
504
  "mix_documents_majority_hit and source_hit_document_fraction to judge severity. "
505
  "Duplicate counting is diagnostic only: de-duplication is out of scope (D-014), "
506
  "contamination removal is not (§3.3)."),
507
- "COVERED_ALL_SHARDS": bool(not missing and docs > 0),
508
- "MEASURED": bool(docs > 0 and grams_seen > 0 and not errors and len(tasks_covered) == 8),
 
 
 
509
  }
510
  report["AUDIT_PASSED"] = bool(report["MEASURED"] and total_overlap <= noise_allow)
511
  txt = json.dumps(report, indent=1, default=str)
 
28
  # Read-only over the mix. CPU session. No credentials in this file.
29
 
30
  import argparse
31
+ import hashlib
32
  import json
33
  import os
34
  import struct
 
94
  return h
95
 
96
 
97
+ def brief_error(e):
98
+ """Short, publishable description of a loader failure.
99
+
100
+ This report is shipped with the mix, and an exception string from a dataset reader can quote a cell of
101
+ benchmark text -- exactly the thing §3.3 keeps out of every artifact. Quoted spans are replaced.
102
+ """
103
+ import re
104
+ msg = re.sub(r"'[^']*'|\"[^\"]*\"", "'…'", str(e).replace("\n", " "))
105
+ return f"{type(e).__name__}: {msg[:140]}"
106
+
107
+
108
  def flatten(v, out):
109
  if isinstance(v, str):
110
  out.append(v)
 
224
  else datasets.load_dataset(repo, split=sp, streaming=True))
225
  n, g = ingest(tk, ds, max_items_per_split)
226
  except Exception as e:
227
+ errors[ckey] = brief_error(e)
228
+ print(f" ref {ckey}: UNREADABLE {brief_error(e)}", flush=True)
229
  continue
230
  if want and n < int(0.9 * want):
231
  print(f" ref {ckey}: {n} of {want} rows via datasets -> rows-API fallback",
 
282
  return [int((bits & np.uint16(1 << ti)).astype(np.uint16).sum()) for ti in range(len(REFS))]
283
 
284
 
285
+ def scan_docs(ref, refmask, docs, seen=None):
286
  """Fold an iterator of (ordinal_within_source, raw_bytes) into counts.
287
 
288
  The ordinal is the only identity a document ever gets here: a filter pass can drop it by index later
289
  without anything in this process knowing what it said. `hit_docs_over_half` is the column that decides
290
  interpretation -- contamination by verbatim inclusion shows up as documents whose grams are *mostly*
291
  matched, while one shared boilerplate sentence shows up as a single gram in a handful of documents.
292
+ Pass one `seen` set across a whole mix, otherwise the duplicate count is per-shard and only a lower
293
+ bound (found in review).
294
  """
295
  import time
296
  import hashlib
297
  t0 = time.time()
298
  s = {"docs": 0, "tokens": 0, "grams": 0, "hit_docs": 0, "hits": 0, "hit_docs_over_half": 0,
299
  "hit_tokens": 0, "dup_docs": 0, "dup_tokens": 0, "per_task": [0] * len(REFS), "ordinals": []}
300
+ if seen is None:
301
+ seen = set()
302
  names = [t[0] for t in REFS]
303
  for idx, raw in docs:
304
  b = bytes(raw)
 
396
  json.dump(srv, open(os.path.join(a.ref_cache, "srv.json"), "w"))
397
  print(f"reference cached under {a.ref_cache}", flush=True)
398
  tasks_covered = sorted({k.split("::")[0] for k, v in refcounts.items()
399
+ if v >= MIN_ITEMS_PER_SPLIT} -
400
+ {k.split("::")[0] for k in errors
401
+ if "::" in k and "[" not in k and not k.startswith("stage::")})
402
  print(f"reference: {ref.size:,} grams, {len(tasks_covered)}/8 tasks covered, "
403
  f"{len(errors)} loader problems", flush=True)
404
 
 
414
  for key in sorted(os.listdir(stage_root)):
415
  sd = os.path.join(stage_root, key)
416
  rd = os.path.join(sd, "record.json")
417
+ if not os.path.isdir(sd):
418
+ continue
419
+ if not os.path.exists(rd):
420
+ # Absent record means the source never finished staging or was built without a Hub
421
+ # repo. Treating it as "nothing to scan" would merge it unfiltered (review finding).
422
+ errors[f"stage::{key}"] = "no record.json -- source is incomplete or unpublished"
423
+ print(f" stage {key}: NO record.json, source left unscanned", flush=True)
424
  continue
425
  rec = json.load(open(rd))
426
  paths = [os.path.join(a.root, s["file"]) for s in rec.get("shards", [])]
 
447
  docs = grams_seen = mix_tokens = hit_docs = hit_docs_over_half = 0
448
  dup_docs = dup_tokens = 0
449
  missing = []
450
+ val = {"docs": 0, "tokens": 0, "grams": 0, "hit_docs": 0, "hits": 0, "hit_docs_over_half": 0}
451
+ manifest_digest = None
452
  if os.path.exists(man_path):
453
  man = json.load(open(man_path))
454
+ # Bound this report to the exact bytes it scanned: publish_mix re-computes the digest from the
455
+ # manifest it is about to ship, so an audit.json carried over from a different mix -- even one of
456
+ # the same total size -- is refused instead of certifying it.
457
+ manifest_digest = hashlib.sha256(json.dumps(
458
+ [[s["file"], s.get("tokens"), s.get("docs")] for s in man["shards"]] +
459
+ [["VAL:" + s["file"], s.get("tokens"), s.get("docs")] for s in man.get("val_shards", [])],
460
+ sort_keys=True).encode()).hexdigest()
461
+ seen_all = set() # one set across the whole mix, so duplicates are counted, not floored
462
  for rec in man["shards"]:
463
  p = os.path.join(a.root, rec["file"])
464
  if not os.path.exists(p):
465
  # A shard not on disk is unmeasured, not clean (E-017's shape).
466
  missing.append(rec["file"])
467
  continue
468
+ s = scan_docs(ref, refmask, doc_stream(BM, [p]), seen=seen_all)
469
  docs += s["docs"]
470
  mix_tokens += s["tokens"]
471
  grams_seen += s["grams"]
 
475
  dup_tokens += s["dup_tokens"]
476
  for n, c in s["per_task_named"].items():
477
  hits[n] = hits.get(n, 0) + c
478
+ # The held-out split is reported on, so it must be scanned too. A benchmark document sitting in
479
+ # validation would flatter every validation-PPL number this project publishes, and nothing else
480
+ # in the pipeline reads those bytes (review finding).
481
+ for rec in man.get("val_shards", []):
482
+ p = os.path.join(a.root, rec["file"])
483
+ if not os.path.exists(p):
484
+ missing.append(rec["file"])
485
+ continue
486
+ v = scan_docs(ref, refmask, doc_stream(BM, [p]), seen=seen_all)
487
+ for k2 in ("docs", "tokens", "grams", "hit_docs", "hits", "hit_docs_over_half"):
488
+ val[k2] += int(v.get(k2, 0))
489
+ total_overlap = sum(hits.values()) + val["hits"]
490
+ print(f" mix: {docs:,} docs, {grams_seen:,} grams, {sum(hits.values()):,} train hits in "
491
+ f"{hit_docs:,} docs ({hit_docs_over_half:,} majority-hit); val: {val['docs']:,} docs, "
492
+ f"{val['hits']:,} hits in {val['hit_docs']:,} docs", flush=True)
493
  else:
494
  total_overlap = 0
495
  print(f"no manifest at {a.root}: merged mix not scanned", flush=True)
496
 
497
+ grams_all = grams_seen + val["grams"]
498
+ expected_fp = grams_all * int(np.unique(ref).size) / float(1 << 64)
499
  noise_allow = max(10.0, 10.0 * expected_fp)
500
  per_task_named = {t[0]: hits.get(t[0], 0) for t in REFS}
501
 
502
  if a.write_filter:
503
  os.makedirs(a.write_filter, exist_ok=True)
504
  summary = {"k": K, "criterion": "any 13-gram of the document appears in a reference "
505
+ "train/validation/dev split",
506
+ "scanned_sources": sorted(masks), "sources": {}}
507
  for key, (ord_sorted, n_docs) in masks.items():
508
  m = np.zeros(n_docs, dtype=np.uint8)
509
  if ord_sorted.size:
 
535
  "mix_grams_audited": grams_seen,
536
  "mix_documents_with_any_hit": hit_docs,
537
  "mix_documents_majority_hit": hit_docs_over_half,
538
+ "val_documents_audited": val["docs"],
539
+ "val_tokens_audited": val["tokens"],
540
+ "val_documents_with_any_hit": val["hit_docs"],
541
+ "val_hits": val["hits"],
542
+ "mix_bytes_sha256": manifest_digest,
543
  "overlap_by_task": per_task_named,
544
  "overlap_total": total_overlap,
545
  "by_source": by_source,
 
556
  "mix_documents_majority_hit and source_hit_document_fraction to judge severity. "
557
  "Duplicate counting is diagnostic only: de-duplication is out of scope (D-014), "
558
  "contamination removal is not (§3.3)."),
559
+ "COVERED_ALL_SHARDS": bool(not missing and docs > 0 and val["docs"] > 0),
560
+ "FILTER_MASKS_WRITTEN": sorted(masks) if a.write_filter else None,
561
+ "MEASURED": bool(docs > 0 and grams_seen > 0 and val["docs"] > 0 and not errors
562
+ and len(tasks_covered) == 8 and manifest_digest
563
+ and (not a.write_filter or masks)),
564
  }
565
  report["AUDIT_PASSED"] = bool(report["MEASURED"] and total_overlap <= noise_allow)
566
  txt = json.dumps(report, indent=1, default=str)