如何让大语言模型听到声音(一)

2024年8月8日 · 245 字 · 2 分钟

本文介绍了音频数据的基本概念、音频信号的预处理流程、音频相关任务以及在深度学习领域,处理音频信号的两种常见架构。

了解音频数据

1. 频率 & 振幅 & 位深

声音的本质是连续信号,要想让物理设备捕获这种连续值,则需要通过采样的方式。这一过程通常涉及几个关键术语:

  • 采样率:即一秒钟内进行采样的频率,以赫兹 (Hz) 为单位。根据奈奎斯特极限,从信号中能够捕获的最高频率正好是采样率的一半。对人类而言,声音的可听频率低于 8kHz,更高频的声音信号人耳是听不到的。因此,16 kHz 的采样率对于处理音频而言足矣。但是如果采样率低于 8kHz,就会丢失一些信息,导致声音变得沉闷。如果训练样本中的音频频率不一致,则需要引入重采样(resampling)的预处理步骤来确保采样频率的一致性。
  • 振幅:声音是由人类可听频率内的气压变化产生的,其中声压的级别用振幅表示,以分贝 (dB) 为单位。例如,低于 60dB 人耳就很难感知到。
  • 位深:刻画振幅值的度量精度。常见的位深有 16-bit 和 24-bit,这些都是整数样本,浮点数样本是 32-bit。

2. 波形 & 频谱 & 光谱

波形图是基于采样点上振幅值所表示的曲线图,横轴是时间,纵轴是振幅值。它记录了音频信号的强度随时间变化的特征。

波形示例
一段波形示例

频谱是波形数据经过离散傅立叶变换得到的,横轴是频率,纵轴是振幅值。它记录了音频信号的强度随频率变化的特征。

image-20240805191047605
一段频谱示例

波形图和频谱图刻画的是振幅在时间/频率维度的变化,光谱图则表示频率在时间维度上的变化。它的基本思想是对时间进行微分,在每个极短的时间窗口内进行傅立叶变化,得到该时刻的频谱,最后将所有时刻的频谱拼接起来,振幅值大小用颜色深浅表示。

image-20240805191528713
频谱示例

人类的听觉系统对较低频率的变化比对较高频率的变化更敏感,这种灵敏度随着频率的增加而呈对数下降。梅尔谱图考虑到这一特性,对频率进行梅尔滤波。在 Whisper 中的输入就是梅尔谱图,每个样本的大小是 [频率维度,时间帧数]。如果采用 80 个 Mel 滤波器,并将音频信号划分为 3000 帧,那么梅尔谱图的特征大小就是 [80, 3000]。

image-20240805191814452
梅尔谱图示例

梅尔光谱图可以捕捉到对人类感知而言更有意义的信号,因此在语音识别、音色分类等任务中应用较广。但相比于标准光谱图,梅尔光谱图由于引入滤波操作,会导致信号的过滤,使得从梅尔光谱图转换回波形图变得比较棘手,需要引入 HiFiGAN 这种模型来解决。

音频信号的预处理流程

第一步:重采样

大多数深度学习模型都是基于 16 kHz 采样的音频信号进行训练的,为了和这些预训练模型保持一致,我们首先需要对自己的数据集进行重采样(如果原始数据采样频率不是 16 kHz)。

from datasets import Audio

minds = minds.cast_column("audio", Audio(sampling_rate=16_000))

下面两张图是采样前后的直观对比,可以看到将 8 kHz 重采样到 16 kHz 之后多了更多的样本点。

image-20240805195059588
8 kHz 采样片段
image-20240805195114381
16 kHz 采样片段

第二步:过滤时长较长的数据

为了防止推理或者训练的时候内存不足,可以限制数据的时长,将时长超过一定阈值的样本从原始数据中删掉。

第三步:特征提取

原始音频数据只有振幅波形,还需要从中抽取更丰富的特征用于模型训练。以 Whisper 为例,其特征提取包含两个部分:

  • 填充/截断,控制每个样本长度都是 30 秒
  • 将音频矩阵转换为对数梅尔光谱图作为输入特征

