亚马逊AWS官方博客
在 Amazon Inferentia 上为 PyTorch 自然语言处理应用程序实现12 倍的吞吐量和低延迟
Snap、Alexa 和 Autodesk 等 Amazon Web Services 客户一直在使用 Amazon Inferentia 部署各种机器学习 (ML) 模型以实现高性能和低成本。自然语言处理 (NLP) 模型在实时和离线批处理使用案例中越来越受欢迎。我们的客户在许多应用程序中部署这些模型,例如聊天机器人、搜索、排名、文档摘要和自然语言理解。借助 Amazon Inferentia,您还可以在开源 NLP 模型上实现开箱即用的高性能和低成本,而无需进行自定义。
在本文中,您将了解如何在低延迟需求下最大限度地提高实时应用程序和批处理的吞吐量,而高吞吐量和低成本是 Amazon Inferentia 的关键性能目标。在本文中,我们使用 HuggingFace Transformers 预训练的 BERT Base模型,不需要对模型进行任何修改,并且在 PyTorch 框架级别只更改一行代码即可使用 Amazon Inferentia。与在 GPU 上部署的相同模型相比,该解决方案在 Amazon Inferentia 上以低 70% 的成本实现了 12 倍的吞吐量。
为了最大限度地提高 Hugging Face 模型在 Amazon Inferentia 上的推理性能,您可以使用 Amazon Neuron PyTorch 框架进行集成。Neuron 是一款软件开发工具包 (SDK),它与常见的机器学习框架(如 TensorFlow 和 PyTorch)集成,从而扩展了框架的 API,从而使您能够在 Amazon EC2 Inf1 实例上轻松且经济高效地运行高性能推理。只需最少的代码更改,您就可以编译和优化已经训练好的模型,以便在 Amazon Inferentia 上运行。Neuron 团队在不断地发布具有新功能和模型性能改进的更新。1.13 版本发布后,基于 Transformer 的模型性能又提高了 10%–15%,以达到更小延迟和更大吞吐量,即使对于更大的 NLP 工作负载也是如此。
要自行测试 Neuron 开发工具包功能,请查看最新的适用于 PyTorch 的利用 Neuron 功能教程。
NeuronCore 管道模式说明
通过 Inf1 实例系列提供的每个 Amazon Inferentia 芯片包含四个 NeuronCore。不同的实例类型将分别提供1 到 16 个 AWS Inferentia芯片,在最大的实例类型 (inf1.24xlarge) 上可提供 64 个 NeuronCore。NeuronCore 是运行神经网络 (NN) 图操作的计算单位。
当您编译没有管道模式的模型时,Neuron 编译器会优化所支持的 NN operation以在单一 NeuronCore 上运行。您可以将 NeuronCores 合并到一个组中,甚至跨 Amazon Inferentia 芯片进行组合,以运行编译后的模型。利用此配置,您可以在数据并行模式中跨 Amazon Inferentia 芯片使用多个 NeuronCore。这意味着,即使在最小的实例类型上,也可以有四个模型同时处于活动状态。在大多数情况下,四个(或更多)模型的数据并行推理可提供更高吞吐量和更低成本。这种性能提升对延迟的影响最小,因为 AWS Inferentia 经过优化,可以最大限度地提高较小的批处理大小的吞吐量。
在管道模式下,Neuron 编译器可以完全自动的跨多个NeuronCore 以实现神经网络图的分区和放置。它允许高效地使用硬件,因为管道中的 NeuronCore 运行流式推理请求,并借助读取速度更快的芯上缓存来保存模型权重。管道中的其中一个核心处理完成第一个请求后,它可以开始处理后续请求,而无需等待最后一个核心完成第一个请求的处理。即使在实时应用程序(例如批处理大小 1)上运行小型批处理大小的推断,这种流式管道推理也会提高每个核心硬件的利用率。
找到适合单个大模型的最佳 NeuronCore 数量是一个实践的过程。使用以下近似公式是一个良好的开端,但我们建议尝试多种配置以实现最佳部署:
neuronCore_pipeline_cores = 4*round(number-of-weights-in-model/(2E7))
通过指定编译中neuroncore-pipeline-cores 的值来明确最终模型管道模式下使用的 NeuronCore的数量,要启用此功能,请将此参数添加到您所需的框架的常用编译流。
在 TensorFlow Neuron 中,使用以下代码:
在 PyTorch Neuron 中,使用以下代码:
关于 NeuronCore 管道和其他 Neuron 功能的更多信息,请参阅 Neuron 功能。
在 Amazon Inferentia 中运行 HuggingFace 问答模型
要在 Amazon Inferentia 上运行 Hugging Face BertForQuestionAnswering 模型,除了导入 torch_neuron 框架之外,您只需在常用的 Transformer 实施中添加一行额外的代码。您可以参考如下 示例:
前述代码中额外的一行是调用 torch.neuron.trace() 方法。此调用将编译模型并返回一个新的 neuron_model() 方法,您可以使用该方法对原始输入运行推理,如脚本最后一行所示。如果您想测试此示例,请参阅 PyTorch Hugging Face 预训练 BERT 教程。
能够编译和运行推理是优化生产中部署的模型第一步。与 GPU部署方案(我们将在本文后面讨论)相比,已经可以将性能提高两倍,成本降低 70%。当您结合 NeuronCore 组和管道功能时,您可以探索在单个 Inf1 实例中打包模型的更多其他方式。
使用 NeuronCore 组和管道优化模型部署
HuggingFace 问答模型的部署需要设置一些模型的参数。Neuron 是一个预先 (AOT) 编译器,它需要在编译时了解张量形状。为此,我们为模型部署定义了批处理大小和序列长度。在前面的示例中,Neuron 框架从传递的输入中推断出这些:(inputs[‘input_ids’], inputs[‘attention_mask’])。
除了这两个模型参数之外,您可以设置编译参数 ‘–neuroncore-pipeline-cores’ 和环境变量 ‘NEURONCORE_GROUP_SIZES‘ 来微调您的模型服务器在 Amazon Inferentia 芯片上使用 NeuronCore 的方式。
例如,为了最大限度提高在单个 Amazon Inferentia 芯片上处理推理请求的并发工作线程数量(四个核心),您将 NEURONCORE_GROUP_SIZES=”1,1,1,1” 以及添加编译参数‘–neuroncore-pipeline-cores’ 并设置为 1。下图描述了这种拆分。它是一个完整的数据并行部署。
为了实现最低延迟,您可以将 ‘–neuroncore-pipeline-cores’ 设置为 4 并设置 NEURONCORE_GROUP_SIZES=”4”,以便使单个模型同时使用全部四个 NeuronCore。Amazon Inferentia 芯片可以将四个推理请求作为一个流并发处理。模型管道并行部署如下图所示。
数据并行部署通过由多个工作线程并发处理请求来提高吞吐量。并行管道模式有利于降低延迟,并可以因流处理行为而提高吞吐量。借助这两个额外的参数,您可以根据场景需求调整这两个参数值。
优化以实现最小延迟:多核管道并行
考虑使用需要低延迟的应用程序,例如 序列分类作为在线聊天机器人工作流程的一部分。当用户提交文本时,运行在后端的模型会对单个用户输入的意图进行分类,并尽可能的快速完成推理。模型很可能必须对单个输入(批处理大小 1)请求提供响应。
下表比较了 Inf1 实例与优化的 GPU 实例系列 g4dn.xlarge 在云中进行推理时的性能和成本,同时在数据并行与管道并行配置和批处理大小 1 中运行 HuggingFace BERT base模型。对比延迟指标的第 95 个百分位数 (p95), 在 4 核 inf1.xlarge 和 16 核 inf1.6xlarge 实例中,我们在管道模式下获取的值更低。Inf1 实例之间的最佳配置是 16 核的情况,其中延迟降低 58%,达到了 6 毫秒。
实例 | 批处理大小 | 推理模式 | NC 管道核心 | 吞吐量 [句/秒] | 延迟 p95 [秒] | 每 100 万次推理的成本 | 吞吐量比率 [inf1/g4dn] | 成本比率 [inf1/g4dn] |
inf1.xlarge | 1 | 数据并行 | 1 | 245 | 0.0165 | 0.42 USD | 1.6 | 43% |
inf1.xlarge | 1 | 管道并行 | 4 | 291 | 0.0138 | 0.35 USD | 2.0 | 36% |
inf1.6xlarge | 1 | 数据并行 | 1 | 974 | 0.0166 | 0.54 USD | 6.5 | 55% |
inf1.6xlarge | 1 | 管道并行 | 16 | 1793 | 0.0069 | 0.30 USD | 12.0 | 30% |
g4dn.xlarge | 1 | – | – | 149 | 0.0082 | 0.98 USD |
测试的模型是PyTorch 版本的 HuggingFace bert-base-uncase ,其序列长度为 128。在 Amazon Inferentia 上,我们编译模型以使用所有可用的核心并且并行运行整个管道。对于数据并行情况,我们为单个核心编译模型,并配置 NeuronCore 组以为每个核心运行工作线程模型。GPU 部署使用了与 AWS Inferentia 相同的设置,模型在其中使用 TorchScript JIT 进行跟踪,并使用 PyTorch AMP Autocast 强制转换为混合精度。
在 Amazon Inferentia 上使用管道模式时,吞吐量也会提高 1.84 倍,从而达到每秒 1793 句,这是 g4dn.xlarge 吞吐量的 12 倍。比起最经济高效的 GPU 选项,使用inf1.6xlarge可以获得更加经济高效的方式,即使每小时成本更高。根据 Amazon Elastic Compute Cloud (Amazon EC2) 按需实例定价,每百万句的成本降低了 70%。对于无法利用 inf1.6xlarge 的全部吞吐量的延迟敏感型应用程序,或者对于 BERT Small 之类的更小模型,我们建议在 inf1.xlarge 上使用管道模式以实现经济高效的部署。
优化以实现最大吞吐量:单核数据并行
一个需要在低延迟的基础上尽可能提高吞吐量的 NLP 使用案例是抽取式问答任务,它属于搜索和文档检索管道的一部分。在这种情况下,增加并行处理的文档部分的数量可以加快搜索结果或提高搜索答案的质量和广度。在这种设置中,推理更有可能批处理运行(批处理大小大于 1)。
为了实现最大吞吐量,我们通过实验发现,对于之前测试的相同模型,Amazon Inferentia 上的最佳批处理大小为 6。在 g4dn.xlarge 上,我们运行了批处理 64(避免显存溢出的前提下)。以下结果有助于显示与 GPU 相比,批处理大小 6 如何在 inf1.6xlarge 上以低 61% 的成本提供 9.2 倍的吞吐量。
实例 | 批处理大小 | 推理模式 | NC 管道核心 | 吞吐量 [句/秒] | 延迟 p95 [秒] | 每 100 万次推理的成本 | 吞吐量比率 [inf1/g4dn] | 成本比率 [inf1/g4dn] |
inf1.xlarge | 6 | 数据并行 | 1 | 985 | 0.0249 | 0.10 USD | 2.3 | 30% |
inf1.xlarge | 6 | 管道并行 | 4 | 945 | 0.0259 | 0.11 USD | 2.2 | 31% |
inf1.6xlarge | 6 | 数据并行 | 1 | 3880 | 0.0258 | 0.14 USD | 9.2 | 39% |
inf1.6xlarge | 6 | 管道并行 | 16 | 2302 | 0.0310 | 0.23 USD | 5.5 | 66% |
g4dn.xlarge | 64 | – | – | 422 | 0.1533 | 0.35 USD |
在此应用程序中,成本因素还会影响最终的服务架构设计。运行批处理推理的最经济高效的方法是使用 inf1.xlarge 实例。它的吞吐量比 GPU 替代产品高 2.3 倍,成本低 70%。在 inf1.xlarge 与 inf1.6xlarge 之间进行选择仅取决于主要目的:追求更低成本还是更高吞吐量。
要自行测试 NeuronCore 管道和组功能,请查看最新的适用于 PyTorch 的利用 Neuron 功能教程。
结论
在本文中,我们使用 NeuronCore 组和管道功能探索了优化 NLP 模型部署的方式。Amazon Neuron 开发工具包与 PyTorch 的原生集成使您可以编译和优化 HuggingFace Transformers 模型,从而以最小的代码更改在 AWS Inferentia 上运行。通过将部署架构调整为管道并行,BERT 模型实现了实时应用程序的更低延迟,其吞吐量比 g4dn.xlarge解决方案高 12 倍,同时运行成本降低了 70%。对于批处理推理,我们的吞吐量提高了 9.2 倍,成本降低了 60%。
本文中描述的 Neuron 开发工具包功能也适用于其他 ML 模型类型和框架。有关更多信息,请参阅 Amazon Neuron 文档。