导读 本文将分享在 GPU 上进行语音 AI 部署的最佳实践,介绍如何利用 Triton 和 TensorRT 为语音应用降本增效。


(资料图片仅供参考)

主要内容包括以下三部分:

1. Conversational AI(对话式 AI)场景总览

2. ASR(语音识别)GPU 部署最佳实践

3. TTS(语音合成)GPU 部署最佳实践

分享嘉宾|刘川 NVIDIA 资深解决方案架构师

编辑整理|李瑜亮

出品社区|DataFun

01

Conversational AI 场景总览

1. 工作流

在对话式 AI 工作流中,主要有三个算法相关模块。 ASR 将用户的语音转换成文字, NLU(自然语言理解) 会针对识别的内容给出文本回复, TTS 会将回复内容转换为音频,作为整个链路的返回。NVIDIA 在这三个领域都有丰富的算法与加速技术,本文重点放在 ASR 和 TTS。

2. 痛点与挑战

语音 AI 工作流的部署面临着诸多挑战 ,主要包括:

① 语音识别准确率难以提升,语音合成音质不佳;

② 涉及到多个模型及前后端,工作管线复杂,对于流式任务调度管理更加复杂,开发难度大,调度不够高效;

③ 因为没有高效利用 GPU 资源,导致服务延时高,并发路数低,部署成本居高不下。

我们主要利用 Triton Inference Server 和 TensorRT 解决以上问题。

--

02

ASR GPU 部署最佳实践

1. Triton Inference Server 介绍

Triton 是一个开源的推理服务的部署框架,可以将训练好的模型部署成一个微服务。该框架会调度请求,管理模型,推理请求并返回结果。这个框架支持 GPU 与 CPU 推理,兼容 Pytorch,Tensorflow 等多种深度学习框架。

2. ASR 工作流一览

NVIDIA 提供了一种基于 Triton Inference Server 部署在云端 GPU 上的 ASR 云服务的工作流, 整个流程分为三部分:

① 使用 Kaldifeat 的 Fbank 特征提取器,在 GPU 上高效提取多个音频的特征;

② Conformer Encoder,根据音频特征推理解码需要的输入;

③ CTC Prefix Beam Search 的解码,我们引入 N-Gram 语言模型,并使用 Conformer Decoder 结合 Encoder 的输出对 N-Best 重新打分。

之所以利用 Triton Inference Server 来部署 WeNet ASR 工作流,让这三个模块能够有序地组合在一起,使数据流能够有条不紊地在三个模块上流动。

3. 使用 Triton 调度模型与请求

Triton 提供的 Ensemble Model 功能允许我们配置各模块之间的依赖关系,上述三个模型就能够部署成为一个工作流。并且三个模型都是独立部署的,能够并行运行,当后置模型在处理上一个请求时,前置模型可以同时推理下一个请求。所以,一方面做到了三个模型的组合,同时也做到了 pipeline 流水线并行和模型推理的解耦。

此外,在上述第三个模块中,涉及到 CTC 和 Decoder Rescoring 的配合,这就存在一个逻辑操作,如果推理到最后一个 chunk 则需要重打分。Triton 的 Business Logic Scripting 功能 可以解决这个问题,这是一个简单的 Python 脚本,可以通过简单的代码调用其它模型,可以便捷地实现各种逻辑操作,控制模型间的数据流。

此外,在请求侧的调度上,Triton 提供的 Dynamic Batching Scheduler 通过将多个客户端同时发送来的请求合并为一个大的 batch,充分利用了硬件资源,实现了高并发高吞吐。

4. Triton 的流式推理机制

前面我们讨论了非流式计算的优化。在实际场景中 ASR 服务需要同时处理多个语音数据流,如同个用户会发送多段语音。Triton 提供了 Streaming API 针对有前后依赖的流式计算进行优化,主要包括以下功能:

① 对每一个 chunk 加上四个标签: Start - 是否是流的起始 chunk,Ready - 是否有数据需要进行推理,End - 是否是流的结束 chunk,Corrid - 该 chunk 属于哪个流。

② 合并多个流上的 chunk 进行推理。 Triton 上以模型实例的方式做推理,在一个 GPU 上可以启动多个实例,每个实例又分为 N 个 Slot,意味该实例同时可进行 N 个数据流的推理。数据流首先会在 Sequence Batcher 的 Candidates 队列中等待处理,当有空闲 Slot 时即可开始处理。为了维护数据流的状态,一个数据流的所有 chunk 只会在同一个实例上推理以维持每个流的状态。同时因为依赖关系,同一个时间步的所有 Slot 中的 chunk 只允许来自不同的流。

