GooGooLM / scripts /01_data /run_all.py
XiaoyanLi's picture
Initial upload: code, training data, tokenizers, notes
83112d8 verified
Raw
History Blame Contribute Delete
7.11 kB
"""
01_data 数据流水线总控
按顺序执行所有数据处理阶段
阶段概览:
1 噪声过滤 → data/1_noise_filtered/
2 OOV过滤 → data/2_oov_filtered/
3 精确去重 → data/3_dedup/
4 格式预处理 → data/4_preprocessed/
5 规则标注 → data/5_rule_labels/
6 Qwen语义标注 → data/6_qwen_labels/ (需GPU)
7 评测句提取 → data/7_eval_sentences/
8A 采样-纯质量基线 → data/8_sample_A/train.txt
8B 采样-配额+质量 → data/8_sample_B/train.txt
8C 采样-加权采样 → data/8_sample_C/train.txt
8D 采样-Embedding → data/8_sample_D/train.txt (需GPU)
用法:
python scripts/01_data/run_all.py # 跑所有阶段 (1-8A)
python scripts/01_data/run_all.py --stage 5 # 只跑某一阶段
python scripts/01_data/run_all.py --from 7 # 从某阶段开始跑
python scripts/01_data/run_all.py --stage 8 # 跑所有 stage 8 采样 (A/B/C/D)
python scripts/01_data/run_all.py --stage 8B # 只跑 stage 8B
python scripts/01_data/run_all.py --stage 8D # 只跑 stage 8D (Embedding)
"""
import argparse
import subprocess
import sys
from pathlib import Path
ROOT = Path(__file__).parent.parent.parent
# ── 阶段定义 ────────────────────────────────────────────────────────────────────
# type="io" : 标准 input/output 参数
# type="plain" : 无参数直接运行
STAGES = [
{
"id": "1", "name": "噪声过滤 (CHAT标注 / 时间戳 / 极短行)",
"script": "stage1_noise_filter.py", "type": "io",
"input": "data/raw_files", "output": "data/1_noise_filtered",
},
{
"id": "2", "name": "OOV过滤 (低频噪声词过多的句子)",
"script": "stage2_oov_filter.py", "type": "io",
"input": "data/1_noise_filtered", "output": "data/2_oov_filtered",
},
{
"id": "3", "name": "精确去重(全局 MD5)",
"script": "stage3_dedup.py", "type": "io",
"input": "data/2_oov_filtered", "output": "data/3_dedup",
},
{
"id": "4", "name": "格式预处理(去说话人前缀 / 全大写规范 / 标题行过滤)",
"script": "stage4_preprocess.py", "type": "io",
"input": "data/3_dedup", "output": "data/4_preprocessed",
},
{
"id": "5", "name": "规则标注(BLiMP 67子任务 / BLiMP Supplement / EWoK 11域)",
"script": "stage5_rule_label.py", "type": "io",
"input": "data/4_preprocessed", "output": "data/5_rule_labels",
},
{
"id": "6", "name": "Qwen语义标注(9维度深度分析,需GPU)",
"script": "stage6_qwen_label.py", "type": "io",
"input": "data/4_preprocessed", "output": "data/6_qwen_labels",
},
{
"id": "7", "name": "评测句提取",
"script": "stage7a_extract_eval.py", "type": "plain",
},
{
"id": "8A", "name": "采样方案A:纯质量基线",
"script": "stage8_sample_A.py", "type": "plain",
},
{
"id": "8B", "name": "采样方案B:任务配额 + 质量填充",
"script": "stage8_sample_B.py", "type": "plain",
},
{
"id": "8C", "name": "采样方案C:加权采样",
"script": "stage8_sample_C.py", "type": "plain",
},
{
"id": "8D", "name": "采样方案D:Embedding 相似度采样(需GPU)",
"script": "stage8_sample_D.py", "type": "plain",
},
]
def run_stage(stage):
script = Path(__file__).parent / stage["script"]
print(f"\n{'='*60}")
print(f"阶段 {stage['id']}: {stage['name']}")
print(f" 脚本: {script.name}")
if stage["type"] == "io":
print(f" 输入: {ROOT / stage['input']}")
print(f" 输出: {ROOT / stage['output']}")
print(f"{'='*60}")
if stage["type"] == "io":
cmd = [sys.executable, str(script),
"--input_dir", str(ROOT / stage["input"]),
"--output_dir", str(ROOT / stage["output"])]
else:
cmd = [sys.executable, str(script)]
result = subprocess.run(cmd, check=False)
if result.returncode != 0:
print(f"\n[ERROR] 阶段 {stage['id']} 失败,退出码 {result.returncode}")
sys.exit(result.returncode)
print(f"\n[OK] 阶段 {stage['id']} 完成")
def match_stages(selector: str) -> list[dict]:
"""根据选择器匹配阶段。支持: "5", "8", "8B", "8D" 等。"""
selector = selector.upper()
matched = []
for s in STAGES:
sid = s["id"].upper()
if sid == selector:
matched.append(s)
elif selector.isdigit() and sid.startswith(selector):
# "8" 匹配 "8A", "8B", "8C", "8D"
matched.append(s)
return matched
def main():
parser = argparse.ArgumentParser(
description="01_data 数据流水线总控",
formatter_class=argparse.RawDescriptionHelpFormatter,
)
parser.add_argument("--stage", type=str, default=None,
help="只运行指定阶段(如 --stage 5, --stage 8, --stage 8B)")
parser.add_argument("--from", type=str, default="1", dest="from_stage",
help="从指定阶段开始运行(如 --from 7)")
parser.add_argument("--to", type=str, default=None, dest="to_stage",
help="运行到指定阶段为止(如 --to 6)")
parser.add_argument("--list", action="store_true",
help="列出所有阶段")
args = parser.parse_args()
if args.list:
print("可用阶段:")
for s in STAGES:
print(f" {s['id']:4s} {s['name']}")
return
if args.stage is not None:
stages_to_run = match_stages(args.stage)
else:
# --from / --to 范围选择(只匹配纯数字前缀)
from_idx = 0
to_idx = len(STAGES)
for i, s in enumerate(STAGES):
num = s["id"].rstrip("ABCD")
if num == args.from_stage:
from_idx = i
break
if args.to_stage:
for i, s in enumerate(STAGES):
num = s["id"].rstrip("ABCD")
if num == args.to_stage:
# 包含该阶段的所有子阶段
to_idx = i + 1
while to_idx < len(STAGES) and STAGES[to_idx]["id"].startswith(args.to_stage):
to_idx += 1
break
stages_to_run = STAGES[from_idx:to_idx]
if not stages_to_run:
print(f"没有找到匹配的阶段: {args.stage or args.from_stage}")
print("使用 --list 查看所有可用阶段")
sys.exit(1)
print(f"将运行 {len(stages_to_run)} 个阶段: {[s['id'] for s in stages_to_run]}")
for stage in stages_to_run:
run_stage(stage)
print(f"\n{'='*60}")
print("数据流水线完成!")
print(f"{'='*60}")
if __name__ == "__main__":
main()