音频相关的任务

  • 音频分类:歌曲识别
  • 自动语音识别 (ASR):将讲者说话的内容自动转录成文字
  • 声纹分割 (speaker diarization):将播客音频中不同讲者的音频分离开来
  • Text to Speech:将文字转录为人声
  • Voice Conversation:输入和输出都是音频

用于处理音频信号的 Transformer

The transformer with audio input and output
语音作为输入和输出的Transformer结构

模型的输入可以是文本、波形、频谱。对于波形和频谱的输入,可以采用 CNN 来作为特征提取器得到初始表征。模型的输出一般是文本或者频谱,如果想得到波形则可以对频谱进行逆变换。

CTC 架构

CTC 全称是 Connectionist Temporal Classification,直译过来就是联结主义时序分类,这是用于训练早期语音模型的损失函数。比如 Wav2Vec2.0 就采用该损失用于下游语音识别任务的微调。在 Wav2Vec2.0 中,模型采用 Temporal Convolution 作为特征抽取器,Transformer 作为编码器。

image-20240806111914404
Wav2Vec 2.0

具体而言,Wav2Vec2.0 首先用卷积层将初始的音频信号离散化,得到初始的音频表征 $\mathcal{Z}$,注意这里采用的是有 overlap 的滑移窗口。表征 $\mathcal{Z}$ 随后有两个去处:

  • 输入 Transformer 编码器得到语义表征 $\mathcal{C}$。
  • 经过量化得到量化表征 $\mathcal{Q}$。这里的量化表征可以看作对连续的 $d$ 维表征空间进行离散化,它首先预设有 $G$ 个 $d/G$ 维的子空间,每个子空间里有 $V$ 个条目 (entries),音频表征 $z \in \mathbb{R}^{d}$ 可以转换为 $G$ 个子空间中原型向量 $e \in \mathbb{R}^{V \times d/G}$ 的组合。基于这一思想,我们可以对初始表征 $z$ 进行映射变换得到索引矩阵 $\mathcal{I} \in \mathbb{R}^{G \times V}$,随后将 $G$ 个子空间中索引概率最大的那一个条目 $i = \text{argmax}\_{j} p\_{g,j}$ 拿出来拼接并进行线性变换,得到量化表征 $q \in \mathbb{R}^{f}$。

这里对比学习不是作用于 $\mathcal{Z}$ 和 $\mathcal{C}$ ,而是引入 product quantization 操作得到量化表征 $\mathcal{Q}$。可以将量化表征看作是 nn.Embedding,它是有限向量的集合,因为量化表征是 G 个子空间有限条目的线性变换而来,因此它也是离散的。

在预训练阶段,Wav2Vec2.0 采用语义表征 $\mathcal{C}$ 与量化表征 $\mathcal{Q}$ 之间的对比学习损失和量化表征 $\mathcal{Q}$ 的熵作为损失函数。在微调阶段,Wav2Vec2.0 采用 CTC 损失。假设这里的音频对应文本是 “hello”,经过卷积后得到 20 个 token,这显然和目标文本(5 个字母)不对齐,因此需要用 CTC 损失。在 CTC 中,我们考虑 20 个 token 预测值的排列组合,得到所有这 5 个字母按照 “h -> e -> l -> l -> o” 顺序构成的序列,计算它们的概率和。微调阶段就是希望这个概率最大,比如这个例子中预测值可能是 “hhheeeeelllllllllloo”,这时候再进行解码即可(连续字母去重)。

Seq2Seq 架构

在 CTC 架构中,输入和输出都是相同的长度,因此在进行 ASR 等任务时需要引入 CTC 来实现文本对齐。但是在 Seq2Seq 架构中,因为模型采用生成式理念,因此输入和输出的长度可以不一致。比如下面 Whisper 架构:

Whisper is a transformer encoder-decoder model
Whisper

在 Whisper 中,输入是音频信号转换的梅尔频谱图,输出是文本。