3. Transformer architectures for audio

Posted by lili on

Transformer模型回顾

在这门课程中,我们将主要考虑Transformer模型以及它们如何应用于音频任务。虽然你不需要了解这些模型的内部细节,但理解使它们工作的主要概念是有用的,所以这里是一个快速的复习。要深入了解transformer,请查看我们的NLP课程

Transformer如何工作?

最初的transformer模型是设计用来将一种语言的书面文本翻译成另一种语言的。它的架构看起来像这样:

左边是编码器,右边是解码器。

  • 编码器接收一个输入,本例中是一个文本token序列,并构建其表示(其特征)。模型的这一部分被训练来从输入中获取理解。

  • 解码器使用编码器的表示(特征)以及其他输入(先前预测的token)来生成一个目标序列。模型的这一部分被训练来生成输出。在最初的设计中,输出序列由文本token组成。

还有一些只使用编码器部分的基于transformer的模型(对于需要理解输入的任务很有用,比如分类),或者只使用解码器部分的模型(对于文本生成等任务很有用)。一个仅使用编码器部分的例子是BERT;一个仅使用解码器部分的例子是GPT2。

Transformer模型的一个关键特征是它们由称为注意力层的特殊层构建。这些层告诉模型在计算特征表示时要特别关注输入序列中的某些元素,并忽略其他元素。

使用transformer进行音频处理

我们在本课程中将介绍的音频模型通常具有标准的transformer架构,如上所示,但在输入或输出方面略有修改,以允许使用音频数据而不是文本。由于所有这些模型本质上都是transformers,它们的架构大部分相同,主要区别在于它们如何被训练和使用。

对于音频任务,输入和/或输出序列可能是音频而不是文本:

  • 自动语音识别(ASR):输入是语音,输出是文本。

  • 语音合成(TTS):输入是文本,输出是语音。

  • 音频分类:输入是音频,输出是类概率 —— 对于序列中的每个元素都有一个,或者对于整个序列只有一个类概率。

  • 语音转换或语音增强:输入和输出都是音频。

处理音频以便与transformer一起使用有几种不同的方法。主要考虑因素是是否将音频使用其原始形式 —— 作为波形 —— 或者将其作为频谱图进行处理。

模型输入

音频模型的输入可以是文本或声音。目标是将此输入转换为可以由transformer架构处理的嵌入向量。

文本输入

文本转语音模型以文本作为输入。这与原始transformer或任何其他NLP模型的工作方式相同:首先对输入文本进行token化,得到一个文本token序列。然后,将此序列通过输入嵌入层发送,将token转换为512维向量。然后,这些嵌入向量被传递到transformer编码器中。

波形输入

自动语音识别模型以音频作为输入。为了能够使用transformer进行ASR,我们首先需要将音频转换为某种嵌入向量序列。

诸如Wav2Vec2和HuBERT之类的模型直接使用音频波形作为模型的输入。正如你在音频数据章节中看到的那样,波形是一维浮点数序列,其中每个数字表示在给定时间采样的幅度。首先将这个原始波形归一化为零均值和单位方差,这有助于在不同音量(幅度)之间标准化音频样本。

归一化后,音频样本序列通过一个小型卷积神经网络进行嵌入,称为特征编码器。这个网络中的每个卷积层处理输入序列,对音频进行子采样以减少序列长度,直到最后一个卷积层输出每25毫秒音频的一个512维向量作为嵌入。一旦输入序列被转换成这样的嵌入序列,transformer将像往常一样处理数据。

频谱图输入

使用原始波形作为输入的一个缺点是它们倾向于具有较长的序列长度。例如,以16 kHz的采样率录制的30秒音频将得到长度为30 * 16000 = 480000的输入序列。更长的序列长度需要在transformer模型中进行更多的计算,因此会占用更多的内存。

因此,原始音频波形通常不是表示音频输入的最有效形式。通过使用频谱图,我们可以获得相同数量的信息,但以更压缩的形式。

