# ConvTasNet-Spatial **Repository Path**: deserted1011/ConvTasNet-Spatial ## Basic Information - **Project Name**: ConvTasNet-Spatial - **Description**: 远场目标说话人提取:Conv-TasNet + 6 路 ITD/ILD 空间特征早融合 - **Primary Language**: Python - **License**: BSD-3-Clause - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-28 - **Last Updated**: 2026-09-28 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 远场双说话人分离 · Conv-TasNet + 6 路 ITD/ILD 空间特征早融合 **纯 PyTorch 实现,离线可跑,只需要 `torch` + `numpy`。** > 输入一段 **≥3 通道**的远场阵列录音,输出 **两路**近场人声。 本仓库是 **2026 iCAN 大学生创新创业大赛 AI 应用创新挑战赛**参赛作品的模型与源代码。 模型以官方 Conv-TasNet(`JorisCos/ConvTasNet_Libri2Mix_sepclean_16k`)为起点, 在自建仿真远场训练集(5777 条 / 20.46 h)上微调 30 轮,并把 mask 网络的 `bottleneck` 1×1 卷积输入通道从 **512 扩到 518**,用于接入 6 路 ITD/ILD 空间特征。 其余结构(编码器 / TCN / 解码器 / mask 头)一字未改。 ## 30 秒跑通 ```bash pip install torch numpy soundfile scipy # torch 用 CPU 版即可 python conv_tasnet_spatial.py --check # 按 config.json 建网 + 载权重 + 前向 → PASS python spatial_feat.py --selftest # 特征提取器自校验 → PASS python separate.py 素材/main_meeting_pos_d8m_1580-141083-0053.wav --outdir 结果 ``` 输出 `结果/*_spk1.wav` 与 `*_spk2.wav` 两路 16 kHz 语音。 更短的一页版见 [`0_三步跑通.md`](0_三步跑通.md)。 不需要 GPU、不需要联网、不需要 `asteroid`、也不需要另下官方 `pytorch_model.bin`。 一条 4.04 秒的 7 通道样本:**CPU ≈ 3.1 s,GPU ≈ 2.5 s**。 ## 它是什么 / 不是什么 - **是**:远场**双说话人分离**模型 —— 把混在一起的两个人的声音分成两路。 - **不是**声纹条件 TSE:它不认识"谁",只负责"把人分开",不负责"挑出指定的人"。 - **不具备拒识能力**:目标人不在场时,它会把在场的另一个人完整输出。 - **不是流式**:整段(或分块)处理,有秒级延迟。 - **中文未经验证**:训练语料是英文。 - **仿真是仿真**:结论来自仿真远场,不等于真实录音上的表现。 ## 成绩(句级口径) **评测条件**:仿真远场测试网格 10800 条(3 房间 × 6 距离 × 600),统计单元 = 句子, 每个极性 **n = 300 句**;目标恒 az+0°、干扰恒 ±90°、SIR 恒 0 dB。 | 指标 | 值 | |---|---| | SI-SDR(选路后) | **6.3433 dB** | | SI-SDRi(选路后) | **6.3441 dB**(95% CI [6.0652, 6.6266]) | | WER | **0.3377**(混合直连 0.5809,相对降 **41.9%**) | | 与单通道基线(同数据、同轮数微调)的差 | ΔSI-SDRi **+0.0156 dB**(95% CI [−0.0118, +0.0447],句级 **p = 0.62**,**不显著**) | | ΔWER(同单通道基线) | **−0.0012**(句级 p = 0.68) | **如实说明**(这也是本仓库最想说清楚的一件事): - 空间特征带来的增益**很小**(+0.0156 dB),**句级统计不显著**; - 分房间:`office` +0.0086 dB(p = 0.51)、`meeting` +0.0079(p = 0.88)、`hall` +0.0303(p = 0.57); - ±45° 干扰方位下 +0.0173 dB(p = 0.39)—— 只能说"**未观察到崩塌**",不能说"有提升"; - 10 m 距离档结果不稳(正负向都出现过波动); - 负向样本(只有干扰人、无目标人)SI-SDRi 约 **−59 dB**,即完全没有拒识能力; - 干净数据上的上界(另一组对照条件)为 **+3.3297 dB**,与上面的网格增益**不是同一把尺子**,不要混引。 因此本仓库的贡献是:**完整实现并量化了"空间特征早融合"这条技术路线,给出可复现的结论**, 而不是宣称在分离质量上超过开源基线。 ## 输入要求(错了不会报错,只会静默变差) | 项 | 取值 | |---|---| | 通道数 | **≥ 3**(第 4 路起忽略;7 通道录音可直接用前 3 路) | | 前 3 路是什么 | **linear3 线性三麦**:ch0 / ch1 / ch2,间距 **2 cm** | | 参考麦 | **ch1**(波形只取这一路,**不是**对多通道求平均) | | 采样率 | **16 kHz**(其它采样率会自动重采样,需要 `scipy`) | | 阵列几何 | 写死为 y 轴 −2 / 0 / +2 cm | > 阵列几何、通道顺序、间距这三条是**写死**的。摆错或接错**不会报任何错**, > 只会让空间特征落到训练分布之外、结果悄悄变差。这是本模型最容易被误用的地方。 ## 输出 ```bash <输入名>_spk1.wav 16 kHz / PCM16 / 峰值归一 0.9 <输入名>_spk2.wav 同上 <输入名>_debug.png 逐帧 ITD/ILD 曲线 + 几何上限参考线(没装 matplotlib 时退化为 .csv) <输入名>_debug.csv 逐帧空间特征(原始量纲 + z 版) ``` > 输出是"**两路**",不是"目标那一路"。`_spk1` / `_spk2` 的编号是**任意**的,**先听再选**。 ## 目录结构 ``` . ├─ 0_三步跑通.md 一页三步跑通(先看这份) ├─ separate.py 主脚本:读录音 → 出两路 ├─ spatial_feat.py 空间特征提取器(6 通道 ITD/ILD) ├─ conv_tasnet_spatial.py 网络定义(纯 PyTorch) ├─ model_loader.py 加载与推理封装(严格加载 + 帧对齐) ├─ load_and_infer.py 最小示例:50 行看懂怎么加载、怎么喂 ├─ config.json 结构配方 + 空间特征契约 + 训练溯源 ├─ convtasnet_spatial.pt 权重:20 389 069 B / md5 c04bfb9257351ecb7b95bef369bfec6a / 345 张量 ├─ space_feat_stats.json 6 通道标准化标尺(md5 f0041eb724322535e0016b896722d2ff) ├─ 素材/ 6 条 7 通道 16 kHz 仿真样本 + 素材清单.csv ├─ README.md 本文档 ├─ LICENSE 本仓库原创代码与文档的许可(BSD-3-Clause) ├─ THIRD_PARTY_NOTICES.md 第三方组件许可与署名(asteroid MIT / 权重 CC BY-SA 4.0) └─ 训练记录/ 留档:ckpt_ep30.pt + 训练侧代码 + 随包官方底座 + 模型说明 ``` ## 训练口径 - **起点**:官方 `JorisCos/ConvTasNet_Libri2Mix_sepclean_16k` (20 394 640 B / md5 `42e901d57d7c2f79b9d8a74a8077b7b0`,随包在 `训练记录/代码/pretrained/`) - **训练集**:自建仿真远场训练集,**5777 条 / 原始 20.46 h** (装载丢弃短于 3 s 的 132 条 → 每 epoch 5645 条 / 可用 20.37 h) - **优化**:Adam,lr 1e-4 + warmup 500 步 + 余弦退火,weight decay 0; batch 2 × 累积 4 = **有效 8**;3 s 段(48000 样本);**PIT SI-SDR** 损失;梯度裁剪 5 - **其他**:`--deterministic` 开、seed 26;**30 epoch**,交付最后一个 epoch,不做验证集与早停 - **耗时**:30 epoch 实测 **19 090 s(≈5.3 h,约 4.1 it/s)** - **训练环境**:PyTorch 2.11.0+cu128 > 训练数据与仿真生成脚本**不在本仓库**(属于内部训练资产)。权重不可再生成,请备份 `convtasnet_spatial.pt`。 ## 结构对照 | | 官方 Conv-TasNet | **本模型** | 单通道基线(同数据、同轮数微调) | |---|---|---|---| | 输入 | 单通道波形 | 单通道波形(ch1)+ **6 路 ITD/ILD** | 单通道波形 | | `bottleneck` 输入通道 | 512 | **518** | 512 | | 参数量 | 5 066 929 | **5 067 697**(+768) | 5 066 929 | | FLOPs(1 s 输入) | — | 9.9451 G | 9.9436 G | | RTF(4 s,稳态) | — | 0.0049 | 0.0051 | | 需要什么硬件 | 任意麦克风 | **2 cm 间距线性三麦** | 任意麦克风 | 本模型相对官方底座**唯一的结构改动**就是 `bottleneck` 那一层的输入通道数 —— 这是"早融合空间特征" 这个自变量能被干净归因的前提。 结构参数(逐字抄自官方配方):`FreeFB`;`n_filters=512` / `kernel_size=32` / `stride=16`; `bn_chan=128` / `hid_chan=512` / `skip_chan=128` / `conv_kernel_size=3`; `n_blocks=8` / `n_repeats=3`;`n_src=2` / `norm_type=gLN` / `mask_act=relu`。 (官方配方里的 `sample_rate = 8000` 是官方自己写错的值,前向只走 `model(wav)`。) ## 一致性核验 本仓库的建模代码是自己写的(纯 PyTorch),所以必须证明它与训练时用的实现完全一致: 把**同一份权重**分别灌进「训练侧实现(asteroid 0.7.0)」与「本仓库实现」,喂同样输入逐元素比对: | 用例 | max 绝对差 | |---|---| | 随机波形 T = 16000(1 s) | **0.000e+00** | | 随机波形 T = 48000(3 s) | **0.000e+00** | | 真实仿真样本 T = 156066(9.75 s) | **0.000e+00** | | 同上,GPU | **0.000e+00** | 另有静态核验:张量名集合一致(345 / 345)、参数量一致(5 067 697)。 即:**换掉的是依赖,不是模型。** 唯一版本差异来自 `numpy` 浮点累加顺序, 实测 z 域特征 max 绝对差 = 4.6e-05,两路输出间 SI-SDR = 131 dB。 ## 来源、许可与致谢 **本仓库按部分适用不同许可**(逐件对照、许可原文与署名见 [`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md)): | 部分 | 来源 | 许可 | |---|---|---| | 算法 | Conv-TasNet(Luo & Mesgarani, TASLP 2019) | 论文 | | 参考实现 | asteroid 0.7.0(网络定义是它的逐行等价移植) | **MIT** | | 权重起点与配方 | HuggingFace `JorisCos/ConvTasNet_Libri2Mix_sepclean_16k`(作者 Cosentino Joris) | **CC BY-SA 4.0** | | **本模型微调权重** `convtasnet_spatial.pt`(含训练检查点 `训练记录/ckpt_ep30.pt`) | 拾音客(**改编自**上面的起点权重) | **CC BY-SA 4.0** | | 随包再分发的起点权重 `训练记录/代码/pretrained/` | 同上(原样再分发) | **CC BY-SA 4.0** | | 训练语音干声 | LibriSpeech(openslr.org/12) | CC BY 4.0 | | 房间冲激响应 | 自建(pyroomacoustics 镜像源法仿真) | MIT | | 本仓库**原创**的代码与文档 | 拾音客 | **BSD-3-Clause**(见 [`LICENSE`](LICENSE)) | - **改编声明(CC BY-SA 要求)**:`convtasnet_spatial.pt` 与训练检查点 `训练记录/ckpt_ep30.pt` 是在 Cosentino Joris 的 `ConvTasNet_Libri2Mix_sepclean_16k` 基础上**修改**得到的 —— 在自建仿真远场训练集上微调 30 轮, 并把 `masker.bottleneck` 的 1×1 卷积输入通道由 512 扩到 518,其余结构未改。 本仓库的微调权重与随包的起点权重均以 **CC BY-SA 4.0** 提供,署名 **Cosentino Joris**。 - **`LICENSE`(BSD-3-Clause)只覆盖本仓库原创的代码与文档**:不覆盖任何权重文件、不覆盖 `素材/` 中的样本、也不覆盖逐行移植自 asteroid 的网络定义(那部分是 MIT)。 - `素材/` 中的 6 条样本由 LibriSpeech 干声 + 自建 RIR 仿真混合生成(**已做修改**), 使用与再分发请保留 LibriSpeech 的 **CC BY 4.0** 署名。 ## 引用 ```bibtex @misc{convtasnet-spatial-2026, title = {ConvTasNet-Spatial:Conv-TasNet + 6 路 ITD/ILD 空间特征早融合的远场双说话人分离}, author = {{拾音客}}, year = {2026}, note = {2026 iCAN 大学生创新创业大赛 AI 应用创新挑战赛参赛作品}, url = {https://gitee.com/deserted1011/ConvTasNet-Spatial} } ```