finetune_moss-sortformer / docs /data_prepare_debug.md
czyhust's picture
Full upload
74e4281 verified
|
Raw
History Blame Contribute Delete
5.55 kB

数据准备问题排查

现象

推理报错

KeyError: 'file .../multispeaker_session_7.wav is already part of AUDIO_RTTM_MAP, 
it might be duplicated, Note: file basename must be unique'

训练异常(6小时训炸)

用户推测为数据问题导致,与推理报错同源。


根因分析

1. Manifest 格式不匹配

数据准备脚本 run_all_speakers_simulation.sh 生成的 manifest 为 训练格式(segment-level)

{"audio_filepath": ".../multispeaker_session_0.wav", "offset": 1.164,  "duration": 19.82, ...}
{"audio_filepath": ".../multispeaker_session_0.wav", "offset": 20.692, "duration": 1.825, ...}
{"audio_filepath": ".../multispeaker_session_0.wav", "offset": 21.982, "duration": 39.57,  ...}

同一个 wav 文件通过不同 offset/duration 被切分为多个 segment 行。训练 dataloader 按 segment 逐条加载,这是正确的。

但推理脚本 e2e_diarize_speech.py:370 调用 audio_rttm_map() 时:

# speaker_utils.py:113
uniqname = get_uniqname_from_filepath(filepath=meta['audio_filepath'])
# → os.path.splitext(os.path.basename(filepath))[0]
# → "multispeaker_session_0"   (所有 segment 返回相同的值)

if uniqname not in AUDIO_RTTM_MAP:
    AUDIO_RTTM_MAP[uniqname] = meta
else:
    raise KeyError(...)   # 第二条 segment 触发此分支

get_uniqname_from_filepath() 仅取 basename,不区分 offset。当同一个 wav 文件有多个 segment 行时,第二条及之后的行必定触发 KeyError。

2. 推理期望的 Manifest 格式

推理端 audio_rttm_map() 设计的前提是 每个 wav 文件只出现一次,即 file-level manifest

{"audio_filepath": ".../multispeaker_session_0.wav", "offset": 0, "duration": null, "rttm_filepath": ".../multispeaker_session_0.rttm", "num_speakers": 10}
{"audio_filepath": ".../multispeaker_session_1.wav", "offset": 0, "duration": null, "rttm_filepath": ".../multispeaker_session_1.rttm", "num_speakers": 10}

关键字段:

  • offset = 0(从文件开头处理)
  • duration = null(处理完整文件)

3. 当前数据结构

Manifest 行数 唯一 wav 文件数 平均 segment/wav 格式
train.json 24,804 1,800 13.8 segment-level
dev.json 3,842 180 21.3 segment-level
test.json 3,772 180 21.0 segment-level

所有 split 均包含重复的 audio_filepath,直接用于推理必然报错。

4. 训练异常的原因推测

训练不会直接调用 audio_rttm_map(),因此 KeyError 不会出现在训练 loop 中。但以下问题可能导致训练失败:

  1. 显存 OOM:当前 10spk config 中 batch_size=12session_len_sec=1200,在 V100-32G 上可能显存不足。
  2. Validation 阶段问题:如果训练配置中某些验证逻辑间接调用了 audio_rttm_map(),会触发同样的 KeyError。
  3. 数据完整性:segment 切分生成时可能存在边界不齐、重叠或缺失的问题。

修复方案

方案 1: 生成推理专用 Manifest(推荐)

#!/usr/bin/env python3
"""从 segment-level manifest 生成 file-level inference manifest"""
import json
import os
from pathlib import Path

def generate_infer_manifest(segment_manifest_path: str, output_path: str):
    seen = set()
    with open(segment_manifest_path) as f_in, open(output_path, 'w') as f_out:
        for line in f_in:
            d = json.loads(line)
            key = d.get('audio_filepath')
            if not key or key in seen:
                continue
            seen.add(key)
            # file-level format for inference
            entry = {
                "audio_filepath": d["audio_filepath"],
                "offset": 0,
                "duration": None,
                "rttm_filepath": d.get("rttm_filepath"),
                "num_speakers": d.get("num_speakers"),
                "text": "-",
            }
            f_out.write(json.dumps(entry) + "\n")
    print(f"Generated {len(seen)} entries → {output_path}")

if __name__ == "__main__":
    base = "data/dump/simulated_10spk_dataset"
    for split in ["train", "dev", "test"]:
        generate_infer_manifest(
            f"{base}/{split}.json",
            f"{base}/{split}_infer.json",
        )

生成后修改 infer.shdataset_manifest 指向新的 test_infer.json

方案 2: 修改音频文件命名避免冲突

确保数据仿真时每个 segment 对应独立命名的 wav 文件(multispeaker_session_0_seg001.wav),但这会增加大量文件复制/软链接。

方案 3: 修改 audio_rttm_map() 对重复做去重

# speaker_utils.py:115
if uniqname not in AUDIO_RTTM_MAP:
    AUDIO_RTTM_MAP[uniqname] = meta
else:
    logging.warning(f"Duplicate audio entry skipped: {meta['audio_filepath']}")
    continue

但这只是绕过错误,不代表推理正确——后续逻辑仍可能因缺少正确的 file-level 映射而出错。


建议的完整修复流程

  1. 用方案 1 脚本生成 train_infer.json / dev_infer.json / test_infer.json
  2. 推理时使用 test_infer.json 作为 manifest
  3. 训练时继续使用 train.json / dev.json(segment-level 格式)
  4. 为避免后续混淆,在 run_all_speakers_simulation.sh 末尾自动生成 file-level manifest
  5. 测试训练:用 batch_size 从小开始(如 2-4),观察 GPU 显存使用和 loss 趋势,逐步上调