Transformer的基本架构
Transformer最初用于从文本到文本的工作,其架构如下
![[transformers.svg]]
左侧为编码器,右侧为解码器。编码器旨在从输入获得语义,亦或理解;而解码器旨在生成输出,一些结构的模型也可能只有二者中的一个。 Transformer模型的一个关键特征是它们由称为 注意力层 的特殊层来构建,注意力层可以让模型在计算特征表示的时候关注一些元素,而忽略一些不重要的元素
Transformer在音频上的应用
在音频模型的层面上,我们的输入与输出不再仅是文本,也可能是音频
- 对于自动语音识别(ASR)模型,输入为语音,输出为文本
- 对于语音合成(TTS)模型, 输入为文本,输出为语音
- 对于语音转换,或语音增强,输入和输出都是音频
![[transformers_blocks.png]]
模型输入
不论是音频还是文本,最终都需要将输入转换为嵌入向量,以便Transformer架构处理
对于文本输入,输入文本首先被分词,得到一个文本token序列,此序列通过一个输入嵌入层,我们就得到了一个512维向量,成为Transformer编码器的输入。
对于音频输入,我们可以直接将波形作为输入,譬如HuBERT模型就是这么做的。波形就是一个浮点数的一维序列,首先我们需要对这个序列进行归一化 (Normalize) ,使其有零均值和单位方差,这样做有利于标准化音量不同的音频样本。 归一化后,音频样本序列会通过一个小型CNN (也叫特征编码器) 转换为嵌入 (Embedding)。这个CNN会把每20ms音频转换为一个嵌入, 之后我们就得到一个嵌入序列,可以给Transformer处理了。
由于CNN有感受野和步长的差异,实际上对音频来说,是每25ms音频变为一个输入token,而且输入token之间互有重叠
![[wav2vec2-input.png]]
然而,用原始波形作为输入常常会导致序列很长,30s 16kHz的音频会生成长度为480000的输入,这会导致更多的计算,更多的占用。因此,通过使用频谱图,譬如梅尔频谱图,我们可以用压缩的形式得到相同的信息量。频谱图同样由一个CNN处理为嵌入序列,输入到Transformer中
![[whisper-input.png]]
模型输出
对于文本输出,通过在Transformer的输出上添加一个语言建模头 (常常是一个单层的线性层),然后再softmax,就可以实现,这一操作会预测词汇表中文本token的出现概率
对于频谱图输出,我们需要一个叫做声码器 (Vocoder) 的神经网络来将频谱图转化为波形,因为我们没法直接由频谱图得到波形。
之前我们通过STFT来将音频转换为得到频谱图,也可以通过逆STFT来得到波形,这是因为由STFT创建的频谱图既包含振幅信息也包含相位信息,如果要得到波形,这两个信息都不能缺少。然而我们音频模型常常不预测相位信息,所以我们需要一个声码器来估计相位信息
同时,有的模型也选择直接将波形作为输出,这种输出就可以直接使用了
CTC (Connectionist Temporal Classification) 架构
CTC模型是一种仅编码器Transformer模型,编码器读取输入序列,然后将其映射为输出token,此类模型的例子有HuBERT,Wav2Vec2。CTC模型会在输出token上应用额外的线性映射,以此获得类别标签预测,CTC模型常用于ASR的场景:
对于ASR任务,类别标签就是字母表中的字符,有了字母表,我们就可以预测目标语言里的单词
![[wav2vec2-ctc.png]]
但是仅仅这样是不够的,在语音中,我们并不知道音频输入和文本输出是如何对齐的,具体地说,我们知道语音的顺序与文本转录的顺序显然是相同的,但是我们不知道转录中的字符该如何与音频对齐,因为显然人们说话的速度和节奏是各不相同的,同一个人每次说话的速度也不一定相同
还有一件事,之前我们提到了CNN特征编码器会把音频拆分开来,使得每20ms音频变为一个输入token,而且token之间互有重叠,20ms可能比音素的持续时间少,重叠的token也可能带来重复的预测,因此如果我们直接将输出token映射为词汇表里字符,结果可能会像这样:
BRIIONSAWWSOMEETHINGCLOSETOPANICONHHISOPPONENT'SSFAACEWHENTHEMANNFINALLLYRREECOGGNNIIZEDHHISSERRRRORR显然,其中有很多不该重复出现的字符,于是我们有了CTC来解决这个问题
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||||现在我们就可以通过过滤掉每个组中重复的字符,过滤掉不该重复的字符了,譬如
ER_RRR_ORR -> ER_R_OR -> ERROR就这样,我们可以解决文本输出与音频输入的对齐问题
还有一件事,的一个缺点是它会输出读起来对,但是实际上不对的单词,所以我们可以再使用一个语言来检查输出,并得到优化的输出。
Seq2Seq架构
不同于CTC加工,Seq2Seq是一种编解码器架构,这种模型可以将一种数据序列映射到另一种数据序列,并且输入序列和输出序列的长度可以不同,这使得其可以用于自然语言处理任务,例如文本摘要,翻译,ASR,TTS等。
在之前的CTC模型例子中,每20ms音频对应了一个预测,也就是输入序列与输出序列的长度相同,或者说一一对应,Seq2Seq的输入与输出序列长度不同,就是针对这个而言的
Seq2Seq模型的编码器与解码器的结构是相似的,两者都为以自注意力为主要特征的相似层,只是解码器执行的任务与编码器不同。我们可以通过一些示例来看Seq2Seq模型的工作原理
Seq2Seq与ASR
我们以Whisper举例,其架构如下
对于Whisper,首先我们有transformer编码器,它以对数梅尔频谱图作为输入(也可以是波形图,这取决于实现 ),然后将其编码为隐藏状态张量,代表整个输入序列
然后,编码器的输出通过交叉注意力的机制被传递到transformer解码器中。解码器会以自回归的形式预测文本标记序列,从仅包含”开始”标记( 即图中的SOT )的序列开始,一次预测一个标记,每一次预测的输入都是上一次预测的输出,正如上图所示,知道预测到”结束”标记或达到最大时间步数为止
其中,解码器的交叉注意力机制使得其可以查看编码器的输出,这可以解决时间对齐的问题,也使得模型可以处理更长的句子 由于拥有Masked Self-Attention机制的掩码,解码器是不允许查看更后面的序列的,也就是“未来”,对于训练来说,这可以防止解码器一味地抄答案
补充地说,对于每一次的Attention计算,Query来自解码器,并且包含已有预测结果和位置信息,由于包含了位置信息,时间对齐的问题可以很好地得到解决。Key和Value来自编码器输出,并且解码器在计算Cross Attention时总是能看到所有的Key与Value,并通过Attention公式来得到一个高维向量。这个高维向量包含了需要预测的词的意思,虽然不是词本身,在这之后这个向量会被映射到词汇表上,得到我们的最终输出
在这种设计里,解码器实际上扮演了语言模型的角色,处理了来自编码器的隐藏状态并生成文本转录,这种方法比CTC更为强大,因为Seq2Seq模型可以使用相同的训练数据和损失函数进行端到端训练
Seq2Seq与TTS
Seq2Seq架构的TTS模型工作原理与上述基本相同,只不过交换了输入和输出。transformer编码器处理文本标记并输出隐藏状态,transformer解码器利用编码器的输出和交叉注意力来输出频谱图
*我们之前说到了”开始”标记,对于TTS模型来说,解码器的开始标记就是所有值都为0,长度为1的一个频谱

在TTS模型中,还需要让解码器知道在何时停止。一个方法是在解码器同时也预测另一个序列,这一序列里包含当前时间步是最后一个时间步的概率,如果此概率超过一个阈值,解码器就应该停止预测频谱图。
这时我们得到的频谱图不一定是高质量的,所以我们可以通过再加入一些后置的网络来优化频谱图,例如多个卷积层
我们之前提到,为了能让我们听,还需要把频谱图转化成波形,为此我们需要专门单独训练一个声码器 (Vocoder ) 来完成这件事情,这个声码器并不在Seq2Seq架构里面
对TTS模型的评估比较困难,因为同一个文本被说出来的方式是千变万化的,因此很难通过loss值判断模型的效果,因此我们还是需要通过实际的推理来自行判断模型的质量
还有一件事, 像这样的编解码器模型速度比较慢,因为解码是一步步进行的,序列越长,预测越慢。而且自回归模型也可能会有重复或跳过单词的问题,早期的TTS模型里这些问题相当显著。束搜索一类的技术可以让预测的质量更高——当然,要以性能为代价
部分信息可能已经过时



