← 阅读室全部精读正在排版公式与图表…
PAPER ANALYZER · P04 · 细粒度方向

wav2vec 2.0:从原始波形中学习能够迁移的语音表示

学术型精读 · 概念、公式、实验、源码与可验收练习

Baevski、Zhou、Mohamed、Auli · NeurIPS 2020 · 论文 · 官方代码 3d262bb25690

一句话总结

wav2vec 2.0 先把波形压缩为连续特征,再遮住部分时间片,用上下文去辨认离散目标;少量转写标签用于后续语音识别微调。语音表示不等于情绪表示,需要独立验证。

先分清预训练与语音识别

这篇论文研究如何利用大量没有转写的语音,减少自动语音识别对人工标注的依赖。预训练阶段不是直接输出汉字或英文单词,而是学习语音时间序列中的规律;微调阶段才使用音频与转写构成的标签数据,通过字符预测和解码得到文字。Figure 1 把这两个层次中的预训练结构画得很清楚。

摘要中“十分钟标注数据”容易被误读。优秀结果同时依赖规模很大的无标注语音预训练,以及某些设置中使用的外部语言模型。十分钟只指微调转写标签量,不是模型一生仅听过十分钟语音,也不是十分钟即可完成训练。评价低资源方法时,必须分别记录无标注音频、标注音频和语言模型文本。

对于情绪研究,最直接的价值是把声音变成随时间变化的表示,供下游分类或融合使用。但原论文优化的最终任务是识别说了什么,情绪任务还关心怎样说。同一个语句的语速、停顿、音高与强度变化可能携带情绪;这些信息是否保留、在哪层保留,需要通过下游实验判断。

原始波形怎样变成较短的序列

原始输入是十六千赫兹采样的波形,一秒包含一万六千个采样点。卷积特征编码器使用七层一维卷积,将高频采样序列压缩成较短的潜在序列。各层步长相乘得到总步长三百二十,感受野约四百个采样点,即二十五毫秒;一秒音频经无填充卷积后约得到四十九个位置。

这些位置不是人工音素边界,也不是每个位置对应一个字。卷积提取器学习局部声学模式,随后 Transformer 利用更长范围的上下文。音频长度变化会改变序列长度,因此批处理中需要有效长度与填充掩码。把十六千赫兹与四十四点一千赫兹波形混用而不重采样,会改变模型理解的时间尺度。

基础上下文网络有十二层、七百六十八维、八个头;大型网络有二十四层、一千零二十四维、十六个头。卷积的下采样已经大幅缩短序列,但长录音仍可能造成较高显存开销。切片长度必须与任务定义一致,不能为了省显存把一句情绪变化明显的话随机截断后继续沿用整句标签而不检查。

为什么遮住特征,却保留目标分支

模型在卷积输出上选择若干连续跨度,用一个可学习向量替换这些位置,再交给上下文网络。目标分支则从未遮挡的原始局部特征产生离散表示。这样上下文网络不能直接读取被遮住位置的局部答案,却可以通过周围声音推断它。若把目标分支也遮住,就破坏了原本需要恢复的信息。

论文设置中开始位置采样概率为 0.065,每个跨度覆盖十个连续位置,而且跨度可以重叠。它不等于最终只遮住百分之六点五的位置;原文报告约一半的位置被遮挡。Figure 2 展示跨度重叠后的长度分布。实现者必须区分“起点概率”“跨度长度”和“最终覆盖比例”这三个量。

被遮住的输入仍然占据原时间位置,位置关系与有效长度没有消失。上下文网络输出对应位置的表示,再与正确离散目标及干扰目标比较。这与把遮挡片段从序列删除不同,删除会压缩时间轴并改变所有后续位置关系,尤其不适合直接沿用原始对齐信息。

离散量化、对比目标与多样性

量化器使用多个码本组,每组选择一个条目,再把它们组合形成目标。原文主要设置为两个组、每组三百二十个条目,因此组合数量远大于单个码本条目数。离散目标可以把连续波形中的细节归纳为可比较的单位,但这些单位由训练学得,不能直接称为人工定义的音素或情绪类别。

选择离散条目本来不可直接反向求导,作者使用 Gumbel-softmax 与直通估计。直观上,前向时使用近似离散的选择,反向时通过连续近似传递梯度。温度影响分布的平滑程度,训练中的温度调度也属于方法。它是优化技巧,不能理解成量化器已经拥有真实语音类别标签。

