diff --git a/apps/negentropy-influence/pipeline/INDEXTTS-2.5-ADVANCED.md b/apps/negentropy-influence/pipeline/INDEXTTS-2.5-ADVANCED.md index df830003..0e13d6e8 100644 --- a/apps/negentropy-influence/pipeline/INDEXTTS-2.5-ADVANCED.md +++ b/apps/negentropy-influence/pipeline/INDEXTTS-2.5-ADVANCED.md @@ -228,8 +228,8 @@ GPT 看到的条件方向越偏离说话人身份)。论文的 GRL 只保证 e | ---- | ------------ | ------------------------------- | ----- | --------- | ---------- | | bias | 1.0 | 0.9375 | 0.875 | 0.6875 | **0.5625** | -即**同样填 0.5,`calm` 的实际强度只有 `sad` 的 56.25%、`surprised` 只有 68.75%**—— -这两个维度「每单位 Σw 预算最贵、见效最差」。 +即**在 WebUI 的 bias 口径下**,同样填 0.5,`calm` 的实际强度只有 `sad` 的 56.25%、 +`surprised` 只有 68.75%——这两个维度在该口径下「每单位 Σw 预算最贵、见效最差」。 **关键事实**:`normalize_emo_vec`(含 bias 与 0.8 上限)**在 `infer()` 内从不被调用**。 全仓唯一调用点是 `webui.py:665` 的「自定义向量」分支;`apply_bias=False` 那条分支 @@ -248,6 +248,14 @@ GPT 看到的条件方向越偏离说话人身份)。论文的 GRL 只保证 e 「不采用 emo_bias」是一个**显式的设计选择**而非遗漏:bias 是上游为 WebUI 交互体验做的感知 补偿,而本管线要的是可复现、可缓存、可折算的线性口径。代价就是上述迁移不可靠性。 +> ⚠️ **这条事实最容易被反向误用**(2026-09-02 实录):既然 bias 不生效,就**不能**再用 +> 「`surprised` 只兑付 68.75%、`calm` 只兑付 56.25%」去论证「这两维不划算、该砍」——那是 +> WebUI 路径的语义。`tts.py` 里 `sunny-pure`(#10)的原始立论正是这么写的,已勘误。 +> 正确读法只有两条:**(a)** 跨来源迁移参数时要按 bias 换算;**(b)** 本管线内名义权重 +> 即实际权重,数值口径一致;各维的听感收益仍受原型基底与参考片段影响,取舍只能靠试听。 +> 反向线索:bias 表里被下调的恰是 `surprised`/`calm`;这只能说明上游做了尺度补偿, +> 不能单独推出听感强弱,本管线拿到的是未经该衰减的版本。 + ### 3.3 73 个情感原型:为何「换选段则标定失效」是必然 情感原型不是「每种情感一个均值」,而是 **73 个「(情感, 具体说话人)」实例**: @@ -598,7 +606,47 @@ s2mel 权重截至 2026-08-20 未公开发布。 并记录了判据被现实纠正的三次(秩相关无标度 → 量级判据;只裁头部 → 最长稳定窗口; 静态内存硬门 → 降级为提示)。 -### 6.4 Apple Silicon 上不可用的加速面(逐条已核实) +### 6.6 内容侧的噪声地板:本协议下韵律 A/B 的操作门槛 ≈ 21%(2026-09-02) + +§6.4–6.5 解决的是**耗时**可测量性。**内容**侧是另一回事,且结论更省钱: + +**前提**:固定 `--seed` 后音频内容是确定性的——同参数两次合成 sha256 逐字节相同(本轮实测, +与路线图 #3 一致;机制是 `tts_server.py:343-347` 每次 infer 前 `set_seed`、`:357` +`use_random=False`)。热节流污染耗时,**不污染采样轨迹**。⇒ **内容指标的 A/B 不需要 75 s +冷却、不需要交替顺序**,可以连续跑完。这把一轮 35 次合成的预算从数小时压到约 18 分钟。 + +**但确定性 ≠ 低方差**。种子换一条(`--seed-offset 1`)就是另一条 take,而 take 间的韵律 +波动很大。实测(`sunny-steady` @ `me-bright`,7 句配对,同档同样本只换 take): + +| 量 | 中位 | 逐句绝对值范围 | +| --- | --- | --- | +| `\|ΔIQR_rel\|`(起伏÷音高中位) | **10.4%** | 2.6% … 21.3% | + +⇒ **在本次协议下,任何 <10% 的韵律「改善」都无法与换一条 take 区分**;按「效应量 ≥ 2×噪声」 +得到的**操作门槛是 ≈21%**,不外推为所有韵律类 A/B 的通用最小效应量。这一条直接废掉了 +一批看起来诱人的小改动: +本轮五个 `surprised` 加载档在单句剂量筛里的档间差(−14%…+2%)**全部落在噪声内**, +排序甚至把 `sunny` 与 `sunny-steady` 的已知高低关系倒置。 + +**配套的三条判据设计教训**: + +1. **主指标必须无量纲**。`f0_iqr` 与 `f0_med` 在 Hz 量纲上耦合(音高整体抬高 20%, + 四分位距通常同比抬高,而听感音程跨度没变),故一律用 `IQR_rel = f0_iqr / f0_med`。 + 否则「把 alpha 推上去」这条假路径必然「赢」——但那是换了个人(§3.1)。 +2. **身份护栏用中位,不用逐句最大值**。§3.1 的 alpha→音高标定曲线(169 / 188 / 199–223 Hz) + 报的是**样本级中位**,拿它去卡逐句 `f0_med` 最大值是量纲错配:生产档 `sunny-steady` + 自己就有单句冲到 186.9 Hz。本轮曾按逐句最大值误判三个候选「撞 180 Hz 红线」, + 改回中位口径后三者反而**低于**基线。 +3. **小样本下看符号一致性,不只看中位**。n=7 时中位数不稳定,不能用固定的「噪声/√7」 + 作为标准误公式;其误差还取决于中位点附近的分布密度。预先指定方向后,`胜出 k/n` 的 + 符号检验更透明(7/7 → p=0.008,5/7 → p=0.23);需要区间时应使用配对 bootstrap。 + 本轮出现过「中位最高(+18.1%)但只有 5/7 一致、靠两句离群值撑起来」的臂,若只看中位就会选错。 + +复现脚本不入库(一次性分析),取数口径全部复用 +[prospect_ref.py](./scripts/prospect_ref.py) 的 `window_stats` 与 +[tts_bench.py](./scripts/tts_bench.py) 的 `asr_metrics`,无第二份指标定义。 + +### 6.7 Apple Silicon 上不可用的加速面(逐条已核实) `use_bf16`(MPS 分支 `:106-109` 硬编码 `False`,注释称 bf16 在 MPS 上是开销)、 `use_cuda_kernel`(同处置 `False`)、`use_deepspeed`(三条分支都以 `torch.cuda.is_available()` @@ -630,13 +678,13 @@ TensorRT-LLM)。仓库内**无 vLLM 后端**,README 只给外链 recipe。 | 7 | `length_penalty>0`(长句吞尾) | 机制成立(§4.2)但**实测在本工作负载上惰性** | — | 11 对配对样本(含 −2/+2 全区间极值):尾覆盖改善 **0/11 句**,秒/字仅 +0.4% | ✅ **已做 → 维持默认 0.0**:束间长度差异太小,除数成公共因子。若日后合并多句成单请求需重测 | | 8 | `repetition_penalty` 定向扫描 | 上游自 v1 沿用 10.0 且无任何测试支撑(§4.3) | — | 11 对样本:3.5–10 是**稳定平台**(8/8 逐项相同);极值两端更差(`1.0` 尾覆盖 0.889、`20.0` 有单句崩到 0.56) | ✅ **已做 → 维持默认 10.0**:上游选择事后成立,它处在避开「无惩罚拖音」与「过强压掉韵尾」的中间带 | | 9 | 预设名义向量归一到 Σvec°=1.0 | 让 alpha 跨预设可比(§3.1) | 零——只动 `lively`/`confident`/`positive`,三集**都不用**这三档 | 有效注入 `w=vec×alpha` 在上游 4 位量化的 1 单位内一致(单测钉死) | ✅ **已做** | -| 10 | 砍掉 `calm`/`surprised` 配料 | bias 只 0.5625/0.6875,占预算却不兑付表达力(§3.2) | 零(**新增** `sunny-pure` 候选档,不动生产档) | 待 A/B:比 F0 中位/起伏/音节率/限带质心 + 人耳 | 🟡 **候选档已就位**,待定档 | +| 10 | 评估是否砍掉 `calm`/`surprised` 配料 | 本管线不应用 WebUI 的 `emo_bias`,删配料收益不能由 0.5625/0.6875 推出(§3.2) | 零(**新增** `sunny-pure` 候选档,不动生产档) | 待 A/B:比 F0 中位/起伏/音节率/限带质心 + 人耳 | 🟡 **候选档已就位**,待定档 | | 11 | 密集技术句改 `df>1` | 方向勘误(§3.4) | 零(**新增** `sunny-clear` 候选档 df=1.05);定档后须重渲(牵动 beat) | 待 A/B:ASR 回转写 CER 作清晰度代理(ASR 通路已就绪,见 §2.3) | 🟡 **候选档已就位**,待定档 | | 12 | 重录目标风格参考样本 | 换段落即 F0 +12~16%、起伏 +25~40%(VOICE-CLONING §3.3);好段落必须放开头(§5) | 一次录制(**须本人操作**) | 工具已就绪:`prospect_ref.py --accept` 判保真度(削波/底噪/动态/带宽/超 15s),再跑纯克隆小样比风格(合格线 F0 ≥155 Hz、起伏 ≥34) | 🟡 **工具就绪,待录音** | | 13 | `prospect_ref.py` 增保真度门 | 现公式 5 项全是「风格」、0 项「保真度」;谱质心把「亮」与「噪」混淆 | 排名口径变更(质心改限带、静音改绝对阈) | 成片在用的 180s 段**被放行** ✅,且正确标出更脏的窗口(底噪 −46 dB/动态 29 dB);超 15s 与 5 kHz 带限反例均被拦 | ✅ **已做** | | 14 | 进程级分片并行(双实例) | 原假设「瓶颈是发射/同步开销」 | — | — | ⛔ **不做**:#6 已定因为**热节流**而非吞吐受限(换页/分配器/泄漏均排除)。两个进程只会更快撞上同一个热墙——单实例都已在 6 次调用内漂 2.4× | | 15 | 降 `diffusion_steps` / 关 CFG | s2mel 占 45–73%,步数 25→12 本可省该段一半 | — | — | ⛔ **不可做**:二者是 `infer()` **函数体内的局部字面量**(`:829-830`),既非参数也非模块常量 ⇒ 无法传入、无法 monkeypatch,只能改上游源码——那是 `glossary.yaml` 被否决的同一模式(不受本仓版本控制、换机即静默失效) | -| 16 | 迁 MLX / 换栈 | 见 §6.3 | 砍掉全部情感控制 ⇒ 7 档风格体系失效 | — | ⛔ **不推荐**:#4 已完成分母校准,缺口基本可归因,无大块性能余量支持换栈 | +| 16 | 迁 MLX / 换栈 | 见 §6.3 | 砍掉全部情感控制 ⇒ 整套风格体系失效 | — | ⛔ **不推荐**:#4 已完成分母校准,缺口基本可归因,无大块性能余量支持换栈 | | 17 | 升级到 2.5-RL 权重 | 论文中文 WER 4.36→3.93、SS 77.10→77.92 | 整集重录 | — | ⛔ **权重未公开**(见下);订阅 upstream release 即可,无需本仓工程 | ### 7.1 候选档怎么定档(#10 / #11 的收尾动作) @@ -681,7 +729,7 @@ release 比自行复现 GRPO 经济得多**——同时也在等 Zipformer 版 s | 迁 CUDA + 开 `--accel` | `model_v2_5.py:761-772` 的 accel 旁路**只认 `temperature`**,其余采样参数全部静默失效 | 「参数明明传了却毫无效果」 | | 迁小显存 CUDA(<10 GB) | `low_vram` 触发,`:509` 把 >40 字符的行按标点**硬切并插 200 ms 静音** | 旁白行中间莫名多出停顿 | | 迁 Linux | 中文归一化引擎从 wetext 换成 `tn.chinese.normalizer`(`front.py:130-142`) | 读法行为可能变化——**必须在 Linux 上重跑空格矩阵**(§2.2) | -| 换 MLX 栈 | 主动放弃 `emo_vector`/`emo_audio_prompt`/`emo_text` 与束搜索 | 本仓 7 档风格体系、alpha 标定、`sunny`/`sunny-steady` 双档全部失效 | +| 换 MLX 栈 | 主动放弃 `emo_vector`/`emo_audio_prompt`/`emo_text` 与束搜索 | 本仓风格体系、alpha 标定、`sunny`/`sunny-steady` 双档全部失效 | | 原地覆盖参考样本 | 上游按路径缓存条件张量 | 「sha1 是新的、音色是旧的」(§5 末) | | 合并多句成单请求 | 118 字段预算与 1815 mel token 同时变成活约束 | 单请求上限约 36 s 语音;溢出表现为**文本尾部未被念出** | | 想调 S2M 扩散步数 / CFG | 二者是 `infer()` 体内的**局部字面量**(`:829-830`),不在签名里、也不是模块常量 | 无法从外部传入或 monkeypatch;只能改上游源码,而那份改动不受本仓版本控制、换机即静默失效(同 `glossary.yaml` 被否决的理由) | diff --git a/apps/negentropy-influence/pipeline/VOICE-CLONING.md b/apps/negentropy-influence/pipeline/VOICE-CLONING.md index c75fc680..81ac28e5 100644 --- a/apps/negentropy-influence/pipeline/VOICE-CLONING.md +++ b/apps/negentropy-influence/pipeline/VOICE-CLONING.md @@ -155,9 +155,29 @@ uv run --no-project --with soundfile --with numpy \ > 最省力的做法其实是**重录一段 10–15 秒的目标风格样本**:用你想要的那种语气念一段自己视频的开场逐字稿(比平时略快、句尾略上扬、带笑意),克隆会把这份韵律一起继承,之后连情感向量都可以只加一点点。 +#### 3.3b 第二轮勘探:把 `me-full-*` 纳入,并换用无量纲主指标(2026-09-02) + +上表的质心列是路线图 #13 改「限带质心」**之前**的旧尺子(1698–1898 Hz),与本轮的限带值(1223–1353 Hz)**不同尺,不可混排**;故本轮单列一张表。本轮新增两件事:把从未勘探的 `me-full-1`、`me-full-2-1`、`me-full-2-2`、`me-full-3`(共 663 s)纳入同一把尺子,并把主指标换成无量纲的 `IQR_rel = 起伏 ÷ F0 中位`(理由见 [ADVANCED §6.6](./INDEXTTS-2.5-ADVANCED.md):Hz 量纲下起伏与音高耦合,「整体抬高」会假装成「起伏变大」)。目标是**抑扬顿挫**,故同时看静音占比(顿)。 + +| 候选(12 s) | 样本 F0 | 样本起伏 | 样本音节率 | 样本限带质心 | 样本静音 | → 小样 F0 | 小样起伏 | **小样 IQR_rel** | 小样静音 | +|---|---|---|---|---|---|---|---|---|---| +| `me-1` @0.36s(= `me-bright`,成片在用) | 161.6 | 36.4 | 4.67 | 1223 | 0.16 | 164.6 | 38.5 | 0.234 | 0.14 | +| **`me-1` @106s** | 151.7 | **46.9** | 4.17 | 1267 | **0.23** | **169.6** | **46.8** | **0.276** | **0.22** | +| `me-full-3` @108s | 154.2 | 43.7 | 4.50 | 1288 | 0.19 | 158.6 | 39.7 | 0.250 | 0.15 | +| `me-full-1` @146s | 149.5 | 44.7 | 4.42 | 1270 | 0.19 | 155.3 | 37.4 | 0.241 | 0.20 | +| `me-full-1` @100s | 153.1 | 43.0 | 4.58 | 1353 | 0.20 | 154.2 | 35.1 | 0.228 | 0.20 | + +(小样 = `--style neutral --seed 4242` 纯克隆,不注入任何情感;四段候选保真旗标全 ✅。) + +**三条可直接复用的结论:** + +1. **`me-1` @106s 是目前所有已勘探选段里韵律动态最大的一段**:`IQR_rel` 比成片在用的 `me-bright` 段高 **+18%**,静音占比高 0.08——即「起伏更大且停顿更多」,正是抑扬顿挫的两个维度。且它与 `me-bright`(@0.36s)、`me-1.wav`(@180s)同源不同窗,无重叠。复现:`uv run --no-project --with soundfile --with numpy $R/prepare_ref.py ~/Documents/dify/me-1.mp3 --start 106 --duration 12 --out $V/me-1-106.wav`(sha1 `3c109eff6aa8`)。 +2. **样本起伏高 ≠ 克隆起伏高,本轮又添两个反例**:`me-full-1` @146s / @100s 的样本起伏分别 44.7 / 43.0(均高于 `me-bright` 的 36.4),克隆出来却只有 37.4 / 35.1(低于 `me-bright` 的 38.5)。**唯一有效判据始终是纯克隆小样**,样本侧指标只能用来生成候选、不能用来否决候选。 +3. **take 噪声只能在同一协议下估计**:§6.6 对 `sunny-steady @ me-bright` 的 7 句配对得到 `|ΔIQR_rel|` 中位 10.4%;旧表 `me-1` @0s 的原始 `f0_iqr` 34.1 与本表 `me-1` @0.36s 的 38.5 既不是同一窗口,也不是同一指标,不能拿来验证该噪声。故行间差异是否可解读,须在同一窗口、文本、seed 和 `IQR_rel` 口径下复测;§3.3 那句「换段落即起伏 +25~40%」仍应按原实验口径理解。 + ## 四、风格与参数 -**情感有三个来源,互斥,只能给一个**(客户端与服务端双向校验;上游对「向量 + 情感音频」是**静默丢弃音频**,本管线改为显式报错): +**情感有三个来源,互斥,只能给一个**(客户端与服务端双向校验;上游允许「向量 + 情感音频」共同参与混合,本管线因 `emo_alpha` 会被消费两次而显式拒绝同传): | 来源 | 开关 | 机制 | 适用 | |---|---|---|---| @@ -190,13 +210,14 @@ uv run --no-project --with soundfile --with numpy \ | confident 自信 | 沉稳有力 | calm=.65, happy=.25 | 0.7 | 0.63 | 1.05 | 1 | | positive 正能量 | 昂扬向上 | happy=.75, calm=.20 | 0.7 | 0.665 | 1.0 | 1 | -> **两个候选档(2026-08-20 新增,尚未定档)**:`sunny-pure`(happy 单载,砍掉 sunny 里 -> 有效强度仅 0.5625/0.6875 的 calm/surprised 配料)与 `sunny-clear`(= `sunny-steady` +> **两个候选档(2026-08-20 新增,尚未定档)**:`sunny-pure`(happy 单载,去掉 sunny 里的 +> calm/surprised 配料;本管线不应用 WebUI 的 `emo_bias`,不能据 0.5625/0.6875 推断其 +> “不划算”,是否保留须以 A/B 与试听为准)与 `sunny-clear`(= `sunny-steady` > 但 df 1.05,护术语密集句的清晰度——df 方向勘误见 §4.3)。二者是**新增**而非改动生产档, > 故对已上线三集的缓存零影响;定档前须按 > [INDEXTTS-2.5-ADVANCED.md §6.5](./INDEXTTS-2.5-ADVANCED.md) 的测量协议做 A/B + 人耳确认。 -预设可自带**束宽**(`STYLE_PRESETS` 的可选键 `beams`,缺省 1)——束宽改变韵律稳定度,属风格的一部分;命令行 `--num-beams` 显式给值时优先(故其 argparse 默认值是 `None` 而非 `1`,否则无法区分"没给"与"给了 1")。`--list-styles` 会打印全部七档的向量/alpha/有效注入/语速/束宽。 +预设可自带**束宽**(`STYLE_PRESETS` 的可选键 `beams`,缺省 1)——束宽改变韵律稳定度,属风格的一部分;命令行 `--num-beams` 显式给值时优先(故其 argparse 默认值是 `None` 而非 `1`,否则无法区分"没给"与"给了 1")。`--list-styles` 会打印**全部预设**的向量/alpha/有效注入/语速/束宽(档数以该输出为准——本文不复制一个会随代码漂移的数字)。 > **`sunny-steady` 的来历**:与 `sunny` 同方向同强度同语速,只把束宽 1→3。同文本同样本实测:语调起伏 **48.4 → 43.5**(更收敛、更"稳")、音节率 4.10 → 4.55,而亮度基本不掉(谱质心 1245 → 1223)——是目前唯一"不牺牲明快度就让语气更可信"的旋钮。代价是 GPT 段耗时按束宽放大:单句墙钟由 20–35 秒变为 **56–131 秒**(同机同参两次实测的区间,受机器负载影响大),整集排期须按 §4.3b 的 3 束口径乘上去。 @@ -275,8 +296,9 @@ curl -s http://127.0.0.1:8766/health uv run --no-project --with mutagen $R/tts_sample.py \ --ref $V/me-bright.wav --style sunny --play -# 4) 全风格 A/B:7 档预设按 STYLE_PRESETS 顺序各一遍,顺序试听择优 -# neutral→passionate→lively→confident→positive→sunny→sunny-steady(末档自带 3 束,耗时见下表) +# 4) 全风格 A/B:全部预设按 STYLE_PRESETS 顺序各一遍,顺序试听择优(档数见 --list-styles) +# 顺序即 STYLE_PRESETS 的定义序,含 §4.1 的候选档;sunny-steady/sunny-clear 自带 3 束。 +# 下方 6.3 分钟是仅 7 档的历史测量;当前排期以 --list-styles 输出的档数与各档束宽重新估算。 uv run --no-project --with mutagen $R/tts_sample.py \ --ref $V/me-bright.wav --all-styles --play @@ -298,7 +320,7 @@ uv run --no-project --with mutagen $R/tts_sample.py \ | 开关 | 作用 | 默认 | |---|---|---| | `--text` / `--text-file` | 试听文本(建议 20–40 字,带数字/术语更易暴露咬字问题) | 内置一句科普文本 | -| `--style` / `--all-styles` | 单档 / 全部 7 档预设 A/B(`--all-styles` 逐档取预设自带的 alpha/语速/束宽,故与 `--emo-vector` `--emo-alpha` `--duration-factor` `--num-beams` 互斥) | `neutral` | +| `--style` / `--all-styles` | 单档 / **全部预设** A/B(`--all-styles` 逐档取预设自带的 alpha/语速/束宽,故与 `--emo-vector` `--emo-alpha` `--duration-factor` `--num-beams` 互斥) | `neutral` | | `--emo-vector` `--emo-alpha` `--duration-factor` | 手动调参,语义与取值范围同 §四 | 随风格 | | `--emo-ref <录音>` | 语调迁移:音色仍取 `--ref`,语气来自这段录音(见 §四) | 关 | | `--emo-text "<描述>"` | 自然语言描述情感(需服务端 `--use-qwen-emo`);推出的向量会打印,可用 `--emo-vector` 固化 | 关 | @@ -313,7 +335,7 @@ uv run --no-project --with mutagen $R/tts_sample.py \ |---|---|---|---| | 单档 · 首档(含服务暖机,1 束,机器空闲) | 6.86s | 47.0s | 6.8 | | 单档 · 暖机后(1 束,机器空闲) | 6.0–6.9s | 20–22s | 3.2–3.4 | -| 全 7 档 A/B(`--all-styles`,含 sunny-steady 的 3 束档,机器有其它负载) | 合计 46.2s | **6.3 分钟** | — | +| 全档 A/B(历史基准:2026-08-19;仅 7 档,含 sunny-steady 的 3 束档,机器有其它负载) | 合计 46.2s | **6.3 分钟(历史值)** | — | > **口径提醒**:小样 RTF(暖机后、机器空闲、单句,≈3.3)与 §4.3b 整集折算 RTF(≈12–14)测的不是同一件事——后者含数小时长跑的降频、机器争用与逐句开销。上表 A/B 行即反例:机器有其它负载时单档墙钟散布在 37.7–86.6 秒(最慢的是该服务会话内首次用该样本的那档),其中 3 束的 sunny-steady 只用 38.6 秒、并未比 1 束档更慢。**小样耗时既不可线性外推到整集,也不足以据单次样本推断束宽代价**——束宽的系统性代价与整集排期一律以 §4.3b 的长跑折算口径为准。 @@ -441,7 +463,7 @@ cd video && pnpm run render:draft && pnpm run render # render 脚本定义在 | `X-Audio-Format=wav` | 服务端 MP3 编码器探测失败 | 按 §2.3 带 `--with lameenc` 重启服务 | | `/health` 报 `supports_duration_factor=false` | 服务为 IndexTTS-2 | 语速控制需 v2.5:重启服务 `--indextts-version 2.5` | | `/health` 报 `supports_emo_text=false`,`--emo-text` 被拒 | 服务未加载 QwenEmotion | 带 `--use-qwen-emo` 重启;若报缺 `model.safetensors` 见 §2.4 补权重 | -| 报「情感来源互斥,只能给一个」 | 同时给了 `--emo-vector`/`--emo-ref`/`--emo-text` 中的两个以上 | 三者择一(上游遇「向量+音频」会静默丢弃音频,故本管线显式拒绝,见 §四) | +| 报「情感来源互斥,只能给一个」 | 同时给了 `--emo-vector`/`--emo-ref`/`--emo-text` 中的两个以上 | 三者择一(上游会把向量与音频共同混合,但 `emo_alpha` 会被消费两次,故本管线显式拒绝,见 §四) | | 生成音色「不像我」 | 样本质量问题 | 按 §三 重录/重裁:换更干净段落、保证单说话人、10–14s(先跑 `prospect_ref.py --accept` 过保真度) | | 长句合成失败 | 超时(HTTP_TIMEOUT=600s) | 重跑(缓存续传);超长句在逐字稿层面拆句 | | edge 模式失败 | 网络 | 与历史行为一致(重试 4 次后报错) | @@ -461,7 +483,7 @@ cd video && pnpm run render:draft && pnpm run render # render 脚本定义在 | edge-tts | ❌ 仅预置 | 仅 rate | 无需部署 | 本管线默认引擎(零成本回退) | | **IndexTTS-2.5** | ✅ 单样本零样本 | ✅ 向量+强度+语速 | ✅ MPS fp32 | **主方案**;中英日西阿 | | IndexTTS-2 | ✅ | ✅ 向量(无语速) | ✅ fp16 成熟 | 服务端一键回退档(`--indextts-version 2`) | -| index-tts-2.5-mlx(社区 MLX 移植) | ✅ | ❌ 砍掉全部情感控制 | ✅ 最省内存 | 0.1.1(2026-08-14)**已支持 2.5**、自带 int8 GPT 权重、uvx 一键;但主动放弃 `emo_vector`/`emo_audio_prompt`/`emo_text` 与束搜索 ⇒ 本仓 7 档风格体系与 alpha 标定全部失效,不可直接替换(评估前置动作见进阶篇 §6) | +| index-tts-2.5-mlx(社区 MLX 移植) | ✅ | ❌ 砍掉全部情感控制 | ✅ 最省内存 | 0.1.1(2026-08-14)**已支持 2.5**、自带 int8 GPT 权重、uvx 一键;但主动放弃 `emo_vector`/`emo_audio_prompt`/`emo_text` 与束搜索 ⇒ 本仓风格体系与 alpha 标定全部失效,不可直接替换(评估前置动作见进阶篇 §6) | | GPT-SoVITS | ✅ 微调最佳 | 依赖参考音频 | 推理可/训练差 | 需训练工作流,过重 | | CosyVoice 2 | ✅ 3–10s | instruct 指令 | ✅ | 克隆相似度略逊 | | 云端(Azure Custom Voice 等) | ✅ | ✅ | 无需 | 收费/审核/隐私,不采纳 | diff --git a/apps/negentropy-influence/pipeline/scripts/tts.py b/apps/negentropy-influence/pipeline/scripts/tts.py index df4d2915..58231b0c 100644 --- a/apps/negentropy-influence/pipeline/scripts/tts.py +++ b/apps/negentropy-influence/pipeline/scripts/tts.py @@ -172,11 +172,15 @@ # 定档前必须按 INDEXTTS-2.5-ADVANCED.md §6.5 的测量协议做 A/B + 人耳确认。 "sunny-pure": { "label": "明快纯载", - # 候选(路线图 #10):砍掉 sunny 里的配料维度。依据是上游 emo_bias - # (infer_v2_5.py:493)8 维不等权——surprised 只有 0.6875、calm 只有 0.5625, - # 它们既占 Σw 预算(等量挤掉本人语调)又只兑付 69%/56% 的表达力。sunny 里的 - # surprised=0.02(加 bias 后 0.0138、占比 1.5%)基本是装饰。 - # 同时这是唯一使 Σvec=1.0 与「happy 单载」同时成立的写法 ⇒ alpha 语义最干净。 + # 候选(路线图 #10):砍掉 sunny 里的配料维度,使 Σvec=1.0 与「happy 单载」 + # 同时成立 ⇒ alpha 语义最干净(它就是被替换掉的本人语调比例)。 + # ⚠️ 立论勘误(2026-09-02):本档原注以 emo_bias「surprised 只兑付 69%、 + # calm 56%」为依据——该折扣**在本管线不生效**。施加 bias 的 normalize_emo_vec + # (infer_v2_5.py:488)全仓唯一调用点是 webui.py:665;infer() 内对 emo_vector + # 的唯一变换是 :605-607 的 int(x*alpha*10000)/10000,无 bias 相乘。故本管线 + # 名义权重即实际权重,「配料维度不划算」这条理由作废,本档退回纯 alpha 语义论证。 + # 顺带:surprised 的原型数是 10(happy 只有 3,emo_num=[3,17,2,8,4,5,10,24]), + # 表达基底并不贫乏——砍它的代价可能比原注设想的大,定档须以试听为准。 "vec": [1.0, 0, 0, 0, 0, 0, 0, 0], "alpha": 0.35, "df": 0.95, diff --git a/apps/negentropy-influence/pipeline/scripts/tts_server.py b/apps/negentropy-influence/pipeline/scripts/tts_server.py index d6572e3d..d4192741 100644 --- a/apps/negentropy-influence/pipeline/scripts/tts_server.py +++ b/apps/negentropy-influence/pipeline/scripts/tts_server.py @@ -449,8 +449,8 @@ async def synthesize(req: SynthesizeRequest): ref = Path(req.ref_path).expanduser() if not ref.is_file(): raise HTTPException(400, f"参考音频不存在: {ref}") - # 三种情感来源互斥:向量 / 参考音频 / 自然语言描述。上游对「向量+音频」是静默丢弃音频, - # 静默降级比报错更难排查,故此处显式拒绝。 + # 三种情感来源互斥:向量 / 参考音频 / 自然语言描述。上游会把向量与音频共同混合, + # 但 emo_alpha 会被消费两次;静默降级比报错更难排查,故此处显式拒绝。 sources = [ name for name, val in (