wikiAudio01|WaveNet:原理、架构与实现01|音频表示、μ-law 量化与概率建模
12 分钟
0 次观看

01|音频表示、μ-law 量化与概率建模

这一篇把声音变成你熟悉的张量与分类任务。读完应能回答:为什么一秒音频有成千上万个预测位置、256 类是怎样编码的,以及模型输出的“概率”究竟对应什么。

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

本篇主线: 声音是时间轴上的振幅序列;μ-law 改变振幅表示,WaveNet 预测下一类别的分布。

1. 离散波形与采样率

数字波形是一列按固定间隔记录的振幅。单声道、16 kHz、1 秒音频含 16000 个数;归一化振幅通常放在 −1 到 1。采样率是每秒记录多少点,基频是周期性信号每秒重复多少次。两者都用 Hz 表示,却不是同一个量。

离散波形的采样点、基频周期,以及波形模型在 TTS 中的位置

图 1|离散采样与波形模型的位置

先看上图的圆点:它们才是模型需要逐个生成的量。连线只是帮助观察形状。用一个简单正弦波把字母和数值对上:

x[n]=Asin⁡(2πF0nfs+ϕ).x[n]=A\sin\left(2\pi F_0\frac{n}{f_s}+\phi\right).
正弦波:符号与单位
数学记号含义、单位与示例
nn采样索引,从 0 开始;n=20n=20 是第 21 个点。
x[n]x[n]索引 nn 处的归一化振幅,无量纲,范围为 [−A,A][-A,A]。
AA振幅系数,无量纲;本例为 0.80.8。
fsf_s采样率,单位为点/秒(Hz);本例为 1600016000。
F0F_0基频,单位为周期/秒(Hz);本例为 200200。
ϕ\phi初相位,单位为弧度;本例为 00。
π\pi圆周率;2π2\pi 弧度对应一周。
sin⁡\sin正弦函数,将相位映射为 [−1,1][-1,1] 内的值。

代入 n=20n=20,按“时间 → 相位 → 振幅”计算:

步骤代入与结果含义
采样时刻20/16000=0.0012520/16000=0.00125 秒第 21 个点对应的时间
相位2π×200×0.00125=π/22\pi\times200\times0.00125=\pi/2四分之一个周期
振幅x[20]=0.8sin⁡(π/2)=0.8x[20]=0.8\sin(\pi/2)=0.8正弦波到达正峰值
周期1/200=0.0051/200=0.005 秒即 55 ms
每周期点数16000/200=8016000/200=80时间被离散为 80 个位置

正弦波只用于解释采样。 真实语音还含谐波、噪声与随时间变化的包络。

2. μ-law 压扩与振幅量化

PCM 常用整数保存振幅。直接把 16 位数值当类别会有 65536 类。经典 WaveNet 方案先做 μ-law 非线性变换,再量化为 256 类;这是一种振幅表示选择。原论文 §2.2

μ-law 压扩曲线,与不压扩的直线对照,并列出小振幅和大振幅算例

图 2|μ-law 压扩曲线与量化示例

μ-law 把更多量化等级分配给小振幅区域。 对照图中的曲线斜率:

原振幅区域压扩曲线在原振幅轴上的量化间隔
零附近更陡,相近输入被拉开更密
靠近 ±1\pm1更平缓更粗

量化格子在压扩后的纵轴上均匀划分,经过反变换后才得到上述不同间隔。

u=sign⁡(x)ln⁡(1+μ∣x∣)ln⁡(1+μ),q=round⁡(u+12μ).u=\operatorname{sign}(x)\frac{\ln(1+\mu|x|)}{\ln(1+\mu)},\qquad q=\operatorname{round}\left(\frac{u+1}{2}\mu\right).
μ-law 编码:符号与运算
数学记号含义、单位与示例
xx归一化输入振幅,先限制到 [−1,1][-1,1];这里省略时间下标。
μ\mu压扩参数,本实现固定为 255255。
QQ类别总数,Q=μ+1=256Q=\mu+1=256。
uu压扩后的连续值,仍在 [−1,1][-1,1] 内。
qq量化后的整数类别,取值为 0,…,2550,\ldots,255;不能直接当作线性振幅。
sign⁡\operatorname{sign}符号函数,区分正、零、负输入。
∣x∣\lvert x\rvert绝对值,取输入振幅的大小。
ln⁡\ln自然对数。
round⁡\operatorname{round}舍入到最近整数;代码采用 PyTorch 的 round 规则。

例如 x=0.5x=0.5:u=ln⁡(128.5)/ln⁡(256)≈0.87570u=\ln(128.5)/\ln(256)\approx0.87570,再算 (u+1)×255/2≈239.151(u+1)\times255/2\approx239.151,舍入得到 q=239q=239。若 x=0.01x=0.01,则 u≈0.22848u\approx0.22848、q=157q=157。这些运算逐点进行,张量的时间长度完全不变。

解码时,先把类别拉回压扩空间,再反变换:

u^=2q/255−1,x^=sign⁡(u^)256∣u^∣−1255.\hat u=2q/255-1,\qquad \hat x=\operatorname{sign}(\hat u)\frac{256^{|\hat u|}-1}{255}.
μ-law 解码:符号与数值示例
数学记号含义、单位与示例
u^\hat u由整数类别重建的压扩值;帽号表示重建量。
x^\hat x解码得到的归一化振幅。
qq已保存的量化类别;本例取 239239。
255255压扩参数 μ\mu。
256256类别数 μ+1\mu+1。

