
这是neurips 2021的为数不多的,oral的,而且多少我能看懂一点点的一篇爽文。来自facebook AI和google AI. (这两个team在一起搞事情---有趣;看了脚注之后,知道,第三作者是在facebook AI期间参与的这项工作!所以本质上还是facebook AI的贡献。) 前几天就被种草了,今天尝试来拔草!
arxiv的投稿的论文在:(35页,建议看这个):
https://arxiv.org/pdf/2105.11084.pdf
neurips 2021的论文【本笔记是基于如下的论文的】在:
https://proceedings.neurips.cc/paper/2021/file/ea159dc9788ffac311592613b7f71fbb-Paper.pdf
他们还有一个补充材料:
https://proceedings.neurips.cc/paper/2021/file/ea159dc9788ffac311592613b7f71fbb-Supplemental.pdf
以及在openreview上的URL:
https://openreview.net/forum?id=QmxFsofRvW9
可以看到,openreview的打分为:8, 8, 7
然后PC chair的评语为:
这项工作被所有审稿人推荐接受。
三位审稿人们一致赞扬了实验设置的彻底性和可重复性,以及结果的重要性。
这项工作有可能对低资源语言的语音识别产生重大影响。是构建实用的语音识别系统的一个重要进步。
背后的思考:
立意鲜明;方法纯粹;结果牛叉。
数据永远不够多。各个地方的方言,口音,各个地区的人的用词习惯,专业领域的专业名词的挑战。人名,地名,机构名等等。这些问题,都在揭示着asr里面的数据的量和质的问题。
一句话,出发点motivation很好,方法值得推敲,结果solid,推广意义显著。没有理由不oral!
【背景】
尽管最近几年,随着深度神经网络的发展,asr取得了快速进展,但当前的语音识别系统仍然需要标记好的训练数据,形如《wav, text》。这将这项技术限制在被全球使用的一小部分语言中,例如英语,中文等联合国官方语言。
【新方法】
本文介绍了wav2vec-U,即wav2vec Unsupervised的缩写。这是一种在没有任何标记数据的情况下训练语音识别模型的方法。
我们利用自我监督(self-supervised)的语音表示(wave representations)来分割未(用文本)标记的音频,并通过对抗性训练学习从这些表示(representations - tensors)到音素(文本的phonemes)的映射。
正确的(关于wav的)表示是我们方法成功的关键。
【实验结果】
与之前最好的无监督工作相比,wav2vec-U 将 TIMIT 基准上的“音素错误率”从 26.1 降低到 11.3。
在更大的英语 Librispeech 基准测试中,wav2vec-U 在 test-other 上达到了5.9(啊!)的“单词错误率”(这个的确很高了!nvidia的citrinet的论文上,最好的结果,也不过是4.5%左右,还是使用了外部语言模型做post-ranking之后。),与仅两年前在 960 小时“有标记数据”上训练的一些最好的已发布系统相媲美【牛了个必了!】。
我们还对其他九种语言进行了试验,包括低资源语言,如吉尔吉斯语、斯瓦希里语和鞑靼语。代码将开源【嗯!必读的了。又被种草了。】。

