wikiAudio02|Tacotron:文本到声学特征的端到端建模04|PyTorch 实现:架构映射与结构验证
9 分钟
1 次观看

04|PyTorch 实现:架构映射与结构验证

返回 Tacotron 总览 · 前一篇:联合训练与波形重建 · 完整源码

本实现用于把 CBHG、注意力和多帧反馈连接成可运行的计算图。输入是两条等长字符 ID 序列与随机声学目标,输出为预测帧和注意力矩阵。读代码前,先根据图确认三类数据:整句文本记忆、单步声学输入、跨步递归状态。

1. 代码架构与实现边界

TinyTacotron代码中tokens经过CBHG得到memory,query和context进入双GRU,输出block并反馈

图 1|教学实现的模块调用、反馈与状态

图中箭头对应 TinyTacotron.forward。memory 在进入解码循环之前计算;每个解码步更新 aq、d1、d2,输出两个不同帧,再从块的最后一帧构造下一步输入。训练时该反馈改为目标序列的对应真实帧。

教学实现缩小维度,保留计算关系;它不是原论文全配置复现。

部件原论文本实现与理由
文本编码embedding 256、两层 pre-net、CBHG bank 1–16embedding 16、单层 pre-net、bank 1–4;缩小 CPU 演示规模
CBHG四层 highway、双向 GRU保留这两项、残差、BN 与多分支结构
注意力内容 tanh attention显式加性打分、文本轴 softmax、掩码接口
声学解码两层残差 GRU、r=2r=2、80 通道两层 GRU,明确的教学残差约定;r=2r=2、8 通道
后处理与声码频谱 CBHG、Griffin–Lim未实现,已在上一篇解释原理和接口
训练数据约 24.6 小时内部英语单说话人数据随机目标,仅用于结构测试
结束规则与补齐训练等设计相关显式指定步数,不预测停止概率

教学 residual 写法为“每层 GRU 输出加本层输入,再送到上层”;递归隐藏状态保存 GRU 自身输出。原论文没有逐行指定这些连接代码,因此这部分作为明确记录的教学实现选择,不声称与某个官方 checkpoint 完全一致。

2. 张量接口与轴约定

代码变量本次形状含义
tokens[2,4],torch.int64两句,每句四个有效字符;0 保留给 padding,本演示禁止传入 0
targets[2,6,8],浮点六帧、八个教学特征通道;随机数不代表真实 mel
memory[2,4,32]CBHG 双向 GRU,每方向 16 维
aq[2,32]attention GRU 状态/查询
weights[2,4]当前解码步的文本权重
context[2,32]对文本记忆加权求和
d1、d2各 [2,32]两个声学 GRU 的独立状态
block[2,2,8]一步产生两帧
拼接后的预测[2,6,8]三步的块沿帧轴连接
alignment[2,3,4]批 × 解码步 × 文本位置

批大小 B=2B=2、文本长度 N=4N=4、目标帧数 T=6T=6、通道数 M=8M=8、每步帧数 r=2r=2。这些字母只描述形状,不是可学习参数。

3. CBHG 的长度保持与偶数卷积核

多个卷积分支必须保留相同的文本长度才能拼接。对于偶数核,仅写对称 padding=k//2 往往会多出一个位置。代码显式补总计“核宽减一”的位置,左右可以不对称:

# x: [B,C,N];这里先做 padding,再做不带 padding 的 Conv1d。
left = (kernel - 1) // 2
right = kernel - 1 - left
x = F.pad(x, (left, right))
out = conv(x)
核宽左补右补输出长度:输入长度加总补齐减核宽加一
100N+0−1+1=NN+0-1+1=N
201N+1−2+1=NN+1-2+1=N
311N+2−3+1=NN+2-3+1=N
412N+3−4+1=NN+3-4+1=N

池化同样使用步长 1。代码右侧补负无穷,避免补齐值在最大池化里胜出。这些是序列边界补齐,不是“用 0 字符补齐批内短句”的同一个问题。

注意力掩码不能自动修复双向 GRU 对文本 padding 的读取。

完整变长批处理还需要卷积边界/长度管理以及 GRU packing 或等效处理。本演示拒绝含 0 的输入,并要求等长无补齐文本;单独测试 Attention 的掩码能力,避免给人“加了 softmax mask 就完成全部变长处理”的错觉。

4. 反馈选择与训练、推理入口

下面片段位于完成当前 block 预测之后。此处 s 从 0 开始,因此选的是当前组最后一帧,供下一步使用:

# block: [B,r,M];targets: [B,T,M];previous: [B,M]
previous = (targets[:, (s + 1) * reduction - 1]
            if targets is not None else block[:, -1])

当 s=0,r=2 时,训练选择 targets[:,1],推理选择第一组的第二帧。下一步预测目标是帧 2、3;若误取目标帧 2,就向模型提供了当前要预测的信息。

调用历史来源步数
model(tokens, targets)真实目标最后一帧从目标帧数除以 reduction 得到
model(tokens, steps=3)上一预测块最后一帧显式指定 3 步

测试推理前调用 model.eval(),使本演示的 dropout 关闭、BN 使用已有统计值;配合固定输入比较索引关系。真实训练/推理的 dropout 策略可能采用不同约定,不能把这个测试模式当作原版全部推理细节。

5. 已执行的结构验证

运行环境为 Python 3.12.14、PyTorch 2.14.0+cpu,CPU 单线程、随机种子 7。命令与完整代码见附录。模型共 33,872 个参数,没有进行语音训练。

检查实际结果能验证的性质
注意力手算权重约 [0.1,0.2,0.7];context 约 [2.2,1.1]与正文数值例一致,使用 PyTorch 默认 close 容差
padding 扰动context 最大绝对差 0被 mask 的位置在当前例中不影响读取
修改真实帧 3预测前四帧最大差 0帧 3 只从第三个解码步开始作为历史输入
同一扰动的后两帧最大差约 0.113219测试确实触发了后续依赖,不是两路都忽略输入
训练/推理输出均为 [2,6,8]分组与拼接长度一致
注意力矩阵[2,3,4]解码步数与文本轴正确
反向传播73 个参数张量获得有限梯度embedding 和 attention 打分层都有非零梯度

这些测试把数值关系和数据依赖变成可检查的证据,尤其能发现错一帧的反馈错误。

随机目标的 L1 约为 0.841422,只用于检查反向传播。它不是收敛曲线,更不是音质指标。不同 PyTorch 版本的初始化或算子实现可能使最后几位以及随机测试值变化;应该关注断言与关系,不要求跨版本逐位相同。

6. 从演示到真实训练的补全路径

需要补全最小验收动作
文本规范化、字符表数字和标点有确定映射;训练/推理一致
音频预处理真值频谱可重建;固定采样率、窗口、log 和归一化
变长数据与补齐短句批处理结果与正确长度处理一致;损失补齐策略记录清楚
原版维度与后处理从编码到 80 通道 mel、1025 通道 linear 的所有接口通过检查
结束与自由生成最长步数有上限;短句、长句、标点样本都不无限重复
评估同时检查内容正确性、声音质量、对齐与泛化,不只看训练 loss

这些扩展尚未执行。附录的定位是可读、可跑、可检验的机制演示,而不是把随机张量接成网络后宣布完成语音合成复现。

正在连接 GitHub 评论…