音频课程文档

CTC 架构

Hugging Face's logo
加入 Hugging Face 社区

并获得增强的文档体验

开始使用

CTC 架构

CTC,即连接主义时间分类(Connectionist Temporal Classification),是一种与仅编码器 Transformer 模型结合用于自动语音识别的技术。此类模型的例子有 Wav2Vec2HuBERTM-CTC-T

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

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

Transformer encoder with a CTC head on top

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

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

💡 在 NLP 模型中,词汇通常由数千个标记组成,这些标记不仅描述单个字符,还描述单词的某些部分甚至整个单词。然而,对于 CTC,小型词汇表效果最好,我们通常会尝试将其保持在 50 个字符以内。我们不关心字母的大小写,所以只使用大写(或只使用小写)就足够了。数字会被拼写出来,例如 `"20"` 变成 `"twenty"`。除了字母,我们至少需要一个单词分隔符标记(空格)和一个填充标记。就像 NLP 模型一样,填充标记允许我们在一个批次中组合多个示例,但它也是模型会预测的用于静默的标记。在英语中,保留字符 `'` 也很有用——毕竟,`"it's"` 和 `"its"` 的含义截然不同。

哥们,我的对齐呢?

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

  • 作为单个字符
  • 作为音素
  • 作为单词标记

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

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

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

The audio waveform gets mapped to a shorter sequence of hidden-states

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

然而,如果我们仅仅每 20 毫秒预测一个字符,我们的输出序列可能看起来像这样:

BRIIONSAWWSOMEETHINGCLOSETOPANICONHHISOPPONENT'SSFAACEWHENTHEMANNFINALLLYRREECOGGNNIIZEDHHISSERRRRORR ...

如果你仔细看,它有点像英语,但很多字符都被重复了。这是因为模型需要为输入序列中每 20 毫秒的音频输出**一些东西**,如果一个字符的持续时间超过 20 毫秒,那么它就会在输出中出现多次。这是无法避免的,特别是我们不知道训练期间转录的时序。CTC 是一种过滤这些重复项的方法。

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

CTC 算法

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||||

`|` 标记是单词分隔符。在这个例子中,我们使用 `|` 而不是空格,这使得识别单词边界变得更容易,但它起着相同的作用。

CTC 空白字符使得过滤重复字符成为可能。例如,让我们看看预测序列中的最后一个单词,`_ER_RRR_ORR`。如果没有 CTC 空白标记,这个单词看起来是这样的:

ERRRRORR

如果只是简单地去除重复字符,它将变成 `EROR`。这显然不是正确的拼写。但是有了 CTC 空白标记,我们可以在每个组中去除重复字符,这样:

_ER_RRR_ORR

变成

_ER_R_OR

现在我们移除 `_` 空白标记,得到最终的单词

ERROR

如果我们将此逻辑应用于整个文本,包括 `|`,并将剩余的 `|` 字符替换为空格,则最终的 CTC 解码输出是:

BRION SAW SOMETHING CLOSE TO PANIC ON HIS OPPONENT'S FACE WHEN THE MAN FINALLY RECOGNIZED HIS ERROR

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

💡 在实际的 Wav2Vec2 模型中,CTC 空白标记与填充标记 `` 相同。模型会预测许多这样的 `` 标记,例如当当前 20 毫秒的音频没有明确的字符可预测时。将相同的标记用于填充和 CTC 空白可以简化解码算法,并有助于保持词汇量较小。

将 CTC 添加到 Transformer 编码器模型很容易:编码器的输出序列进入一个线性层,将声学特征投射到词汇表中。模型使用特殊的 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 的启发,学习预测“离散语音单元”,这类似于文本句子中的标记,因此可以使用已建立的 NLP 技术处理语音。

需要澄清的是,这里强调的模型并非唯一的基于 Transformer 的 CTC 模型。还有许多其他模型,但现在你知道它们的工作方式都类似。

< > 在 GitHub 上更新