| """ |
| BLiMP + BLiMP Supplement 覆盖率分析 |
| |
| 对每个子任务: |
| 1. 提取 good 句中的"判别性关键词"(good有但bad没有的词) |
| 2. 统计这些词在训练数据(3_dedup)里的总频次 |
| 3. 输出每个子任务的覆盖得分,找出弱点 |
| """ |
|
|
| import json, re |
| from pathlib import Path |
| from collections import Counter, defaultdict |
|
|
| ROOT = Path(__file__).parent.parent.parent |
| BLIMP_DIR = ROOT / "evaluation-pipeline-2025/evaluation_data/full_eval/blimp_filtered" |
| SUPP_DIR = ROOT / "evaluation-pipeline-2025/evaluation_data/full_eval/supplement_filtered" |
| TRAIN_DIR = ROOT / "data/3_dedup" |
| OUT_DIR = ROOT / "results/analysis" |
| OUT_DIR.mkdir(parents=True, exist_ok=True) |
|
|
| TRAIN_FILES = [ |
| "gutenberg.train.txt", |
| "simple_wiki.train.txt", |
| "bnc_spoken.train.txt", |
| "switchboard.train.txt", |
| "open_subtitles_cleaned_ckpt_70.txt", |
| "childes.train.txt", |
| "open_subtitles.train.txt", |
| ] |
|
|
| def tokenize(text): |
| return re.findall(r"[a-z']+", text.lower()) |
|
|
| |
| print("统计训练数据词频...") |
| train_freq = Counter() |
| train_total = 0 |
| for fname in TRAIN_FILES: |
| path = TRAIN_DIR / fname |
| if not path.exists(): |
| continue |
| with open(path, errors="ignore") as f: |
| for line in f: |
| words = tokenize(line) |
| train_total += len(words) |
| train_freq.update(words) |
| print(f" 训练数据总词数: {train_total:,}") |
|
|
| |
| def analyze_task(jfile): |
| good_words = Counter() |
| bad_words = Counter() |
| n_pairs = 0 |
| with open(jfile) as f: |
| for line in f: |
| d = json.loads(line) |
| good_words.update(tokenize(d["sentence_good"])) |
| bad_words.update(tokenize(d["sentence_bad"])) |
| n_pairs += 1 |
|
|
| |
| discriminative = {} |
| for w, gc in good_words.items(): |
| bc = bad_words.get(w, 0) |
| if gc - bc >= max(3, gc * 0.3): |
| discriminative[w] = gc - bc |
|
|
| |
| if not discriminative: |
| return None |
|
|
| top_words = sorted(discriminative.items(), key=lambda x: -x[1])[:10] |
| coverage_scores = [] |
| for w, diff in top_words: |
| per_million = train_freq.get(w, 0) / train_total * 1e6 |
| coverage_scores.append((w, diff, per_million)) |
|
|
| |
| avg_coverage = sum(s for _, _, s in coverage_scores) / len(coverage_scores) |
|
|
| return { |
| "task": jfile.stem, |
| "n_pairs": n_pairs, |
| "top_keywords": coverage_scores, |
| "avg_coverage": avg_coverage, |
| } |
|
|
| |
| print("\n分析 BLiMP 子任务...") |
| blimp_results = [] |
| for jfile in sorted(BLIMP_DIR.glob("*.jsonl")): |
| r = analyze_task(jfile) |
| if r: |
| blimp_results.append(r) |
|
|
| |
| print("分析 BLiMP Supplement 子任务...") |
| supp_results = [] |
| for jfile in sorted(SUPP_DIR.glob("*.jsonl")): |
| r = analyze_task(jfile) |
| if r: |
| supp_results.append(r) |
|
|
| |
| def print_results(results, title): |
| print(f"\n{'='*70}") |
| print(f"{title}(按覆盖率从低到高,最需要补充的在前)") |
| print(f"{'='*70}") |
| print(f"{'子任务':<45} {'覆盖分':>8} {'关键词(每百万词)'}") |
| print("─" * 70) |
| for r in sorted(results, key=lambda x: x["avg_coverage"]): |
| kw_str = ", ".join(f"{w}({s:.0f})" for w, _, s in r["top_keywords"][:4]) |
| print(f"{r['task']:<45} {r['avg_coverage']:>8.1f} {kw_str}") |
|
|
| print_results(blimp_results, "BLiMP 子任务覆盖分析") |
| print_results(supp_results, "BLiMP Supplement 覆盖分析") |
|
|
| |
| import json as _json |
| out_path = OUT_DIR / "blimp_coverage.json" |
| _json.dump({"blimp": blimp_results, "supplement": supp_results}, |
| open(out_path, "w"), ensure_ascii=False, indent=2) |
| print(f"\n完整结果已保存: {out_path}") |
|
|