图一,wav2vec unsupervised的精髓图示表示
上图一,给出了wav2vec unsupervised的核心框架算法。一共有七个步骤:
获取speech 的表示,这个相对简单,例如使用gpt2或者bert类似的方法,都可以基于self-supervised learning来得到一段语音的稠密向量表示(dense vector representations);这里使用的是所谓wav2vec 2.0。
对每个时间步,执行k-means 聚类。(感觉应该是把相似发音合并在一起,把距离比较远的,切开);
切分成音素单元(这个就有点问题了,这里是知道每个音素单元的reference 波形和wav length吗?如果是简单根据第二步的k-means来切分,那其实并不能保证一个segment就对应一个phoneme的!这个的准确度是多少?需要仔细check 论文。
构建segment 表示。这个应该是根据本segment内部的若干frames的表示,来构造本segment(切片)的向量表示;(抠细节:对来自wav2vec 2.0的表示执行mean pooling,然后是搞一下PCA,主成分分析,之后是相邻segments之间的第二次mean pooling--好吧,细节还是不怎么清晰,后面会搞懂的!!!)
使用一个generator(怎么来的?)来从语音的segment sequence生成phoneme sequence。
从非标签文本(即这些文本是同一个语言的,但是不保证是wav的原样文本!)进行音素化,例如把一个个的英文单词,转换成phoneme序列。(cmu dict就可以实现这个功能);
对抗训练,输入有两个部分,其一是来自第六步的“音素化”,其二是来自第五步的generator生成的音素序列。然后对比这两个序列,进行phoneme-by-phonme(?)的real或者fake的判断。
可以进一步图示如下:

图1.2 关于wav2vec 2.0的图示
看一个细节:
我们还引入了一种无监督的交叉验证指标,以支持基于“无标记开发数据”的模型开发(检验集合,发展集合,开发集合)。我们的无监督语音识别模型的“生成器”(generator),非常轻量级:它由一个仅包含大约90k(啊。。。这个也太小了!)个参数的时间卷积组成,我们向其中输入了冻结的 wav2vec 2.0 表示(即来自wav2vec2.0的关于语音的表示张量无法修改!)。
还是看的有点云里雾里。
wav2vec2.0的训练的时候,应该是需要《wav,text》的!感觉是借用了一些来自wav2vec2.0里面的文字/音素的记忆?【有待于进一步印证!TODO -》印证了,不需要!】
这里一开头就说,要搞下speech和text的分别的“表示”(representations),为的是无监督学习asr所用。好的表示,是无监督地构建从speech到text的“映射关系”的关键所在!
本文采用的是wav2vec2.0。(看来没有用文字,只用了语音!)。其包括了一个卷积特征编码器:

即f函数,负责把一个语音序列X,映射到一个latent speech representation表示:

然后,再经过一个transformer g,来把Z变成上下文相关的表示
。即:
这里的每个z,表示一个长度为25ms的语音片段(stride=20ms=步长)。
另外,这里的transformer,是按照bert的形式构造的。(mlm容易理解,可是next sentence prediction这个loss呢???看来需要回头细看wav2vec2.0的详细内核了。)
在训练wav2vec 2.0的时候,上面的latent speech representation表示:
,会经过一个量化模块(quantization module)来被离散化(discretized):
to represent the targets in the objective?(为的是在目标函数中表示“目标targets”?这一句话不理解。。。)
接着,论文中说,quantization (量化) uses a Gumbel softmax to choose entries from two codebooks. 这块的“two codebooks”,完全不理解是啥。。。以及Gumbel softmax是啥?【论文第二页的bottom的部分】
在本论文的实验中,使用的包括两个wav2vec 2.0的预训练模型:
53K小时 LibriLight下的英文预训练模型;
XLSR-53,是53种语言下的,60K小时的,多语言预训练模型。
【去除silences】
我们实验的很多数据,都包括带有“静音”的语音文件(例如前导静音 -- 语音文件中的前几秒是没有人声的那种。)因为这些“静音”不对应到文本文字,我们尽可能多地删除它们。
这里使用的是rVAD,一个无监督的voice activity detection (VAD)模型,其决定语音讯号的哪些片段是对应到“静音”的。然后这些“静音片段”就被删除了。
【语音表示】
去除静音之后,我们用wav2vec 2.0来把无标签纯语音文件做“嵌入”(embedding),从而获取语音表示(向量,张量表示)。
具体为,这里的context network包括24个transformer (encoder) blocks,然后,对于第l个(英文el,L的小写)block,的第t个时间步的输出,我们标记为:
我们的目标:把上面的
映射为phonemes(音素),而且是在无标签数据的前提下!
但是,【这个但是很重要】,wav2vec 2.0的最上面一层(第24层)block的输出,可能无法很好地满足我们的任务的要求!这是因为,它们是被MLM(masked language model)类型的目标来训练的。即,目标是直接预测:
masked latent representations (例如梅尔谱)spanning 25ms of speech audio。
(跨度为25ms的梅尔谱)
而,这个目标,是比我们的phoneme的duration,要短很多很多的。(即一个Phoneme的发音时长,一般是远远超过25ms的!)
为了通过实验验证这一点,我们搞个实验:
一个wav2vec 2.0 LARGE的英文预训练模型。该模型有24层,是基于Libri-Light数据集预训练好的。
一个有监督的phoneme recognizer,用的是CTC loss;
recognizer用的是wav2vec 2.0 LARGE的第1到24层的分别的输出;
评估用的是phone error rate (PER),使用的“评估集合”是librispeech 里面的dev-other。
分类器的输入是
;然后分类器本身是包括了一个单层linear mapping接上softmax-normalization。
示意图为:

图二,测试wav2vec 2.0的第1到24层的输出,对有监督phoneme recognizer的精度的影响
或者用下图:

图2.2 语音数据预处理
根据上图的配置,下图很好地展示了1到24层输出,对于per的最终的影响:

图三,24层transformer encoder,每层输出对最终per的效果的影响。第十五层的输出,取得了最好的per。
从上图中可以看到:
从1到10层,per不行(错误率太大);
最后的21到24层,per也不行(太大);
从14-19层,效果不错,其中第15个block的输出,得到了最好的效果的per=7.5%。
附录A里面,还有关于其他的语言的介绍。为了简单期间,以后(?)default l=15,从而我们的简化方法为:

在“好的”地方,对原始语音信号进行切割,可以让切割出来的信号片段更好地和目标phoneme对齐。
本文使用的是一个简单的把wav2vec 2.0的语音表示
进行“聚类”的方法。
把(无文本标签的)语音的latent speech representation,即
按照k=128,进行k-means聚类!这里使用的是FAISS库来在gpu上进行fast clustering!每个
被对应的聚类ID
标注,并且我们在标签被改变的地方,加入切割点。
例如,如果聚类之后的ID的序列为,1 1 2 2 3 3 4 4 4 2 2,那么加了标签之后的结果为:
1 1 ||| 2 2 ||| 3 3 ||| 4 4 4 ||| 2 2
这样就得到被切割之后的结果了。一旦切割完毕之后,we compute a 512-dimensional PCA over all speech representations output by wav2vec 2.0 for the training set。这个句子不是很理解。
这是在
上面搞个512维度的PCA吗???
然后,对于每个segment,我们对PCA的表示,进行mean-pooling(取均值pooling),从而获取关于当前segment的“均值表示”。PCA只保留最重要的特征,我们也通过实验证实这个的确真实有效!
另外,segment 边界,都是噪音比较高的,因为没有用文本来“规整”。因此,我们发现,可以扩展一下,对相邻的segment pairs进行mean-pool操作。这个操作,可以提高robustness。
这样,得到的是sequences of speech segment representation:

附录B里面,有基于一个实际例子的切割策略。我们这里直接看下。

图四,k-means切割(太细粒度了),GAN切割,以及人工的gold reference
上图四中,可以看到,和人工切割结果对比,k-means的切割太细了(例如jh这个phoneme,在k-means的序列里面,有56, 5, 39, 123这四个segment和其对应。)需要尽量把这么细粒度的,再次“结合”“合并”一下。

表1 k-means切割,和,wav2vec-U下的viterbi prediction切割的对比
上表给出了k-means切割和wav2vec-U下的viterbi prediction切割的对比。
k-means可以实现高的precision,但是recall非常低。综合起来F1只有,53.9%;另外一方面,本文中的wav2vec-U viterbi prediction(具体是怎么操作的???TODO)则达到了更好的precision和recall的平衡,即,62.9%的F1精度。
我们按照和处理语音信号类似的方法,来处理文本信息(unlabeled text data)。我们应用两个前处理步骤:
1、音素化,类似于(“你好”-》“ni hao”;英文的“cat”-》“K AE T”);(背后的原因在于,作者们发现,学习语音和音素之间的关系,比学习语音和单词,或者,语音和单字,之间的关系,要更容易!)
用数学符号表示就是,要把一个单字的序列Y,转换成音素的序列P:

2、插入“静音”(silence)token。
考虑到语音里面的很多“静音”符号并没有被全部顺利删除,这可能会导致其中的“隐式alignment”的学习的进一步困难的加剧。为了解决这个问题,我们把音素序列的开头和结尾都加上“静音”token。我们还“随机地“向该音素序列增加”静音“token,主要是在words之间,或者phrase之间。(即,一个词对应的多个Phoneme的内部,不会被增加
下图,给出的就是,调节了这个25%的参数的值之后,per的变化情况:

图五,调节增加到文本音素序列中的<sil>(静音符号)的占比,带来的per的变化
上图给出了占比变化的,导致的per的变化。可以看到25%的时候,per效果最好。
方法核心是采用对抗学习的方法,来训练一个无监督的语音识别模型。输入包括两种:
无标签的语音数据的”表示“;
无标签的因素序列的”表示“。
下面,会详细逐一介绍:
模型架构;
训练目标函数;
(本文作者开发的)无监督的交叉检验”评测标准“。
依照GAN(对抗生成网络)的基本架构,会有一个生成器G,和一个判别器C。生成器负责做假币,而判别器负责判定是真钱还是假钱。
生成器部分
生成器G的输入和输出:
输入:时长为T的语音表示,

输出:M个音素组成的序列,即:

这里的,生成器G,是:
predicts a distribution over the phoneme set O for each segment and outputs the phoneme with the highest probability。
即为每个segment(语音片段)预测一个”音素表O“上的分布,并从中选择一个概率最高的音素输出。
特别的,如果相邻的两个segment,被预测出来了同样的音素,那么我们就取一个。(sample one of these segments)。从而,M <= T。即语音片段的数量,大于等于,音素序列中音素的个数。
”音素表O“里面有个silence token,
需要注意的是,S,这个来自wav2vec 2.0的输出表示,在无监督训练过程中,不会被修改。
生成器是一个单层CNN网络。相对单薄了一些。。。
判别器部分
判别器一次接受的输入,可能是两个来源的:
其一,来自真实数据分布
的一个序列
;
其二,来自生成器的输出
.
每个输入的vector,都有|O|个维度,表示的是每个segment上的关于音素的分布。
我们的判别器,也是一个CNN,输出的是一个概率,代表的是一个输入的样本服从真实数据分布的概率。
把这两个部分,融合一下,如下图所示:

图六,gan的输入
通过上图,我们再重温一下。
左边是,随便(例如从wikipedia)上找的句子,然后抽取其音素序列,然后映射到音素词表,构造出1-hot向量的集合。
右边是,语音,经过wav2vec 2.0,然后是使用k-means进行聚类,切割segments,再往后是根据gan的生成器,来构造出语音对应的phomeme的序列,把相邻segment预测出来同一个phoneme的时候(这里的向量的长度,也是音素词表的大小)。然后,中间是一个判别器,接受左边和右边。进行real或者fake的判定。
目前还是感觉有点奇怪,随便找个句子就行???这不科学啊。
打个比方,我们的目标如果是造美元纸币,你给我一堆人民币,日币等等的图,我还是最终无法分辨出来哪张是目标啊。
下图进一步进行了总结:

图6.2 关于生成器和判别器的架构,只有区区90K的参数。啊?存疑了
除了GAN的标准的目标函数之外,这里还额外引入三个penalty:
gradient penalty;
segment smoothness penalty;
phoneme diversity penalty。
从而,我们得到的目标函数如下:

图七,目标函数,五个部分组成
第一项,训练判别器为真实的文本赋予高的概率;
第二项,鼓励判别器,为生成器的输出,赋予低的得分;
第三项,是概率惩罚项?
第四项,片段平滑惩罚项。
第五项,音素多样性loss(后面会详细阐述)。
训练的时候,生成器和判别器会被交替更新;所使用的batches,要么来自生成器,要么取自无标签的真实音素数据,也是被交替使用的。
梯度惩罚项

图八,梯度惩罚项
为了让训练更加稳定,我们对”判别器
的关于输入
的梯度
的范式“
”(的相关的函数)进行惩罚。即,整体上,期望这个L的值,越小越好。从而期望,梯度的范式,越接近1越好。
【目前的疑问:】然后如果这个值更加接近于1,这意味着real和fake的音素序列之间,需要有什么样的关系呢?线性组合之后,是一个标准正则化后的一个高维空间上的”单位向量“???
片段平滑惩罚项
这个的背后的考量是,基于k-means得到的对segment的切割,要比基于reference transcription文本的phoneme序列的粒度更细。所以,我们希望生成器可以为相邻的segments来生成一样的音素。从而,我们使用如下的惩罚项,尽量最小化下面的值:

图九:片段平滑惩罚项(这个L越小越好)
【思考】感觉这块有点问题,如果是从t=1到T,都是争取,尽量让生成器G,对于相邻的segments,产出相同的phoneme,这个会不会训练出来一堆a a a a a a ...这样的重复性的玩意???有待于深度研究。
p是one-hot的表示,即向量的维度是|O|的,涵盖了整个音素词汇表。
音素多样性loss

图十,尽量促使产出的音素的种类越多越好
这个损失函数,是基于一个batch来计算的。目标是,对音素序列中的音素的种类进行“鼓励”。
我们的终极目标是,构建一个完全不用标注数据的asr系统。这里,我们开发一个不需要借助外在人工标注数据的一个评测标准(用于挑选model checkpoint)。
这个标准(metric)被用来做如下几个事情:
early stopping,结束点;
selecting a random seed,选择随机种子;
超参数选择,主要是上面图七的公式中的若干参数,例如,
。
在我们的标准中,我们引入两个量化指标:
LM negative log-likelihood, NLL,即,语言模型的负对数相似度;
vocabulary usage,词汇的使用。
下面的这一个段(论文中的page 5的最下面的一段),有点不好理解,我们直接上截屏,并且在截屏上查看:

图十一,无监督的交叉检验评测标准的“前戏”
上图中出现了一些符号,我们梳理一下:
生成器G;
无标签的语音输入,多次迭代思考之后,认为Ns应该是输入的样本的个数:{X1, X2, ..., X_Ns},这里有j=1,。。。,N_s。【好吧,这里还是一个个的样本?样本的个数???】
viterbi解码结果,由Ns个多个长度同样为M(?这个M,不应该和具体的j相关吗。。。)的音素序列组成,所有序列,可以表示为:P1, P2, ..., P_Ns。
NLL-LM(P),这个就有点奇怪了。P1代表的是voice segment 1所被解码出来的Phoneme(的所有可能的情况?)。
里面的M是啥来着???上图中的标识出来的4和5,都需要进一步确认。。。(貌似只能看代码了)。词表使用方面,是简单定义了一个
。可以简单理解为,使用词表中的词越多,则最终的U的取值越大。
然后看看,基于NLL-LM和U,我们如何进行最优的音素序列的解码:

即,最大化语言模型(例如wikipedia之类的公开文本数据,然后转音素序列,最后训练语言模型)的概率,并且最大化对于音素词汇表中不同的音素的使用。
然后,就是把上面的取值作为一个“锚”,其他配置下(超参数集合下)的模型配置,如果不满足如下的不等式,我们就扔掉了:

图十二,“锚”点过滤一些模型配置P
这里的一个奇葩在于log1.2。
The log1.2 factor serves as another margin allowing checkpoints with slightly worse vocabulary-usage adjusted NLL to be included.
log1.2 因子作为另一个边界,允许包含“稍微差一点的词汇使用调整的” NLL 的检查点。
【这句话真绕。。。】
解释一下:有了Log1.2,我们就可以放过如下的一类checkpoint:
词汇使用情况更差(使用的词汇种类更少);
最后,我们的解码函数为:

图十三,最终的viterbi解码函数
这里的Ns和M的使用,把我彻底绕晕了。
M,肯定是一个音素序列中的音素的个数了。
Ns,“目测应该是类似viterbi解码的时候,得到的完整的音素序列的个数。”-》非也,是数据集合中的样本的个数。
看了如下35页的论文之后:
https://arxiv.org/pdf/2105.11084.pdf

图十四,数据集的表示,证实了Ns是样本的个数
个人侧重对方法的学习,从动机,到具体技术细节,训练解码等等。对于结果部分,会尽量只保留最重要的部分。

表2,无监督方法和有监督,以及半监督方法的结果的对比
上面的表格,给出了三个流派的结果的对比。其中容易看到ssl的优势还是很明显的。不过,用了90k的参数,居然就能达到这么好的效果,总感觉哪里有点不对劲。可能是我的直觉的问题。
反而是ssl的结果,很值得follow。

表2.2 wer的结果的对比!librispeech数据集的最难的test-other测试集上的结果。

表三,timit数据集,以及其他几个语言下的无监督asr的结果对比
图示为:

表3.2 补充对比,all-test TIMIT数据集下的结果。per降低了一半还多!
上面的结果,整体per精度和wer精度,都不怎么样。。。这可能也决定于语言的本身的难度。
上面的六种语言下的对比:

表3.3 六种语言下的对比的结果

表四,其他几个low-resource语言下的结果
最后,有条件的大神,可以跟着neurips2021的oral talk走一遍。【如下url,需要自己注册neurips2021才能访问!】
https://nips.cc/virtual/2021/session/44831
