wikiAudio01|WaveNet:原理、架构与实现03|门控残差结构与条件对齐
12 分钟
0 次观看

03|门控残差结构与条件对齐

门控残差块把“历史”和“这个时刻要生成什么”结合起来。本篇沿一张结构图读模块,再用两个通道的具体数值走完门控、残差与 skip,最后检查条件边界。

返回 WaveNet 导读 · 代码架构与完整源码

读图先分清: residual 送下一层,skip 送输出头;条件与被预测的目标对齐。

1. 门控残差块的计算结构

教学实现的门控残差块计算图:条件加法、通道拆分、逐元素乘法、独立投影和恒等残差路径

图 1|门控残差块的计算结构

蓝色路径读取历史,绿色路径注入条件,橙色路径产生门控结果。 各步骤与图中的节点对应如下:

节点输入到输出应检查的关系
历史卷积与条件投影两路分别得到 [B,2C,T],随后相加两路时间轴必须对齐
通道拆分[B,2C,T] → 两份 [B,C,T]拆通道,不拆时间
门控tanh 结果与 sigmoid 结果逐元素相乘形状一致,得到 zz
残差zz 投影后与直达的 xx 相加并缩放图左侧恒等通路没有经过门控
skipzz 经独立投影送输出头不作为下一块的主干输入

导读中的原论文图 4 给出基本骨架;此图根据本教程实际代码重画,进一步显式画出条件投影、两个独立的 1×1 分支,以及 /√2。两图用途不同,不能把本图的所有选择都归为论文固定配置。

隐藏输入 xx 的形状为 [B,C,T],条件 cc 为 [B,H,T]。

输入维度说明
数学记号含义、单位与示例
BB批大小;本例为 44。
CC隐藏通道数;本例为 2424。
TT网络时间长度;本例为 512512。
HH条件通道数;本例为 22。

一个残差块的计算为:

a=Wf∗x+Vfc+bf,b=Wg∗x+Vgc+bg,a=W_f*x+V_fc+b_f,\qquad b=W_g*x+V_gc+b_g, z=tanh⁡(a)⊙σ(b),r=(x+Wrz+br)/2,s=Wsz+bs.z=\tanh(a)\odot\sigma(b),\qquad r=(x+W_rz+b_r)/\sqrt 2,\qquad s=W_sz+b_s.
门控残差块:符号与张量形状
数学记号含义、单位与示例
∗\ast因果时间卷积;本例核宽为 22。
xx隐藏输入,形状为 [B,C,T]。
cc与目标对齐的条件,形状为 [B,H,T]。
WfW_ftanh 分支的卷积权重,形状为 [C,C,2]。
WgW_gsigmoid 分支的卷积权重,形状同上;代码把两支合为 [2C,C,2]。
VfV_ftanh 分支的条件投影,矩阵形状为 [C,H]。
VgV_gsigmoid 分支的条件投影;逐位置应用,等价于 1×1 卷积。
bfb_ftanh 分支的总偏置,包含历史卷积与条件投影的偏置,长度为 CC。
bgb_gsigmoid 分支的总偏置,长度为 CC。
aatanh 分支激活前的张量,形状为 [B,C,T]。
bbsigmoid 分支激活前的张量;单独的 bb 与带下标的偏置 bfb_f 不同。
tanh⁡\tanh双曲正切函数,输出范围为 (−1,1)(-1,1)。
σ\sigmasigmoid 函数,输出范围为 (0,1)(0,1)。
⊙\odot逐元素乘法。
zz门控结果,形状为 [B,C,T]。
WrW_r残差分支的独立投影矩阵,形状为 [C,C]。
brb_r残差投影的偏置,长度为 CC。
WsW_sskip 分支的独立投影矩阵,形状为 [C,C]。
bsb_sskip 投影的偏置,长度为 CC。
rr送入下一层的残差结果,形状为 [B,C,T]。
ss送入输出头的 skip 结果,形状为 [B,C,T]。
2\sqrt 2本教程采用的残差缩放因子。

1×1 卷积只混合当前位置的通道,不扩大时间感受野。残差保留 xx 的直达路径,skip 让输出头读取不同深度的结果;两路不是同一个张量换名。上述 /√2 是本教学实现的尺度控制选择,并非原论文所有实现的固定规定。原论文 §2.3—2.5

2. 双通道门控与残差计算示例

用两通道数值演算 tanh、sigmoid、逐元素门控,以及残差与 skip 的不同结果

图 2|双通道门控与残差计算

固定一个时间位置,取 C=2C=2。下表逐步代入;atanh⁡\operatorname{atanh} 是 tanh 的反函数:

步骤设定或计算结果
内容分支a=[atanh⁡(0.5),−atanh⁡(0.5)]a=[\operatorname{atanh}(0.5),-\operatorname{atanh}(0.5)]tanh⁡(a)=[0.5,−0.5]\tanh(a)=[0.5,-0.5]
门分支b=[0,ln⁡3]b=[0,\ln3]σ(b)=[0.5,0.75]\sigma(b)=[0.5,0.75]
逐元素门控z=tanh⁡(a)⊙σ(b)z=\tanh(a)\odot\sigma(b)[0.25,−0.375][0.25,-0.375]
残差支路x=[0.2,−0.1]x=[0.2,-0.1],投影为恒等、偏置为零r=(x+z)/2≈[0.3182,−0.3359]r=(x+z)/\sqrt2\approx[0.3182,-0.3359]
skip 支路投影为 2 倍恒等、偏置为零s=2z=[0.5,−0.75]s=2z=[0.5,-0.75]

