| """ |
| 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 |
|
|
| |
| |
| |
|
|
| 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): |
| |
| 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_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() |
|
|