诸如Whisper之类的模型首先将波形转换为对数梅尔频谱图。Whisper总是将音频拆分成30秒的段,每个段的对数梅尔频谱图形状为(80,3000),其中80是梅尔频率的数量,3000是序列长度。通过转换为对数梅尔频谱图,我们减少了输入数据的量,但更重要的是,这比原始波形要短得多的序列。然后,对数梅尔频谱图通过一个小型CNN处理成一系列嵌入,然后像往常一样输入到transformer中。

在这两种情况下,即波形和频谱图输入,transformer前面都有一个小型网络将输入转换为嵌入,然后transformer接管并进行其操作。

模型输出

transformer架构输出一系列隐藏状态向量,也称为输出嵌入。我们的目标是将这些向量转换为文本或音频输出。

文本输出

自动语音识别模型的目标是预测一系列文本token。这是通过在transformer输出的顶部添加一个语言建模头 —— 通常是一个单一的线性层 —— 然后跟随softmax完成的。这个头在词汇表中预测文本token上的概率。

频谱图输出

对于生成音频的模型,例如文本转语音(TTS)模型,我们必须添加能够产生音频序列的层。非常常见的做法是生成一个频谱图,然后使用另一个称为声码器的神经网络将这个频谱图转换成一个波形。

例如,在SpeechT5 TTS模型中,transformer网络的输出是一个768元素向量序列。一个线性层将该序列投影到对数梅尔频谱图上。一个所谓的后处理网络,由额外的线性和卷积层组成,通过减少噪声来完善频谱图。然后声码器生成最终的音频波形。

💡如果你拿一个现有的波形并应用短时傅里叶变换或STFT,就可以执行逆操作,即ISTFT,以再次获得原始波形。这是因为STFT创建的频谱图包含幅度和相位信息,而两者都需要用来重建波形。然而,将频谱图转换成波形的音频模型通常只预测幅度信息,而不是相位信息。为了将这样的频谱图转换成波形,我们必须以某种方式估计相位信息。这就是声码器的作用。

波形输出

模型也可以直接输出波形,而不是将频谱图作为中间步骤,但目前🤗 Transformers中没有执行此操作的模型。

结论

总之:大多数音频transformer模型更相似而不是不同 —— 它们都建立在相同的transformer架构和注意力层上,尽管有些模型只使用transformer的编码器部分,而其他模型使用编码器和解码器。

你也看到了如何将音频数据输入和输出到transformer模型中。要执行ASR、TTS等不同的音频任务,我们只需替换用于将输入预处理成嵌入的层,并替换用于将预测的嵌入后处理成输出的层,而transformer主干保持不变。

接下来,让我们看一看这些模型可以被训练用于执行自动语音识别的几种不同方式。

CTC架构

CTC或Connectionist Temporal Classification是一种与仅编码器Transformer模型一起用于自动语音识别的技术。这类模型的示例包括Wav2Vec2、HuBERT和M-CTC-T。

仅编码器Transformer是最简单的Transformer类型,因为它只使用模型的编码器部分。编码器读取输入序列(音频波形),并将其映射到一系列隐藏状态,也称为输出嵌入。

在CTC模型中,我们对隐藏状态序列应用额外的线性映射以获得类别标签预测。类别标签是字母表中的字符(a、b、c等)。通过这种方式,我们能够使用一个小的分类头来预测目标语言中的任何单词,因为词汇只需包含26个字符加上一些特殊token。

到目前为止,这与我们在NLP中使用BERT等模型所做的非常相似:仅编码器Transformer模型将我们的文本token映射到一系列编码器隐藏状态,然后我们应用线性映射以获得每个隐藏状态的一个类别标签预测。

这里的关键在于:在语音中,我们不知道音频输入和文本输出的对齐。我们知道语音的播放顺序与文本转录的顺序相同(对齐是所谓的单调的),但我们不知道文本中的字符如何与音频对齐。这就是CTC算法发挥作用的地方。