门值可以单独核验:对激活前标量 v=ln⁡3v=\ln3,σ(v)=1/(1+e−v)=1/(1+1/3)=3/4\sigma(v)=1/(1+e^{-v})=1/(1+1/3)=3/4。

门值是连续缩放,不是布尔开关;residual 与 skip 使用独立参数,因此结果不同。 门也不必对应某个可以命名的语音概念。

下面五行正好对应图中的步骤。返回值顺序是“下一层输入、输出头支路”,调用方必须分别接住。

def forward(self, x, cond):
    a, b = (self.causal(x) + self.condition(cond)).chunk(2, dim=1)
    z = torch.tanh(a) * torch.sigmoid(b)
    return (x + self.residual(z)) / math.sqrt(2), self.skip(z)

chunk(2,dim=1) 沿通道拆分,48 通道变成两份 24 通道;不是把时间截成两段。加法前两项都是 [4,48,512],乘法前两项都是 [4,24,512]。这两项 shape 检查比记类名更能发现实现问题。

3. 条件注入与时间对齐

条件类型时间上的变化注入方式例子
全局条件整段固定投影后沿时间广播说话人向量
局部条件随位置或帧变化对齐每个预测目标后注入语言特征或声学帧

源码只有局部接口 cond_target[B,H,T],没有额外的说话人 embedding。 即使某条人工信号的条件恰好不变,也沿用这个逐位置接口。

本实验使用两个条件通道,各块分别学习自己的条件投影:

通道定义与单位125 Hz、振幅 0.55 的例子
基频通道F0/(250 Hz)F_0/(250\ \mathrm{Hz}),无量纲125/250=0.5125/250=0.5
振幅通道无量纲振幅系数 AA0.550.55

因此输入条件为 [0.5,0.55],在这一条人工信号内保持不变。

每十毫秒一帧的条件与十六千赫兹波形对齐,突出第159点预测第160点时的帧切换

图 3|条件帧与预测目标对齐

图中使用另一组便于算边界的教学配置:采样率 16 kHz,条件每 10 ms 一帧,因此一帧覆盖 16000×0.010=160 点。帧 0 覆盖目标 q[0]q[0]…q[159]q[159],帧 1 从 q[160]q[160] 开始。用 q[159]q[159] 预测 q[160]q[160] 时,条件必须切到帧 1。

一种最简单的对齐规则是 ctarget[n]=h[⌊(n+1)/160⌋]c_{\mathrm{target}}[n]=h[\lfloor(n+1)/160\rfloor]。

条件对齐:索引说明
数学记号含义、单位与示例
nn网络输入的位置。
n+1n+1当前输入对应的波形预测目标位置。
ctarget[n]c_{\mathrm{target}}[n]网络位置 nn 所使用的目标条件。
mm条件帧的索引。
h[m]h[m]第 mm 帧的条件向量。
⌊⋅⌋\lfloor\cdot\rfloor向下取整;点号代表需要取整的表达式。
160160本例每帧覆盖的波形采样点数。

代入 n=158n=158 得帧 00,n=159n=159 得帧 11。这个例子假设音频与条件从同一起点开始,没有额外前瞻或上采样延迟。

代码的 cond[:,:,1:] 正在完成“与目标同偏移”。条件的时间 shape 正确,不代表帧边界就正确。真实系统还要统一裁剪起点、补零、上采样延迟;简单重复或可学习上采样只是实现选项,不能替代索引约定。

本实验的限制: 因为每条信号的条件是常数,错位一格也看不出来。接真实数据前应构造在指定索引突然变化的条件,检查目标落在边界左右时读到哪一帧。离线 TTS 可以利用已知的整句文本;禁止偷看的是尚未生成的目标波形。流式系统还需另行约束条件网络的前瞻。

4. 参数量核算与结构校验

固定 C=24C=24、H=2H=2。每行乘法计算权重,末尾加法计算偏置:

部件参数计算参数数
单块因果卷积48×24×2+4848\times24\times2+4823522352
单块条件投影48×2+4848\times2+48144144
单块残差投影24×24+2424\times24+24600600
单块 skip 投影24×24+2424\times24+24600600
12 个块12×(2352+144+600+600)12\times(2352+144+600+600)4435244352
Embedding256×24256\times2461446144
输出头(24×24+24)+(256×24+256)(24\times24+24)+(256\times24+256)70007000
全模型44352+6144+700044352+6144+70005749657496

总数与脚本统计一致。参数数与 shape 是必要检查,但不能独自证明连接关系正确。

自测:删掉 skip、只把最后一层残差送输出头,shape 能否仍然正确?能,但网络函数已改变,不能仅靠 shape 证明结构忠实。下一篇会展示各层 skip 怎样汇总,以及损失究竟在哪里计算。

正在连接 GitHub 评论…