GLM-4-Voice:智谱新一代端到端语音大模型

GLM-4-Voice | 端到端中英语音对话模型

代码仓库:https://github.com/THUDM/GLM-4-Voice

继语言模型、图像理解、视频理解、图像生成、视频生成等模型之后,今天,智谱的多模态大模型家族再次加入新成员——GLM-4-Voice(端到端语音模型)。这一成果使得大模型具备了完整的感官系统,实现了机器与人交互的自然与流畅。
GLM-4-Voice 模型具备直接理解和生成中英文语音的能力,能够根据用户指令灵活调整语音的情感、语调、语速及方言等特征,且具有更低的延时,支持实时打断,进一步提升交互体验。
具体来说,GLM-4-Voice具备:

  1. 情感表达和情感共鸣:模拟不同的情感和语调,如高兴、悲伤、生气、害怕等情绪,用合适的情绪语气进行回复。传统 TTS 通常在情感表达上比较僵硬,声音缺少起伏和细腻的变化。
  2. 调节语速:在同一轮对话中,可以要求 TA 快点说 or 慢点说。
  3. 随时打断,灵活输入指令:根据实时的用户指令,调整语音输出的内容、风格和情感,支持更灵活的对话互动。例如,你可以随时打断 TA,让 TA 输出新的内容,更加符合日常对话情境。
  4. 多语言、多方言支持:目前 GLM-4-Voice 支持中英文语音以及中国各地方言,尤其擅长粤语、重庆话、北京话等。

技术细节

与传统的 ASR + LLM + TTS 的级联方案相比,端到端模型以音频 token 的形式直接建模语音,在一个模型里面同时完成语音的理解和生成,避免了级联方案“语音转文字再转语音” 的中间过程中带来的信息损失,也解锁了更高的能力上限。

GLM-4-Voice 由三个部分组成:

  • GLM-4-Voice-Tokenizer: 通过在 Whisper 的 Encoder 部分增加 Vector Quantization [单层量化]训练,通过在 ASR 数据上有监督训练的方式得到,将连续的语音输入转化为离散的 token,每秒音频转化为 12.5 个离散 token。
  • GLM-4-Voice-9B: 在 GLM-4-9B 的基础上进行语音模态的预训练和对齐,从而能够理解和生成离散化的语音。
  • GLM-4-Voice-Decoder: 基于 CosyVoice 的 Flow Matching 模型结构训练的支持流式推理的语音解码器,将离散化的语音 token 转化为连续的语音输出。最少只需要 10 个音频 token 即可开始生成,降低端到端对话延迟。
 CosyVoice  模型架构

具体来说,GLM-4-Voice 以离散 token 的方式表示音频,实现了音频的输入和输出的端到端建模。具体来说,我们基于语音识别(ASR)模型以有监督方式训练了音频 Tokenizer,能够在 12.5Hz(12.5 个音频 token)单码表的超低码率下准确保留语义信息,并包含语速,情感等副语言信息。

语音合成方面,我们采用 Flow Matching 模型流式从音频 token 合成音频,最低只需要 10 个 token 合成语音,最大限度降低对话延迟。

预训练方面,为了攻克模型在语音模态下的智商和合成表现力两个难关,我们将 Speech2Speech 任务解耦合为 Speech2Text(根据用户音频做出文本回复) 和 Text2Speech(根据文本回复和用户语音合成回复语音)两个任务,并设计两种预训练目标适配这两种任务形式:

  • Speech2Text:从文本数据中,随机选取文本句子转换为音频 token;
  • Text2Speech:从音频数据中,随机选取音频句子加入文本 transcription。

分别基于文本预训练数据和无监督音频数据合成语音-文本交错数据以适配这两种任务形式。

GLM-4-Voice 在 GLM-4-9B 的基座模型基础之上,经过了数百万小时音频和数千亿 token 的音频文本交错数据预训练,拥有很强的音频理解和建模能力。对齐方面,为了支持高质量的语音对话,我们设计了一套流式思考架构:输入用户语音,GLM-4-Voice 可以流式交替输出文本和语音两个模态的内容,其中语音模态以文本模态作为参照保证回复内容的高质量,并根据用户的语音指令变化感情需求,在保证智商的情况下仍然具有端到端建模的能力,同时保持低延迟性(最低只需要输出 20 个 token 便可以合成语音)。

Model List

ModelTypeDownload
GLM-4-Voice-TokenizerSpeech Tokenizer🤗 Huggingface 🤖 ModelScope
GLM-4-Voice-9BChat Model🤗 Huggingface 🤖 ModelScope
GLM-4-Voice-DecoderSpeech Decoder🤗 Huggingface 🤖 ModelScope

效果和其他说明

支持语音输入/文本输入,以及语音+文本交替输出

音频实时生成的质量较差,Gradio 的流式音频播放效果不稳定。在生成完成后点击对话框中的音频质量会更高。目前仅支持女声输出,指令遵循能力较强。

关于实时打断功能

作者目前还没给出实现方法和demo。有关打断问题,可以考虑参考开源项目 CleanS2S,虽然是级联式 pipeline【ASR+LLM+TTS】,但是相关代码逻辑应该可以结合 GLM-4-Voice 这样的 end-to-end 模型。目前支持实时输入语音打断和输入文字打断两种方式,后续还会设计更多有趣的打断模式(例如 agent 视角的主动打断)。

https://github.com/opendilab/CleanS2S/blob/main/README.zh.md

OpenAI o1复现项目进展报告

摘自:机器之心

O1 Replication Journey: A Strategic Progress Report

Report | Walnut Plan | Citation

团队介绍:本项目的核心开发团队主要由上海交通大学 GAIR 研究组的本科三年级、四年级学生以及直博一年级研究生组成。项目得到了来自 NYU 等一线大型语言模型领域顶尖研究科学家的指导。详细作者介绍见:https://github.com/GAIR-NLP/O1-Journey#about-the-team。


人工智能领域掀起巨浪的 OpenAI o1 模型发布三周后,一支由高校年轻研究者组成的团队今天发布了题为 “o1 Replication Journey: A Strategic Progress Report (o1 探索之旅:战略进展报告)” 的研究进展报告。这份报告的独特之处在于 (1)不仅提出并验证了 “旅程学习” 的技术的巨大潜力(研究者也认为是 o1 取得成功的关键技术):通过 327 条训练样本,鼓励模型学会反思、纠错、回溯,其在复杂数学题目上表现 绝对性能就超过了传统监督学习 8% 以上,相对性能提升超过 20%;(2)并且,其前所未有的透明度和即时性,不仅详细记录了团队在复现过程中的发现、挑战、试错和创新方法,更重要的是,它倡导了一种全新的 AI 研究范式。研究团队负责人表示:” 我们的主要目标不是达到与 OpenAI 的 o1 相当的性能 —— 考虑到可用资源有限,这是一个极具挑战性的任务。相反,我们的使命是透明地记录和分享我们的探索过程,聚焦于我们遇到的根本问题,发现新的科学问题,并识别导致 o1 的成功的关键因素,并与更广泛的 AI 社区分享我们的试错经验。o1 技术无疑会成为全球各大 AI 科技公司争相复现的目标。如果我们能够及早分享一些复现过程中的经验教训,就能帮助其他公司减少不必要的试错,从而降低全球范围内 o1 技术复现的总体成本和时间。这不仅有利于推动技术的快速发展,也能促进整个 AI 行业的共同进步。

团队提出的模型在同一道数学题上,与 OpenAI 的 o1-preview (答对)及 GPT-4o(答错)的比较实例,证明旅程学习不断试错、反思、自我纠正的能力在复杂推理任务场景上非常关键。
  • 技术报告链接:https://github.com/GAIR-NLP/O1-Journey/blob/main/resource/report.pdf
  • Github 链接:https://github.com/GAIR-NLP/O1-Journey
  • o1 讨论资源:https://github.com/GAIR-NLP/O1-Journey/tree/main/resource’

该报告发现了什么?从 “”捷径学习”” 到 “旅程学习”,从 “浮光掠影” 到 “深耕细作”

图:从 “捷径学习” 到 “旅程学习” 的范式转变。这是一个用于推理任务的搜索树。对于数学问题解决任务,根节点代表初始问题,而叶节点则是最终结论。绿色节点表示正确答案,红色节点表示错误答案。传统上,学习主要集中在对直接从根到叶的捷径路径进行监督训练。然而,本研究探索了对整个探索路径进行监督学习,这包括了试错和纠正的过程。

团队认为,大多数现有的机器学习或大模型训练方法(如监督式微调)都可以被归类为 “捷径学习” (Shortcut Learning),即模型学习到达正确答案的直接路径。这种传统范式虽然在特定、明确定义的任务中可能有效,但在面对复杂、动态和开放性问题时显示出明显的局限性。捷径学习具有以下几个关键特征:(1) 注重快速结果:强调在短时间内达到特定的性能指标或完成特定任务。(2) 高度依赖数据:性能改进通常依赖于增加训练数据量,而非改进学习算法本身。(3) 泛化能力有限:在训练数据分布之外的场景中,性能可能会急剧下降。(4) 缺乏自我纠正能力:这些系统通常缺乏识别和纠正自身错误的能力。尽管捷径学习推动了人工智能的许多进步,但它难以产生真正智能和可靠的人工智能系统,无法应对现实世界挑战的复杂性。随着我们追求更高级形式的人工智能甚至超级智能,这种方法的局限性变得越来越明显。
认识到这些缺点,本文提出了一种名为 “旅程学习”(Journey Learning) 的新范式。旅程学习旨在使人工智能系统能够通过学习、反思、回溯和适应不断进步,就像人类一样,从而展现出更高水平的智能。

如图所示,团队提出了 “旅程学习” 范式,它鼓励模型不仅学习捷径,还要学习完整的探索过程,包括试错、反思和回溯。仅使用 327 个训练样本,不借助任何额外训练技巧,旅程学习在 MATH 数据集上的表现就超过了传统监督学习 8% 以上,展示了其极其强大的潜力。作者也认为这是 o1 技术中最关键的组成部分

表:捷径学习和旅程学习的多维度比较

模型生成的例子:

技术细节是什么?o1 技术探索之旅

如图所示,从 OpenAI o1 9 月 12 日发布的过去三周内,该团队对 o1 技术已经完成了系统化、多阶段的探索。这个过程始于使用 OlympicArena 数据集对 o1 进行初步评估(如下表格),旨在全面了解其在多个学科领域的认知能力。研究的核心集中在 o1 思维结构的分析上,特别关注 “长思维” 这一关键概念整个探索技术涉及多个复杂的步骤,包括奖励模型的开发、在策略推理树的构建,以及将这些元素整合为连贯的长思维过程。整个研究过程采用了迭代和并行的方法。进行了多次尝试,不断调整和完善技术和方法。评估过程包括定量和定性分析,结合人工检查和专门的分析工具,以确保研究的准确性和有效性。

