Experiments¶
一个实验一页,写完冻结。推进新实验只新增一页 + 下表加一行,不改动已有记录。 概念一律以 Glossary 的锚点为准。
实验设置与实现细节(论文 §4.1 Experimental Setup / Implementation Details)¶
论文里超参数放在实验节开头的 Implementation Details。下面每个数字都来自训练脚本
train_m17.py、四段运行脚本run_m20{,b,c,d}.sh与训练日志,不是估计。方法本身见 03 Method。
4.1.1 数据¶
| 项 | 值 |
|---|---|
| 语料 | ESD(Emotional Speech Database):完整版 20 位,本机已下载 17 位——中文 0001–0010 + 英文 0011、0015–0020;0012–0014 尚未下载(清单已含,train 799 / test 102 / eval 102,补齐后按同一 %10 规则自动纳入,见 scripts/esd_complete.sh)。每人 350 句 × 5 情感(中立 / 生气 / 高兴 / 悲伤 / 惊讶) |
| 训练样本 | 平行对 (x_e, x_n):同人同句的一条情感录音 + 一条中立录音;4 种情感各成一对 |
| 划分 | 按句子编号:编号 % 10 == 0 → test,== 1 → evaluation,其余 → train;不留说话人(17 位全部在训练集里出现) |
| 训练对数 | 16,997(中文 10,097 / 2,706 句 + 英文 6,900 / 1,862 句)= train 划分中 DTW+R3 对齐成功且 whisper 特征齐全的对;清单上限 18,284,成功率 93% |
| 评测对数 | test 2,137 对:中文 1,276(342 句)、英文 861(235 句)(S7 §2,样本冻结于 manifests/frozen/);evaluation 划分(2,133 对)未使用 |
| 输入表示 | 情感录音重采到 16 kHz → 冻结的 whisper-large-v3 编码器最后一层(50 Hz,1280 维,pad_or_trim 30 s,取前 K 帧;预抽取存盘);CAM++ x-vector 192 维(CosyVoice 前端,冻结) |
| 目标表示 | 80 维 log-mel,24 kHz,hop 480(20 ms),n_fft = win = 1920,fmin 0,fmax 12 kHz(Matcha mel_spectrogram,center = False) |
| 中立目标对齐 | DTW 锚点每 250 ms、速率夹 [0.4, 2.5],RubberBand R3(realtime,块长 256 采样点)把中立录音变速到情感录音的时间轴(Method §3.1.1) |
| 长度 | 整句训练,不裁剪;ESD 句长 1–6 s(K = 50–300 帧),远小于 whisper 30 s 上限 |
4.1.2 模型与初始化¶
| 模块 | 结构 | 参数量 | 初始化 | 训练 |
|---|---|---|---|---|
| DiT_B(基塔) | CosyVoice3 流匹配解码器:DiT,dim 1024,depth 22,16 头 × 64,FFN ×2;输入 = Y_t (80) ⊕ μ (80) ⊕ prompt-mel 通道 (80,恒 0),说话人向量 80 维经 AdaLN 注入 | 331.2M | 基座 flow.pt 全量 |
✅ 全量 |
| DiT_Δ(残差塔) | 同上 | 331.2M | 基座权重,输出投影 proj_out 权重与偏置置零(第 0 步 v_emo ≡ v_B) |
✅ 全量 |
| Adapter × 2(μ_B、μ_Δ) | Conv1d(1280→512, k=3) → GELU → Conv1d(512→80, k=3) | 2.09M × 2 | PyTorch 默认随机 | ✅ |
| 说话人仿射 | Linear(192→80)(基座 spk_embed_affine_layer) |
15.4K | 基座 | ✅ |
| whisper-large-v3 编码器 / CAM++ / HiFT 声码器 | — | — | 预训练 | ❄ 冻结 |
| 可训练合计 | 666.48M |
4.1.3 训练超参数¶
| 超参数 | 值 | 备注 |
|---|---|---|
| 优化器 | AdamW,β = (0.9, 0.999),ε = 1e-8,weight decay 0.01(PyTorch 默认) | 全部可训练参数同一组,adapter 不单独设 lr |
| 学习率 | 1e-5,常数;无 warm-up、无衰减 | — |
| 梯度裁剪 | 全局范数 1.0 | 日志 grad_norm 全程 3–8,裁剪长期生效 |
| 精度 | fp32(无 AMP、无 EMA) | — |
| 全局 batch | 8 句/步(DDP 8 卡 × 每卡 1 句;第三段 4 卡 × 每卡 2 句) | 每卡内按最长句 pad,损失只算有效帧 |
| 总步数 | 420,000(≈ 198 epoch;2,124 步/epoch) | 四段续训,见下表 |
| 时间步 t | U(0.05, 0.95),每句一个 | 避开两端 |
| 强度 α | U(0, 1),每句一个 | 训练不外推 |
| σ_min | 1e-6 | 与基座 CFM 相同 |
| 噪声 z | 每句一份,两端目标共用 | u_e、u_n 用同一个 z |
| 损失 | L = ‖v_B − u_n‖² + ‖(v_B + v_Δ) − u_e‖² + λ·L_⊥;每项 = 该句有效帧 80×K 元素均值,再对 batch 平均 | Method §3.2 |
| λ(L_⊥ 权重) | 1.0(主线);消融 λ ∈ {0, 1, 2, 5} @100k 见 M22(λ=0 更优,主线未切换) | — |
| CFG | 训练不丢条件,推理不用 classifier-free guidance | 与基座 CFM 的 0.2 / 0.7 不同 |
| 数据加载 | DistributedSampler 打乱,drop_last,4 worker | — |
| 随机种子 | 每段一个:1234 / 4567 / 6789 / 7890(每卡 = seed + rank) | — |
| 保存 / 日志 | 每 10k 步存 ckpt;每 100 步记 L_B、L_A、L_⊥、L_delta_diag、A_share、cos_A_B、grad_norm | — |
四段续训(每段从上一段权重恢复,优化器状态重置):
| 段 | 步数 | 累计 | 卡数 × 每卡 batch | seed | 耗时 | 输出 |
|---|---|---|---|---|---|---|
| M20 | 100k | 100k | 8 × 1 | 1234 | 6.85 h | outputs/m20 |
| M20b | 80k | 180k | 8 × 1 | 4567 | 5.40 h | outputs/m20b |
| M20c | 80k | 260k | 4 × 2 | 6789 | 8.43 h | outputs/m20c |
| M20d | 160k | 420k | 8 × 1 | 7890 | 10.81 h | outputs/m20d/ckpts/step160000.pt(主模型) |
合计 ≈ 31.5 h,8 × H100 上 ≈ 4.1 步/s。分段是工程原因(每段结束后先评测再决定是否续训),不是课程学习;段间只重置优化器,不改任何超参数。
4.1.4 推理设置¶
| 项 | 值 |
|---|---|
| ODE | Euler 10 步,余弦调度 t_j = 1 − cos(πj/20),j = 0…10;只跑 α = 0 与 α = 1 两端 |
| 噪声 | z ~ N(0, I),K = 输入帧数;评测固定 seed 1234;两端共用同一个 z |
| 条件 | 与训练相同,只用情感录音;prompt-mel 通道恒 0;无 CFG |
| 强度施加 | 音高对齐混合(Method §4.3):HiFT → 16 kHz → WORLD(Harvest / CheapTrick / D4C,帧移 20 ms,有声阈 50 Hz)→ 共享 F0 对数插值(任意 α 同一公式)→ 两端重建 → mel 域 (1−α)/α 混合 → HiFT |
| α 网格 | 评测 0 / 0.25 / 0.5 / 0.75 / 1 / 1.25 / 1.5;外推探针 −1、2、3、5 只在 160 条上 |
| 声码器 | HiFT(CosyVoice3 自带,24 kHz),评测音频重采到 16 kHz |
4.1.5 评测¶
指标面板(UTMOS / CER / SECS / RA)及其出处、锚点与退化规则见 E4 §1;RA 尺子的训练与校准见 E2 §2.1;全量 test 数字以 S7 为准。
论文可直接用的英文段落(Implementation details)
Implementation details. Both towers reuse the conditional flow-matching decoder of CosyVoice 3: a 22-layer DiT (width 1024, 16 heads of dimension 64, FFN multiplier 2; 331M parameters) whose input is the noisy mel \(Y_t\) (80-d) concatenated with a frame-aligned condition \(\mu\) (80-d) and a zeroed prompt-mel channel, with the speaker vector (80-d) injected through adaptive layer norm. The base tower \(\mathrm{DiT}_B\) is initialised from the pretrained decoder; the residual tower \(\mathrm{DiT}_\Delta\) is initialised identically except that its output projection is zeroed, so that \(v_B + v_\Delta = v_B\) at step 0. Conditions are computed from the emotional recording only: a frozen Whisper-large-v3 encoder (last layer, 50 Hz, 1280-d) followed by two randomly initialised adapters (Conv1d 1280→512→80, kernel 3, GELU; 2.1M parameters each) producing \(\mu_B\) and \(\mu_\Delta\), and a frozen CAM++ x-vector (192-d) mapped to 80-d by the pretrained affine layer. In total 666M parameters are trained; Whisper, CAM++ and the HiFT vocoder stay frozen. Targets are 80-bin log-mel spectrograms (24 kHz, 20 ms hop, 1920-point window); the neutral target is time-aligned to the emotional recording with DTW anchors every 250 ms (rate clipped to [0.4, 2.5]) and Rubber Band R3 time-stretching. We train on the ESD training split (sentence index mod 10 ∉ {0, 1}; all 17 Mandarin and English speakers): 16,997 (emotional, neutral) utterance pairs over four emotions, each used as a whole utterance. Per utterance we draw \(t \sim U(0.05, 0.95)\) and \(\alpha \sim U(0, 1)\), use \(\sigma_{\min} = 10^{-6}\), and share the noise \(z\) between the two targets; the loss is \(\|v_B - u_n\|^2 + \|(v_B + v_\Delta) - u_e\|^2 + \lambda L_\perp\) with \(\lambda = 1\), averaged over valid frames. We use AdamW (constant learning rate \(10^{-5}\), \(\beta = (0.9, 0.999)\), weight decay 0.01, no warm-up), gradient clipping at 1.0, fp32, a global batch of 8 utterances, and 420k steps (≈198 epochs) run as four resumed segments of 100k/80k/80k/160k steps with the optimiser state reset at each resume; training takes ≈31 h on 8×H100. No classifier-free guidance is used in training or inference. At inference we run 10 Euler steps with the cosine schedule \(t_j = 1 - \cos(\pi j / 20)\) from a fixed seed to obtain the two endpoints (\(\alpha = 0\) and \(\alpha = 1\)), and apply the intensity \(\alpha\) by pitch-aligned mixing (WORLD at 16 kHz, 20 ms frames; log-F0 interpolation shared by both endpoints, then mel-domain blending) before the HiFT vocoder.
时间线¶
| 日期 | 实验 | 状态 | 一句话 |
|---|---|---|---|
| 08-14 | M1 截断调色板 | ⚠️ 作废 | 让各情感贡献自己的 token 骨架,再截断到最短对齐 —— 帧级音素错位,失真明显 |
| 08-14/15 | M2 参考探针 | ⚠️ 证伪 | 固定一组各情感时长几乎相同的参考,既压不到逐帧混合所需的整齐度,压到了也无用 |
| 08-14 | M3 调色板六臂 | ✅ 成立 | DTW 内容对齐使混合 CER 降低 8–12 倍,而「改条件还是改状态」本身无关紧要 |
| 08-15 | M4 时间归一化重训 | ⚠️ 无法判定 | 训练期把平行对拉到同一时间轴,截断彻底归零、A 能量占比掉 3.2 倍,但下游指标纹丝不动 |
| 08-15/17 | M5 A 结构探针 | ✅ 部分成立 | A 沿时间比 v_neu 变化更剧烈、能量集中在句首,但显著低秩;主子空间不承载情感身份 |
| 08-17 | M6 分段 α | ✅ 成立 | α 改成沿时间的函数后定位精确(仅句首档的句身残留 0.05 dB),且判据全程不经过情感分类器 |
| 08-18 | M7 把 α 搬到情感 embedding 上 | ✅ 成立 | embedding 层的 α 插值同样平滑、外推也不崩,但时长响应只有速度场层的 1/10 |
| 08-17 | M8 instruction 通道 | ✅ 成立 | instruct 能给情感类别但给不了强度(程度副词的单调率 22.9%,随机基线 16.7%),且它改的是能量而几乎不动 F0 |
| 08-17 | M9 不训练能否调 α | 🔄 重新设计 | 旧版结论建立在 93–95% 饱和的二值指标 + n=12 + 1 组差异上,已作废并删除资产;M9-R 提案见页内 |
| 08-26 | M10 训推一致重训 | ⚠️ H1成立/H2证伪 | 训推一致达成(截断归零、共享 t 与噪声),但 L_ortho 在修正定义后依然无效——堵死了「A 定义错了」这条辩解 🎧 音频全量对照 |
| 08-27 | M12 TSM 等长对 + 完整双路 | ⚠️ H1部分/H2通过 | TSM 训练目标回收 DTW 代价 55–85%;完整双路可行(E4n α=0 音质超 v4)但 CER 翻倍;TSM 禁止进推理条件(E2:MOS@α0 3.35→1.36) 🎧 音频 |
| 08-27 | M13 R3 重建 + λ 平行扫描 | ⚠️ H1'/H2'通过·H3'零结果 | R3 目标把 MOS@α0 拉到 3.57/3.71(v4=3.74)、整体 MOS 3.04 超 v4;λ∈{0,0.1,0.5,1.0} 双路下仍与情感无关(<2σ),P4 证据链闭环 🎧 音频 |
| 08-28 | M14 从基座重训 | ⚠️ 起点成立·λ终局零结果 | 基座起点不弱于 v4 起点(受控 9/12);λ∈{0..10} 五点扫描:正交可压到 0.019 而情感无变化(<2σ)——P4 终局 🎧 音频 |
| 08-28 | M15 单路分解器 | ❌ 负结果 | 同空间加减兑现(中段 V 形消失),但中立化支崩坏(α=0 MOS 1.27、L_B 欠收敛 3×、rank_A 塌到 5.4)——凭空生成中立版是生成任务,比双条件难一个量级 🎧 音频 |
| 08-29 | M15-E 中立化修复五路探索 | ❌ 全部未修复 | 五路干预(dropout/随机重置/MLP头/课程/续训加权)均未把 α=0 修到可用;E2 诊断证明 L_B≈0.95 是条件生成的内在下限;E5 最优(1.27→2.14);下一步首选教师蒸馏 |
| 08-29 | M16 并行双塔 | 📝 提案 | 条件全同 + 参数全分:两张独立 DiT 同输入分别出 v_A/v_B,消除级联耦合与容量竞争;80k 步,主判据 = MOS@α=0 随步数轨迹(不以 L_B 判) |
| 08-29 | M17 音频到音频情感编辑 | ⚠️ 随机臂未成声 | 架构通(CER@α1 0.40 内容确立)但 MOS 1.28 平线——25h 从零学不出谱纹理;零步验证证明基座先验可穿透 → M18 接跑 |
| 08-30 | M18 权重承接 | ✅ 基座兑现·λ首次正向 | 随机→基座:MOS 1.28→1.98、delta 0.48→0.91;λ=1.0 优于 0.1(外推 CER 3×)——四代零结果后 λ_ortho 首次与下游同向(待重复种子);遗留 α=0 乱说与中段谷 🎧 音频 |
| 08-30 | M19 DTW+双adapter+残差塔 | 📝 提案 | 三处改动:DTW 对齐目标(mock 验收 ≤1 帧)、adapter×2、残差参数化 v(α)=v_B+α·v_Δ——残差首次被直接监督,和式损失耦合两塔 |
结果自洽性标准¶
一个实验必须自己回答自己的动机。 §1 说要探究什么,§5 就得拿出对应证据 —— 缺一半不算做完。 实验脚本在设计时就要产出这些,不能事后补。
| 要什么 | |
|---|---|
| 定性 | 一张图或一段视频,让人直接看见结论成不成立 |
| 定量 | 表格,带单位 / n / 统计量口径 / 验收线 |
| 趋势 | 随某变量变化的量用图不用表 |
| 对照 | 基线或消融 —— 否则绝对数说明不了任何事 |
实验脚本的产出契约¶
runs/<实验>/
metrics.json 汇总(含 n、单位、口径)
per_scene.json 逐场景明细 + **原始量测轨迹**
curves.png 趋势
videos/ 定性证据,至少 2 段
轨迹一定要存 —— 事后换判据、重画图都不必再占 GPU 重跑。
Benchmarks & Metrics¶
目前采用的指标与基线。接入公开 benchmark 时在此登记。
| 指标 | 定义 | 单位 | 天花板 / 底线 | 用在哪 |
|---|---|---|---|---|
| 情感分 | emotion2vec_plus_large 给目标情感的概率 | 比例 | 纯情感配方 0.78 | 全部 |
| CER | Paraformer-zh,标点归一化后的字错率 | 比例 ↓ | 纯情感配方 0.017 | 全部 |
| SECS | campplus 说话人嵌入余弦 | 比例 | 纯情感配方 0.849 | 全部 |
| UTMOS | UTMOS22 strong | MOS 1–5 | 纯情感配方 3.29;<2.5 视为破音 | 全部 |
| mono | 相邻 α 步中情感分上升的比例 | 比例 | 量化到 1/6 格点 | α 阶梯 |
| delta | α=1 与 α=0 的情感分之差 | 比例 | — | α 阶梯 |
| 长度离散度 | max_e K_e / min_e K_e | 比值 | 逐帧混合需 ≲1.05 | 调色板 |
依赖关系¶
flowchart TD
M0[M0] --> M1[M1]