Instructions to use czyhust/finetune_moss-sortformer with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- NeMo
How to use czyhust/finetune_moss-sortformer with NeMo:
# tag did not correspond to a valid NeMo domain.
- Notebooks
- Google Colab
- Kaggle
数据准备问题排查
现象
推理报错
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 中。但以下问题可能导致训练失败:
- 显存 OOM:当前 10spk config 中
batch_size=12、session_len_sec=1200,在 V100-32G 上可能显存不足。 - Validation 阶段问题:如果训练配置中某些验证逻辑间接调用了
audio_rttm_map(),会触发同样的 KeyError。 - 数据完整性: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.sh 中 dataset_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 脚本生成
train_infer.json/dev_infer.json/test_infer.json - 推理时使用
test_infer.json作为 manifest - 训练时继续使用
train.json/dev.json(segment-level 格式) - 为避免后续混淆,在
run_all_speakers_simulation.sh末尾自动生成 file-level manifest - 测试训练:用
batch_size从小开始(如 2-4),观察 GPU 显存使用和 loss 趋势,逐步上调