对比学习让当前位置的上下文表示识别正确量化目标,并排斥干扰目标。原文从同一语音中抽取其他被掩码时间位置作为负例,主要设置为一百个负例。模型必须依靠上下文分辨局部内容,而不是仅重建每一个波形采样点;这与普通均方误差的声音重建目标不同。

如果量化器总使用少数几个条目,很多声音会被映射到相同目标,学习任务便退化。多样性损失鼓励平均码本使用分布具有较高熵。要注意它作用于批次平均使用情况,而不是强制每个单独位置都随机均匀选择;后者会使每个目标失去确定性,反而不利于辨认。

微调、解码与指标

微调使用 CTC 将较长的帧级输出序列映射到较短的字符序列。它通过对多种可能对齐路径求和,允许同一个字符占据多个时间位置,再折叠重复与空白符。CTC 并不要求人工为每一个音频帧标注字符,但仍需要整段转写作为监督,因此不能称为完全无标注训练。

外部语言模型在解码阶段利用文本规律改善候选转写。它可能显著降低词错误率,所以比较结果时必须明确有没有语言模型、使用哪一种以及解码参数如何选择。仅用网络贪心输出与结合强语言模型的结果不是同一个系统;表格中好看的数字不一定只由声学编码器产生。

词错误率计算替换、删除和插入相对于参考词数的比例。它衡量转写错误,不能当作情绪分类准确率。若把模型用于情绪特征提取,应重新定义 UAR、宏平均 F1 或其他适合类别不平衡的指标,而不是用识别文本更准确来直接证明情绪表示更好。

实验与版本内差异

Table 1 报告十分钟标注设置下,大型模型在大规模无标签语音预训练并结合 Transformer 语言模型后达到 4.8/8.2 的测试词错误率。正文 Section 5.1 仍出现 5.2/8.6 的数值,本页按表格及摘要采用 4.8/8.2,并明确保留差异。不要悄悄混合不同段落的版本读数。

Table 9 展示同一低标注大型模型在没有语言模型、四元语言模型和 Transformer 语言模型下的巨大差异。这比只看最佳值更能说明系统的组成。Table 4 则比较连续输入和量化目标的搭配,支持让上下文网络接收连续输入而用离散目标监督的设计;这类消融应在同一缩减训练设置中比较。

Table 13 进一步检查多样性权重与量化方式,说明目标设计不是任意拼接。Figure 3 的码本与音素分析展示一定相关性,但不能推断每个码本条目唯一对应一个音素。观察相关结构只是表示分析的一部分,还需要考虑数据频次、语音变体和聚类边界。

面向情绪研究的边界

作者讨论了 CTC 架构及字符输出与语言模型配合的限制,附录错误分析也显示低标注设置中的稀有词和拼写问题。独立判断还应补充:主要实验基于英语语音识别,无法直接保证中文、多方言、噪声录音和情绪分类的效果。部署到新场景时,采样率相同不代表声音分布相同。

细粒度方向可以先比较不同层的表示对情绪变化的敏感程度,并检查均值池化是否抹平短时变化。跨场景方向可以比较干净录音与设备噪声、不同说话人或不同语言。先固定编码器、仅改变池化或分类头,再考虑微调;否则难以判断收益来自表示层、任务监督还是更大的优化预算。

公开 fairseq 仓库持续加入工程选项,当前版本包含更多掩码与设备兼容逻辑。本文固定提交并核对核心机制,不宣称所有默认值都与原论文实验逐项相同。若使用第三方封装,应继续记录特征归一化、输出层、是否冻结卷积与有效长度处理,不能仅保存一个模型名字。

公式逐步读:变量、运算与适用范围

原文式 (1):Gumbel 选择概率

$$p_{g,v}=\frac{\exp((l_{g,v}+n_v)/\tau)}{\sum_{k=1}^{V}\exp((l_{g,k}+n_k)/\tau)}$$

g 表示码本组,v 表示条目,n 为 Gumbel 噪声。温度与随机扰动服务于可训练的离散选择。

原文式 (2):联合目标

$$L=L_m+\alpha L_d$$

对比损失与码本多样性损失组合,主要设置的权重为 0.1;不能只保留对比项却仍称完整目标。

原文式 (3):对比预测