③ Triton 提供了 Implicit State Management ,通过在配置文件中定义模型的状态输入与状态输出即可对进行状态 Tensor 进行管理、更新。此外当数据流进行切换时,也可切换到对应数据流的状态。极大的简化了流式计算中状态管理的工作。

5. 性能提升

我们在 A10 GPU 上测试了 WeNet 模型流式 ASR 的性能,在有 attention rescoring 的情况下,往前看 5 个 chunk,每个 chunk 长度为 640ms,能够在 400-500 并发路数下实时推理 (注:此处测试并未模拟用户真实流式地说话,而是将每个流的所有 chunk 不停顿地异步发送给服务端) 。

非流式场景下,我们测试了 ONNX 与 TensorRT 两种后端。ONNX 能每秒吞吐 180 个 8 秒音频的请求。另外,我们还提供了 TensorRT 加速方案,针对使用原生 TensorRT 存在的如某些层数据溢出、某些 OP 不支持以及精度和速度下降等问题进行了解决。TensorRT 每秒吞吐能达到 280,进一步高于 ONNX。

6. 进一步的扩展

我们的最佳实践可以进一步进行扩展。比如在 ASR 基础上,加入了 VAD 模块,以及音频切割模块。这样整个 pipeline 包括:音频特征提取,VAD 的端点检测,音频切割,之后是 ASR 推理,这些模块通过前面提到的 Business Logic Scripting 进行串联。还可以根据需要加入说话人识别、情感分析、标点预测等更多模块。

另外,Triton 还解决了一个问题,一个音频切成多段后,可以独立推理,推理完后可以再拼回去,不同客户端不同请求切完后的所有音频小段可以打成一个 batch 一齐推理,最后也可以认出每个音频小段是属于哪个音频请求的。

整个 Triton Inference Server 可以作为一个 Docker 容器,可以部署在 K8S 集群中作为一个 pod,在不同节点上可以部署多个 Triton pod,更可以通过 Triton 提供的 Metrics 来进行弹性扩缩容,形成分布式部署,线性提升吞吐量,从而适应更大流量的业务场景。

--

03

TTS GPU 部署最佳实践

1. 流式 TTS 的部署实践

相对于 ASR,TTS 缺乏较好的开源社区,这也是 TTS 的挑战之一。我们实现了一个Triton C++ Custom Backend 用于管理和调度客户端送来的文本请求,并进行 Padding, Batching 等预处理。然后这个 Backend 会调用两个使用 Triton Ensemble 集成的模块:

① Frontend-Encoder 模块 包括两个组件,文本预处理前端(我们使用 Python Backend)和声学模型 Encoder(我们用的是 FastPitch 及 TensorRT Backend)。一段文本只经过这两个组件一次,所以将他们集成在一起。

② Decoder-Vocoder 模块 包含了Decoder(我们使用 FastPitch 及 TensorRT Backend)和 Vocoder(我们使用 HiFi-GAN 及 TensorRT Backend),因为这两个组件在流式计算中都需要多次调用,所以将它们组合在一个 Ensemble 内。

在这个过程中,Triton Custom Backend 功能允许我们用 C++ 或 Python 开发逻辑模块,这些自定义模块也可以当作模型进行部署。对于声学模型我们使用 Triton 自带的 TensorRT 作为 backend 进行部署,对模型推理速度有较好提升。

TTS 的输入有时为大段文字,为了降低首包延时,我们的实践采用 Triton 给出流式的,由多个 chunk 组成的输出。Triton 提供的 Decoupled Response 可以将模型的多个输出与原始输入的 request 绑定,帮助我们对每一个 chunk 定位其对应的文本和用户。

2. 推理性能

我们在 A10 上测试了这套部署方案对不同长度文本(Short 为 15 个字,Middle 为 20 个字,Long 为 30 个字)的推理性能。在 QPS(每秒请求数)为 200 的情况下,这套部署方案的首包延时可以控制在 100ms 以下。

--

04

结语

Nvidia 在语音领域主要产出了以下有帮助的最佳实践。

ASR 领域中:

① 我们有基于 Triton 部署流式和非流式 WeNet 的实践,并且我们对非流式的 WeNet 使用 TensorRT 进行加速;

② 这套方案支持在 K8S 集群上进行多机多卡的分布式部署;

③ 我们在这套实践的基础上给出了集成 VAD 的参考方案;

④ 对 WeNet 的 WeSpeaker 说话人识别功能的支持。

TTS 方面:

① 流式双语基于 FastPitch+HiFiGAN 部署最佳实践;

② 我们正在研究多说话人 TTS。

