# Simulation Data Pipelines 本文档描述 G-STAR finetuning pipeline 中两条独立的多说话人数据仿真流水线:**FastMSS 流水线(主)**和 **NeMo 流水线(旧)**。 --- ## 一、全局概览 两条流水线共享 LibriSpeech 源数据,但在仿真引擎、中间格式和最终产物上完全不同。 ``` ┌─── LibriSpeech 源数据 ──────────────┐ │ WHAM/MUSAN 噪声 │ │ │ ┌─────▼──────────────────────────────────┐ │ │ PIPE A: NeMo 仿真流水线(旧) │ │ │ data_simulation_nemo.sh │ │ │ run_all_speakers_simulation_nemo.sh │ │ │ → sentence_level_multispeaker_ │ │ │ simulator.py │ │ │ → utterance-level JSON │ │ │ → standardize_manifest_format.py │ │ │ → segment-level JSONL │ │ └────────────────────────────────────────┘ │ │ ┌─────▼──────────────────────────────────┐ │ │ PIPE B: FastMSS 仿真流水线(主) │ │ │ data_simulation_fastmss.sh │ │ │ run_fastmss-*.sh │ │ │ → recipes/sim.py (5-stage Hydra) │ │ │ → Lhotse CutSet → WAV + RTTM │ │ │ → nemo_manifest.jsonl │ │ └────────────────────────────────────────┘ │ │ ┌─────▼──────────────────────────────────┐ │ │ Training / Inference │ │ │ train.sh → streaming_sortformer_ │ │ │ diar_train.py │ │ │ infer.sh → e2e_diarize_speech.py │ │ │ (消耗 segment-level JSONL) │ │ └────────────────────────────────────────┘ │ ``` --- ## 二、根目录 Shell 脚本总览 | 脚本 | 用途 | 所属流水线 | |---|---|---| | `data/nemo/simulate.sh` | NeMo 单次仿真:并行跑 train/dev/test | Pipe A | | `data/nemo/run_all_speakers.sh` | NeMo 全量仿真:遍历 2-10 spk,合并输出,标准化为 JSONL | Pipe A | | `data/fastmss/simulate.sh` | FastMSS 单次仿真入口:调用 `recipes/sim.py` + 分析脚本 | Pipe B | | `data/fastmss/run_6spk_v1.sh` | v1 config: 90s, WHAM noise, 1-6 spk, 30k train / 3k dev / 3k test | Pipe B | | `data/fastmss/run_6spk_v1.1.sh` | v1.1 config: 50% reverb/noise 概率, 2-6 spk, speed perturbation | Pipe B | | `data/fastmss/run_6spk_v2.sh` | v2 config: WHAM + MUSAN 双噪声源, 基于 v1.1 | Pipe B | | `data/fastmss/run_mini_testset.sh` | 小测试集: 600 meetings, seed=45, 8 workers, 用于调试验证 | Pipe B | | `train.sh` | Sortformer 微调入口 (Hydra) | 训练 | | `run_finetune_8spk.sh` | 8-spk 微调预设 | 训练 | | `run_train_10spk.sh` | 10-spk 微调预设(从 4-spk checkpoint 扩展) | 训练 | | `infer.sh` | 流式 diarization 推理 + DER 评估 | 推理 | | `run_infer_8spk.sh` / `run_infer_8spk_base.sh` | 8-spk 推理(微调模型 / 预训练 baseline) | 推理 | | `path.sh` | 环境配置:PYTHONPATH + conda env 激活 | 全局 | | `data/nemo/prepare_data.sh` | 6 阶段数据预处理(详见第三节) | Pipe A 前置 | --- ## 三、Pipe A:NeMo 仿真流水线(旧) ### 3.1 数据预处理:`data/nemo/prepare_data.sh` 为 NeMo 模拟器准备 LibriSpeech + WHAM 源数据,共 6 个阶段(stage 参数控制): | 阶段 | 脚本 | 说明 | |---|---|---| | Stage 1 | `data/nemo/scripts/get_librispeech_data.py` | FLAC → WAV 转换(sox),生成 JSON manifest | | Stage 2 | `data/nemo/scripts/create_alignment_manifest.py` | 集成 CorentinJ 格式的词级对齐,产出 CTM + 对齐 manifest | | Stage 3 | `data/shared/scripts/pathfiles_to_diarize_manifest.py` | WHAM 噪声 wav → diarization manifest | | Stage 4 | `cat` | 合并 train clean_100+360+other_500 → train_960(test/dev 同理) | | Stage 5 | `data/fastmss/scripts/get_max_audio_duration.py` | 分析仿真数据集音频时长分布(直方图 + CDF) | | Stage 6 | `data/shared/scripts/split_manifest_by_spk.py` | 按说话人数拆分标准化 manifest(≤4 / >4) | ### 3.2 仿真过程 ``` data_simulation_nemo.sh → sentence_level_multispeaker_simulator.py → 输出:utterance-level JSON(每行一个 utterance) → standardize_manifest_format.py → 输出:segment-level JSONL(每行一个音频段) → split_manifest_by_spk.py → 输出:按 spk 数拆分的 JSONL ``` **核心脚本:`data/nemo/scripts/sentence_level_multispeaker_simulator.py`** - NeMo `MultiSpeakerSimulator` 的子类 - 以整句为单位拼接(非词级 chunk) - 可配置 silence/overlap/session_length/spk_count - 输出 utterance-level JSON + RTTM 文件 **桥接脚本:`data/nemo/scripts/standardize_manifest_format.py`** - NeMo utterance-level JSON → 标准 segment-level JSONL - 添加 `uniq_id` 字段防止 key 冲突 - 这是训练/推理实际消费的格式 ### 3.3 相关文件清单 ``` data/ ├── prepare_data.sh # 6 阶段数据预处理 ├── conf/default_data_simulator.yaml # NeMo 仿真器配置 └── scripts/ ├── get_librispeech_data.py # FLAC→WAV + manifest ├── create_alignment_manifest.py # 对齐 manifest ├── pathfiles_to_diarize_manifest.py # 噪声 manifest ├── sentence_level_multispeaker_simulator.py # 句子级模拟器(入口) ├── multispeaker_simulator.py # 词级模拟器(旧,已弃用) ├── standardize_manifest_format.py # 格式标准化(桥接) └── get_max_audio_duration.py # 时长分布分析 ``` --- ## 四、Pipe B:FastMSS 仿真流水线(主) ### 4.1 前置准备 FastMSS 的输入是 Lhotse CutSet(含词级对齐),由以下脚本生成: **`data/fastmss/scripts/create_cutsets.py`** - 从 `/F00120240032/librispeech/.../lhotse_format_manifests/` 读取 recordings + supervisions manifests - 生成 `librispeech_cutset_{split}.jsonl.gz` **`src/third_party/FastMSS/scripts/split_musan.py`**(v2 新增) - 将 MUSAN 噪声按 8:1:1 拆分到 `{tr,cv,tt}.wavlist` ### 4.2 仿真过程 ``` run_fastmss-*.sh → data_simulation_fastmss.sh → src/third_party/FastMSS/recipes/sim.py (Hydra 5 阶段流水线) → Stage 1: 加载 CutSet → 停顿处切分 → 保存 merged CutSet → Stage 2: 扫描噪声目录/wavlist → 过滤短噪声 → noise_files.txt → Stage 3: RIRSimulator → pyroomacoustics → all_rooms.json → Stage 4: ConversationalMeetingSimulator → 并行生成 WAV + Lhotse manifests → Stage 5: 生成 RTTM + nemo_manifest.jsonl → analyze_speaker_distribution.py → analyze_duration_distribution.py ``` ### 4.3 `recipes/sim.py` 5 阶段详解 | 阶段 | 输入 | 输出 | 说明 | |---|---|---|---| | **Stage 1** | `librispeech_cutset_{split}.jsonl.gz` | `{data_dir}/manifests/all_cuts.jsonl.gz` | 加载 CutSet,merge 指定 split,在词对齐停顿处切分 utterance | | **Stage 2** | 噪声目录 + wavlist 文件 | `{output_dir}/manifests/noise_files.txt` | 递归扫描音频文件(支持目录 glob 和 wavlist 逐行读取),过滤 <2s 的短噪声 | | **Stage 3** | 房间/麦克风/RIR 配置 | `{rir_dir}/all_rooms.json` | pyroomacoustics 生成房间脉冲响应,可配 RT60/房间尺寸/麦克风类型 | | **Stage 4** | CutSet + 噪声 + RIR | WAV 文件 + Lhotse manifests | 并行生成 n_meetings 场会议:HMM 轮次切换、spk 权重采样、增益随机化、RIR 卷积、噪声混合 | | **Stage 5** | Stage 4 manifests | RTTM 文件 + `nemo_manifest.jsonl` | 生成逐 meeting 的 RTTM(0.2s 间隙合并),生成 NeMo 格式 diarization manifest | ### 4.4 配置文件层级 ``` src/third_party/FastMSS/recipes/ ├── default.yaml # 基础配置 └── extend_sortformer/6spk/ ├── v1.yaml # 6-spk base: 90s, WHAM, RIR, Markov HMM ├── v1.1.yaml # 增强版: 50% reverb/noise, speed perturbation ├── v2.yaml # 新增 MUSAN 双噪声 └── dataset_splits/ ├── train.yaml # cutset_train-clean-{100,360,500} ├── dev.yaml # cutset_dev-{clean,other} └── test.yaml # cutset_test-{clean,other} ``` ### 4.5 相关文件清单 ``` src/third_party/FastMSS/ ├── fastmss/ │ ├── simulator.py # ConversationalMeetingSimulator 核心引擎 │ ├── hmm_turn_taking.py # 4 状态 HMM 轮次模型 │ ├── rirsimulator.py # RIR 生成器 (pyroomacoustics) │ └── utils.py # 音频工具 ├── recipes/ │ ├── sim.py # 5 阶段 Hydra 仿真入口 │ ├── default.yaml │ └── extend_sortformer/6spk/ # 6-spk 配置 ├── scripts/ │ ├── split_musan.py # MUSAN 噪声拆分 │ ├── analyze_speaker_distribution.py # 说话人分布统计 │ └── analyze_duration_distribution.py # 时长分布统计 └── preprocessing/ ├── download_wham.sh # 下载 WHAM 噪声 └── download_otospeech.sh # 下载 otoSpeech ``` --- ## 五、两条流水线对比 | 维度 | Pipe A (NeMo) | Pipe B (FastMSS) | |---|---|---| | **模仿真引擎** | `sentence_level_multispeaker_simulator.py` | `recipes/sim.py` (Hydra) | | **输入格式** | LibriSpeech WAV + 对齐 JSON | Lhotse CutSet (`.jsonl.gz`) | | **轮次模型** | 简单 silence/overlap 控制 | 4 状态 Markov HMM(hold/switch/interruption/backchannel) | | **房间仿真** | NeMo RIRMultiSpeakerSimulator | pyroomacoustics RIRSimulator | | **噪声输入** | WHAM dir | 目录 + wavlist(支持 WHAM/MUSAN 等) | | **仿真粒度** | 句子级 chunk 拼接 | 词级对齐切分,更细粒度 | | **并行策略** | Shell 级 `&` 后台并行 | Python 多进程 `parallel_map` | | **中间输出** | utterance-level JSON | Lhotse Recording + Supervision manifests | | **最终产物** | segment-level JSONL(需 `standardize_manifest_format.py` 转换) | `nemo_manifest.jsonl`(直接可用) | | **当前状态** | 旧流水线,用于 10-spk | **主线流水线**,用于 Sortformer 微调 | --- ## 六、关键桥接脚本 | 脚本 | 方向 | 说明 | |---|---|---| | `data/fastmss/scripts/create_cutsets.py` | Lhotse manifests → CutSet | 为 FastMSS 生成输入 | | `data/nemo/scripts/standardize_manifest_format.py` | NeMo utterance JSON → segment JSONL | 为训练/推理转换格式 | **注意**:FastMSS Stage 5 直接产出 `nemo_manifest.jsonl`,格式与训练/推理消费的 segment-level JSONL 兼容,无需额外转换步骤。 --- ## 七、典型使用流程 ### 使用 FastMSS (Pipe B) 生成 v2 数据集: ```bash # 1. 拆分 MUSAN(仅 v2 需要) python src/third_party/FastMSS/scripts/split_musan.py /path/to/musan data/dump_fastmss/musan_noise_wavlists # 2. 运行仿真(生成 train/dev/test) bash run_fastmss-extend_sortformer-6spk-dataset_v2.sh # 3. 产物位于 data/dump_fastmss/simulated_sessions/extend_sortformer-6spk-dataset_v2/{train,dev,test}/ # 每个目录包含: audio/*.wav, rttm/*.rttm, nemo_manifest.jsonl ``` ### 使用 NeMo (Pipe A) 生成 10-spk 数据集: ```bash # 1. 预处理 bash data/prepare_data.sh # 2. 全量仿真 bash run_all_speakers_simulation_nemo.sh ``` --- ## 八、路径约定 | 用途 | 默认路径 | 说明 | |---|---|---| | LibriSpeech | `/F00120240032/librispeech/corpus_librispeech/corpus` | 源数据 | | lhotse manifests | `/F00120240032/librispeech/.../lhotse_format_manifests` | FastMSS 输入 | | WHAM noise | `/F00120240032/wham_noise/wham_noise/wham_noise/{tr,cv,tt}` | 噪声目录 | | LibriSpeech Alignments | `/F00120240032/LibriSpeech-Alignments` | 词级对齐 | | FastMSS 输出 | `data/dump_fastmss/simulated_sessions/{version}/{split}/` | 仿真产物 | | NeMo 输出 | `data/dump/simulated_10spk_dataset/` | 旧流水线产物 | | 训练输出 | `exp/` | gitignored | | 模型 checkpoints | `checkpoints/` | gitignored |