💡 在NLP模型中,词汇通常由成千上万个token组成,这些token不仅描述单个字符,还描述单词的部分甚至整个单词。但是,对于CTC来说,较小的词汇表效果最佳,我们通常尽量保持在50个字符以下。我们不关心字母的大小写,因此仅使用大写(或仅使用小写)即可。数字用文字表示,例如,”20”变成”twenty”。除了字母,我们至少需要一个单词分隔token(空格)和一个填充token。与NLP模型一样,填充token允许我们将多个示例组合到一个批次中,但它也是模型将为沉默预测的token。在英语中,保留’字符也很有用——毕竟,”it’s”和”its”的含义完全不同。

我的对齐在哪里?

自动语音识别或ASR涉及将音频作为输入并生成文本作为输出。我们有几种选择来预测文本:

  • 作为单个字符
  • 作为音素(phoneme)
  • 作为单词token

ASR模型是在包含(音频,文本)对的数据集上训练的,其中文本是音频文件的人工制作转录。通常数据集不包括任何关于单词或音节在音频文件中出现位置的时间信息。由于在训练过程中不能依赖于时间信息,我们不知道输入和输出序列应该如何对齐。

假设我们的输入是一个一秒的音频文件。在Wav2Vec2中,模型首先使用CNN特征编码器对音频输入进行下采样,将其转换为更短的一系列隐藏状态,其中每20毫秒的音频有一个隐藏状态向量。对于一秒的音频,我们然后将一系列50个隐藏状态向前传递到Transformer编码器。(从输入序列提取的音频片段部分重叠,因此即使每20毫秒发出一个隐藏状态向量,每个隐藏状态实际上代表25毫秒的音频。)

Transformer编码器预测每个隐藏状态的一个特征表示,这意味着我们从Transformer接收到一系列50个输出。每个输出的维度为768。因此,在此示例中,Transformer编码器的输出序列的形状为(768,50)。由于每个预测覆盖了25毫秒的时间,这比音素的持续时间要短,因此预测单个音素或字符而不是整个单词是有意义的。CTC与小词汇表配合效果最佳,因此我们将预测字符。

为了进行文本预测,我们使用线性层(“CTC头”)将每个768维编码器输出映射到我们的字符标签。然后,模型预测一个包含逻辑值的(50,32)张量,其中32是词汇表中的token数。由于我们针对序列中的每个特征进行一次预测,因此每秒音频总共会有50个字符预测。

然而,如果我们仅每20毫秒预测一个字符,我们的输出序列可能如下所示:

BRIIONSAWWSOMEETHINGCLOSETOPANICONHHISOPPONENT'SSFAACEWHENTHEMANNFINALLLYRREECOGGNNIIZEDHHISSERRRRORR ...

仔细观察,它在某种程度上类似于英语,但许多字符已经重复。这是因为模型需要为输入序列中的每20毫秒音频输出一些内容,如果一个字符在20毫秒以上的时间内分布,则它将在输出中出现多次。由于我们在训练期间不知道转录的时间,无法避免这种情况。CTC是一种过滤这些重复字符的方法。

(实际上,预测的序列中还包含许多填充token,用于当模型不确定声音代表什么时,或用于字符之间的空白空间。为了清晰起见,我们从示例中删除了这些填充token。音频片段之间的部分重叠是输出中字符重复的另一个原因。)

CTC算法

CTC算法的关键是使用一种特殊token,通常称为空白token(blank token)。这只是模型将预测的另一个token,它是词汇表的一部分。在本示例中,空白token显示为_。这个特殊token用作字符组之间的硬边界。

CTC模型的完整输出可能如下:

B_R_II_O_N_||_S_AWW_|||||_S_OMEE_TH_ING_||_C_L_O_S_E||TO|_P_A_N_I_C_||_ON||HHI_S||_OP_P_O_N_EN_T_'SS||_F_AA_C_E||_W_H_EN||THE||M_A_NN_||||_F_I_N_AL_LL_Y||||_RREE_C_O_GG_NN_II_Z_ED|||HHISS|||_ER_RRR_ORR||||

| token是单词分隔符。在示例中,我们使用|而不是空格,以便更容易找到单词的分隔位置,但其目的相同。