NLU 方面我们还做了 INT8 量化的优化,这方面没有介绍,大家可以参考我们的半开源 Github 项目 CISI (github.com/nvidia-china-sae/CISI) , 可以发邮件获取权限,欢迎大家关注。

--

05

问答环节

Q1:模型和模型间是否用队列进行衔接?是否会导致高延迟?

A1:Triton 对于模型的连接非常高效。若多个模块都在 GPU 上,Triton 会避免 GPU 和Memory 之间的拷贝。Ensemble 方式下,工作流中的多个模型可以并行。基于这些特性,Triton 能减少不必要的 overhead,提高效率。

Q2:流式推理中,如果实例中起了两个 Slots,但只有一个数据流,效率会低吗?

A2:会的。这种情况下说明 GPU 性能超过需求,建议做 GPU 的切分(MIG)。或者在同个 GPU 上部署另外多个模型,充分利用资源。

Q3:等待请求打 batch 过程中会有延时吗?

A3:可以配置等待时间,如果时间设置的很短,只会将同时收到的请求打 batch。

Q4:千分之几的实时率很快了,如果算上 WST 会不会成为瓶颈?

A4:WST 最大的问题并不是性能,在于 LM 的图非常的大,对于显存的消耗非常大。我们也在考虑有没有其他方式来解决。

--

06

互问互答

刘川:WeNet 社区正在扩展其覆盖的领域,请问彬彬老师是怎么设计和规划 WeNet 的发展,希望 WeNet 最终的形态是怎样?

张彬彬:这也是我们在思考的问题像 Transducer 和识别相关的,我们直接做在 WeNet 的项目里。比如和说话人相关的 diarization,我们放在单独的项目 WeSpeaker 里。TTS 的功能我们也是这样。横向整合还是纵向整合是很多开源项目设计之初就要思考的。我们 WeNet 社区是以生产力,轻量级,可维护性为标准。所以社区中会有较多横向的项目。

刘川:您既是 WeNet 的负责人,也是地平线的研究员。您是怎样平衡开源项目开发者与企业工程师的工作呢?您是怎样将开源社和工业落地相结合的?

张彬彬:首先看公司是否支持开源。我之前的公司相对支持开源。另外一点现在的公司对于开源的看法有着不一样的高度。地平线和开源社区相互输出,达到双赢。我目前在地平线承担了较多的开发工作,愿意投入工作外的时间和精力,在开源社区一起讨论和解决问题。对于第二个问题,因为我们社区的定位就是关注和解决工业界的痛点,所以能很好平衡开源和工程化。

刘川:我们观察到 WeNet 逐渐成为语音行业最受欢迎的社区,您是否考虑开设课程分享语音领域的知识和经验?

张彬彬:我们有过考虑。我们目前和语音之家一起做了一份实战收费课程。最早我们社区的成员希望做免费课程,但商业化更可以保证产品的质量。未来我们可能会在公众号,视频号,直接投放一些其他项目的课程。

刘川:英伟达自身在做一些开源项目。包括也支持了像 WeNet 的一些开源项目。未来英伟达在语音方面会有哪些开源的工作呢?

张彬彬:一方面我们有 Triton,NeMo 这些开源产品,我们的产品团队会不断收集工业界的反馈打磨这些产品。另一方面,我们鼓励我们的工程师参与到开源社区里。通过这种方式我们能将英伟达的加速技术优化这些开源项目。未来我们具体会关注训练方面的优化,支持更多模型与解码器,比如 Transducer,CTC 等。

刘川:人工智能依赖算力支持,而对于个人开发者算力较为昂贵,英伟达未来有考虑为开源社区提供算力支持吗?

张彬彬:在我们参与到开源项目的过程中,我们利用内部的 GPU 算力做了很多加速优化的工作,一定程度上缓解了 GPU 的缺乏。另一方面英伟达有 Inception 初创加速计划,为愿意贡献开源社区的公司给与算力优惠。此外,对于高效学生我们会和公有云厂商做一些合作,提供算力支持。

今天的分享就到这里,谢谢大家。

▌2023数据智能创新与实践大会

4大体系,专业解构数据智能 16个主题论坛,覆盖当下热点与趋势 40+演讲,兼具创新与最佳实践 1000+专业观众,内行人的技术盛会

第四届DataFunCon数据智能创新与实践大会将于⏰ 7月21-22日 在北京召开,会议主题为新基建·新征程,聚焦数据智能四大体系: 数据架构 数据效能 算法创新 智能应用 。在这里, 你将 领略到数据智能技术实践最前沿的景观

欢迎大家 点击下方链接 获取大会门票~