对话式人工智能

借助 NVIDIA NeMo 实现出色的 ASR 模型 10 倍加速

NVIDIA NeMo 持续开发了设定行业基准的 自动语音识别(ASR) 模型,尤其是在 Hugging Face Open ASR 排行榜 上拔得头筹的模型。

这些可将语音转录为文本的 NVIDIA NeMo ASR 模型提供了一系列旨在优化速度和准确性的架构:

  • CTC 模型 ( NVIDIA/parakeet-ctc-1.1b ):此模型具有 FastConformer 编码器和 softmax 预测头。它是非自回归的,这意味着未来的预测不依赖于之前的预测,从而实现快速高效的推理。
  • RNN-T 模型 ( NVIDIA/parakeet-rnnt-1.1b ):此传感器模型向 FastConformer 编码器添加了预测和联合网络,使其成为自回归模型 – 每个预测都取决于先前的预测历史。由于此属性,人们普遍认为 RNN-T 模型的 GPU 推理速度较慢,更适合 CPU。
  • TDT 模型 ( NVIDIA/parakeet-tdt-1.1b ):另一个传感器模型,但使用名为 token-and-duration 传感器 (TDT) 的改进传感器目标进行训练。虽然仍然是自回归模型,但它可以在每个步骤中执行多个预测,从而加快推理速度。
  • TDT-CTC 模型 ( parakeet-tdt_ctc-110m ):这是传感器和 CTC 解码器的混合变体,可同时引入两个解码器,从而在训练期间加快收敛速度。它只需训练一个模型即可训练两个解码器。
  • AED 模型 ( NVIDIA/canary-1b ):Attention-encoder-decoder (AED) 模型也基于 FastConformer,具有自回归性,能够以额外计算为代价提供更高的准确性(更低的 词错误率或 WER )。

以前,这些模型面临速度性能瓶颈,例如投射开销、低计算强度和发散性能问题。

在本文中,您将了解 NVIDIA 如何通过将张量自动投射到 bfloat16、创新的标签循环算法以及引入 NeMo 2.0.0 中可用的 CUDA Graphs 等关键增强功能,将 NeMo ASR 模型的推理速度提升高达 10 倍(图 1)。

Bar graph illustrating NeMo ASR models up to 10x speed improvements with autocasting tensors to bfloat16, the innovative label-looping algorithm, and the introduction of CUDA graphs speed performance enhancements.
图 1. 通过近期优化,NVIDIA NeMo ASR 模型在逆实时系数(RTFx)方面实现高达 10 倍的速度提升。

克服速度性能瓶颈 

本节将深入探讨 NVIDIA 自动语音识别(ASR)模型如何克服各种速度性能瓶颈,包括投射开销、批量处理优化、低计算强度和发散性能问题。

自动混合精度会产生额外开销 

从 NeMo 的早期开始,便一直在 torch.amp.autocast 上下文管理器中 执行推理。这将在矩阵乘法之前自动将 float32 权重投射到 float16bfloat16,从而实现半精度张量核心运算的使用。在幕后,自动混合精度(AMP)维护一个“投射缓存”,用于存储这些转换,通常会加快训练速度。然而,会出现以下问题:

  • 过时的自动投射行为 :自动投射是在 softmaxlayer norm 等运算较为罕见时开发的。在像 Conformers 和 Transformers 这样的现代模型中,这些运算很常见,会 将float16bfloat16 输入投射回 float32 ,从而在每次矩阵乘法之前导致额外的投射。
  • 参数处理: 要使 AMP Cast 缓存有效,参数需要 requires_grad=True。遗憾的是,在 NeMo 转录 API 中,此标志设置为 False( requires_grad=False ),从而阻止缓存工作,并导致不必要的 Cast 开销。
  • 频繁的缓存清除 :每次退出 torch.amp.autocast 上下文管理器时,都会清除转换缓存。用户通常会在上下文管理器中包装单个推理调用,从而无法有效利用缓存。