CTC空白字符使得可以过滤掉重复字符。例如,让我们看看从预测的序列中的最后一个单词_ER_RRR_ORR。如果没有CTC空白token,该单词将如下所示:

ERRRRORR

如果我们简单地删除重复字符,这将变成EROR。这显然不是正确的拼写。但是使用CTC空白token,我们可以删除每个组中的重复字符,因此:

_ER_RRR_ORR

变成了:

_ER_R_OR

现在我们移除空白_token以获得最终单词:

ERROR
如果我们将此逻辑应用于整个文本,包括 ,并将幸存的 字符替换为空格,最终的CTC解码输出为:
BRION SAW SOMETHING CLOSE TO PANIC ON HIS OPPONENT'S FACE WHEN THE MAN FINALLY RECOGNIZED HIS ERROR

总之,模型为输入波形的每20毫秒(部分重叠的)音频预测一个token(字符)。这会产生很多重复。多亏了CTC空白token,我们可以轻松地删除这些重复项,而不会破坏单词的正确拼写。这是解决输出文本与输入音频对齐问题的一种非常简单和方便的方法。

💡 在实际的Wav2Vec2模型中,CTC空白token与填充token相同。模型将预测许多这些token,例如当当前20毫秒的音频没有清晰的字符可预测时。使用相同的填充token作为空白token简化了解码算法,并有助于保持词汇表的小规模化。

向Transformer编码器模型添加CTC很简单:编码器的输出序列进入线性层,将声学特征投影到词汇表。模型使用特殊的CTC损失进行训练。

CTC的一个缺点是它可能输出听起来正确但拼写不正确的单词。毕竟,CTC头只考虑单个字符,而不是完整的单词。提高音频转录质量的一种方法是使用外部语言模型。这种语言模型本质上充当CTC输出的拼写检查器。

Wav2Vec2、HuBERT、M-CTC-T等之间有什么区别?

所有基于Transformer的CTC模型在架构上非常相似:它们使用Transformer编码器(但不使用解码器),并在顶部带有CTC头。在架构上它们更像而不是不同。

Wav2Vec2和M-CTC-T之间的一个区别是前者处理原始音频波形,而后者使用梅尔频谱图作为输入。这些模型还是为不同的目的而训练的。例如,M-CTC-T是为多语言语音识别而训练的,因此具有相对较大的CTC头,其中包括中文字符以及其他字母。

Wav2Vec2和HuBERT使用完全相同的架构,但训练方式却大不相同。Wav2Vec2像BERT的掩码语言建模一样进行预训练,通过预测音频中被掩盖部分的语音单位。HuBERT进一步发展了BERT的灵感,并学会预测“离散语音单位”,这类似于文本句子中的token,以便可以使用已建立的NLP技术处理语音。

澄清一下,这里突出显示的模型并不是唯一的基于Transformer的CTC模型。还有许多其他模型,但现在您知道它们都以相似的方式工作。

Seq2Seq 架构

在前面讨论的CTC模型中,只使用了transformer架构的编码器部分。当我们还添加解码器来创建一个编码器-解码器模型时,这被称为序列到序列模型或简称为seq2seq。该模型将一种数据序列映射到另一种数据序列。

对于仅编码器transformer模型,编码器对输入序列中的每个元素进行了预测。因此,输入和输出序列的长度始终相同。在诸如Wav2Vec2之类的CTC模型的情况下,输入波形首先被下采样,但仍然有一个对每20毫秒音频的预测。

对于seq2seq模型,没有这种一对一的对应关系,输入和输出序列的长度可以不同。这使得seq2seq模型适用于NLP任务,如文本摘要或不同语言之间的翻译,但也适用于音频任务,如语音识别。

解码器的架构与编码器的架构非常相似,两者都使用具有自注意力作为主要特征的相似层。然而,解码器执行的任务与编码器不同。为了了解其工作原理,让我们来看看seq2seq模型如何进行自动语音识别。

自动语音识别

Whisper的架构如下(图片由OpenAI Whisper博客提供):