$$L_m=-\log\frac{\exp(\operatorname{sim}(c_t,q_t)/\kappa)}{\sum_{\widetilde q\in Q_t}\exp(\operatorname{sim}(c_t,\widetilde q)/\kappa)}$$

候选集合包含正确目标与负例,c 是上下文表示,q 是量化目标。主要实验温度为 0.1。

原文式 (4):多样性项

$$L_d=\frac1{GV}\sum_{g=1}^{G}\sum_{v=1}^{V}\bar p_{g,v}\log\bar p_{g,v}$$

最小化负熵形式鼓励使用更多码本条目。部分实现使用 perplexity 形式,需要核对尺度与权重,不能只因名字相同就当成数值完全一样。

教学整理:词错误率

$$WER=\frac{S+D+I}{N}\times100\%$$

S、D、I 是替换、删除、插入数,N 是参考词数。此为评价指标定义的教学整理,不是新增的原文编号公式。

实验读数:先固定协议,再比较数值

原文 Table 1:十分钟标签,Transformer LM,WER 越低越好
预训练与模型test-cleantest-other
BASE / LS-9606.912.9
LARGE / LS-9606.810.8
LARGE / LV-60k4.88.2
原文 Table 9:LARGE / LV-60k 十分钟标签,解码不同
语言模型test-cleantest-other
无40.238.7
4-gram6.610.3
Transformer4.88.2

计算流程图

flowchart LR
A[16 kHz waveform] --> B[Convolutional features]
B --> C[Span masking]
C --> D[Context Transformer]
B --> E[Unmasked target quantization]
D --> F[Contrastive prediction]
E --> F
E --> G[Codebook diversity]
D --> H[Downstream CTC or emotion head]

沿图逐条检查箭头:每个箭头传递的是张量或监督信号,并不代表额外的数据集;训练目标旁的分支在部署时未必保留。建议先在纸上填入批大小、序列长度、通道数,再阅读下面的源码。一个模块即使名字相同,只要输入轴、掩码或输出使用方式改变,也不能直接视作同一个实验。

论文方法与固定版本源码对照

fairseq/models/wav2vec/wav2vec2.py:458–473

            if mask_indices is None:
                mask_indices = compute_mask_indices(
                    (B, T),
                    padding_mask,
                    self.mask_prob,
                    self.mask_length,
                    self.mask_selection,
                    self.mask_other,
                    min_masks=2,
                    no_overlap=self.no_mask_overlap,
                    min_space=self.mask_min_space,
                    require_same_masks=self.cfg.require_same_masks,
                    mask_dropout=self.cfg.mask_dropout,
                )
                mask_indices = torch.from_numpy(mask_indices).to(x.device)
            x = index_put(x, mask_indices, self.mask_emb)

掩码索引根据概率与跨度生成,再把选中位置替换成 mask_emb。这是替换,不是删除位置;padding_mask 参与避免把填充当作真实语音。

fairseq/models/wav2vec/wav2vec2.py:557–577

    def compute_preds(self, x, y, negatives):

        neg_is_pos = (y == negatives).all(-1)
        y = y.unsqueeze(0)
        targets = torch.cat([y, negatives], dim=0)

        logits = torch.cosine_similarity(x.float(), targets.float(), dim=-1)
        logits = logits / self.logit_temp
        logits = logits.type_as(x)

        if is_xla_tensor(logits) or neg_is_pos.any():
            if not hasattr(self, "_inftensor"):
                fillval = -float(2**30)
                self._inftensor = (
                    torch.tensor(fillval).to(x.device)
                    if is_xla_tensor(logits)
                    else float("-inf")
                )
            logits[1:] = index_put(logits[1:], neg_is_pos, self._inftensor)

        return logits

正确目标与负例拼接后计算余弦分数并除以温度;与正例完全相同的负例受到屏蔽。注意候选轴与批次、时间轴不同,不能直接套普通二维分类逻辑而不检查形状。

代码核查固定在提交 3d262bb25690e4eb2e7d3c1309b1e9c406ca4b99。这里展示的是公开仓库的实际文件,不把重新写的教学代码冒充作者实现。仓库后续可能包含新版本、工程兼容选项和不同默认参数;本文只将已核实的语句对应到论文机制。下载权重成功、模型能够前向传播、复现论文最终指标是三个不同的验收层级。

从读懂到能够独立实现:可执行学习任务