这些额外投射的开销非常高。图 2 显示了 Parakeet CTC 1.1B 模型中矩阵乘法之前的投射如何增加 200 微秒的开销,而矩阵乘法本身仅需 200 微秒,这意味着一半的运行时间用于投射。这由 NVIDIA Nsight Systems 捕获,NVIDIA Nsight Systems 是一种分析工具,可在时间轴上可视化工作负载指标,以实现性能调优。

在图 2 的 CUDA 硬件行中:

  • 前两个浅蓝色部分表示处理从 float32bfloat16 的投射的内核。
  • 空白区域表示投射开销占总运行时间 400 微秒中的 200 微秒。
Screenshot illustrating that half of the total runtime is spent on casting operations instead of matrix multiplication, as captured with NVIDIA Nsight Systems performance analysis tool.
图 2. 总运行时间的一半用于投射,而非矩阵乘法,如 NVIDIA Nsight Systems 所示。

借助全半精度推理解决 AMP 开销问题

为了应对与 AMP 相关的挑战,我们通过完全以半精度(float16bfloat16)执行推理来实施最佳实践。这种方法如 NVIDIA/NeMo 在 GitHub 上的拉取请求中所述,可在不影响准确性的情况下消除不必要的投射开销,因为像 softmaxlayer norm 这样的精度敏感型操作在后台仍使用 float32,即使指定了半精度输入也是如此。请参阅 AccumulateType SoftMax 示例。

您可以通过设置 compute_dtype=float16compute_dtype=bfloat16examples/asr/transcribe_speech.py 中启用此功能,同时确保未设置 amp=True (默认值为 amp=False)。同时设置 amp=Truecompute_dtype 值将导致 错误 。如果您正在编写自己的 Python 代码,只需调用 model.to(torch.bfloat16)model.to(torch.float16) 即可实现此优化,如 NeMo/examples/asr/transcribe_speech.py 所示。

优化批处理以提升性能

在 NeMo 中,某些操作最初是依次执行的,一次处理一个迷你批量的一个元素。这种方法导致速度减慢,因为每个内核操作在批量大小为 1 时运行得很快,但为每个元素启动 CUDA 内核的开销会导致效率低下。通过切换到全批量处理,我们充分利用了 GPU 流多处理器资源。

两个特定操作( CTC 贪婪解码 特征归一化 )受到此问题的影响。通过从顺序处理转向完全批量处理,我们将每次操作的吞吐量提高了 10%,总体速度提高了约 20%。

在解决了类似问题后, SpecAugment 的速度提高了 8-10 倍。(此操作仅在训练期间运行,因此这里不是重点。)

RNN-T 和 TDT 预测网络中的低计算强度

RNN-T 和 TDT 模型长期以来一直被认为不适合服务器端 GPU 推理,因为它们具有自回归预测和联合网络。例如,在 Parakeet RNN-T 1.1B 模型中,贪婪解码占用了总运行时间的 67%,尽管预测和联合网络仅占模型参数的不到 1%。

原因是?这些内核执行的任务很少,因此其性能完全受内核启动开销的限制,因此在大部分时间内 GPU 都处于空闲状态。例如,执行 CUDA 内核可能只需 1 到 3 微秒,而启动 CUDA 内核可能需要 5 到 10 微秒。在实践中,我们发现 GPU 空闲时间约为 80%,这表明消除这一空闲时间可以将推理速度提高 5 倍。

图 3 显示了 RNN-T 贪婪解码算法的几个“外部时间步长”的快照。CUDA HW 行包含多个空白(非蓝色)区域,表示没有执行 CUDA 代码的时间。由于算法中的每个外部时间步长对应于处理单个 80 毫秒的输入帧,因此运行 1.5 到 4.3 毫秒的速度慢得令人无法接受。

在图 3 的 CUDA 硬件行中,非蓝色区域表示何时未执行 CUDA 代码(GPU 处于空闲状态)。

Screenshot illustrating low GPU utilization during RNN-T greedy decoding as captured with NVIDIA Nsight Systems performance analysis tool.
图 3. RNN-T 贪婪解码期间的低 GPU 利用率,如 Nsight Systems 所示。

通过 CUDA 图形条件节点中的动态控制流消除低计算强度