Whisper是一个transformer编码器-解码器模型

这应该看起来很熟悉。左边是transformer编码器。它以对数梅尔频谱图为输入,并对该频谱图进行编码,形成一个包含来自口语中重要特征的编码器隐藏状态序列。这个隐藏状态张量代表整个输入序列,并有效地编码了输入语音的“含义”。

💡 对于这些seq2seq模型来说,使用频谱图作为输入是常见的。然而,可以设计一个seq2seq模型,直接在音频波形上工作。

然后,将编码器的输出传递到transformer解码器,显示在右边,使用一种称为交叉注意力的机制。这类似于自注意力,但是会关注编码器的输出。从这一点开始,编码器不再需要。

解码器以自回归方式预测文本token序列,一次预测一个token,从一个初始序列开始,该序列只包含一个“开始”token(在Whisper的情况下是SOT)。在每个后续时间步长,前一个输出序列被反馈到解码器中作为新的输入序列。通过这种方式,解码器每次发出一个新token,逐步增加输出序列的长度,直到预测出一个“结束”token或达到最大时间步长。

虽然解码器的架构与编码器的大部分相同,但有两个重要的区别:

  • 解码器具有交叉(cross)注意力机制,允许其查看编码器对输入序列的表示
  • 解码器的注意力是因果的——解码器不允许查看未来。

在这个设计中,解码器扮演语言模型的角色,处理来自编码器的隐藏状态表示,并生成相应的文本转录。这是比CTC更强大的方法,即使CTC模型与外部语言模型结合在一起,因为seq2seq系统可以使用相同的训练数据和损失函数进行端到端训练,具有更大的灵活性和通常更好的性能。

💡 而CTC模型输出的是一系列单个字符,Whisper预测的token是完整的单词或部分单词。它使用了GPT-2的分词器,并具有50k+个独特的token。因此,与相同的转录相比,seq2seq模型可以输出一个更短的序列。

seq2seq ASR模型的典型损失函数是交叉熵损失,因为模型的最终层预测了可能token的概率分布。通常结合诸如束搜索(beam search)之类的技术来生成最终的序列。语音识别的指标是WER或单词错误率,它衡量了将预测文本转换为目标文本所需的替换、插入和删除的数量——数量越少,得分越好。

文本到语音

也许不足为奇:TTS的seq2seq模型的工作原理与上述描述基本相同,但输入和输出被交换了!transformer编码器接受一系列文本token,并提取代表输入文本的隐藏状态序列。transformer解码器应用交叉注意力于编码器的输出,并预测频谱图。

💡 请记住,频谱图是通过对音频波形的连续时间片段进行频率谱分析并将它们堆叠在一起得到的。换句话说,频谱图是一个序列,其中元素是(对数梅尔)频谱,每个时间步长一个。

对于ASR模型,解码器是通过使用一个只包含特殊“开始”token的序列来启动的。对于TTS模型,我们可以使用一个全零的长度为一的频谱图作为“开始token”来启动解码。给定这个初始频谱图和对编码器隐藏状态表示的交叉注意力,解码器然后逐步预测此频谱图的下一个时间片段,一次一个时间步骤地增加频谱图。

但是解码器如何知道何时停止呢?在SpeechT5模型中,这是通过使解码器预测第二个序列来处理的。这个序列包含当前时间步长是最后一个时间步长的概率。在推断时生成音频时,如果此概率超过一定阈值(例如0.5),则解码器指示频谱图已完成,并且生成循环应该结束。

在解码完成后,我们获得一个包含频谱图的输出序列,SpeechT5使用一个称为后处理网络的网络,由几个卷积层组成,以精炼频谱图。

在TTS模型的训练过程中,目标也是频谱图,损失是L1或MSE。在推断时,我们希望将输出频谱图转换为音频波形,以便我们实际听到它。为此,使用外部模型,即声码器。这个声码器不是seq2seq架构的一部分,而是单独训练的。

