引言:语音语言模型的兴起与挑战
今天想和大家探讨的是语音语言模型的发展。在过去的课程中,我们已经讨论过如何利用类似语言模型的技术来实现影像生成,大家也知道影像生成技术最近非常热门。今天,我们将分享语音是如何通过类似的技术被创造出来的。
即便多数同学未来不一定会从事语音相关的技术研究,但了解语音技术的发展历程,或许能为大家带来一些启发,看看不同领域的研究者是如何看待“生成”这件事的。
那么,什么是语音语言模型呢?它希望实现的目标就是让语言模型既能听懂声音,也能产生声音。与处理纯文字相比,输入和输出声音面临着独特的挑战。因为声音相较于文字,承载了更丰富的信息和变化。
声音中不仅包含文字内容,还蕴含着其他维度的信息。一个号称能听懂声音的模型,必须能够识别说话者的身份、情绪,甚至根据环境音推断其所处的环境和状态。因此,开发语音语言模型比纯文本模型更具挑战性。
如今,我们已经能看到一些语音语言模型的应用,例如比较知名的ChatGPT的“高级语音模式”和Gemini的语音互动功能。除此之外,市面上还涌现了大量其他的语音语言模型,例如Moshi、GLM、STEP、Q1、KeyMe等等。
Moshi可以说是最早真正向公众发布的语音语言模型,其发布时间是去年10月。你可能会提到GPT-4o在5月就做过演示,但那仅仅是演示,并未真正发布服务。实际上,GPT-4o的语音模式(Voice mode)直到去年年底才正式上线。
在目前所有可用的语音语言模型中,我个人认为互动体验最流畅、最令人惊艳的可能是Sesame。
(讲者现场演示了与Sesame模型的英文互动,展示了其流畅的对话、打断、讲笑话和听从指令等能力,并指出该模型目前尚不支持中文。)
语音生成的基石:Tokenization
在第六讲中,我们曾探讨过如何让语言模型在学会听懂声音的同时,不遗忘其作为文字模型的原有技能。本堂课将更侧重于讲解语音或声音是如何被生成出来的。
要打造一个能产生声音的模型,原理与文字模型类似。文字模型通过读取一段文字Token(Token: 在自然语言处理中,指文本的基本单位,可以是一个词、一个字符或一个子词)并进行“文字接龙”来生成更多内容。同样,语音模型也遵循这一原理。只要我们能将一段语音信号表示成语音的Token,就可以训练一个语音版的语言模型,它接收语音Token作为输入,通过“Token接龙”产生更多的语音Token。
然而,这些语音Token本身只是离散的单元(discrete unit),人类无法直接听懂。因此,我们还需要一个detokenizer,将这些Token转换回声音信号。所以,整个流程的核心在于如何实现声音信号与Token之间的相互转换。
训练一个语音版语言模型的步骤与文字模型大同小异:
- 预训练 (Pre-train): 从网络上(如影音平台)抓取海量的语音数据进行预训练,得到一个只能做“语音接龙”的初版模型。
- 监督式微调 (Supervised Fine-tuning): 使用人工标注的人类对话数据,对预训练模型进行微调,使其能够与人进行有意义的互动。
- 基于人类反馈的强化学习 (RLHF): 告诉模型什么样的回答是好的,什么是不好的,进一步优化其表现。
这一切的基础,首先要解决的问题是:语音生成的基本单位,即语音的Token,到底应该是什么样子?
探索语音Token:两种极端的思路
对于文字而言,Token的概念非常自然。一个英文单词通常就是一个Token。例如,“I want to learn generative AI”这句话可以很自然地被切分成多个Token。
但对于语音,情况就复杂得多。一段连续的声音信号,如何表示成一个Token序列呢?
极端思路一:语音识别 + 语音合成
一个直接的想法是,我们的Tokenization过程就是一个语音识别系统。它将声音信号转换成文字,而文字本身就是Token。反之,detokenization过程则是一个语音合成系统,将文字转回语音。
如果采用这种方式,我们的“语音模型”本质上就成了一个纯粹的文字模型,输入输出都是文字,无需开发任何新技术。
但这种设计存在严重问题。例如,对于“你实在是真的好棒喔”这句话,无论是真诚的赞美还是带有反讽意味的语调,语音识别系统输出的文字可能完全相同。文字模型看到相同的文本,可能会给出“谢谢你的夸奖”这样的标准回答,完全忽略了语气中蕴含的重要信息。这证明,简单地将声音转为文字会丢失大量关键信息。
极端思路二:以原始采样点为Token
另一个极端是保留所有信息。声音信号由一个个采样点构成,我们可以直接将每个采样点视为一个Token。这样,模型就不会损失任何原始信号中的信息。
然而,这种方法的代价是序列长度的急剧膨胀。为了保证基本的语音质量(如电话通话),采样率通常至少为8kHz,即每秒有8000个采样点。这意味着生成一分钟的语音,模型需要处理和生成将近五十万个Token。目前,能够处理如此长序列的自回归模型(autoregressive model)非常罕有,这使得该方案在实践中并不可行。
寻找中间地带:现代语音Tokenizer的崛起
我们需要一个介于上述两种极端之间的解决方案:既能保留语音中的重要信息,又能有效压缩信号,避免序列过长。如何将语音转化为Token,即打造语音的tokenizer,是当前语音领域的热门研究课题。
过去一年,涌现了大量关于语音tokenization的新方法。由于方法众多,我们无法一一详述。
那么,如何评判哪种tokenizer是最好的呢?最精确的方式是使用不同tokenizer产生的Token去训练语音语言模型,看哪个模型效果最好。但训练语言模型本身耗费巨大。因此,出现了一些基准测试(benchmark),试图在训练前就评估Token的质量。
主要有两类评测方法:
- Codec-SUPERB: 这个基准测试将声音信号通过tokenizer转为Token,再通过detokenizer还原回声音。然后评估还原后声音的音质,以及它是否还能被现有的语音识别或情绪识别系统正确处理。如果信息损失严重,说明Token质量不佳。
- DASB: 这种方法直接检测Token本身包含的信息。例如,用这些Token去训练一个语音识别或情绪识别模型,如果能成功训练,就证明Token中保留了相应的文字或情绪信息。
两大主流方向:自监督模型与神经编解码器
目前,产生Token的方式主要有两大方向。
方向一:利用现成的自监督学习(SSL)模型
我们可以使用一个现成的语音自监督学习模型(Speech Self-supervised Model)作为编码器(encoder)。这些模型能将一段声音信号转换成一个向量序列(vector sequence),通常每0.02秒对应一个向量。
但我们需要的是离散的Token,而这些是连续的向量。因此,需要进行向量量化(Vector Quantization: 一种将连续向量空间划分为有限个区域,并用一个唯一的ID或符号来代表每个区域的技术)。通过聚类(clustering),将相近的向量用同一个ID(即同一个Token)表示。
为了进一步缩短序列长度,通常会采取两个步骤:
- 去重 (Deduplicate): 移除连续重复的Token。
- 字节对编码 (Byte Pair Encoding, BPE): 一种数据压缩算法,它会迭代地将最常出现的相邻Token对合并成一个新的、单一的Token。这个算法也广泛应用于文字模型中。
通过这一系列步骤,我们可以将声音信号转化为一串离散的Token序列。这个过程通常不需要额外训练模型。但我们还需要一个detokenizer,将Token还原回声音,这就需要另外训练一个反向模型了。
方向二:神经语音编解码器 (Neural Speech Codec)
与前一个方向不同,神经语音编解码器(Neural Speech Codec)会同时训练tokenizer和detokenizer。这个词由 Compression(压缩,即tokenizer)和 Decompression(解压,即detokenizer)组成。其训练方式类似于自编码器(autoencoder),目标是让输入的声音信号经过编解码后,输出的信号与输入尽可能接近。
“语义”与“声学”Token之辨
在语音领域,通过SSL模型产生的Token常被称为语义Token (Semantic Token),而由Neural Codec产生的Token则被称为声学Token (Acoustic Token)。这个命名源于一篇早期的论文《AudioLM》,但实际上这种称呼并不精确,甚至具有误导性。
所谓的“语义Token”,其“语义”与语言学中的含义不同。它并非指词汇层面的意义(如“高雄”和“打狗”),而是更接近于音素(Phoneme: 语音中能区别意义的最小单位),类似于KK音标。它主要捕捉的是发音信息。
而“声学Token”也并非只包含声学信息(如情绪、韵律),它同样保留了内容信息,否则detokenizer无法将其还原成可理解的语音。
总而言之,这是一个历史遗留的命名问题。两种方法都能将声音信号转为Token。如今的Neural Codec通常会为一段声音抽取多组Token,从不同层面来完整地表示它。
复杂生成策略:驾驭多层级Token
既然有这么多组不同层级的Token,我们应该如何选择?答案是“全都要”。在语音语言模型领域,一个热门的研究方向就是如何在生成时结合多种不同层级的Token。
假设我们有三组长度相同的Token,从左到右分别代表从粗略(如内容)到精细(如声学细节)的信息。
策略一:从粗到细生成
模型可以先生成所有最粗略的Token,然后基于这些Token生成中间层级的Token,最后再生成最精细的Token。像AudioLM和VALLE等模型就采用了类似技术。这种方法的缺点是难以实现流式传输(Streaming: 指模型能够即时响应,边生成边输出,而不是等全部内容生成完毕后再一次性输出)。因为它需要等待所有层级的Token都生成完毕后才能进行detokenization。
策略二:交错生成
为了加快响应速度,模型可以采用交错生成的方式:先生成第一个最粗的Token,然后是第一个中间的,再是第一个最细的;接着再生成第二个最粗的,以此类推。这样,每生成完一组(例如所有编号为1的Token),就可以立即送入detokenizer产生声音,从而更容易实现流式传输。
策略三:声学延迟 (Acoustic Delay)
即便采用交错生成,当Token种类很多时(例如Moshi使用8组Token),生成的序列长度依然非常可观。为了进一步缩短序列,一个想法是让模型每一步产生多种Token。但这会带来一个问题:在生成粗粒度Token之前,模型很难预测出细粒度Token应该是什么样子。
声学延迟就是一种改进方案。例如,第一步只产生第一个粗粒度Token;第二步产生第二个粗粒度Token和第一个中等粒度Token;第三步产生第三个粗粒度Token、第二个中等粒度Token和第一个细粒度Token。这样,在生成细粒度Token时,模型已经有了更多上下文信息,预测会更容易。
离散Token的优势与未来可能性
我们为什么要坚持使用离散的Token,而不是直接生成连续的向量呢?
对于输入端(理解声音)而言,使用连续向量甚至效果更好,因为离散化会损失信息。离散Token的真正优势体现在生成端。
生成任务的一个本质特性是“一对多”:同一个输入可以有多种合理的输出。例如,对“你好”的回应可以是多样的。如果模型的目标是生成一个连续向量,而训练数据中有两个可能的正确答案(比如一个绿色向量和一个蓝色向量),模型很可能会学习生成它们的平均值——一个错误的、模糊的结果。
而使用离散Token则可以避免这个问题。模型学习的是一个概率分布,例如,有60%的概率生成Token 1,40%的概率生成Token 2。在实际生成时,模型会从这个分布中采样,要么得到Token 1,要么得到Token 2,而不会产生它们的平均值。
不过,这并非唯一解。只要能通过特殊设计的损失函数(loss function)来处理“一对多”问题,理论上也可以使用连续向量进行生成。事实上,在影像生成领域,很多优秀模型就是直接生成连续表示的。语音领域也已开始有相关的研究探索。
训练困境:为何仅靠语音数据远远不够?
尽管我们讨论了各种复杂的生成策略,但这些方法在实际训练一个真正的对话式语音语言模型时,效果并不理想。即使使用上万小时的语音数据进行预训练,得到的模型也常常只会生成一些毫无意义的“胡言乱语”。
为什么会这样?原因在于数据量的巨大差异。假设你收集了100万小时的语音信号,这听起来很多。但换算成文字量,大约只有60亿(6B)个Token。相比之下,像Llama 3这样的现代文字模型,其预训练数据量高达15万亿(15T)个Token。60亿Token的规模,可能只相当于GPT-2的水平。
反过来看,如果将15T的文字Token用语音合成系统念出来,其总时长将达到惊人的28.5万年。这说明,我们几乎不可能收集到与顶尖文字模型相匹配的语音数据量。
文字本质上是语音的压缩版本,信息密度更高,学习起来相对容易。语音则像是解压缩版本,包含了更多复杂信息,学习难度也更大。数据显示,在同等算力投入下,语音模型在语义理解能力上的提升速度远慢于文字模型。
突破口:站在文字巨人的肩膀上
既然从零开始训练语音模型如此困难,而我们已经拥有了非常强大的文字模型,一个自然的想法就是:我们不需要从头开始。我们可以从一个预训练好的文字模型出发,教它学会处理语音。
当前的主流范式是,不仅使用文字模型作为语音模型的初始化参数,而且在生成时采取混合解码(Hybrid Decoding)的策略——让模型同时产生文字和语音。这就像模型在说话前,先在脑中打好草稿(生成文字),然后再将它说出来(生成语音)。这种方式可以使语音生成过程更加稳定。
如何让一个模型同时生成两种不同类型的Token序列呢?这里有多种策略:
- 先文后语: 模型先完整生成所有文字Token,然后再生成对应的语音Token。这本质上是“文字生成 + 语音合成”,技术相对成熟,但缺点是响应延迟高。
- 字-音交错: 模型生成一个文字Token,紧接着生成其对应的语音Token,实现“想一个字,念一个字”的效果,响应更即时。但这要求训练数据有精确的字词与语音时间戳对齐,获取难度大。
- 同步生成: 每一步同时生成一个文字Token和一个语音Token。这面临的最大挑战是,语音和文字的序列长度通常不一致,对应关系复杂,需要设计复杂的策略来对齐它们。
TASTE模型:一种创新的文本对齐Tokenization方案
为了解决上述混合解码中长度不一致的难题,我们实验室的曾亮轩同学等人提出了一种名为TASTE(Text-Aligned Speech Tokenization and Embedding)的新方法。
TASTE的核心思想是:既然模型已经会生成文字,那么语音Token就不再需要承载文字内容信息,只需专注于编码“如何说出这个字”的声学信息(如语速、语调、音色等)。更关键的是,TASTE设计了一个特殊的Tokenizer,它能确保生成的语音Token数量与对应的文字Token数量完全一致。
TASTE的实现方式如下:
- 输入一段声音信号,首先通过一个预训练的语音编码器抽取出特征向量。
- 同时,用语音识别系统得到这段声音对应的文字Token序列。
- 设计一个聚合器(aggregator),以文字Token作为查询(query),去语音特征向量中进行注意力(attention)计算,为每一个文字Token聚合出一个专属的、代表其发音方式的语音Token。
这样,无论原始语音信号多长,最终输出的语音Token序列长度都与文字Token序列长度严格相等。其detokenizer则像一个高级的语音合成系统,根据文字Token和对应的语音Token,就能精准地还原出带有特定风格的声音。
实验证明,TASTE产生的语音Token确实有效地编码了发音方式。例如,将一个慢速句子的语音Token与一个快速句子的语音Token进行交换,合成出的语音就会相应地变快或变慢。
训练与展望:从预训练到真实对话
有了TASTE这样高效的Tokenization方法后,我们就可以训练语音语言模型了。我们使用了一个约4万小时的英文语料库,在一个1B参数的Llama 3.2模型基础上进行初始化,训练出了一个能够进行“语音接龙”的预训练模型。
(讲者展示了多个模型进行语音接龙的例子,包括续写句子、模仿不同口音,甚至对网络迷因做出反应,展示了模型捕捉和生成多样化语音风格的能力。)
当然,预训练只是第一步。要让模型真正能与人互动,还需要后续的步骤:
- 监督式微调 (SFT): 使用高质量的对话数据对模型进行微调。为了避免“灾难性遗忘”(forgetting),一种常见的做法是让原始的文字大模型自己生成对话脚本,再用语音合成系统念出来,作为微调数据。通过准备不同类型的资料(如包含环境音、咳嗽声的对话),可以教模型理解和应对更丰富的声学场景。
- RLHF / RLAIF: 通过人类反馈或AI反馈来进一步优化模型。早期的研究侧重于提升音质,而近期的趋势则更多地利用RLHF来增强模型对音乐、环境音等非文字声音的理解能力。
未来的挑战:全双工交互与评估体系
最后,目前的语音交互大多仍是“回合制”的。而真实的人类对话是全双工(Full-duplex)的——我们同时在听也在说,对话中充满了打断和重叠。要实现这种自然的交互,需要不同于标准自回归模型的新技术。
此外,如何评估一个语音语言模型的好坏也是一个巨大的挑战。除了评估内容的准确性,我们还需要考虑声音本身的特性,如语气的恰当性、情感的表达是否得体等。这需要建立一套全新的、多维度的评估体系。