传统上,CUDA 图形用于消除内核启动开销。然而,它们不支持动态控制流,例如 if-else 循环,使得它们不适合直接用于贪婪解码。 CUDA 工具包 12.4 引入了 CUDA 图形条件节点 ,可启用动态控制流。

我们使用这些节点对 RNN-T 和 TDT 模型实施贪婪解码,有效消除了以下文件中的所有内核启动开销:

后两个文件实现了贪婪解码的标签循环变体,这将在下一节中讨论。

有关该问题和我们的解决方案的详细说明,请参阅我们的论文 《Speed of Light Exact Greedy Decoding for RNN-T Speech Recognition Models on GPU》。此外,我们还 向 PyTorch 提交了一个拉取请求 ,以支持在纯 PyTorch 中使用其新的 torch.condtorch.while_loop 控制流 API 的条件节点,而无需与 CUDA API 进行任何直接交互。

RNN-T 和 TDT 预测网络的差异 

执行批量 RNN-T 和 TDT 推理的一个重要问题是 vanilla 贪婪搜索算法的分歧。这种分歧会导致一些输入进展缓慢,而另一些则停滞不前,从而导致在使用更大批量大小时增加延迟。因此,许多实现选择批量大小为 1 的推理来避免此问题。但是,使用批量大小为 1 会导致硬件利用率不充分,这既低效又不经济。

常用于传感器解码的传统解码算法(图 4)采用了嵌套循环设计:

  • 外循环:对帧(编码器输出)进行迭代。
  • 内循环:逐个检索标签,直到遇到特殊的空白符号。

对于每个非空白符号,应更新自回归预测网络的隐藏状态和输出。在批量推理期间,内循环可以为批量中的不同发音生成不同数量的标签。因此,对于每帧,预测网络的调用次数由所有发音的非空白标签的最大数量决定,这是次优的。

图 4 展示了传统帧循环解码算法的示例,该算法分批处理两个词,每个词 4 帧,并进行 CAT 和 DOG 转录。∅ 表示批量解码中不必要的计算。

Conventional frame-looping decoding algorithm example with 2 utterances in a batch, 4 frames each, and “CAT” and “DOG” transcriptions. There is 6 unnecessary computations in batched decoding, denoted with ∅.
图 4. 常规帧循环解码算法示例。

使用高效的新解码算法解决分歧

为了解决传统的帧循环解码算法问题,我们推出了一个新的标签循环算法 ,该算法仍使用嵌套循环,但区别在于循环的角色发生了交换(图 5)。

  • 外循环:在标签上迭代,直到所有帧都已解码。
  • 内循环:对帧进行迭代,识别批处理中每个语句的下一帧,其标签为非空白。这是通过推进指向当前编码器帧的索引来完成的,这些索引因批处理中每个语句而有所不同。

图 5 展示了新的标签循环解码算法的示例,该算法分批处理两个语句,每个语句 4 帧,CAT 和 DOG 转录。∅ 表示批量解码中不必要的计算。

New Label-looping decoding algorithm example with 2 utterances in a batch, 4 frames each, and “CAT” and “DOG” transcriptions. There is 2 unnecessary computations in batched decoding, denoted with ∅.
图 5. 新的标签循环解码算法示例

在这种方法中,我们会在外循环的每个步骤上以尽可能大的批量大小评估预测网络。这种评估的数量恰好是所有句子中最长转录的长度(以令牌数量表示),这使其成为所需评估的最小数量。内循环仅使用联合网络执行操作。为了提高效率,我们在此过程的早期应用了编码器和预测网络投影,从而最大限度地减少了昂贵的重新计算需求。

这种批量标签循环算法显著提高了 RNN-T 和 TDT 网络的效率,即使使用纯 PyTorch 代码执行时无需额外的 GPU 特定优化,也能实现更快的解码速度。

性能提升速度提升高达 10 倍,成本效益提升高达 4.5 倍

