GooGooLM / scripts /01_data /analyze_blimp_coverage.py
XiaoyanLi's picture
Initial upload: code, training data, tokenizers, notes
83112d8 verified
Raw
History Blame Contribute Delete
4.4 kB
"""
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())
# ── 1. 统计训练数据词频 ───────────────────────────────────
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:,}")
# ── 2. 分析每个BLiMP子任务 ───────────────────────────────
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
# 判别性关键词:good句里有,bad句里没有(或少很多)
discriminative = {}
for w, gc in good_words.items():
bc = bad_words.get(w, 0)
if gc - bc >= max(3, gc * 0.3): # good比bad多30%以上且至少差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,
}
# 分析BLiMP
print("\n分析 BLiMP 子任务...")
blimp_results = []
for jfile in sorted(BLIMP_DIR.glob("*.jsonl")):
r = analyze_task(jfile)
if r:
blimp_results.append(r)
# 分析BLiMP Supplement
print("分析 BLiMP Supplement 子任务...")
supp_results = []
for jfile in sorted(SUPP_DIR.glob("*.jsonl")):
r = analyze_task(jfile)
if r:
supp_results.append(r)
# ── 3. 输出结果 ──────────────────────────────────────────
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}")