取 q=239q=239,有 u^=223/255≈0.87451\hat u=223/255\approx0.87451、x^≈0.49668\hat x\approx0.49668,与原振幅 0.50.5 相差约 −0.00332-0.00332。量化后通常不能无损恢复。

下面代码仅实现上面的编码过程。输入是浮点波形,输出是相同形状的 long 类别;变量 y 对应公式中的 uu。log1p(v) 计算 ln⁡(1+v)\ln(1+v),用于小数值时更稳健。

def mu_encode(x, mu=255):
    x = x.clamp(-1, 1)
    y = x.sign() * torch.log1p(mu * x.abs()) / math.log1p(mu)
    return ((y + 1) * mu / 2).round().long()
输入振幅编码类别解码或使用时的含义
−1-100最负振幅,不是静音
00128128解码约为 +0.000086+0.000086,并非精确的零
+1+1255255最正振幅

256 个等级是偶数,中心没有恰好落在零上的等级。卷积的左侧零填充发生在隐藏空间,不能用波形类别 0 替代。

3. 自回归概率分解与分类目标

量化后的序列记为 q0q_0,…,qtq_t。对 NN 个点、已知条件 cc,概率链式法则给出:

p(q0,…,qN−1∣c)=p(q0∣c)∏t=1N−1p(qt∣q0,…,qt−1,c).p(q_0,\ldots,q_{N-1}\mid c)=p(q_0\mid c)\prod_{t=1}^{N-1}p(q_t\mid q_0,\ldots,q_{t-1},c).
概率链式分解:符号与索引
数学记号含义、单位与示例
pp离散变量的概率或条件概率。
NN原始序列的点数;下面的示例取 N=3N=3。
tt当前目标的索引,从 11 到 N−1N-1。
qtq_t索引 tt 处的量化类别。
cc给定的条件序列。
∣\mid条件分隔符,表示右侧的信息已知。
∏t=1N−1\prod_{t=1}^{N-1}把各步条件概率相乘。

这是概率恒等式,尚未规定卷积结构。实际网络只读取最近有限的历史,属于建模近似。

取 N=3N=3,种子 q0q_0 已给定。如果 p(q1=18∣q0,c)=0.2p(q_1=18\mid q_0,c)=0.2,接着 p(q2=25∣q0,q1=18,c)=0.3p(q_2=25\mid q_0,q_1=18,c)=0.3,那么这段延续 [18,25] 的条件概率为 0.2×0.3=0.060.2\times0.3=0.06。本脚本给定第一个种子,学习后面的条件概率,没有训练 q0q_0 的先验。

分布建模相对于单值均方误差的区别,以及四类别 softmax 与损失的数值演算

图 3|分布预测与四类别 Softmax

上半图是一个人为反例:下一个振幅只可能是 ±0.5,各占一半。单值均方误差的最优答案是平均数 0,却不是这个分布中可能发生的结果。分布预测能保留多种可能,再抽出一个;这个例子不意味着所有回归模型都会失败。

下半图对应实际模型的最后一步。网络给每个类别一个未归一化分数 logit,记为 ℓj\ell_j:

pj=exp⁡(ℓj)∑k=0Q−1exp⁡(ℓk),Lt=−ln⁡pyt.p_j=\frac{\exp(\ell_j)}{\sum_{k=0}^{Q-1}\exp(\ell_k)},\qquad \mathcal L_t=-\ln p_{y_t}.
Softmax 与交叉熵:逐项符号说明
数学记号含义、单位与示例
QQ类别总数;实际模型取 Q=256Q=256,下方手算示例取 Q=4Q=4。
jj要查询的类别编号,0≤j<Q0\le j<Q。
kk分母中遍历所有类别的求和索引。
ℓj\ell_j网络对类别 jj 给出的未归一化分数(logit),不是概率。
exp⁡\exp指数函数;exp⁡(v)=ev\exp(v)=e^v,其中 ee 是自然常数,vv 是输入标量。
pjp_j归一化后的类别概率;所有类别概率之和为 11。
tt当前预测目标的时间索引。
yty_t时刻 tt 的真实类别编号。
pytp_{y_t}从预测分布中取出真实类别对应的概率。
Lt\mathcal L_t该目标的负对数似然损失;使用自然对数时,单位为 nats。
ln⁡\ln自然对数;正确类别的概率越高,损失越小。

图中临时使用 Q=4Q=4。从分数到概率,每一步都可直接核对:

类别 jj分数 ℓj\ell_j指数 exp⁡(ℓj)\exp(\ell_j)概率 pjp_j
0000110.10.1
11ln⁡2\ln2220.20.2
22ln⁡3\ln3330.30.3
33ln⁡4\ln4440.40.4

指数总和为 1010。损失只取真实类别对应的概率:当 yt=2y_t=2 时,Lt=−ln⁡0.3≈1.2040\mathcal L_t=-\ln0.3\approx1.2040;正确类别概率升至 0.60.6,损失降至约 0.51080.5108。实际 256 类完全均匀时,ln⁡256≈5.5452\ln256\approx5.5452 是一个有用的数量级检查。

概念检查

检查问题结论原因
16 kHz 改为 8 kHz,μ-law 会自动减半点数吗?不会μ-law 改振幅编码;重采样才改时间上的采样密度
训练损失很小,能认定说话自然吗?不能训练读取真实历史,自由生成读取自己的结果;第 04 篇用执行图对照

正在连接 GitHub 评论…