标签循环和 CUDA 图形使传感器模型的逆实时系数(即 RTFx(生成音频的持续时间/计算时间;越高越好)比以往更接近 CTC 模型。这种影响在较小的模型中尤为明显,在这些模型中,减少内核启动开销(尤其是在涉及预测网络权重和输入张量等小数据大小的操作中)会带来更大的性能提升。此外,得益于新实施的向量化特征归一化解码实现,CTC 模型的速度有了显著提高。

在搭载 NeMo 2.0.0 NVIDIA NeMo ASR 型号中,所有这些速度提升高达 10 倍(图 1),可提供快速且经济高效的 CPU 替代方案。

为了更好地说明基于 ASR GPU 的推理的优势,我们估算了使用 CPU 和 AWS 等云平台上常见的 NVIDIA GPU 转录 100 万小时语音的成本,重点是计算优化的实例。在此比较中,我们使用了 NVIDIA Parakeet RNN-T 1.1B 模型。

  • 基于 CPU 的估计: 对于 CPU 估计,我们在单个固定的 CPU 核心上运行批量大小为 1 的 NeMo ASR。这是一种常见的行业实践方法,允许跨多个核心进行线性扩展,同时保持恒定的 RTFx。我们选择了测量 RTFx 为 4.5 的 AMD EPYC 9454 CPU,可通过 Amazon EC2 C7a 计算优化实例获得。
  • 基于 GPU 的估算: 对于 GPU 我们使用了 Hugging Face Open ASR 排行榜的结果,该排行榜在 NVIDIA A100 80GB 上运行。等效的 AWS 实例为 p4de.24xlarge,配备 8 个 NVIDIA A100 80GB GPU。
  • 成本计算:为了计算 CPU 和 GPU 的总成本,我们:
    • 将 100 万小时的语音除以相应的 RTFx。
    • 四舍五入到最近的一个小时。
    • 将结果乘以每小时实例成本。

如表 1 所示,从 CPU 切换到 GPU 进行 RNN-T 推理可节省高达 4.5 倍的成本。

CPU/GPU AWS 实例 每小时成本 vCPU/GPU 数量 每个实例的流数量* RTFx
(单台)
总计 RTFx 转录 100 万小时的成本
第四代 AMD Epyc C7a.48 xlarge 9.85 美元 192 192 4.5 864 11410 美元
NVIDIA A100 80GB P4de.24 xlarge 40.97 美元 8 512 2053 16425 2499 美元
表 1. 对于转录 1,000,000 小时的语音,NVIDIA Parakeet RNNT 1.1B 模型在 GPU 上运行比在 CPU 上运行节省了高达 4.5 倍的时间。定价适用于截至 2024 年 8 月 14 日的按需 AWS 实例。

*GPU 的 CPU 或全局批量大小

借助 NVIDIA ASR 加速转录 

NVIDIA NeMo 可将 ASR 模型的性能提升高达 10 倍,在 Hugging Face Open ASR 排行榜上名列前茅。这一速度飞跃由自动投射到 bfloat16 的张量、标签循环算法和 CUDA Graphs 优化等创新提供动力支持。

这些加速性能还可显著节省成本。例如,与基于 CPU 的替代方案相比,基于 NVIDIA A100 的 NeMo GPU 驱动的推理在转录 100 万小时语音时可节省高达 4.5 倍的成本。

持续优化 NVIDIA Canary 1B 和 Whisper 等模型的努力将进一步降低运行注意力编码器 – 解码器和基于语音 LLM 的 ASR 模型的成本。NVIDIA 还在改进其 CUDA Graphs 条件节点,并将其与编译器框架 TorchInductor 集成,这将进一步加快 GPU 运行速度并提高效率。有关更多详情,请 查看我们的拉取请求,获取 PyTorch 中的条件节点支持

我们还发布了更小的 Parakeet 混合传感器-ctc 模型, Parakeet TDT CTC 10M ,可实现约 4,300 的 RTFx,并将 HF ASR 排行榜测试集的平均 WER 准确度提高到 7.5,进一步扩展了 NeMo ASR 的功能。

探索 NVIDIA NIM,用于语音和翻译 ,以更快、更具成本效益地将多语种转录和翻译集成到在云端、数据中心或工作站上运行的生产应用中。

 

Tags