wikiAudio03|Tacotron 2 与说话人迁移:声学接口的形成02|位置敏感注意力:累计对齐与解码状态
8 分钟
0 次观看

02|位置敏感注意力:累计对齐与解码状态

Tacotron 2 的输入文字有 NN 个位置,输出有 TT 个 mel 帧;一个字符通常持续多个帧,因此不能让“第几个解码步”直接等于“第几个字符”。注意力每步决定从哪些文字位置读取信息,位置敏感机制再利用过去的读取轨迹,降低重复或跳过文字的风险。

本文沿着一次解码步追踪状态。前置知识只需 softmax、卷积和 LSTM。原论文 §2.2描述累计注意力;NVIDIA 实现还把上一帧和累计权重一起交给位置卷积。两者不能混为逐行相同的代码。

位置敏感注意力提供推进线索,并不构成严格的单调路径约束。

图 1|内容记忆、解码状态与历史对齐共同决定读取位置

图 1|内容记忆、解码状态与历史对齐共同决定读取位置

1. 解码状态与历史信息

对象教学形状从哪里来下一步是否保留
文本记忆[B,N,H]=[1,4,512]卷积编码器与双向 LSTM全句固定
注意力查询[B,Q]=[1,1024]解码循环状态继续更新
上一步权重[B,N]=[1,4]上一次 softmax保留一份
累计权重[B,N]=[1,4]历史权重逐步相加持续累积
上一帧 mel[B,F]=[1,80]训练读标签,推理读预测反馈给 prenet

这里 BB 是批大小,NN 是文字位置数,HH 是编码维度,QQ 是查询维度,FF 是 mel 频带数。N=4 只是演示;padding 位置必须从 softmax 中排除。位置卷积沿文字轴移动,不能误放在 mel 时间轴上。

2. 从历史权重到上下文向量

把上一时刻的累计权重卷积成位置特征,再与内容和查询相加。下面先用论文式累计特征解释;若采用 NVIDIA 实现,可将上一帧权重与累计权重堆成两个输入通道。

at−1,ncum=∑τ=1t−1ατ,n,ft,n=Conv⁡(at−1cum)n,et,n=v⊤tanh⁡(Wqqt+Whhn+Wfft,n+b),αt,n=exp⁡et,n∑j∈Vexp⁡et,j,ct=∑n∈Vαt,nhn.\begin{aligned} a^{\rm cum}_{t-1,n}&=\sum_{\tau=1}^{t-1}\alpha_{\tau,n},\\ f_{t,n}&=\operatorname{Conv}(a^{\rm cum}_{t-1})_n,\\ e_{t,n}&=v^\top\tanh(W_q q_t+W_h h_n+W_f f_{t,n}+b),\\ \alpha_{t,n}&=\frac{\exp e_{t,n}}{\sum_{j\in\mathcal V}\exp e_{t,j}},\qquad c_t=\sum_{n\in\mathcal V}\alpha_{t,n}h_n. \end{aligned}
符号、形状与约定
符号解释与例值
t,τt,\tau当前及历史解码帧索引;从 1 开始。
n,j,Vn,j,\mathcal V文字索引与有效文字位置集合;padding 不属于该集合。
αt,n\alpha_{t,n}第 t 帧对文字 n 的概率,单行和为 1。
at−1,ncuma^{\rm cum}_{t-1,n}之前读到该位置的权重总量;可大于 1,不是概率分布。
ft,nf_{t,n}沿文字轴卷积得到的位置向量;卷积核可看到相邻文字的历史。
qt,hnq_t,h_n解码查询与第 n 个文字的编码向量。
Wq,Wh,Wf,bW_q,W_h,W_f,b把三类输入投到相同注意力维度的可训练矩阵及偏置。
v⊤,et,nv^\top,e_{t,n}可训练向量的转置,将隐藏向量压成一个未归一化标量分数。
tanh⁡,exp⁡\tanh,\exp逐元素双曲正切与指数函数。
ctc_t加权读取到的上下文向量,维度与文字记忆一致。

为什么要累加?若连续三帧都集中在第一个字符,累计值会显著增大,网络有机会学到“这里已停留很久”。但 softmax 仍允许回头,是否推进由学习结果决定。严格不回退需要额外约束,不能由图上画出的斜线自动推出。

3. 注意力读取的数值示例

设三个有效分数是 0、ln 2、ln 7,第四个位置是 padding。指数分别为 1、2、7,和为 10,因此概率是 0.1、0.2、0.7、0。

有效文字位置记忆向量概率加权贡献
0(1,0)0.1(0.1,0)
1(0,2)0.2(0,0.4)
2(3,3)0.7(2.1,2.1)
padding(99,99)0(0,0)

输出上下文为 (2.2,2.5)。即使 padding 分数误设为 100,先屏蔽再 softmax 仍会把其概率置零;先 softmax 再清零则会破坏归一化。

图 2|注意力矩阵中的正常推进、停留与跳跃示意

图 2|注意力矩阵中的正常推进、停留与跳跃示意

4. 核心实现及执行地图

图 1 中 energy → mask → softmax → bmm 是以下片段的边界。能量网络和循环更新放在调用方;这使我们能用已知分数独立验证读取逻辑。

def attend(energy, memory, valid):
    # energy [B,N], memory [B,N,H], valid [B,N]
    if not valid.any(-1).all():
        raise ValueError('each item needs a valid text position')
    weights = energy.masked_fill(~valid, -torch.inf).softmax(-1)
    context = torch.bmm(weights[:,None,:], memory).squeeze(1)
    return weights, context

masked_fill 将无效位置设为负无穷;[:,None,:] 把权重变为 [B,1,N],与 [B,N,H] 相乘得到 [B,1,H]。最后只移除长度为 1 的读取轴,不能用无参数 squeeze() 意外删掉批轴。

CPU 实验实际得到权重 [0.1,0.2,0.7,0] 和上下文 [2.2,2.5]。它证明遮罩和加权读取正确,尚不能证明完整网络学到了对齐。

先检查概率归一化、padding 为零和状态是否跨步累积,再判断注意力是否学会推进。

5. 根据对齐轨迹定位错误

现象首查对象区分实验
同一竖列长期高亮,语音重复累计状态、prenet 输入、训练覆盖对比 teacher forcing 与自由生成
跳过一大片文字文字规范化、长度、异常长句固定音频,将文本分句对照
尾部注意力跑到 padding有效长度和 softmax mask给 padding 极大分数,检查概率仍为零
不同句子互相影响上一句的循环状态没有清空单独生成与批量生成对比

注意力图漂亮只说明一种内部行为;仍要检查漏字、结束位置和最终音频。

继续阅读 训练、停止判断与损失,把对齐状态接到完整解码循环。

专题导航:TTS 总目录 · 上级章节 · 实验代码与实测记录

正在连接 GitHub 评论…