第一步,对一段自己有权使用的音频记录采样率、声道数、时长与振幅范围,转换为十六千赫兹单声道后再输入。验收:输入样本数与时长吻合,输出时间长度与卷积总步长相符;不要把重采样仅写成修改文件头。

第二步,用一百个时间位置模拟掩码起点与十位置跨度,统计起点比例和最终覆盖比例。验收:两者明显不同,并能解释重叠导致的变化;画出遮挡条带,证明目标分支仍保存未遮挡特征。

第三步,构造一个正确目标和三个负例,用手算或小脚本得到余弦分数、温度缩放和交叉熵。验收:把正确目标分数提高后损失下降;改变温度会改变分布,但不会改变固定分数的排序。

第四步,在小型情绪划分上缓存不同层的表示,先比较简单平均池化与保留时间序列的轻量模型。验收:记录层编号、有效长度、冻结状态和同一组数据编号;所有比较使用相同标签与选择协议。

第五步,单独测试说话人变化或噪声变化,只选择一个作为第一项跨场景实验。验收:分别报告源域与目标域各类召回,保存失败音频编号,并能说明错误来自情绪信息不足、设备差异还是明显预处理错误。

建立可检查的实验记录

开始第一轮实验前,建立四份小文件:数据清单记录样本编号、来源、标签与划分;配置文件记录预处理、随机种子、模型名称和冻结范围;结果表记录验证指标、选中轮次与最后测试指标;错误清单保存预测错误的样本编号及观察理由。这些文件比一张最高准确率截图更能说明你真正控制了实验条件,也能让后续细粒度或跨场景拓展沿用同一条证据链。

对视频、语音或多模态情绪数据,必须优先检查主体、会话和视频来源是否跨集合重复。同一原始视频切出的多个片段高度相关,随机按片段划分可能让模型记住说话人、背景或录制设备。跨场景问题至少要明确源域训练集、源域验证集和目标域测试集;若使用目标域标签选择提示词或超参数,就不应再把它描述为完全未见目标域的泛化结果。

为避免把实现错误误认为研究发现,先运行一个极小批次,打印输入输出形状、数值范围、有效长度以及损失是否有限。随后在少量训练样本上尝试拟合,验证模型确实能够更新指定参数。如果极小训练集都学不会,优先检查标签编码、掩码方向、归一化、学习率和冻结设置;此时直接扩大数据量通常只会延长排查时间,而不能证明模型本身不适合任务。

消融实验一次只改变一个关键因素,其他预处理、划分、优化预算和选择规则保持一致。第一轮以发现实现问题为目标,只用一个种子;确认代码与趋势合理之后,再增加多个种子并保留每次独立结果。均值用于概括趋势,标准差用于展示训练波动,但都不能替代对样本泄漏和评价口径的检查。不同论文中的最优数字不能在协议不明时直接相减。

解释实验失败时,先区分三层原因:实现层是否正确地执行了计算;优化层是否在给定预算内学到了信号;数据层是否提供了任务需要的信息。比如文本缺少反讽语调、静态图像看不到表情变化、音频包含录音噪声,这些问题不能仅靠增加网络深度解决。把失败样本分组后再提出修改,每项修改应能对应一个可观察的问题和一个预先规定的验证指标。

学习笔记采用“论文本身说了什么—源码实际做了什么—我在本地验证了什么”三栏记录。第一栏附页码或图表编号,第二栏附固定提交与行号,第三栏附命令、环境和输出。本文已完成原文及源码核对,未宣称在你的机器上重训原论文。下面的练习属于待执行计划;只有真正运行并保存结果后,才能把相应项目改为“已完成”。

短引语与阅读定位

原文短语 Self-Supervised Learning(标题):监督来自音频自身构造的目标。

原文短语 Quantization Module(Section 2.2):离散目标由可学习码本形成。

原文短语 Contrastive Loss(Section 3.2):任务是从候选中辨认正确的局部目标。

参考资料与核验边界

论文摘要与版本信息;完整论文 PDF;作者公开仓库固定版本。公式中标注“教学整理”的表达用于显式说明原文的计算步骤,不声称具有原文公式编号。所有实验数字均指原论文报告结果,不是本次新训练得到的结果。英文短引语合计不超过二十五个词。

自己的解释与验收记录

写出一条输入到输出的链路、一个关键公式的含义,以及你完成的最小检查。笔记仅保存在当前浏览器,可从主站「我的学习笔记」导出。