TTS的难点在于它是一对多的映射。对于语音到文本,只有一个正确的输出文本与输入语音相对应,但对于文本到语音,输入文本可以映射到许多可能的语音音素。不同的说话者可能选择强调句子的不同部分,例如。这使得TTS模型难以评估。因此,L1或MSE损失值实际上并不是非常有意义——表示相同文本的频谱图有多种方式。这就是为什么TTS模型通常通过人类听众使用MOS或平均意见分数这样的度量标准进行评估的原因。

结论

seq2seq方法比仅编码器模型更强大。通过将输入序列的编码与输出序列的解码分离,音频和文本的对齐问题就不再是一个问题。

但是,编码器-解码器模型的速度也较慢,因为解码过程是逐步进行的,而不是一次性完成的。序列越长,预测速度越慢。自回归模型也可能陷入重复或跳过单词。诸如束搜索之类的技术可以帮助提高预测的质量,但也会进一步减慢解码速度。

音频分类架构

音频分类的目标是为音频输入预测一个类别标签。模型可以预测一个覆盖整个输入序列的单个类别标签,或者它可以为每个音频帧(通常是每20毫秒的输入音频)预测一个标签,此时模型的输出是一系列类别标签的概率。前者的例子是检测特定声音是哪种鸟的声音;后者的例子是说话人分离,其中模型预测在任何给定时刻正在说话的说话人。

使用语谱图进行分类

执行音频分类的一种最简单的方法是假装它是一个图像分类问题!

回想一下,频谱图是一个形状为(频率,序列长度)的二维张量。在关于音频数据的章节中,我们将这些频谱图绘制为图像。你猜怎么着?我们可以把频谱图真的当作图像,并将其传递给常规的CNN分类器模型,例如ResNet,并获得非常好的预测。甚至更好的是,我们可以使用图像transformer模型,例如ViT。

这就是音频频谱图transformer(Audio Spectrogram Transformer)的做法。它使用ViT或Vision Transformer模型,并将频谱图作为输入传递,而不是常规图像。由于transformer的自注意力层,模型能够比CNN更好地捕捉全局上下文。

就像ViT一样,AST模型将音频频谱图分成一个部分重叠的图像块序列,大小为16×16像素。然后,将这个图像块序列投影到一系列嵌入中,并像往常一样将其作为输入传递给transformer编码器。AST是一个仅编码器的transformer模型,因此输出是一个隐藏状态序列,每个16×16输入块对应一个隐藏状态。在此之上是一个简单的分类层,带有sigmoid激活函数,将隐藏状态映射到分类概率。

💡 尽管在这里我们假装频谱图与图像相同,但它们之间存在重要的区别。例如,将图像的内容向上或向下移动通常不会改变图像中的含义。然而,将频谱图向上或向下移动将改变声音中的频率,并完全改变其特性。图像在平移下不变,但频谱图不是。将频谱图视为图像在实践中可以工作得很好,但请记住它们实际上并不相同。

任何transformer都可以成为分类器

在前面的部分中,你已经看到CTC是使用仅编码器transformer执行自动语音识别的一种有效技术。这样的CTC模型已经是分类器,从分词器词汇表中预测类别标签的概率。我们可以通过更改标签,并使用常规的交叉熵损失函数而不是特殊的CTC损失来训练它,将CTC模型转变为通用音频分类器。

例如,HF Transformers有一个Wav2Vec2ForCTC模型,但也有Wav2Vec2ForSequenceClassification和Wav2Vec2ForAudioFrameClassification。这些模型的架构之间的唯一区别是分类层的大小和使用的损失函数。

事实上,任何仅编码器音频transformer模型都可以通过在隐藏状态序列顶部添加分类层来转变为音频分类器。(分类器通常不需要transformer解码器。)

为了为整个序列预测单个分类分数(Wav2Vec2ForSequenceClassification),模型对隐藏状态取平均并将其馈送到分类层。输出是一个单一的概率分布。

为了对每个音频帧进行单独分类(Wav2Vec2ForAudioFrameClassification),分类器在隐藏状态序列上运行,因此分类器的输出也是一个序列。