团队强调了探索过程的重要性,而不仅仅关注最终结果。这种重视科研探索过程的思路与团推提出的 “旅程学习” 范式相一致,强调了在复杂、动态环境中不断试错、纠错的持续学习和适应的重要性。通过这个过程,不仅获得了关于 o1 技术的深入理解,还开发了一套探索未知 AI 技术的系统方法。研究过程涉及决策分析、挑战识别以及创新解决方案的开发。最终,这项研究不仅仅是对 o1 技术的探索,更是对先进 AI 系统研究方法的一次实践和验证。通过分享研究过程,包括成功和失败的经验,旨在为 AI 研究社区提供有价值的见解,促进该领域的集体进步。
这个探索过程展示了开放、协作的 AI 研究在推动技术边界方面的重要性,为未来更复杂的 AI 系统研究提供了有益的参考和指导。
具体地,团队凝炼了复现 o1 过程中的几个关键问题,并做了非常细致的探索分享:

  • Q1: o1 的思维链是什么样子的?
  • Q2: 长思维 (Long thought) 是如何工作的?
  • Q3: 如何构建长思维?
  • Q4: 如何构建奖励模型?
  • Q5: 如何构建 on-policy 推理树?
  • Q6: 如何从推理树中推导出长思维?
  • Q7: 如何评估我们的尝试方法?
  • Q8: 如何训练我们的模型?
  • Q9: 什么是人类和 AI 协同标注的有效策略?

  • Q1: o1 的思维链是什么样子的?
  • 经过探索,团队确定需要构建的长思维数据应具有以下特征:

    • 迭代式问题解决:模型首先定义函数,然后逐步探索相关表达式,将复杂方程分解为更简单的组成部分,反映了一种结构化和有条理的方法。 
    • 关键思维指标:使用 “Therefore” 表示结论,”Alternatively” 探索不同路径,”Wait” 表示反思,以及 “Let me compute” 过渡到计算,突出了模型的推理阶段。 
    • 递归和反思方法:模型经常重新评估和验证中间结果,使用递归结构确保一致性,这在严谨的数学推理中很典型。 
    • 假设探索:模型测试不同的假设,随着获得更多信息而调整其方法,展示了推理过程中的灵活性
    • 结论和验证:最后,模型解方程并验证结果,强调在完成之前验证结论的重要性。 

    Q2: 长思维 (Long thought) 是如何工作的?
    这是团队认为重要的问题。然而,在当前的研究阶段,该团队仅仅提出了猜想。团队认为还没有足够的经验证据来验证它们的准确性,这也是未来需要重点展开的工作。
    o1 长思维方法的显著成功可以归因于在上述中介绍的旅程学习 (Journey Learning)。与传统的捷径学习 (Shortcut Learning) 不同,旅程学习允许模型探索整个决策轨迹,模仿人类的问题解决过程。这种全面的探索使 o1 能够考虑多种解决方案路径,从错误中学习,并理解完整的问题解决过程。通过经历正确和错误的路径,模型发展出强大的错误处理和自我纠正能力,增强了其适应新挑战的能力。这种方法培养了对问题领域更深入的理解,不仅仅是知道正确答案,而是理解为什么以及如何得出答案。旅程学习过程密切模拟人类的认知过程,包含试错、反思和调整。这大大增加了模型输出内容的可解释性,因为 o1 可以提供详细的解决步骤并解释其推理过程,包括如何从错误中恢复。因此,基于旅程学习的 o1 长思维过程不仅仅是计算时间的扩展,还代表了一种彻底的、人类般的推理探索。这种方法使 o1 能够处理更复杂的问题,提供更可靠和可解释的答案,并在面对新挑战时表现出更大的适应性,从而解释了它在各种任务中的卓越表现。


    Q3: 如何构建长思维?
    尝试 1:基于 LLM 和奖励的树搜索 根据在 Q1 中对长思维的观察,其最显著的特征是在推理产生错误时或遇到冗余的推理步骤时尝试反思和回溯。这类似于在推理树上搜索问题的解决方案,在错误节点处回溯,直到找到正确的解决路径。为实现这一点,需要构建一棵推理树,其中根节点代表问题,其他每个节点代表一个推理步骤。从根到任何节点的路径代表从问题到该结论的推理过程。此外,回溯和反思必须基于错误的推理步骤,这需要一个更细粒度的奖励模型(即过程级)来指示树中每个节点的正确性。通过在具有过程级奖励的推理树上执行搜索算法,可以将错误步骤整合到思维链中,从而构建包含回溯和反思等行为的长思维。
    尝试 2:提议 – 批评循环 尝试 1 通过基于预定义规则在树上执行搜索来构建长思维,但这限制了回溯和反思等行为的自由度。因此,团队尝试让模型选择自己当前的行为。团队构建了一个提议 – 批评循环,其中为模型预定义了一些可能的行为(即继续、回溯、反思、终止),并让模型自身选择行为来构建推理树。如果树没有达到最终答案,可以将这个负面信号告知模型,引导它反思和纠正其方法。
    尝试 3:多智能体方法 基于推理树构建长思维存在几个挑战,包括存在许多冗余的无效节点,以及存在不依赖于反思行为的推理步骤,从而引起构建的长思维逻辑不一致。为解决这个问题,团队设计了一个利用多智能体辩论的算法,其中一个智能体充当策略模型,持续推理,而另一个智能体充当评论模型,指示策略模型是否应该继续当前推理或执行回溯等行为。两个智能体进行持续对话,在找到正确答案时自然构建长思维数据集。
    尝试 4:完整的人类思维过程注释 当人类处理推理问题时,他们通常不会不断地向前推理直到解决问题或失败;相反,他们在无法继续时会反思、回溯和重写推理。这种行为与长思维的特征高度一致。因此,可以忠实且全面地记录人类解决推理任务的过程,从而产生高质量的长思维。


    Q4: 如何构建奖励模型?
    使用奖励模型的第一步是定义粒度。团队的目标不仅仅是关注最终结果,而是专门提高 LLMs 在反思、回溯和相关认知过程方面的能力。因此,团队将评估粒度定义在步骤层面。具体来说,团队使用来自 Abel 的微调数据,通过行号使解决方案变得清晰可辨。
    实现奖励模型的过程可以使用开源模型或是调用闭源模型的 api。团队比较了不同奖励模型在 PRM800K 和 MR-GSM8K 子集上的元评估表现。如下表格展示了结果,其中,o1-mini 在不同数据集上表现最佳,证明其是一个良好的奖励模型。

    Q5: 如何构建 on-policy 推理树?

    构建推理树需要一个能够执行单步推理的策略模型。给定一个问题及其相应的最终答案,策略模型从问题作为根节点开始,不断向树中添加新节点。它首先生成 w 个可能的第一步推理步骤作为根节点的子节点。然后,它迭代地进行前向推理,为每个当前节点(如第一步推理)生成 w 个可能的后续推理步骤作为该节点的子节点。这个过程重复进行,直到达到预设的最大深度或所有叶节点达到最终答案。

    策略模型和步骤分段 构建推理树需要清晰定义推理步骤。为此,团队采用 Abel 提出的数据格式,将数学问题解决方案转化为具有清晰步骤的形式,将答案分成多行,每行以行号开始,并包含该行内的推理。因此,使用 Abel 数据集对 DeepSeekMath-7B-Base 进行微调,得到 Abel-DSMath,作为策略模型。在这种特定格式数据上微调的模型可以方便地控制单个推理步骤的生成。

    奖励模型和剪枝 上述提出的树生成算法计算成本高昂。当设置后续推理步骤数目为 3 和深度为 10 时,最后一次迭代需要生成 3 的 10 次方个推理步骤。因此,使用奖励模型来剪除错误的推理步骤,提高操作效率。具体来说,团队采用束搜索,在每次迭代中只选择少量候选项保留到下一轮。根据使用的奖励模型,剪枝实现的细节有所不同。团队尝试了两个奖励模型:math-shepherd 和 o1-mini。

    Math-shepherd 为每个步骤提供一个介于 0 和 1 之间的实数,表示当前步骤正确的概率。在树生成的每次迭代中,对所有推理步骤进行评分,并选择得分最高的前 K 个进入下一次迭代。这将总生成次数进行剪枝。然而,math-shepherd 在评估困难问题的推理步骤时存在困难,需要一个更强大的奖励模型,能够为每个步骤提供高准确度的正确性指示。因此,最终使用 o1-mini 为每个步骤提供奖励,直接指示每个推理步骤是否正确。此时,在树生成的每次迭代中,利用来自 o1-mini 的奖励,选择最多 K 个正确的推理步骤进入下一次迭代。

    Q6: 如何从推理树中推导出长思维?
    一旦构建了推理树,目标就变为探索如何从推理树转换为包含试错过程的长思维。在该团队的框架中,推理树的每个节点都被奖励模型标注,指示该步骤是否正确或错误。具体的合成步骤如下:

    • 从推理树构建捷径 首先从推理树构建捷径,其中只包括正确答案和有效的中间步骤。从代表问题的根节点开始,找出通向正确答案叶节点的路径。如果有多个正确答案节点,则建立多条正确路径。
    • 遍历推理树 为了得到长思维,采用深度优先搜索(DFS)遍历树。这种遍历按 DFS 顺序构建路径,记录从根问题节点到正确答案叶节点的每一步,同时包括任何被标记为错误的节点的推理。DFS 的挑战在于它探索了庞大的搜索空间,产生了大量可能无法得到正确解决方案的试错路径。为了简化这一初始探索,团队还引入了具体的约束来缓解由于遍历路径过长导致的合成数据的复杂性。首先,根据节点是否位于正确路径(即捷径)上来标记树中的所有节点。遍历遵循以下规则: 
    • 正确路径上的节点:DFS 遇到正确路径上的节点时,它可能会探索导致错误结果的子节点,从而模拟试错的过程。一旦这个节点到达叶节点并被确定为错误,算法就会回溯并切换到正确的路径继续遍历。 
    • 不在正确路径上的节点:随机选择一个子节点进行探索,并不产生试错的分支。

     为进一步简化过程,应用了一个额外的约束:正确路径上的每个节点最多允许 K 次试错 —— 一次在错误路径上的试错和一次在正确路径上的探索。 这些约束确保 DFS 遍历专注有意义的试错探索,同时避免过度探索错误路径。在未来的实验中,计划移除或调整这些约束,以研究试错路径长度与最终模型性能之间的关系。

    • 从遍历路径得到长思维 生成遍历路径并将推理附加到错误节点后,通过连接路径中的所有步骤来构建长思维,其中还包含了每个错误步骤的推理。然而,初步实验表明,使用这个形式的长思维数据来训练模型的性能不佳。为解决这个问题,团队尝试使用 GPT-4o 来修改草稿。GPT-4o 在保留所有推理步骤(包括错误步骤、反思和修正)的同时,增强了思维过程的连贯性和流畅性。这种方法确保最终的长思维不仅准确,而且自然流畅,模拟了包含正确和错误步骤的人类问题解决过程。

    Q7: 如何评估我们的尝试方法?

    除了使用特定评估指标在基准测试上测试准确率分数外,人工审查实际案例(输入输出)是评估数据和模型的关键步骤。因此,为了提供一种更直观的方式来评估模型在特定问题上的表现,团队构建了一个可视化数据分析平台。
    具体来说,可视化平台包括合成树及其对应长思维的可视化,以及训练模型的输出。此外,在可视化结果时,支持详细的条件过滤,例如过滤正确或错误回答的问题,或输出是否包含表示反思或犹豫的关键词(如 “wait”)。另外,可视化平台支持不同迭代轮次的合成数据和模型输出之间的比较,这使得团队可以非常直观地验证新一轮的数据或模型是否有效。

    Q8: 如何训练我们的模型?
    团队实验使用预训练语言模型 deepseek-math-7b-base(更多其他模型已经在等待列表中)。训练过程分为两个主要阶段:监督微调(SFT)和直接偏好学习(DPO)。
    第一阶段:监督微调(SFT): 
    SFT 过程包括两个阶段:

    • 初始阶段:在这个初始阶段,团队专注于使用只包含正确中间步骤和最终正确答案的响应来微调模型。在 Abel 数据集和 PRM800K 数据集上微调 Deepseek-math-7b-base。对于 PRM800K 中的每个问题,使用单个正确的逐步解决方案,丢弃不导向最终答案的回复。在这个阶段,对每个数据集进行一个 epoch 的微调,主要目的是让模型熟悉所需的响应格式。
    • 旅程学习:在第二阶段,使用构建的长思维(包含 327 个示例)进一步微调初始阶段的 SFT 模型。这个阶段旨在增强模型发现错误、自我反思、自我修正和执行回溯的能力。通过在合成的包含试错、反思的长思维数据上训练,模型对更长推理链中涉及的复杂性有更深入的理解。为了比较,团队还在从同一推理树生成的相应捷径上 (Shortcut Learning) 微调模型(同样是 327 个),从而更直观的比较旅程学习相比捷径学习所带来的增益。

    第二阶段:直接偏好学习(DPO)
    在这个阶段,使用核采样(top_p = 0.95 和温度 T = 0.7)从 MATH Train 数据集为每个问题生成 20 个回复。这 20 个回复根据最终答案的正确性分类为正面和负面响应。从中,随机选择 5 个正面响应和 5 个负面响应来创建 5 对偏好对。然后,使用这些偏好对和 DPO 损失来训练模型,使其能够从正确和错误答案的比较中学习。


    Q9: 什么是人类和 AI 协同标注的有效策略?
    团队开发了一种人类和 AI 协作的数据标注流程,用于生成基于 MATH 数据集的高质量、长文本推理数据。通过这个流程,我们将短短几行人类标注的解题方案扩展为包含数千个 token 的、符合 “旅程学习” 范式的详细推理过程。在构建流程的过程中,我们发现了下面几种有效的标注技巧:

    • 完整的思维过程:标注者不必详细记录每一个想到的词语,但必须记录每一个尝试、反思、联想和修正的过程。这些发散的认知路径在日常思考中可能并未被表达成文字,甚至没有被显式认知。然而,捕捉这些思维转变以及背后的原因是至关重要的。这种规划和理解认知转换的能力是大语言模型从我们的数据中必须学习的核心技能。
    • 补充解释常识:人类在用语中经常省略一些可以从上下文中推断的信息,比如对前述公式的引用,或是对广为人知的理论的应用。然而,当大语言模型尝试解读人类标注时,这种省略可能导致幻觉。因此,高质量的数据必须包括对常识性知识的明确解释,以防止大模型的误解。

    遵循以上两个关键要素,人类专家即可完成数据标注,这些数据精简但准确,非常利于大模型做进一步增强。下一阶段,通过设计复杂的提示词,我们通过大语言模型实现了数据扩展和增强。我们的提示词包含以下关键点:

    • 数据颗粒度的增强:提示词强调将问题解决过程分解为更细小的步骤。通过将过程拆解成细粒度且易于理解的步骤块,大语言模型能更好地掌握和内化每个概念,确保在每个阶段都有深入的理解。
    • 逐步推理:提示词控制大语言模型需频繁暂停,反思已知信息或提出下一步的操作。这种停顿模仿了学生在思考问题时的自然过程,帮助他们保持参与感和对推理过程的连接感,而不仅仅是被动地遵循指令。
    • 探索者视角:与直接呈现答案不同,大语言模型被鼓励以探索的语气进行推理,即假设自己是第一次思考这个问题。这种方式可以激发某种程度的 “好奇心”,鼓励模型批判性思考,使他们感觉自己是学习过程的一部分,而不是简单地接收信息。

    为什么科学进展报告很重要?
    研究团队表示:传统发论文方无法适应新的科研范式,人工智能技术的快速发展开创了一个新的研究范式时代,其特点是长期的、基于团队的努力,通常持续六个月或更长时间。这种转变虽然有利于突破性创新,但无意中给科学过程带来了新的挑战。长期团队合作的内向性经常导致向更广泛科学界信息流动的减少。此外,这些项目的长期性质往往导致研究人员满足感的延迟,可能在整个研究过程中培养焦虑和动力减弱。另外,大规模团队项目的复杂性使得认可个人贡献变得复杂,可能侵蚀传统的学术激励结构。团队的进展报告方法旨在通过增强透明度、促进实时反馈和认可,以及鼓励对长期研究计划的持续承诺来解决这些新出现的挑战。在这样的背景下,团队认为 ”Scientific Progress Report“ (科研进展报告)是一种比 现在”Scentific Paper“ (科研论文)更有价值的科研产出和成果分享的组织形式。团队科学探索过程的细致记录,尤其在 AI 能力快速发展的背景下,具有深远意义。通过全面记录探索过程,包括成功和失败,团队正在培育一个独特而宝贵的数据集。这份全面的记录对于训练真正理解科学方法的 AI 模型至关重要。o1 的成功强调了 AI 系统不仅要学习结果,还要学习完整的科学探索过程,包括试错的重要性。通过科研进展报告,不仅可以捕捉技术细节,还包括决策理由、灵感来源和思维过程。这些 “人类因素” 对于训练能够进行真实科学发现的 AI 模型至关重要。
    下一步探索
    团队根据的研究时间线和取得的进展,确定了几个未来探索和发展的关键方向:

    • 扩展长思维的合成: 基于在长思维合成方面的成功迭代,团队计划进行第三轮的数据集成。这将涉及处理更复杂和多样的思维模式,可能揭示 o1 能力的新维度。
    • 长思维扩展定律实验: 这个研究流程旨在理解模型的性能和能力如何随着数据、模型大小和计算资源的增加而扩展。对这个规律的掌握对优化方法和挖掘超级 AI 系统背后的基本原理至关重要。
    • 细粒度、以思考为中心的评估: 计划开发和实施更复杂的评估方法,专注于细粒度、以思考为中心的评估。这种方法将让我们更准确地衡量生成的长思维的质量和连贯性,为模型推理能力提供更深入的洞察。
    • 人机协作以提高思考质量: 未来计划的一个关键部分是探索和增强人机协作,以产生更贴近人类思维的高质量思考数据。这涉及开发利用人类智能和 AI 能力的共同优势,促进 AI 能力的突破。
    • 持续改进奖励和批评模型: 基于过程级奖励模型和评论模型设置,旨在进一步完善这些系统。这个持续的过程将涉及迭代改进,以更好地提供细粒度的监督信号。
    • 推理树的合成优化: 计划探索从推理树中推导和集成长思维更复杂、有效的方法。这将涉及探索更加先进高效的算法来遍历并利用复杂结构中的信息。
    • 扩展训练方法: 未来计划包括进一步实验和完善训练流程。这包括增加预训练阶段、迭代训练、强化学习、偏好学习和 DPO(直接偏好优化)。
    • 持续的透明度和资源共享: 将继续分享在整个科研旅程中开发的资源、观察到的结论和工具。这种持续的做法旨在促进更广泛的 AI 研究社区的协作和加速进展。
    • 探索多代理方法: 基于在多代理系统方面的初步尝试,计划深入研究这一领域,发现建模复杂推理和决策过程潜在的新方法。
    • 完善分析工具: 旨在进一步开发和增强分析工具。这些工具对解释模型输出、跟踪进展和指导未来研究方向至关重要。

    通过追求这些途径,不仅推进我们对 o1 能力的理解和复制,还要推动 AI 研究方法的边界。

    核桃计划:

    团队借本项目正式引出 “核桃计划” (https://gair-nlp.github.io/walnut-plan),团队成员表示:“对 o1 技术路线的探索及复现工作,仅仅是我们核桃计划的一部分。核桃计划旨在成为人工智能复杂推理和深度思考能力研究的开放先锋,致力于推动 AI 从简单的信息处理工具演变为具备 “牛顿” 和 “爱因斯坦” 级别深度思考能力的智能系统。我们将着眼于更长远的研究,最终的伟大愿景是让未来可以呈现 AI 驱动的科研范式,即 AI 完全具备参与人类科研的水准,从而更好地服务人类、改变世界。”

    OpenMusic:音乐生成更高质量,更有乐感

    中科大&科大讯飞重磅开源OpenMusic

    文章链接:https://arxiv.org/pdf/2405.15863
    代码链接:https://github.com/ivcylc/qa-mdt
    Huggingface链接:https://huggingface.co/spaces/jadechoghari/OpenMusic
    Demo链接:https://qa-mdt.github.io/  (chatgpt * 30, musiccaps * 30)

    • 提出了一种质量感知训练范式,使模型在训练过程中能够感知数据集的质量,从而在音乐性(美学角度)和音频质量方面实现卓越的音乐生成效果。
    • 创新性地将masked扩散Transformer引入到音乐信号中,展示了其在建模音乐潜在空间上的独特效果,以及其在质量控制感知方面的卓越能力,从而进一步提升了生成音乐的质量和音乐性。
    • 解决了大型音乐数据集中文本与音频低相关性的问题,有效提高了文本对齐度和生成的多样性。

    背景

    近年来,基于扩散的文本到音乐(TTM)生成方法逐渐受到重视,提供了一种创新的方法,将文本描述合成音乐内容。要在这一生成过程中实现高准确性和多样性,必须依赖大量高质量的数据,包括高保真音频波形和详细的文本描述,但这些通常仅占现有数据集中的一小部分。在开源数据集中,低质量音乐波形、标签错误、弱标签和无标签数据等问题显著阻碍了音乐生成模型的发展。为了解决这些挑战,今天和大家分享一种全新的高质量音乐生成范式,该范式结合了质量感知训练策略,使生成模型能够在训练过程中辨别输入音乐波形的质量。利用音乐信号的独特特性,首先针对TTM任务调整并实现了一个掩码扩散Transformer(MDT)模型,展现出其在质量控制和音乐性增强方面的独特能力。此外,还通过字幕优化数据处理方法解决了TTM中低质量字幕的问题。实验结果表明,在MusicCaps和Song-Describer数据集上取得了当前最先进的(SOTA)性能。

    当前音乐生成(音效生成)领域的问题为质量低,具体来说分为三个方面:

    • 大部分的开源数据集音质低(FMA,AudioSet,MSD),旋律杂乱
    • 音乐性(美学角度)差
    • 文本对齐度低,大多数的音频处于少标签,弱标签,错标签。其中, 第1点可以由下图蓝色分布CLAP分数表征,2,3点可以由数据集的平均MOS分布表征(颜色由 μ +α * σ 分割)
    图 1:大规模开源音乐数据库 AudioSet 和 FMA 的 CLAP 相似性和伪 MOS 的分布曲线,其中较暗的区域代表较高的文本音频对齐或音频质量。

    创新方法及思路

    质量信息注入

    解决: 引入质量感知训练策略。采用主观数据集中的MOS分训练出的质量评分模型,在训练过程中注入(伪MOS分)音频质量信息。

    两种注入方法:

    • 利用 text encoder 对分级后的 low quality, medium quality, high quality 质量文本进行cross attn嵌入 【粗粒度,适配unet架构和transformer类架构】
    • 参考U-ViT内 时间信息和label信息的融入方式,以量化(阈值由 决定)后转换为quality embedding, 以token 形式进行控制注入,【细粒度,并且只适配transformer类架构】

    结论:质量感知策略允许了在推理阶段以高质量文本和质量token进行引导,从而生成显著高于训练集平均质量的音频。

    以类似解耦的方式在训练中感知音频的质量(类似TTS中分离出音色训练),从而更好地促进了模型的训练(大幅降低FAD,KL,并提升IS,REL,CLAP等指标)

    我们还发现,粗粒度文本控制和细粒度token控制相结合,更有助于模型训练中解耦,感知,并控制更高质量音频的生成,从而解决训练数据集影响的问题

    质量感知型 masked扩散Transformer

    解决:从音乐性建模角度,我们发现 U-ViT/DiT 类架构对频谱隐空间建模也具有图像上表达的scale ability,并能更好建模谐波,音色等方面(反应在主观评分)

    优化

    • 对频谱切片而言,此类结构的收敛速度慢。消融数据集中,20w步时依然不能很好控制收敛,推测来源于时域/频域相关性弱。故在预训练阶段加入掩码,加速训练速度和频谱关联性。微调阶段以高质量数据进一步强化模型(5W步就有收敛迹象)。
    • 相比于U-Net,transformer based架构对text encoder的质量信息感知能力增强,并且U-ViT 式 token 质量融入策略显著有效进一步提升质量并降低客观指标
    • 图像中切块未考虑 overlap,探究了overlap策略在合成中的作用(大幅降低FAD,但在主观听感上有trade off)

    优化音乐标注描述

    解决:首次在音乐生成领域使用预训练标注模型(LP-Musiccaps)进行大规模标注优化

    • 考虑到标注模型的不充分训练导致错标,以CLAP文本-音频分数+阈值筛选低分数据
    • 考虑到原始标注中有些词(例如说American,R&B等标注器不一定能标注出的词)。使用CLAP分数过滤出生成的与原始的文本相似度低低数据,利用语言模型 融合原始标注中有用信息

    实验

    总体对比与,对比U-net架构和transformer based架构

    对比overlap策略和patch size:

    质量感知消融

    此图证明了相比于无质量感知,大幅提升了生成质量和客观指标。并且,MDT(我们的架构)比 U-Net 在文本质量控制感知上的独特优势(生成质量更高,总体客观指标更好)

    左图展示了 token as control 的准确感知控制生成能力,生成的高质量数据(黄色区域)显著高于训练集MOS分。

    右图展示了文本质量控制和token质量控制的结合效果与单纯token和文本控制的对比。

    主观评测结果

    • PO:产品运营
    • PMP:专业音乐制作人
    • VE:视频编辑人
    • BEGINNERS:不懂音乐的小白

    各个人的评分下,均有优势。

    结论与展望

    本研究识别出大规模音频质量不均和文本标注未对齐所带来的挑战,这些挑战阻碍了基于扩散的文本到音乐(TTM)生成的发展。通过采用基于p-MOS的新型质量感知学习方法,以及以masked扩散Transformer作为扩散过程的主干,在音乐生成中实现了更高的生成质量和音乐性。

    为什么BERT输入的最大长度要限制为512?

    来自 知乎

    总的来说是为了计算效率,所以把长度限制在了512。

    To speed up pretraing in our experiments, we pre-train the model with sequence length of 128 for 90% of the steps. Then, we train the rest 10% of the steps of sequence of 512 to learn the positional embeddings.

    当然,最最本质的原因还是在于BERT中的Positional Embedding和Transformer中的Positional Embedding实现方式不一样,后者是通过公式计算得到的,而前者本质上则是一个可学习的参数,也就是说每个位置所对应的向量就类似于Token Embedding中每个词对应的词向量。

    class PositionalEmbedding(nn.Module):
        """
        位置编码。
          *** 注意: Bert中的位置编码完全不同于Transformer中的位置编码,
                    前者本质上也是一个普通的Embedding层,而后者是通过公式计算得到,
                    而这也是为什么Bert只能接受长度为512字符的原因,因为位置编码的最大size为512 ***
          # Since the position embedding table is a learned variable, we create it
          # using a (long) sequence length `max_position_embeddings`. The actual
          # sequence length might be shorter than this, for faster training of
          # tasks that do not have long sequences.
                                                     ————————  GoogleResearch
        https://github.com/google-research/bert/blob/eedf5716ce1268e56f0a50264a88cafad334ac61/modeling.py
        """
    
        def __init__(self, hidden_size, max_position_embeddings=512, initializer_range=0.02):
            super(PositionalEmbedding, self).__init__()
            self.embedding = nn.Embedding(max_position_embeddings, hidden_size)
            self._reset_parameters(initializer_range)

    因此,除非是你自己从零开始训练一个模型,否则如果你使用的是谷歌开源的预训练模型,那么这个词表的大小将会被限制在512。 当然,你依旧可以突破这个限制,那就是自己在从新初始化Positional Embedding中的向量,然后对前512个进行替换,后面的就自己在对于语料上训练微调。

    Triton Inference Server推理引擎

    https://github.com/triton-inference-server/server

    Triton 从入门到精通

    https://docs.nvidia.com/deeplearning/triton-inference-server/release-notes/index.html

    深度学习部署神器——triton-inference-server入门教程指北

    triton-inference-server的backend(一)——关于推理框架的一些讨论

    Triton Inference Server是Nvida开源的机器学习推理引擎(可以理解为同TF Serving对等的产品),其提供了多种开箱即用的功能帮助我们快速落地AI模型到生产环境以提供业务使用。当我们团队人手资源受限或开发时间不足的情况下,没有能力自研一套机器学习推理引擎,Triton是一个非常好的选择。

    从Triton的不断完善的进程来,其已经逐渐的具有了一个深度学习推理引擎应该所具有的的全部功能(当然还是有一些不够完善的地方)。

    Triton Inference Server核心的几个功能:

    • 多框架支持:Triton支持了几乎所有主流的机器学习框架,例如Tensorflow、TensorRT、Pytorch、Python、ONNX等;同时也可以custom backend的方式来扩展解码引擎。
    • 高性能:Triton提供了dynamic batching、concurrent execution、optimal model configuration、model ensemble、dali model 等策略来提升在线推理的性能;同时也提供了perf analyze和model analyze工具来辅助我们进行性能调优。
    • MLOps:Triton提供了Prometheus exporter、模型在线更新、http server 、grpc server等多种在线服务策略以满足用户生产场景多样化的部署和运维需求

    triton可以充当服务框架去部署你的深度学习模型,其他用户可以通过http或者grpc去请求你搭建的服务,相当于你用flask搭了个服务供别人请求,当然相比flask的性能高很多了。triton也可以摘出C-API充当多线程推理服务框架,去除http和grpc部分,适合本地部署多模型,比如你有很多模型要部署,然后分时段调用,或者有pipeline,有了triton就省去你处理显存、内存和线程的麻烦。

    借用官方的图,triton的使用场景结构如下:

    涉及到运维部分,我也不是很懂,抛去K8S后,结构清爽了些:

    triton的一些优点

    通过上述的两个结构图,可以大概知道triton的一些功能和特点

    • 支持HTTP/GRPC
    • 支持多backend,TensorRT、libtorch、onnx、paddle、tvm啥的都支持,也可以自己custom,所以理论上所有backend都可以支持
    • 单GPU、多GPU都可以支持,CPU也支持
    • 模型可以在CPU层面并行执行
    • 很多基本的服务框架的功能都有,模型管理比如热加载、模型版本切换、动态batch,类似于之前的tensorflow server
    • 开源,可以自定义修改,很多问题可以直接issue,官方回复及时
    • NVIDIA官方出品,对NVIDIA系列GPU比较友好,也是大厂购买NVIDIA云服务器推荐使用的框架
    • 很多公司都在用triton,真的很多,不管是互联网大厂还是NVIDIA的竞品都在用,用户多代表啥不用我多说了吧
    大厂都在用triton

    如何学习triton

    两年前开始学习的时候,官方资料比较匮乏, 只能通过看源码来熟悉triton的使用方式,所幸知乎上有个关于TensorRT serving不错的教程[2],跟着看了几篇大致了解了triton的框架结构。那会triton叫做TensorRT serving,专门针对TensorRT设计的服务器框架,后来才变为triton,支持其他推理后端的。

    现在triton的教程比较多了,官方的docs写着比较详细,还有issue中各种用例可以参考,B站上也有视频教程[3],比两年前的生态要好了不少。

    当然,最重要的,还是上手使用,然后看源码, 然后客制化。

    源码学习

    从triton的源码中可以学到:

    • C++各种高级语法
    • 设计模式
    • 不同backend(libtorch、TensorRT、onnxruntime等)如何正确创建推理端,如何多线程推理
    • C++多线程编程/互斥/队列
    • API接口暴露/SDK设计
    • CMAKE高级用法

    等等等等,不列举了,对于程序员来说,好的源码就是好的学习资料。当然,也可以看老潘的文章哈。

    triton系列教程计划

    triton相关系列也会写一些文章,目前大概规划是这些:

    • 什么是triton以及triton入门、triton编译、triton运行
    • triton管理模型、调度模型的方式
    • triton的backend介绍、自定义backend
    • 自定义客户端,python和c++
    • 高级特性、优先级、rate limiter等等

    编译和安装

    一般来说,如果想快速使用triton,直接使用官方的镜像[4]最快。但是官方镜像有个尴尬点,那就是编译好的镜像需要的环境一般都是最新的,和你的不一定一致

    比如22.09版本的镜像需要的显卡驱动为520及以上,如果想满足自己的显卡驱动,就需要自行编译了。官方也提供了使用镜像的快速使用方法

    # 第一步,创建 model repository 
    git clone -b r22.09 https://github.com/triton-inference-server/server.git
    cd server/docs/examples
    ./fetch_models.sh

    # 第二步,从 NGC Triton container 中拉取最新的镜像并启动
    docker run --gpus=1 --rm --net=host -v ${PWD}/model_repository:/models nvcr.io/nvidia/tritonserver:22.09-py3 tritonserver --model-repository=/models

    # 第三步,发送
    # In a separate console, launch the image_client example from the NGC Triton SDK container
    docker run -it --rm --net=host nvcr.io/nvidia/tritonserver:22.09-py3-sdk
    /workspace/install/bin/image_client -m densenet_onnx -c 3 -s INCEPTION /workspace/images/mug.jpg

    # Inference should return the following
    Image '/workspace/images/mug.jpg':
        15.346230 (504) = COFFEE MUG
        13.224326 (968) = CUP
        10.422965 (505) = COFFEEPOT

    triton官方仓库

    两年前的triton只有一个大仓库,tensorrt_backend也默认在triton主仓库中,但是现在tensorrt_backend被拆分出来了,很显然triton除了支持tensorrt还支持很多其他的后端,我们可以自定义使用很多后端。

    现在是目前的triton包含的一些仓库:

    • [server[5]] triton服务外层框架,包含了http收发请求,服务内存分配等一些功能代码
    • [core[6]] triton主框架,如果处理请求、后端管理、模型调度啥的全在这里
    • [common[7]] 通用工具,没啥好说的,打日志的代码在这里
    • [backend[8]] backend后端框架代码,存放了一些后端通用父类,自定义后端可以集成这些类仿写新的后端
    • [third_party[9]] triton使用的第三方库的汇总,主要是cmake里头会包含
    • [tensorrt_backend[10]] tensorrt后端代码
    • [pytorch_backend[11]] libtorch后端代码

    最开始的时候,server、core、common、backend这些代码仓库都是合在一起的,后来都拆分出来了,增加了triton的灵活性。

    比如,上述的core仓库可以单独暴露出cAPI作为动态链接库供其他程序调用,去掉http、grpc的外层请求接口,直接一步到位调用。

    一般来说,我们都是从最主要的server开始编,编译的时候会链接core、common、backend中的代码,其他自定义backend(比如tensorrt_backend)在编译的时候也需要带上common、core、backend这三个仓库,这些关系我们可以从相应的CMakeList中找到。

    自行编译

    如果想要研究源码,修改源码实现客制化,那么自行编译是必须的。

    triton的编译和安装其实很简单,唯一的难点就是需要加速,因为triton在编译的时候会clone很多第三方库,第三方库也会克隆它们需要的第三方库,这些库当然都是国外的,所以有个好的网络环境很重要。

    比如在编译triton的时候需要下载grpc这个库,grpc又依赖很多第三方其他库,网络不好的话,会经常遇到下面的问题:

    Failed to recurse into submodule path 'third_party/bloaty'
    CMake Error at /tmp/tritonbuild/tritonserver/build/_deps/repo-third-party-build/grpc-repo/tmp/grpc-repo-gitclone.cmake:52 (message):
      Failed to update submodules in:
      '/tmp/tritonbuild/tritonserver/build/_deps/repo-third-party-build/grpc-repo/src/grpc'


    make[3]: *** [_deps/repo-third-party-build/CMakeFiles/grpc-repo.dir/build.make:99: _deps/repo-third-party-build/grpc-repo/src/grpc-repo-stamp/grpc-repo-download] Error 1
    make[3]: Leaving directory '/tmp/tritonbuild/tritonserver/build'
    make[2]: *** [CMakeFiles/Makefile2:590: _deps/repo-third-party-build/CMakeFiles/grpc-repo.dir/all] Error 2
    make[2]: Leaving directory '/tmp/tritonbuild/tritonserver/build'
    make[1]: *** [CMakeFiles/Makefile2:145: CMakeFiles/server.dir/rule] Error 2
    make[1]: Leaving directory '/tmp/tritonbuild/tritonserver/build'

    开加速是最好的办法,不管是UI还是命令行,都有相应的软件可以用,比如clash。

    如果你的服务器实在是开不了加速,也有其他办法,那就是将triton库中大部分重量级库的git地址全换为国内的

    怎么替换,我是在gitee中,同步github上的仓库,比如triton的core仓库,同步过来,就可以使用国内的地址了。

    当然也需要将这些库的submodule中的库也修改为国内源,比如grpc这个库依赖很多第三方库,克隆的时候,这是要一个一个下载的:

    改起来稍微麻烦,还需要注意,要改特定commit分支的git地址:

    ver/build/_deps/repo-third-party-build/grpc-repo/src/grpc/third_part目录然后手动git clone xxx,然后执行一下git submodule init / git submodule update下就可以带进去。

    示例:

    root@64da25af2629:/tmp/tritonbuild/tritonserver/build/_deps/repo-third-party-build/grpc-repo/src/grpc# git submodule init
    root@64da25af2629:/tmp/tritonbuild/tritonserver/build/_deps/repo-third-party-build/grpc-repo/src/grpc# git submodule update
    Submodule path 'third_party/googletest': checked out 'c9ccac7cb7345901884aabf5d1a786cfa6e2f397'

    太麻烦了,不过确实为一种办法呃呃。

    还有一点,triton每次build都会clone,是因为其用了cmake中的ExternalProject_Add指令,假如我们已经有下载好的grpc,那么直接替换到server/build/_deps/repo-third-party-build/grpc-repo/src中然后将/data/oldpan/software/server/build/_deps/repo-third-party-src/CMakeLists.txt

    注释掉git下载部分,修改自己本地的就行,就不需要每次再clone一遍了。

    #
    # Get the protobuf and grpc source used for the GRPC endpoint. We must
    # use v1.25.0 because later GRPC has significant performance
    # regressions (e.g. resnet50 bs128).
    #
    ExternalProject_Add(grpc-repo
      PREFIX grpc-repo
      # GIT_REPOSITORY "https://gitee.com/Oldpann/grpc.git"
      # GIT_TAG "v1.25.x"
      SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/grpc-repo/src/grpc"
      CONFIGURE_COMMAND ""
      BUILD_COMMAND ""
      INSTALL_COMMAND ""
      TEST_COMMAND ""
      PATCH_COMMAND python3 ${CMAKE_CURRENT_SOURCE_DIR}/tools/install_src.py --src <SOURCE_DIR> ${INSTALL_SRC_DEST_ARG} --dest-basename=grpc_1.25.0
    )

    说了这么多,总之,最好的办法当然还是开科学,全局一下就OK,省去那么多麻烦事儿。

    搞定好网络问题,编译triton就很简单了!

    git clone --recursive https://github.com/triton-inference-server/server.git
    cd server
    python build.py  --enable-logging --enable-stats --enable-tracing --enable-gpu  --endpoint=http --repo-tag=common:r22.06 --repo-tag=core:r22.06 --repo-tag=backend:r22.06 --repo-tag=thirdparty:r22.06 --backend=ensemble --backend=tensorrt

    在克隆好的server的目录下执行以上命令(下面是我的设置,我们可以个根据自己的需求进行修改)就可以了。

    执行这个命令后triton就会构建docker在docker中编译,最终会创建3个镜像:

    • tritonserver:latest
    • tritonserver_buildbase:latest
    • tritonserver_cibase:latest

    最终编译好的tritonserver_buildbase:latest镜像,我们可以在其中开发,因为环境都帮忙配好了,只需要再执行编译命令,就可以编译了,我们也可以自定义源码进行个性功能的开发。

    在镜像中开发

    需要注意,在编译的时候需要pull官方默认的镜像,而这个镜像是有显卡驱动限制的,比如r22.06需要显卡驱动版本为470。

    同志们看看自己的显卡驱动,别下了不能用hhh

    可以通过triton镜像历史[12]查看镜像版本要求:

    接上,我们不是编译好了triton镜像,直接进去就可以开发了:

    docker run -v/home/oldpan/code:/code -v/home/oldpan/software:/software  -d tritonserver_buildbase:latest /usr/bin/sh -c "while true; do echo hello world; sleep 20;done"

    在docker中修改triton的源码,继续执行以下命令就可以编译,和之前的区别就是加了 --no-container-build参数。

    python build.py  --enable-logging --enable-stats --enable-tracing --enable-gpu  --endpoint=http --repo-tag=common:r22.06 --repo-tag=core:r22.06 --repo-tag=backend:r22.06 --repo-tag=thirdparty:r22.06 --backend=ensemble --no-container-build --build-dir=./build

    我们如果想编译debug版本的triton,可以在命令中添加:--build-type=Debug

    另外,原始triton镜像中已经有tensorrt,如果想换版本,可以删除原始docker中的旧的tensorrt,自行安装新的tensorrt即可:

    • https://docs.nvidia.com/deeplearning/tensorrt/install-guide/index.html[13]

    说下运行流程吧!

    讲了这么多铺垫,接下来简单说下运行流程。

    这里通过代码简单梳理下triton运行的整体流程,之后的具体细节,放到接下来的篇章讲解

    首先一开始,main函数在servers/main.cc下,triton在启动的时候会执行以下函数:

    // src/servers/main.cc 经过简化
    int
    main(int argc, char** argv)
    {
      // 解析参数
      TRITONSERVER_ServerOptions* server_options = nullptr;
      if (!Parse(&server_options, argc, argv)) {
        exit(1);
      }
      ...
      // 这里创建server
      TRITONSERVER_Server* server_ptr = nullptr;
      FAIL_IF_ERR(
          TRITONSERVER_ServerNew(&server_ptr, server_options), "creating server"); // 这里创建server
      FAIL_IF_ERR(
          TRITONSERVER_ServerOptionsDelete(server_options),
          "deleting server options");
      std::shared_ptr<TRITONSERVER_Server> server(
          server_ptr, TRITONSERVER_ServerDelete);
      ...
      // 启动HTTP, GRPC, 以及性能统计的端口
      if (!StartEndpoints(server, trace_manager, shm_manager)) {
        exit(1);
      }
      // Trap SIGINT and SIGTERM to allow server to exit gracefully
      signal(SIGINT, SignalHandler);
      signal(SIGTERM, SignalHandler);
      // 等待kill信号区关闭triton 
      while (!exiting_) {
       ...
          // 做一些监控模型仓库是否变动的操作
      }
      // 优雅地关闭triton
      TRITONSERVER_Error* stop_err = TRITONSERVER_ServerStop(server_ptr);
      // 如果无法优雅地关掉,旧直接exit即可
      if (stop_err != nullptr) {
        LOG_TRITONSERVER_ERROR(stop_err, "failed to stop server");
        exit(1);
      }
      // 停止监控http、grpc
      StopEndpoints();
      ...
      return 0;
    }

    TRITONSERVER_ServerNew这个函数中,会:

    • new一个triton类InferenceServer对象
    • 根据参数设置配置一下,执行一堆Set函数
    • 配置好参数后,Init服务,这里初始化服务的状态,校验参数
    • 创建各种模块,经常使用的有后端管理TritonBackendManager以及模型仓库管理ModelRepositoryManager
    • 再进行一些检查、配置一些状态

    在启动过程中最重要的是模型仓库,运行triton当然你要有模型,要不然你开它干嘛?

    这里我使用的模型仓库目录结构如下(是一个识别姿态的hrnet,hrnet官方有很多预训练模型,转tensorrt也很简单):

    debug目录下有一个模型文件夹叫做hrnet-pose-estimate-debug的模型文件夹,这个文件夹地址(/path/to/hrnet-pose-estimate-debug)需要传给triton启动命令行,文件夹内的四个子模型文件夹,会被triton检测到并且一一加载。

    需要注意的是,除了hrnet_pose_estimate这个其余三个在目录的1子目录下有个so或者model.plan,这代表hrnet-trt-staticimage_preprocess还有pose_postprocess都属于model,使用了backend,backend会在各自的config中指明:

    name: "hrnet-trt-static"
    backend: "tensorrt"

    因为hrnet-trt-static是tensorrt的模型,所以backend设置为tensorrt,model.plan就是tensorrt的engine。其backend的so文件我放到了其他位置(放到和model.plan同目录也是可以的),而另外两个预处理和后处理的backend就放到了模型仓库中,也就是libtorch_image_preprocess.solibtriton_pose_postprocess,包含了你的backend代码,封装成so供triton调用

    关于backend、model以及modelinstanc的关系,说实话稍微复杂点,各自有完整的生命周期,这个嘛,之后文章说,感兴趣的也可以提前看官方文档的介绍:

    • https://github.com/triton-inference-server/backend[14]

    然后我们就启动triton吧!

    # 执行以下函数,模型目录通过 --model-repository 指定     tensorrt的backend通过  --backend-directory 指定
    ./tritonserver --model-repository=/path/to/hrnet-pose-estimate-debug --backend-directory=/workspace/backends/tensorrt_backend/ 

    模型加载成功之后会输出:

    ...
    I1016 08:25:37.952055 51771 server.cc:587] 
    +------------------+----------------------------------------------------------------+----------------------------------------------------------------+
    | Backend          | Path                                                           | Config                                                         |
    +------------------+----------------------------------------------------------------+----------------------------------------------------------------+
    | image_preprocess | /workspace/triton-models/debug/hrnet-pose-estimate-debug/image | {"cmdline":{"auto-complete-config":"false","min-compute-capabi |
    |                  | _preprocess/1/libtriton_image_preprocess.so                    | lity":"6.000000","backend-directory":"/workspace/backends/tens |
    |                  |                                                                | orrt_backend/","default-max-batch-size":"4"}}     |
    |                  |                                                                |                                                                |
    | pose_postprocess | /workspace/triton-models/debug/hrnet-pose-estimate-debug/pose_ | {"cmdline":{"auto-complete-config":"false","min-compute-capabi |
    |                  | postprocess/1/libtriton_pose_postprocess.so                    | lity":"6.000000","backend-directory":"/workspace/backends/tens |
    |                  |                                                                | orrt_backend/","default-max-batch-size":"4"}}     |
    |                  |                                                                |                                                                |
    | tensorrt         | /workspace/backends/tensorrt_backend/li              | {"cmdline":{"auto-complete-config":"false","min-compute-capabi |
    |                  | btriton_tensorrt.so                                            | lity":"6.000000","backend-directory":"/workspace/backends/tens |
    |                  |                                                                | orrt_backend/","default-max-batch-size":"4"}}     |
    |                  |                                                                |                                                                |
    +------------------+----------------------------------------------------------------+----------------------------------------------------------------+

    I1016 08:25:37.952252 51771 server.cc:630] 
    +---------------------+---------+--------+
    | Model               | Version | Status |
    +---------------------+---------+--------+
    | hrnet-trt-static    | 1       | READY  |
    | hrnet_pose_estimate | 1       | READY  |
    | image_preprocess    | 1       | READY  |
    | pose_postprocess    | 1       | READY  |
    +---------------------+---------+--------+

    I1016 08:25:38.051742 51771 metrics.cc:650] Collecting metrics for GPU 0: NVIDIA GeForce RTX 3080
    I1016 08:25:38.055197 51771 tritonserver.cc:2159] 
    +----------------------------------+------------------------------------------------------------------------------------------------------------------+
    | Option                           | Value                                                                                                            |
    +----------------------------------+------------------------------------------------------------------------------------------------------------------+
    | server_id                        | triton                                                                                                           |
    | server_version                   | 2.23.0                                                                                                           |
    | server_extensions                | classification sequence model_repository model_repository(unload_dependents) schedule_policy model_configuration |
    |                                  |  system_shared_memory cuda_shared_memory binary_tensor_data statistics trace                                     |
    | model_repository_path[0]         | /workspace/triton-models/debug/hrnet-pose-estimate-debug                                                         |
    | model_control_mode               | MODE_NONE                                                                                                        |
    | strict_model_config              | 1                                                                                                                |
    | rate_limit                       | OFF                                                                                                              |
    | pinned_memory_pool_byte_size     | 268435456                                                                                                        |
    | cuda_memory_pool_byte_size{0}    | 300021772                                                                                                        |
    | response_cache_byte_size         | 0                                                                                                                |
    | min_supported_compute_capability | 6.0                                                                                                              |
    | strict_readiness                 | 1                                                                                                                |
    | exit_timeout                     | 30                                                                                                               |
    +----------------------------------+------------------------------------------------------------------------------------------------------------------+

    I1016 08:25:38.055627 51771 http_server.cc:3303] Started HTTPService at 0.0.0.0:8000
    I1016 08:25:38.097213 51771 http_server.cc:178] Started Metrics Service at 0.0.0.0:8001

    加载好之后,我们开启了http端口,端口号为8000,另一个是metric接口,端口号8001

    此时可以使用http请求试一下。

    简单请求

    请求的话有http和grpc协议,我对http协议熟悉些,所以就搞http吧。

    官方也提供了客户端,C++和python的都可以有,可以直接使用官方的,也可以根据官方提供的http协议构造自己的客户端,只要会构造body,一切都很简单。

    请求协议可以参考官方:

    • https://github.com/kserve/kserve/blob/master/docs/predict-api/v2/required_api.md[15]

    这里我们用python简单构造一个body

    # 构造triton的输入body
    json_buf = b'{\"inputs\":[{\"name\":\"INPUT\",\"datatype\":\"BYTES\",\"shape\":[1],\"parameters\":{\"binary_data_size\":' + \
            bytes(str(len(data)), encoding = "utf8") + b'}}],\"outputs\":[{\"name\":\"RESULT\",\"parameters\":{\"binary_data\":true}}]}'
    push_data = json_buf + data

    print("Inference-Header-Content-Length ",str(len(json_buf)), " Content-Length ",str(len(data) + len(json_buf)))
    # 构造triton-header
    header = {"Content-Type": "application/octet-stream", "Accept": "*/*",
              "Inference-Header-Content-Length":str(len(json_buf)),
              "Content-Length":str(len(data) + len(json_buf))}

    server_url = "127.0.0.1:8000"
    model_name = "hrnet_pose_estimate"

    # 请求
    response = post('http://' + server_url + '/v2/models/' + model_name + '/infer', data=push_data, headers=header)

    就可以发送请求,结果也会传回response里。我们也可以使用curl命令,直接传递构造好的body(这个body将上述的push_data写到本地即可):

    [oldpan@have-fun client]$ curl -v --max-time 1 --request POST 'http://192.168.1.102:9006/v2/models/hrnet_pose_estimate/infer' --header 'Inference-Header-Content-Length: 230' --header 'Content-Type: application/octet-stream' --data-binary '@data.txt' --output temp_res
    Note: Unnecessary use of -X or --request, POST is already inferred.
    *   Trying 192.168.1.102:9006...
      % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                     Dload  Upload   Total   Spent    Left  Speed
      0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0* Connected to 172.29.210.105 (172.29.210.105) port 9006 (#0)
    > POST /v2/models/aocr_cnprint_trt8p/infer HTTP/1.1
    > Host: 192.168.1.102:9006
    > User-Agent: curl/7.71.1
    > Accept: */*
    > Inference-Header-Content-Length: 230
    > Content-Type: application/octet-stream
    > Content-Length: 1573102
    > Expect: 100-continue

    * Mark bundle as not supporting multiuse
    < HTTP/1.1 100 Continue
    } [56480 bytes data]
    * We are completely uploaded and fine
    * Mark bundle as not supporting multiuse
    < HTTP/1.1 200 OK
    < Content-Type: application/json
    < Inference-Header-Content-Length: 394
    < Content-Length: 6794

    { [6794 bytes data]
    100 1542k  100  6794  100 1536k   127k  28.8M --:--:-- --:--:-- --:--:-- 28.9M

    结果就不发了,验证没啥问题。

    关于如何使用curl直接请求triton,有一些相关链接可以参考:

    • https://github.com/triton-inference-server/server/issues/2563[16]
    • https://github.com/triton-inference-server/server/issues/1822[17]
    参考资料
    https://www.bilibili.com/video/BV1KS4y1v7zd/?spm_id_from=333.788&vd_source=eec038509607175d58cdfe2e824e8ba2[18]
    https://github.com/triton-inference-server/server/releases[19]
    https://docs.nvidia.com/deeplearning/triton-inference-server/release-notes/index.html[20]
    https://zhuanlan.zhihu.com/p/462817679[21]
    参考资料
    [1]
    triton: https://github.com/openai/triton
    
    [2]
    教程: https://www.zhihu.com/people/pwlazy/posts
    
    [3]
    视频教程: https://www.bilibili.com/video/BV1KS4y1v7zd/?spm_id_from=333.337.search-card.all.click&vd_source=eec038509607175d58cdfe2e824e8ba2
    
    [4]
    官方的镜像: https://docs.nvidia.com/deeplearning/triton-inference-server/release-notes/index.html
    
    [5]
    [server: https://github.com/triton-inference-server/server
    
    [6]
    [core: https://github.com/triton-inference-server/core
    
    [7]
    [common: https://github.com/triton-inference-server/common
    
    [8]
    [backend: https://github.com/triton-inference-server/backend
    
    [9]
    [third_party: https://github.com/triton-inference-server/third_party.git
    
    [10]
    [tensorrt_backend: https://github.com/triton-inference-server/tensorrt_backend
    
    [11]
    [pytorch_backend: https://github.com/triton-inference-server/pytorch_backend
    
    [12]
    triton镜像历史: https://docs.nvidia.com/deeplearning/triton-inference-server/release-notes/rel_22-06.html
    
    [13]
    https://docs.nvidia.com/deeplearning/tensorrt/install-guide/index.html: https://docs.nvidia.com/deeplearning/tensorrt/install-guide/index.html
    
    [14]
    https://github.com/triton-inference-server/backend: https://github.com/triton-inference-server/backend
    
    [15]
    https://github.com/kserve/kserve/blob/master/docs/predict-api/v2/required_api.md: https://github.com/kserve/kserve/blob/master/docs/predict-api/v2/required_api.md
    
    [16]
    https://github.com/triton-inference-server/server/issues/2563: https://github.com/triton-inference-server/server/issues/2563
    
    [17]
    https://github.com/triton-inference-server/server/issues/1822: https://github.com/triton-inference-server/server/issues/1822
    
    [18]
    https://www.bilibili.com/video/BV1KS4y1v7zd/?spm_id_from=333.788&vd_source=eec038509607175d58cdfe2e824e8ba2: https://www.bilibili.com/video/BV1KS4y1v7zd/?spm_id_from=333.788&vd_source=eec038509607175d58cdfe2e824e8ba2
    
    [19]
    https://github.com/triton-inference-server/server/releases: https://github.com/triton-inference-server/server/releases
    
    [20]
    https://docs.nvidia.com/deeplearning/triton-inference-server/release-notes/index.html: https://docs.nvidia.com/deeplearning/triton-inference-server/release-notes/index.html
    
    [21]
    https://zhuanlan.zhihu.com/p/462817679: https://zhuanlan.zhihu.com/p/462817679

    基于MEL谱+VAE的latents的TTS相关工作

    Zero-Shot TTS目前有不少工作用了MEL谱作为中间特征,然后在梅尔谱的基础上,或是用VQ提供离散token,或是用CNN来提取连续latent。对于MEL+latents的工作,有:AudioLDM 1&2、StyleTTS 1&2。我们来简单看看是它们是怎么做的。

    AudioLDM 1&2

    AudioLDM: Text-to-Audio Generation with Latent Diffusion Models

    [Paper on ArXiv][Code on GitHub][Hugging Face Space]

    AudioLDM 2: Learning Holistic Audio Generation with Self-supervised Pretraining

    [Paper on ArXiv][Code on GitHub][HuggingFace Demo][Discord Community]

    AudioLDM 1&2使用的语音latents是一致的,均通过MEL+VAE获得。既然是连续的latents,使用扩散模型来建模也合情合理。解码过程也相当简单:VAE decoder获得梅尔谱,然后用声码器转换为音频波形。该系列工作的核心创新点是利用多模态模型统一了扩散模型条件输入侧的信息:AudioLDM 1用CLAP统一了文本模态和音频模态,用单模态的音频数据就能完成模型的训练;AudioLDM 2则包含了图像、文本、转录文本等更多模态,模型泛用性也更强,既能做语音合成,也能做音乐生成、音频事件生成。

    StyleTTS 1&2

    StyleTTS: A Style-Based Generative Model for Natural and Diverse Text-to-Speech Synthesis

    StyleTTS 2: Towards Human-Level Text-to-Speech through Style Diffusion and Adversarial Training with Large Speech Language Models

    StyleTTS系列的模型一众zero-shot TTS模型显得比较老派,整体结构基本上沿袭了非自回归的FastSpeech 2,不同之处在于增加了基于参考音频抽取的风格信息。说是风格,其实跟megatts的音色很像。StyleTTS 2的工作则将风格进一步拆分成声学风格和韵律风格。训练时的风格信息由音频提供,推断时的风格信息则由扩散模型提供。StyleTTS 2通过一个扩散模型桥接了文本韵律和语音风格之间的联系,摆脱推断时对参考音频的依赖。不用参考音频其实对产品的意义还挺大的,要都用现实世界中真人尤其是名人的声音作为参考音频,那这势必会引起版权纠纷。这种纠纷在国内国外都有相关的事件。最近寡姐投诉OpenAI的事件就是一例。

    在 StyleTTS 中,我们提出了“全局风格迁移”(GST),这是一个在Tacotron(最先进的端到端语音合成系统)中联合训练的嵌入库。嵌入在没有明确标签的情况下进行训练,但学会了对大范围的声学表现力进行建模。商品及服务税会带来一系列丰富的重要结果。它们生成的软可解释“标签”可用于以新颖的方式控制合成,例如改变速度和说话风格 – 独立于文本内容。它们还可用于风格转换,在整个长格式文本语料库中复制单个音频剪辑的说话风格。当对嘈杂的、未标记的发现数据进行训练时,GST 学会分解噪声和说话人身份,为高度可扩展但强大的语音合成提供了一条途径。

    StyleTTS 2的不同之处在于,通过扩散模型将风格建模为潜在随机变量,以生成最适合文本的风格,而无需参考语音,实现高效的潜在扩散,同时受益于扩散模型提供的多样化语音合成。 此外采用大型预训练SLM(如WavLM)作为鉴别器,并使用新颖的可微分持续时间建模进行端到端训练,从而提高了语音自然度。

    TTS+指令prompt的遵循 系列工作

    SLM(speech language model, SLM)不仅要合成合乎上下文语义的高表现力语音,合成的语音还要符合用户的即时要求。一些text-guided zero-shot TTS的工作值得参考。这些工作一般都是在已有的zero-shot TTS模型或者text-to-audio模型上改造而来,同时吸收transcription和description两路条件。其中的重点还是在于数据集的构建。这方面的工作有:PromptTTS、InstructTTS、ParlerTTS、VoiceLDM和Audiobox。

    TTS模型同样可以遵循文本指令或者语音指令,合成符合用户即时要求的语音,摆脱对参考音频的依赖。text-guided zero-shot TTS在模型架构上和zero-shot TTS有非常大的相似性,但训练数据可能较为缺乏。因此,先开发zero-shot TTS,再用类似SALMONN 或者 Qwen2-audio那样的多模态理解模型来打标签(类似DALLE3的做法),这样数据集构造方式,可能会是更好的选择

    ParlerTTS

     Natural language guidance of high-fidelity text-to-speech with synthetic annotations

    训练代码开源:https://github.com/huggingface/parler-tts

    ParlerTTS。VALL-E/VoiceCraft的增强版,通过T5编码器和cross-attention旁路引入了描述性文本的信息。该工作的目的是想使用自然语言prompt来指定说话风格和环境信息,摆脱对参考音频的依赖。描述性标签文本的收集过程也显得相当朴素:通过定制化的监督式模型获取语音数据的口音特征、录音质量特征、音高语速特征。然后用LLM将这些特征转换为自然语言的描述。在我看来,这个工作有这么几点局限性吧:其一,缺乏情绪标签;其二,语音描述性标签的收集并不具备通用性,较为繁琐,远不如一个强大的多模态语音理解模型来得实在。文章demo虽然达到了预期的效果,但场景似乎局限在朗读的情景中。

    VoiceLDM

    VoiceLDM: Text-to-Speech with Environmental Context

    VoiceLDM。在VoiceLDM1的基础上增加了转录文本的输入。这个工作和AudioLDM 1很像,同样使用CLAP注入语音的描述性信息。不同地是,为了做TTS任务,该工作通过cross-attention旁路增加了transcription的信息。

    OpenAI o1技术报告

    技术报告:https://openai.com/index/learning-to-reason-with-llms/

    OpenAI o1介绍:https://openai.com/index/introducing-openai-o1-preview/

    我们正在引入OpenAI o1,这是一种新的大型语言模型,经过强化学习训练,可以执行复杂的推理。o1在回答之前思考–它可以在对用户做出响应之前产生一个很长的内部思考链。

    OpenAI发布新模型o1系列,可以实现复杂推理,旨在花更多时间思考,然后再做出响应。这些模型可以推理复杂的任务并解决比以前的科学、编码和数学模型更难的问题。 并且效果得到了极大的提升,大概从高中生提升到了博士生。

    具体来说,o1系列是OpenAI首个经过强化学习训练的模型,在输出回答之前,会在产生一个很长的思维链,以此增强模型的能力。换句话说,内部思维链越长,o1思考得越久,模型在推理任务上的表现就越好。

    o1有多强?

    CEO奥特曼给出答案:

    在刚刚结束的2024 IOI信息学奥赛题目中,o1的微调版本在每题尝试50次条件下取得了213分,属于人类选手中前49%的成绩。

    如果允许它每道题尝试10000次,就能获得362.14分,高于金牌选手门槛,可获得金牌

    另外它还在竞争性编程问题 (Codeforces) 中排名前89%,在美国数学奥林匹克 (AIME) 预选赛题目中跻身美国前500名学生之列。

    与GPT-4o相比,o1在数理化生、英语法律经济等各种科目都有不同成绩改进。

    发布的模型包括哪些?

    o1:暂未对外开放使用。

    o1-preiview:o1的先行版本,可以立即提供给ChatGPT付费用户和Tier 5级API用户

    o1-mini:速度更快、性价比更高,适用于需要推理和无需广泛世界知识的任务。

    OpenAI o1原理

    OpenAI o1 是经过强化学习训练来执行复杂推理任务的新型语言模型。特点就是,o1 在回答之前会思考——它可以在响应用户之前产生一个很长的内部思维链

    也就是该模型在作出反应之前,需要像人类一样,花更多时间思考问题。通过训练,它们学会完善自己的思维过程,尝试不同的策略,并认识到自己的错误。

    对于复杂的推理任务来说,这是一个重大进步,OpenAI称代表了人工智能的最高水平。

    鉴于此,他们决定将计数器重置,并将该系列模型命名为OpenAI o1。

    重点在于,OpenAI的大规模强化学习算法,教会模型如何在数据高度有效的训练过程中利用其思想链进行高效思考。换言之,类似于强化学习的 Scaling Law

    OpenAI发现,随着更多的强化学习(训练时计算)和更多的思考时间(测试时计算),o1的性能持续提高。而且扩展这种方法的限制与大模型预训练的限制有很大不同,OpenAI也还在继续研究。

    模型评估

    为了突出相对于 GPT-4o 的推理性能改进,OpenAI 在一系列不同的人类考试和机器学习基准测试中测试了 o1 模型。实验结果表明,在绝大多数推理任务中,o1 的表现明显优于 GPT-4o。

    在许多推理密集型基准测试中,o1的表现可与人类专家相媲美。最近的前沿模型在 MATH 和GSM8K 上表现得非常好,以至于这些基准测试在区分模型方面不再有效。因此,OpenAI 在 AIME 上评估了数学成绩,这是一项旨在测试美国最聪明高中数学学生的考试。

    OpenAI 还在 GPQA Diamond 基准上评估了 o1,这是一个困难的智力基准,用于测试化学、物理和生物学方面的专业知识。为了将模型与人类进行比较,OpenAI 聘请了拥有博士学位的专家来回答 GPQA Diamond 基准问题。

    实验结果表明:o1 超越了人类专家的表现,成为第一个在该基准测试中做到这一点的模型。

    启用视觉感知能力后,o1 在 MMMU 基准上得分为 78.2%,成为第一个与人类专家相当的模型。o1 还在 57 个 MMLU 子类别中的 54 个上优于 GPT-4o。

    思维链(Chain of Thought)

    与人类在回答难题之前会长时间思考类似,o1 在尝试解决问题时会使用思维链。通过强化学习,o1 学会磨练其思维链并改进其使用的策略。o1 学会了识别和纠正错误,并可以将棘手的步骤分解为更简单的步骤。o1 还学会了在当前方法不起作用时尝试不同的方法。这个过程极大地提高了模型的推理能力。

    编程能力(Coding)

    基于 o1 进行了初始化并进一步训练了其编程技能后,OpenAI 训练得到了一个非常强大的编程模型(o1-ioi)。该模型在 2024 年国际信息学奥林匹克竞赛(IOI)赛题上得到了 213 分,达到了排名前 49% 的水平。并且该模型参与竞赛的条件与 2024 IOI 的人类参赛者一样:需要在 10 个小时内解答 6 个高难度算法问题,并且每个问题仅能提交 50 次答案。

    OpenAI发现,如果放宽提交限制条件,则模型性能更是能大幅提升。如果每个问题允许提交 1 万次答案,即使不使用上述测试时选取策略,该模型也能得到 362.14 分——高于金牌门槛。

    最后,OpenAI 模拟Codeforces 主办的竞争性编程竞赛,以展示该模型的编码技能。采用的评估与竞赛规则非常接近,允许提交 10 份代码。GPT-4o 的 Elo评分为 808,在人类竞争对手中处于前 11% 的水平。该模型远远超过了 GPT-4o 和 o1——它的 Elo 评分为 1807,表现优于 93% 的竞争对手。

    人类偏好评估(Human preference evaluation

    除了考试和学术基准之外,OpenAI 还在更多领域的具有挑战性的开放式提示上评估了人类对 o1-preview 和 GPT-4o 的偏好。

    在这次评估中,人类训练者对 o1-preview 和 GPT-4o 的提示进行匿名回答,并投票选出他们更喜欢的回答。在数据分析、编程和数学等推理能力较强的类别中,o1-preview 的受欢迎程度远远高于 GPT-4o。然而,o1-preview 在某些自然语言任务上并不受欢迎,这表明它并不适合所有用例。

    安全性(Safety)

    思维链(CoT)推理为安全和对齐提供了新的思路。OpenAI 发现,将模型行为策略整合到推理模型的思维链中,可以高效、稳健地教导人类价值观和原则。通过向模型教导自己的安全规则以及如何在上下文中推理它们,OpenAI 发现推理能力直接有利于模型稳健性的证据:o1-preview 在关键越狱评估和用于评估模型安全拒绝边界的最严格内部基准上取得了显著的改进。

    OpenAI认为,使用思维链可以为安全和对齐带来重大进步,因为

    1)它能够以清晰的方式观察模型思维;

    2)关于安全规则的模型推理对于分布外场景更具稳健性。

    为了对自己的改进进行压力测试, OpenAI 在部署之前根据自己的安全准备框架进行了一系列安全测试和红队测试。结果发现,思维链推理有助于在整个评估过程中提高能力。尤其值得注意的是,OpenAI 观察到了有趣的奖励黑客攻击实例。

    隐式思维链(Hiding the Chains of Thought)

    OpenAI认为隐式思维链为监控模型提供了独特的机会。假设它是忠实且清晰的,隐式思维链使得能够读懂模型的思想并了解其思维过程。例如,人们将来可能希望监控思维链以寻找操控用户的迹象。

    但要做到这一点,模型必须能够自由地以未改变的形式表达其思想,因此不能在思维链训练进行任何政策合规性或用户偏好性训练。OpenAI也不想让用户直接看到不一致的思维链。

    因此,在权衡用户体验、竞争优势和追求思维链监控的选项等多种因素后,OpenAI决定不向用户展示原始的思维链。OpenAI承认这个决定有不好的地方,因此努力通过教导模型在答案中重现思维链中的任何有用想法来部分弥补。同时对于 o1 模型系列,OpenAI展示了模型生成的思维链摘要。

    OpenAI o1-mini

    o1系列擅长准确生成和调试复杂代码。为了为开发人员提供更有效的解决方案,OpenAI还发布了OpenAI o1-mini,这是一种更快、更便宜的推理模型,在编码方面特别有效。作为一个较小的模型,o1-mini比o1-preview便宜80%,使其成为需要推理但不需要广泛知识的应用程序的强大、经济高效的模型。

    o1-mini擅长STEM,尤其是数学和编码——在AIME和Codeforce等评估基准上几乎与OpenAI o1的性能相当。预计o1-mini将是一种更快、更具成本效益的模型,适用于需要在没有广泛知识的情况下进行推理的应用程序。

    STEM推理优化(Optimized for STEM Reasoning)

    像o1这样的大型语言模型是在庞大的文本数据集上预先训练的。虽然这些高容量模型具有广泛的世界知识,但对于现实世界的应用来说,它们可能既昂贵又缓慢。相比之下,o1-mini是一个较小的模型,在预训练期间针对STEM推理进行了优化。在使用与o1相同的高计算强化学习(RL)管道进行训练后,o1-mini在许多有用的推理任务上取得了相当的性能,同时具有更高的性价比。

    当在需要智能和推理的基准上进行评估时,o1-mini与o1-preview和o1相比表现良好。然而,o1-mini在需要非STEM事实知识的任务上表现较差。

    数学能力:在高中AIME数学竞赛中,o1-mini(70.0%)与o1(74.4%)具有竞争力,同时价格明显更低,表现优于o1-preview(44.6%)。o1-mini的分数(约11/15个问题)使其跻身美国高中生前500名左右。

    编码能力:在 Codeforces 竞赛网站上,o1-mini 的 Elo 得分为 1650,与 o1 (1673) 不相上下,并且高于 o1-preview (1258)。此外,o1-mini 在 HumanEval 编码基准和高中网络安全夺旗挑战 (CTF) 中也表现出色。

    STEM:在一些需要推理的学术基准上,例如 GPQA(科学)和 MATH-500,o1-mini 的表现优于 GPT-4o。o1-mini 在MMLU 等任务上的表现则不如 GPT-4o,并且由于缺乏广泛的世界知识而在 GPQA 基准上落后于 o1-preview。

    人类偏好评估:OpenAI让人类评分员在各个领域具有挑战性的开放式提示上比较 o1-mini 和 GPT-4o。与o1-preview 类似,在推理量大的领域,o1-mini 比 GPT-4o 更受欢迎;但在以语言为中心的领域,o1-mini 并不比 GPT-4o 更受青睐。

    在速度层面,OpenAI 比较GPT-4o、o1-mini和 o1-preview 对一个单词推理问题的回答。结果显示,GPT-4o回答不正确,而 o1-mini 和 o1-preview 均回答正确,并且 o1-mini 得出答案的速度快了大约 3-5 倍。

    安全性

    o1-mini使用与o1-preview相同的对齐和安全技术进行训练。与GPT-4o相比,该模型在StrongREJECT数据集的内部版本上的越狱鲁棒性提高了59%。在部署之前,使用与o1-preview相同的安全评估方法,仔细评估了o1-mini的安全风险。

    QWen-Audio语音大模型

    https://github.com/QwenLM/Qwen-Audio

    Qwen-Audio:通过统一的大规模音频语言模型推进通用音频理解

    Qwen-Audio 🤖 🤗  | Qwen-Audio-Chat 🤖 🤗  |    Demo 🤖 | 🤗

      Homepage  |   Paper   |    WeChat   |   Discord

    本文提出了Qwen-Audio模型,旨在通过扩大音频语言预训练的范围,覆盖超过30个任务和多种音频类型,如人声、自然声音、音乐和歌曲,从而促进通用音频理解能力的提升。然而,直接联合训练所有任务和数据集可能导致干扰问题,因为不同数据集相关的文本标签由于任务焦点、语言、标注的细粒度和文本结构的差异而存在显著变化。为了解决一对多的干扰问题,我们精心设计了一个多任务训练框架,通过对解码器的分层标签序列进行条件化,促进知识共享并通过共享和特定标签分别避免干扰。值得注意的是,Qwen-Audio在多种基准任务中实现了卓越的性能,而无需任何任务特定的微调,超越了同类模型。在Qwen-Audio的基础上,我们进一步开发了Qwen-Audio-Chat,允许多种音频和文本输入,实现多轮对话并支持多种以音频为中心的场景。

    Qwen-Audio 可以以多种音频 (包括说话人语音、自然音、音乐、歌声)和文本作为输入,并以文本作为输出。Qwen-Audio 系列模型的特点包括:

    • 音频基石模型:Qwen-Audio是一个性能卓越的通用的音频理解模型,支持各种任务、语言和音频类型。在Qwen-Audio的基础上,我们通过指令微调开发了Qwen-Audio-Chat,支持多轮、多语言对话。Qwen-Audio和Qwen-Audio-Chat模型均已开源。
    • 兼容多种复杂音频的多任务学习框架:为了避免由于数据收集来源不同以及任务类型不同,带来的音频到文本的一对多的干扰问题,我们提出了一种多任务训练框架,实现相似任务的知识共享,并尽可能减少不同任务之间的干扰。通过提出的框架,Qwen-Audio可以容纳训练超过30多种不同的音频任务;
    • 出色的性能:Qwen-Audio在不需要任何任务特定的微调的情况下,在各种基准任务上取得了领先的结果。具体得,Qwen-Audio在Aishell1、cochlscene、ClothoAQA和VocalSound的测试集上都达到了SOTA;
    • 支持多轮音频和文本对话,支持各种语音场景:Qwen-Audio-Chat支持声音理解和推理、音乐欣赏、多音频分析、多轮音频-文本交错对话以及外部语音工具的使用。
    图3
    图 1:Qwen-Audio 和多任务音频文本学习模型之前的顶级性能,例如 SpeechT5、SpeechNet、SpeechLLaMA、SALMONN和 Pengi。我们展示了 12 个数据集的测试集结果,包括自动语音识别 (ASR)、语音到文本翻译 (S2TT)、自动音频字幕 (AAC)、声学场景分类 (ASC)、语音情感识别 (SER)、音频问答 (AQA)、声音分类 (VSC) 和音符分析 (MNA)。ASR 数据集(例如 Librispeech、Aishell1 和 Aishell2)的结果引用 1 – WER%。CoVoST2 的结果是七个翻译方向(en-de、de-en、en-zh、zh-en、es-en、fr-en 和 it-en)的平均 BLEU 分数。Qwen-Audio 无需任何特定于任务的微调即可实现卓越的性能,超越了同类产品。

    Methodology 

    本节提供了Qwen-Audio和Qwen-Audio-Chat的详细信息,这些模型旨在实现通用音频理解和基于人类指令的灵活互动。首先,在第1节中介绍了Qwen-Audio和Qwen-Audio-Chat的模型结构。我们的模型训练过程分为两个阶段:多任务预训练监督微调。我们在第2节中描述了通过多任务学习进行的Qwen-Audio训练。随后,在第3节中描述了Qwen-Audio-Chat的监督微调过程,使其能够实现灵活的人机互动。

    模型架构

    Qwen-Audio 模型的架构如图 3 所示。Qwen-Audio 包含一个音频编码器和一个大型语言模型。给定配对数据 (𝒂,𝒙) ,其中 𝒂 和 𝒙 表示音频序列和文本序列,训练目标是将下一个文本标记概率最大化为:

    Audio Encoder 音频编码器

    音频编码器Qwen-Audio采用单一音频编码器处理多种类型的音频。该音频编码器基于Whisper-large-v2模型初始化,该模型为32层Transformer结构,包含两个卷积下采样层作为前端。音频编码器由640M参数构成。尽管Whisper是针对语音识别和翻译进行监督训练的,其编码表示仍然包含丰富的信息,如背景噪声,甚至可以用于恢复原始语音。在音频数据预处理过程中,Whisper将其重采样至16kHz,并使用25ms的窗口大小和10ms的步长将原始波形转换为80通道梅尔谱图。此外,模型还包含一个步幅为2的池化层,以减少音频表示的长度。因此,编码器输出的每一帧大约对应于原始音频信号的40ms片段。在训练时,采用SpecAugment作为数据增强技术。

    大型语言模型Qwen-Audio将大型语言模型作为其基础组件。该模型使用从Qwen-7B中获得的预训练权重进行初始化。Qwen-7B是一个32层的Transformer解码器模型,隐藏层大小为4096,总参数量为7.7B。

    多任务预训练

    在音频处理领域,已开发出多样化的音频数据集以应对特定任务,如表1所示。Qwen-Audio旨在利用广泛的音频数据集进行联合训练,目标是训练一个统一的模型,能够支持所有音频任务,从而消除在处理不同任务时繁琐的模型切换需求。更重要的是,在联合训练过程中,各任务可以相互受益,原因在于:1)相似任务能够通过知识共享和协同学习而获益,因为它们关注音频信号中嵌入的基本信息;2)依赖于低层次感知能力的任务可以帮助需要高层次理解或推理能力的任务。

    然而,由于任务聚焦、语言、标注的细粒度和文本结构等方面的差异,不同数据集在文本标签上存在显著变化(例如,有些数据是结构化的,而其他数据则是非结构化的)为了训练适用于不同任务的网络,仅仅混合这些多样化的数据集无法实现相互增强;相反,它会引入干扰。目前大多数现有的多任务训练方法要么将相似任务分组(例如,音频描述、转录),要么为每个数据集分配一个数据集ID,以避免干扰。尽管这些方法取得了一定效果,但仍有很大的改进空间。Whisper提出了一种多任务训练格式,通过将任务和条件信息作为输入特定令牌的序列传递给语言解码器,如语音活动检测、语言识别和句子级时间戳标签。然而,Whisper主要集中于语音翻译和识别任务。

    多任务训练格式框架

    受到Whisper的启发,为了融合不同类型的音频,我们提出了一种多任务训练格式框架,具体如下:

    • 转录标签:预测的启动由转录标签表示。使用<|startoftranscripts|>来指示涉及准确转录口语和捕捉语音录音语言内容的任务,如语音识别和语音翻译任务。对于其他任务,则使用<|startofanalysis|>标签。
    • 音频语言标签:然后,我们引入一个语言标签,指示音频中所说的语言。该标签使用分配给训练集中每种语言的唯一令牌,共计八种语言。当音频片段不包含任何语音(例如自然声音和音乐)时,模型训练预测<|unknown|>令牌。
    • 任务标签:后续令牌指定任务。我们将收集的音频任务分为五类:<|transcribe|>、<|translate|>、<|caption|>、<|analysis|>和<|question-answer|>任务。对于问答(QA)任务,我们在标签后附加相应的问题。
    • 文本语言标签标签令牌指定输出文本序列的语言。
    • 时间戳标签:<|timestamps|>或<|notimestamps|>令牌的存在决定模型是否需要预测时间戳。与Whisper使用的句子级时间戳不同,包含<|timestamps|>标签要求模型进行细粒度的单词级时间戳预测,简称为SRWT(具有单词级时间戳的语音识别)。这些时间戳的预测与转录单词交错进行:开始时间令牌在每个转录令牌之前预测,而结束时间令牌在之后预测。根据我们的实验,SRWT提高了模型将音频信号与时间戳对齐的能力。这种改进的对齐有助于模型对语音信号的全面理解,从而在语音识别和音频问答任务等多个任务中取得显著进展。
    • 输出指令最后,我们提供输出指令,以进一步指定任务和不同子任务所需的格式,然后开始文本输出。

    我们框架的指导原则是通过共享标签最大限度地提高相似任务之间的知识共享,从而提升它们的性能。同时,我们确保不同任务和输出格式可以区分,以避免模型的一对多映射问题。有关Qwen-Audio多任务格式的概述,请参见图3。

    监督微调

    多任务模型的广泛预训练赋予了它们对音频的广泛理解。在此基础上,我们采用基于指令的微调技术,以提高模型与人类意图的对齐能力,从而形成一个交互式聊天模型,称为Qwen-Audio-Chat。为实现这一目标,我们手动创建每个任务的示例。这些示例包括原始文本标签、问题和答案。随后,我们利用GPT-3.5基于提供的原始文本标签生成更多的问题和答案。此外,我们还通过手动标注、模型生成和策略串联创建了一套音频对话数据集。该数据集帮助我们将推理、故事生成和多图像理解能力融入模型中。

    为了有效处理多音频对话和多个音频输入,我们引入了用“Audio id:”标记不同音频的约定,其中id对应于音频输入对话的顺序。在对话格式方面,我们使用ChatML(OpenAI)格式构建指令调优数据集。在这种格式中,每个交互的声明用两个特殊令牌(<im_start>和<im_end>)进行标记,以便于对话结束。

    为了促进在多轮对话中来自音频和纯文本模态的多样化输入,我们在此训练过程中结合使用上述以音频为中心的指令数据和纯文本指令数据。这种方法使模型能够无缝处理多种输入形式。指令调优数据的总量为20k。

    Experiments

    设置

    多任务预训练阶段,我们冻结大型语言模型(LLM)的权重,仅优化音频编码器。该训练模型被称为Qwen-Audio。在随后的监督微调阶段,我们固定音频编码器的权重,仅优化LLM。最终模型被标记为Qwen-Audio-Chat。两个阶段的详细训练配置列在表6中。

    评估

    为了评估Qwen-Audio的通用理解能力,如表2所示,我们进行了全面的评估,涵盖多种任务,包括自动语音识别(ASR)、语音转文本翻译(S2TT)、自动音频描述(AAC)、声学场景分类(ASC)、语音情感识别(SER)、音频问答(AQA)、声乐声音分类(VSC)和音乐音符分析(MNA)。此次评估涉及12个数据集。评估数据集严格排除在训练数据之外,以避免数据泄露。两个阶段的详细训练配置列在表6中。

    主要结果

    在本节中,我们对Qwen-Audio模型进行了全面评估,评估其在各种任务上的表现,而无需任何任务特定的微调。首先,我们检查其在英语自动语音识别(ASR)方面的结果,如表3所示,Qwen-Audio的表现优于以往的多任务学习模型。具体而言,它在librispeech的test-clean和test-other数据集上分别取得了2.0%和4.2%的词错误率(WER)。同样,中文普通话的ASR结果显示Qwen-Audio在与之前方法的对比中表现出竞争力。根据我们所知,Qwen-Audio在Aishell1的开发集和测试集上达到了最新的研究成果。此外,我们还评估了Qwen-Audio在CoVoST2数据集上的语音翻译性能。结果显示,Qwen-Audio在所有七个翻译方向上均显著超越基线模型。

    最后,我们分析了Qwen-Audio在各种音频分析任务上的表现,包括AAC、SWRT、ASC、SER、AQA、VSC和MNA,结果汇总在表3中。在这些任务中,Qwen-Audio始终显著优于基线模型。特别地,它在CochlScene、ClothoAQA和VocalSound上取得了最新的研究成果,展示了模型强大的音频理解能力。

    表3:自动语音识别(ASR)、语音转文本翻译(S2TT)、自动音频描述(AAC)、带有词级时间戳的语音识别(SRWT)、声学场景分类(ASC)、语音情感识别(SER)、音频问答(AQA)、声乐声音分类(VSC)和音乐音符分析(MNA)任务的结果。在SRWT任务中,Forced-aligner(McAuliffe等,2017)的结果是基于真实转录文本预测时间戳,而Paraformer-large-TP(Gao等,2023)和Qwen-Audio则在更具挑战性的场景中,通过直接生成包含转录文本和时间戳的序列来应对。

    互动聊天结果

    我们通过图2中的示例案例展示了Qwen-Audio-Chat的对话能力。此外,我们计划向公众开放训练好的模型,以便进行在线聊天互动。

    词级时间戳预测分析

    我们通过训练Qwen-Audio提出了带有词级时间戳的语音识别任务(SRWT),旨在不仅识别语音转录,还预测每个单词的时间戳。SRWT的目的有两个:首先,改善模型将音频信号与细粒度时间戳对齐的能力;其次,支持Qwen-Audio-Chat中的语音和音频的基础对接,以及基于对接的问答任务,例如找到提到某人姓名的音频片段的开始和结束时间,或识别给定音频中是否出现某种声音。

    在本节中,我们在多任务预训练中排除了SRWT任务的训练,同时保持其他任务不变。值得注意的是,去除SRWT并不影响训练的音频数据集的覆盖范围,因为SRWT任务与自动语音识别(ASR)任务共享相同的音频数据集。结果如表4和表5所示,训练中包含SRWT的模型在自动语音识别和音频问答任务中表现优越,包括自然声音问答和音乐问答。这些结果突显了将细粒度词级时间戳纳入模型以增强通用音频信号对接能力,并进而提高声音和音乐信号问答任务性能的有效性。

    结论

    在本文中,我们提出了Qwen-Audio系列,这是一个具备通用音频理解能力的大规模音频语言模型集合。为了融合不同类型的音频进行共同训练,我们提出了一个统一的多任务学习框架,该框架促进了相似任务之间的知识共享,并避免了由于不同文本格式引起的一对多映射问题。在没有任何任务特定微调的情况下,所得到的Qwen-Audio模型在各种基准测试中超越了以往的工作,证明了其通用音频理解能力。通过监督指令微调,Qwen-Audio-Chat展示了与人类意图对齐的强大能力,支持来自音频和文本输入的多语言和多轮对话。

    SALMONN-语音大模型

    code:https://github.com/bytedance/SALMONN/

    paper:https://arxiv.org/abs/2310.13289

    SALMONN 是一个大型语言模型 (LLM),支持语音、音频事件和音乐输入,由清华大学电子工程系和字节跳动开发。SALMONN 可以感知和理解各种音频输入,从而获得多语言语音识别和翻译、音频语音共推理等新兴能力,而不是纯语音输入或音频事件输入。这可以被视为赋予 LLM “耳朵”和认知听力能力,这使得 SALMONN 向具有听力的通用人工智能迈出了一步。

    SALMONN 的模型架构如下所示。窗口级 Q-Former 用作连接模块,将 Whisper 语音编码器和 BEATs 音频编码器的输出融合为增强音频令牌,这些令牌与 LLM 输入空间对齐。LoRA 适配器将增强的 LLM 输入空间与其输出空间对齐。文本提示用于指示 SALMONN 回答有关一般音频输入的开放式问题,答案位于 LLM 文本响应中。

    相较于语音识别、音频字幕等传统语音和音频处理任务,SALMONN 利用 LLM来实现认知导向的音频感知,极大地提高了模型的通用性和任务的丰富性。此外,SALMONN 能够以相对较高的准确性遵循文本命令甚至语音命令。由于 SALMONN 只使用基于文本命令的训练数据,因此聆听语音命令也是一种跨模态新兴能力。

    为了解决由于在预训练和微调阶段出现的任务过拟合问题,即LLM局限于在指令微调中使用的特定任务,而对于没有出现的任务能力很差,而提出了一个额外的少量样本激活微调阶段,以使SALMONN重新获得LLM的突现能力。

    Introduction

    在本文中,我们提出了一种语音音频语言音乐开放神经网络(SALMONN),它是一种单一音频-文本多模态大语言模型(LLM),能够感知和理解三种基本类型的声音,包括语音、音频事件和音乐。为了增强在语音和非语音音频任务上的表现,SALMONN采用了双编码器结构,其中包括来自Whisper语音模型的语音编码器(Radford等,2023)和BEATs音频编码器(Chen等,2023c)。使用窗口级查询Transformer(Q-Former)(Li等,2023a)作为连接模块,将可变长度的编码器输出序列转换为可变数量的增强音频token,以输入到Vicuna LLM(Chiang等,2023),并能够以高时间分辨率实现音频-文本对齐低秩适应(LoRA)方法(Hu等,2022)应用于Vicuna,作为跨模态适配器,将Vicuna的增强输入空间与其输出空间对齐,从而进一步提升其性能。在窗口级Q-Former和LoRA的跨模态预训练和指令微调阶段使用了一系列语音、音频和音乐任务最终得到的多模态LLM局限于在指令微调中使用的特定任务,特别是语音识别和音频描述,表现出有限或没有的跨模态突现能力,我们称之为任务过拟合问题。本文中,跨模态突现能力指的是在训练中未见的跨模态任务的执行能力,实质上是LLM的突现能力(Wei等,2022b),在指令微调过程中丧失。为此,我们提出了一个额外的少量样本激活微调阶段,以使SALMONN重新获得LLM的突现能力,并减轻对已训练任务的显著灾难性遗忘。

    为了评估 SALMONN 的认知听力能力,使用了广泛的语音、音频事件和音乐基准。 任务可以分为三个级别。 第一级对经过指令调优训练的八个任务进行基准测试,例如语音识别、翻译和音频总结,而其他两个级别对未经训练的任务进行基准测试。 第二级包括五个基于语音的 NLP 任务,例如翻译为未经训练的语言和槽填充(slot filling,即从文本中提取特定信息并填充到预定义的槽位中),这依赖于语音和文本标记之间的多语言和高质量对齐。 最后一级的任务,包括基于音频的讲故事和语音音频协同推理,不仅需要理解语音,还需要理解非语音听觉信息。 实验结果表明,SALMONN 作为单一模型可以执行所有这些任务,并在标准基准上实现具有竞争力的性能,这揭示了构建能够“听到”并理解通用音频输入的人工智能 (AI) 的可行性由语音、音频事件和音乐的混合组成。

    本文的主要贡献可以总结如下。

    • 我们提出了SALMONN,尽我们所知,这是第一个能够感知和理解包括语音、音频事件和音乐在内的一般音频输入的多模态LLM。
    • 我们通过调整LoRA缩放因子来研究跨模态涌现能力的存在,并提出了一种低成本的激活调优方法,作为额外的训练阶段,能够激活跨模态涌现能力,并减轻对训练中已见任务的灾难性遗忘。
    • 我们在一系列反映一般听觉能力的任务上评估SALMONN,并提出了两个新任务:基于音频的讲故事和语音音频共同推理。

    模型和训练

    模型架构

    SALMONN 的模型架构如图 1所示。



    图1:SALMONN的模型架构。窗口级Q-Former作为连接模块,用于融合来自Whisper语音编码器和BEATs音频编码器的输出,生成增强音频标记,这些标记与LLM输入空间对齐。LoRA适配器将增强的LLM输入空间与其输出空间对齐。文本提示用于指导SALMONN回答有关一般音频输入的开放式问题,答案则以LLM文本响应的形式呈现。在训练过程中,LLM和编码器保持固定,而其余部分可以更新。

    两个互补听觉编码器【用于建模语音音频和非语音音频】的输出特征被同步并结合在一起。Q-Former被用作连接模块,并应用于帧级别,其输出序列与文本指令提示集成,并通过LoRA适配器输入到LLM中,以生成文本响应。

    双重听觉编码器:使用了OpenAI的Whisper模型(Radford等,2023)的语音编码器和BEATs音频编码器(Chen等,2023c)。(Whisper模型经过大量弱监督数据的训练,适用于语音识别和翻译,其编码器输出特征适合建模语音并包含背景噪音的信息(Gong等,2023a)。BEATs经过迭代自监督学习训练,提取高级非语音音频语义信息,并提出有效的声学tokenizer,将连续音频特征量化为丰富的语义离散标签)输入音频首先被标记化,然后在训练中被掩蔽和预测。标记器通过提炼音频标记的语义知识进行更新(Chen等,2023c)。因此,这两个编码器的结果听觉特征是互补的,适合包含语音和非语音信息的一般音频输入。由于两个编码器具有相同的输出帧率50Hz,连接后的输出特征表示为:

    Z=Concat(Encoderwhisper​(X),Encoderbeats​(X)),

    其中 X 是可变长度的一般音频输入序列,Encoderwhisper​(⋅) Encoderbeats​(⋅) 分别是Whisper和BEATs编码器,Concat(⋅) 是在特征维度上逐帧连接的操作,Z 是具有 T 帧的连接编码器输出序列。

    窗口级Q-Former:Q-Former结构通常用于将图像编码器的输出转换为固定数量的LLM文本输入标记(Li等,2023a),在处理可变长度的音频输入时需要进行修改。具体而言,将输入图像的编码器输出表示为 Zl​,Q-Former使用固定数量的可训练查询 Q 将 Zl​ 转换为 N 个文本标记 Hl​,这需要多个堆叠的Q-Former块。Q-Former块类似于Transformer解码器块(Vaswani等,2017),但在第一个块中使用固定数量的可训练静态查询 Q,并从自注意力层中移除因果掩码。通过这种方式,Q-Former允许查询在 Q中首先使用自注意力层相互引用,然后使用交叉注意力层与 Zl​ 进行交互。

    对于一个变长的通用音频输入Z=[Zt​]t=1T,通过将 Z 分割成大小为 L 的窗口,并用零填充最后一个窗口,可以表示为{{Zt​}t=(l−1)×L+1l×L​}l=1T/L⌉​。而不是在序列级别使用 Q-Former 将整个 Z转换为 N 个文本标记,SALMONN 在窗口级别使用 Q-Former,就好像每个窗口中的编码器输出帧堆叠在一起形成一幅图像一样。因此,文本标记序列 H 变为:

    其中 Q-Former(·) 是 Q-Former 函数,H 的形状为 ⌈T/L⌉×N 的文本标记。窗口级的 Q-Former 使用可变数量的文本标记,因此在处理可变长度序列时效率更高。此外,H 被强制与 Z 具有单调对齐,从而提高了时间分辨率,这对于语音识别非常重要。

    LLM 和 LoRA:本工作中使用的是预训练的 Vicuna LLM(Chiang et al., 2023),该模型是针对指令微调的 LLaMA LLM(Touvron et al., 2023)。LoRA(Hu et al., 2022)是一种广泛使用的参数高效微调方法,用于 LLM 适应,在 SALMONN 中用于调整 Vicuna 自注意力层中的查询和数值权重矩阵。在本工作中,LoRA 是可训练的,而 Vicuna 不是。

    训练方法

    本节介绍了 SALMONN 的三阶段跨模态训练方法。除了最近视觉 LLM 所采用的预训练指令微调阶段(Dai et al., 2023; Zhang et al., 2023b),还提出了一个额外的激活微调阶段,以解决指令微调中对语音识别和音频描述任务的过拟合问题

    预训练阶段:基于语音识别和语音描述音频进行预训练

    为了减小预训练参数(LLM 和编码器)与随机初始化参数(连接模块和适配器)之间的差距,使用大量的语音识别和音频描述数据对窗口级 Q-Former 和 LoRA 进行预训练。这两个任务包含关于语音和非语音音频事件内容的关键听觉信息,并且都不需要复杂的推理和理解,因此可以帮助 SALMONN 学习听觉信息与文本信息之间的高质量对齐。

    指令微调阶段:

    类似于 NLP(Wei et al., 2022a)和视觉语言(Dai et al., 2023),音频-文本指令微调使用了一系列监督的语音、音频事件和音乐任务,如表 1 所示,作为 SALMONN 训练的第二阶段。根据任务的重要性(例如语音识别和音频描述)以及在测试中拥有此能力的不可或缺性(例如重叠语音识别、电话识别和音乐描述)选择这些任务。指令提示基于与音频数据配对的文本生成。

    任务过拟合:

    尽管仅通过前两个训练阶段构建的 SALMONN 可以在指令微调中训练的任务上产生有竞争力的结果,但它在执行未训练的跨模态任务时表现出有限或几乎没有能力,尤其是那些需要跨模态共同推理能力的任务。特别是,该模型有时会违反指令提示,生成与其所接受的任务无关的响应,仿佛它接收到的指令与训练中常见的任务相关(例如语音识别)。我们将这一现象称为任务过拟合。在这里,我们对该问题进行了理论分析,详细的实验验证见第 5.3 和 5.4 节。

    我们将任务过拟合归因于两个原因。首先,与用于 LLM 训练的纯文本数据相比,我们的跨模态指令微调中仅使用了更简单的指令提示(Wei et al., 2022a),因此生成的响应并不复杂且多样。同时,指令微调中包含的一些任务,特别是语音识别和音频描述,具有比其他任务(如语音和音频问答)更确定的输出这两个原因结合导致内在条件语言模型(LM)偏向于一个缺乏良好泛化能力的错误分布,阻止了 SALMONN 执行未训练的跨模态任务。更具体地,在测试时,给定新指令提示 I 的测试输入 X 的响应文本序列 Y^ 可以生成为 Y^=argmaxY​PΛ​(Y|X,I),这也是训练中要最大化的目标。利用贝叶斯法则,有

    由于在 SALMONN 训练中仅看到有限的文本响应,内在条件 LM PΛ(Y∣X) 偏向于与 X 强对齐的 Y 序列,例如自动语音识别(ASR)和自动音频描述(AAC)任务的转录,尤其是简单且短的转录。根据公式(3),这导致 I′(具有更多样本响应的zero-shot 指令)具有小的 PΛ(Y∣X,I′)。

    激活微调阶段:

    缓解任务过拟合的有效方法是对内在条件 LM PΛ​(Y∣X) 进行正则化。实现这一点的简单方法是对具有更长和更多样化响应的任务进行微调,例如基于听觉信息的问答和讲故事。这类任务的配对训练数据可以基于与语音识别或音频和音乐字幕数据配对的文本生成,可以由人工注释者手动生成,也可以通过提示文本基础 LLM 自动生成。

    我们采用一种高效的方法,使 SALMONN 能够通过简单地降低 LoRA 适配器的缩放因子来生成长且多样化的响应。这是一种正则化 PΛ​(Y∣X) 的替代方法,因为内在条件 LM 只能通过窗口级 Q-Former 和 LoRA 学习,因为它们是训练中唯一更新的模块。降低 LoRA 缩放因子的效果在第 5.2 节中可以找到,确实可以激活问答和讲故事能力,并生成长且多样化的响应,但也会显著降低在训练任务上的结果。为了在恢复跨模态突现能力的同时保持竞争力的结果,我们建议使用以降低的 LoRA 缩放因子生成的 SALMONN 响应来执行称为激活微调的第三阶段微调。随后在第 5.4 节中展示的实验结果表明,激活微调是一种高效且有效的少样本自监督训练方法。

    实验设置

    模型设置

    SALMONN 使用 Whisper-Large-v2(Radford et al., 2023)模型的编码器作为语音编码器,使用微调后的 BEATs(Chen et al., 2023c)编码器作为音频编码器,以及具有 13B 参数的 Vicuna LLM(Chiang et al., 2023)作为基础 LLM。对于窗口级 Q-Former,我们使用 N = 1,仅有一个可训练查询,设置L = 17,这大约对应于每个窗口 0.33 秒。因此,对于 30 秒的音频,Q-Former 输出 88 个文本标记。关于 LoRA(Hu et al., 2022)的超参数,我们将秩设置为 8,缩放因子设置为 4.0。在训练中,仅更新 Q-Former 和 LoRA 的参数,结果约为 3300 万(M)参数,约占整个 SALMONN 模型的 0.24%。

    数据设置

    采用第 3.2 节中提出的三阶段训练。用于第一预训练阶段的数据包括 960 小时的 LibriSpeech 训练集(Panayotov et al., 2015)和 1000 小时的 GigaSpeech M 集(Chen et al., 2021)用于语音识别,以及 2800 小时的 WavCaps(Mei et al., 2023)(去除音频片段超过 180 秒的部分)、AudioCaps(Kim et al., 2019)和 Clotho(Drossos et al., 2020)数据集用于音频描述生成。

    第二个指令调优阶段涉及多个任务,包括自动语音识别(ASR)、自动语音翻译(AST)、自动音频字幕(AAC)、音素识别(PR)、情感识别(ER)、音乐字幕(MC)、重叠语音识别(OSR)、说话人验证(SV)、性别识别(GR)、语音问答(SQA)、音频问答(AQA)和音乐问答(MQA)。在SQA、AQA和MQA任务中,问题是基于文本字幕标签使用ChatGPT生成的,模型需要根据通用音频输入和带有问题的文本提示提供答案。本阶段使用的数据列在表1中,其中“En2Zh”指的是从英语到中文的AST。

    在最后的激活调优阶段,SALMONN基于音频片段编写了十二个故事,使用了reduced的LoRA。然后,模型使用基于教师强制的交叉熵训练进行12步训练,每一步只使用一个故事样本,以激活SALMONN的跨模态突现能力。

    任务设置

    由于文本LLM具备通过指令调优进行zero-shot学习的能力(Wei et al., 2022a),因此当将基于文本的主干LLM与多模态编码器连接时,期望能实现高质量的跨模态对齐,从而出现这样的能力。为了评估SALMONN的zero-shot跨模态突现能力,选择了15种语音、音频和音乐任务,并将其分为三个不同的层次。

    任务层级1包括在指令调优中使用的任务,因此对SALMONN来说最容易执行。这些任务及其训练数据的列表在第4.2节中给出,各任务的评估指标见表2。

    任务层级2包括未训练的任务,因此比层级1更具挑战性。层级2的任务是基于语音的NLP任务,包括语音关键词提取(KE),评估基于语音内容提取的关键词的准确性;基于口语查询的问题回答(SQQA),评估根据语音中的问题检索的常识知识;基于语音的槽填充(SF),评估从语音内容中获得的所需槽值(通常是命名实体)的准确性。还包括两个AST任务,En2De(英语到德语)和En2Ja(英语到日语),它们也被视为跨模态突现能力,因为指令调优中仅训练了En2Zh。SALMONN的主干LLM Vicuna可以根据语音转录执行所有层级2的任务,因此SALMONN将以完全端到端的方式实现这些任务,而无需任何显式的语音识别。

    任务层级3是最具挑战性的任务,包括基于音频的故事讲述(Story)和语音音频共同推理(SAC)。基于音频的故事讲述是根据来自一般音频输入的听觉信息编写有意义的故事。SAC要求模型理解嵌入在输入音频片段中的口语问题,从背景音频事件或音乐中寻找证据,并根据此进行推理以回答问题。根据我们的知识,这两个层级3的任务是首次在本文中提出的,要求SALMONN以完全端到端的方式感知语音、音频和音乐,并根据听觉信息进行理解和推理。

    表2列出了所有测试集及其评估指标。跟随率(FR)是某些层级2和层级3任务的额外指标,测量SALMONN能够成功遵循指令的百分比。考虑到所选任务复杂,且更容易因任务过拟合导致指令违反,因此引入FR。值得注意的是,我们仅通过计算故事中不同单词的数量来计算故事任务的多样性指标,这仅代表故事的丰富性,而非质量

    表2:三层任务中使用的测试集、指标及参考值来源。SQQA和KE中使用的语音数据是通过商业文本转语音产品合成的。
    参考值说明:“Whisper”指使用Whisper-Large-v2进行自动语音识别(ASR),“Whisper + Vicuna”指将Whisper-Large-v2 ASR输出的转录结果输入到Vicuna中,其余则是我们所知的最新成果。

    实验结果

    所有15个任务的完整结果:
    表3展示了SALMONN在所有15个任务上的结果。从结果来看,无论是否进行激活调优,SALMONN在所有一级任务上都能产生竞争力的结果。然而,未进行激活调优的模型在二级和三级任务上表现严重受限,几乎无法执行。特别是在SQQA、故事和SAC等强调多模态交互的任务中,未调优的SALMONN几乎无法遵循指令。进行激活调优后,SQQA、SF、故事和SAC任务的执行成功率显著提高。图2展示了在激活调优不同训练步骤中,模型在ASR和PR、SQQA、故事和SAC任务上的表现变化趋势,表明激活调优只需少量训练样本和步骤即可激活新兴能力:ASR和PR的结果几乎保持不变,而SQQA、故事和SAC的结果则出现了新兴趋势。由于篇幅限制,结果的更详细分析在附录B中讨论。

    降低LoRA缩放因子的影响
    本节探讨在未进行激活调优的情况下,测试时降低LoRA缩放因子对缓解任务过拟合问题的影响。如图3所示,当LoRA缩放因子降至约2.0,即其原始值的一半时,模型突然展现出跨模态推理能力,这与%PER的下降一起证明了LoRA中嵌入的内在条件语言模型的存在。

    任务过拟合与激活调优分析
    为了验证内在条件语言模型的影响,我们计算了每个激活调优阶段步骤的困惑度(PPL)。具体而言,对于给定的音频 X,使用基于特定任务的文本指令提示I 的教师强制方法计算与探测任务对应的 Y 序列的概率,或在不使用 I 的情况下进行计算。

    如图4所示,比较了故事/SAC任务的真实响应(通过折扣LoRA缩放因子生成)与由于任务过拟合而导致模型错误执行的任务响应(本例中为AAC)。在子图(a)和(b)中,计算 PΛ(Y∣X) 时未使用文本指令提示,结果显示未进行激活调优时,AAC的 Y 的PPL明显低于Story/SAC的 Y。在激活调优过程中,这些任务之间的PPL差距得到缓解,表明对主导AAC任务的偏向显著降低。在子图(c)和(d)中,我们探测了带有Story和SAC指令的 PΛ(Y∣X,I)。结果表明,在激活调优之前,即使文本指令提示是执行Story/SAC,AAC的PPL仍低于Story/SAC,这解释了模型未能遵循指令的原因。在激活调优过程中,Story/SAC的 Y 的PPL值逐渐低于AAC,最终模型能够执行指令任务。

    使用不同任务和数据的激活调优:
    我们探索了几种激活方法来激活模型,包括基于音频编写的长故事、带有长答案的文本问答(QA)任务对,以及长语音转录的ASR任务。这三种方法都对LoRA和Q-Former进行了微调。通过忽略Q-Former和音频输入,Vicuna和LoRA被微调为适应的文本基础LLM。作为另一对照组,进行了使用LoRA和Q-Former但不微调Q-Former的实验。

    结果如表4所示。从结果来看,ASR(长)即用长标签训练的ASR任务,或仅基于文本提示输入的故事(文本基础)都无法激活模型。而使用长答案的故事或QA训练(故事或QA(长))则能够激活模型。这是因为ASR任务强调提高高质量的跨模态对齐,使得分布更加偏向内在条件语言模型。至于基于文本的故事微调,实际上影响的是P(Y∣Tx,I) 而不是 P(Y∣X,I),其中Tx 是语音的参考文本。因此,基于文本的训练无法缓解任务过拟合。带有长答案的QA数据能够激活LLM,但激活模型的性能不如使用故事任务激活的模型,尤其导致生成响应的重复率较高。这可能是因为QA任务的配对答案多样性低于故事任务,从而导致内在条件LM PΛ(Y∣X) 的正则化效果不如预期。

    附录:EXAMPLES OF SALMONN