使用 Amazon SageMaker 提高 Falcon 模型的性能 | 亚马逊网络服务

使用 Amazon SageMaker 提高 Falcon 模型的性能 | 亚马逊网络服务

用于托管文本生成 AI 应用程序的大型语言模型 (LLM) 的最佳框架和配置是什么? 尽管为法学硕士提供丰富的选择,但由于模型的规模、不同的模型架构、应用程序的性能要求等,这是一个很难回答的问题。 这 亚马逊SageMaker 大型模型推理 (LMI) 容器 通过汇集大量不同的框架和技术来优化法学硕士的部署,使为法学硕士提供服务变得简单。 LMI 容器有一个强大的服务堆栈,称为 DJL 服务 这与底层的法学硕士是不可知的。 它提供了系统级配置参数,可以调整这些参数来为给定的 LLM 提取托管基础设施的最佳性能。 它还支持最近的优化,例如连续批处理(也称为迭代批处理或滚动批处理),这可显着提高吞吐量。

在一个早期 发表,我们展示了如何使用 LMI 容器在 SageMaker 上部署 Falcon 系列模型。 在这篇文章中,我们演示了如何使用连续批处理等技术来提高 Falcon-40B 服务的吞吐量和延迟。 我们还提供对 SageMaker LMI 容器提供的配置参数的直观理解,可以帮助您找到适合实际应用程序的最佳配置。

法学硕士文本生成推理的基础知识

让我们首先看一下关于如何为法学硕士执行文本生成推理的一些基础知识。

前向传递、激活和 KV 缓存

给定令牌的输入序列,它们在 forward pass 跨越 LLM 的所有层(如 Falcon)来生成下一个令牌。 A forward pass 是指输入数据通过神经网络产生输出的过程。 在文本生成的情况下,前向传播涉及将初始种子或上下文输入到语言模型中,并生成序列中的下一个字符或标记。 为了生成文本序列,该过程通常是迭代完成的,这意味着输出序列中的每个步骤或位置都会重复该过程。 在每次迭代中,模型都会生成下一个字符或标记,该字符或标记将成为生成文本的一部分,并且此过程将持续下去,直到生成所需长度的文本。

使用 Falcon 或 GPT 等语言模型生成文本 autoregressive。 这意味着模型一次生成一个令牌,同时以之前生成的令牌为条件。 换句话说,在每次迭代中,模型将先前生成的文本作为输入,并根据该上下文预测下一个标记。 正如中提到的 vLLM:通过 PagedAttention 轻松、快速且廉价地提供 LLM 服务,在这个自回归解码过程中,LLM 的所有输入标记都会产生它们的注意键和值张量,并且这些张量被保存在 GPU 内存中以生成下一个标记。 这些缓存的键和值张量通常称为 KV cache.

预填充和解码阶段

在自回归解码过程中,就像使用 Falcon 等语言模型生成文本时使用的过程一样,通常有两个主要阶段: prefill 相和 decode 阶段。 这些阶段对于生成连贯且上下文相关的文本至关重要。

预填充阶段包括以下内容:

  • 初始背景 – 预填充阶段从用户提供的初始上下文或种子文本开始。 这个初始上下文可以是一个句子、一个短语,甚至只是一个单词。 它为文本生成设定了起点,并为接下来的内容提供了上下文。
  • 模型调理 – 提供的上下文用于调节语言模型。 该模型将此上下文作为输入,并根据对上下文的理解生成序列中的下一个标记(单词或字符)。
  • 代币生成 – 模型一次生成一个标记,预测文本中接下来应该出现的内容。 该标记被附加到上下文中,有效地扩展了它。
  • 迭代过程 – 迭代重复生成代币的过程。 在每个步骤中,模型都会在考虑更新的上下文的同时生成一个令牌,其中现在包含先前步骤中生成的令牌。

预填充阶段持续到满足预定的停止条件为止。 此条件可以是生成的文本的最大长度、表示文本结束的特定标记或用户或应用程序设置的任何其他标准。

解码阶段包括以下内容:

  • 完成 – 在预填充阶段之后,您将得到部分生成的文本,该文本可能不完整或在某些时候被切断。 解码阶段负责完成文本,使其连贯且语法正确。
  • 从最后一个标记继续 – 在解码阶段,模型从预填充阶段生成的最后一个令牌开始。 它使用此标记作为初始上下文并生成下一个标记以继续文本。
  • 迭代完成 – 与预填充阶段一样,生成令牌的过程再次迭代。 该模型一次生成一个标记,以序列中前面的标记为条件。
  • 停止条件 – 解码阶段也有一个停止条件,这可能与预填充阶段相同,例如达到最大长度或遇到文本结束标记。 当满足这个条件时,生成过程停止。

预填充和解码阶段的组合允许自回归模型生成基于初始上下文的文本,并生成连贯的、上下文相关的和上下文一致的文本序列。

请参阅 基于变压器的生成模型的分布式服务系统 有关该过程的详细说明。

使用动态批处理优化吞吐量

到目前为止,我们只讨论了单个输入。 在实践中,我们期望同时或以交错方式处理来自应用程序客户端随机传入的多个请求以进行推理。 传统方式中,可以使用基本批处理来提高吞吐量和GPU计算资源的利用率。 批处理是有效地将多个请求的数字表示组合在一批中,并执行自回归前向传递的并行运行。 这种智能批处理是在服务端完成的。 通过在 服务.properties:

这基本上表明 DJLServing 会将请求一次排队 100 毫秒,或者如果排队的请求数量达到指定的 batch_size,则该批次将被安排运行到后端进行推理。 这被称为 dynamic batching。 它是动态的,因为批量大小可能会根据在该时间内添加的请求数量而在不同批次之间发生变化。 但是,由于请求可能具有不同的特征(例如,某些请求的形状可能是 20 个输入令牌和 500 个输出令牌,而其他请求可能是相反的,具有 500 个输入令牌但只有 20 个输出令牌),因此某些请求可能会比同批次的其他公司更快地完成处理。 这可能会导致在等待批处理中的所有正在进行的请求完成其解码阶段时 GPU 的利用率不足,即使队列中还有其他请求等待处理。 下图说明了此过程。

简单的动态批处理视觉

动态批处理视觉 - 注意请求 2 和 3 末尾的空闲窗口

使用连续批处理优化吞吐量

continuous batching,也被称为 iterative or rolling 批处理时,我们利用预填充和解码阶段之间的差异。 为了激活连续批处理,DJServing 根据serving.properties 提供以下附加配置:

  • 发动机=MPI – 我们鼓励您使用 MPI 引擎进行连续批处理。
  • 选项.rolling_batch=auto 或 lmi-dist – 我们建议使用 auto,因为它会自动选择最合适的滚动批处理算法以及将来的其他优化。
  • option.max_rolling_batch_size=32 – 这限制了并发请求的数量。 默认值为 32。

通过连续批处理,服务堆栈 (DJLServing) 不会等待批处理中的所有正在进行的请求完成其解码阶段。 相反,在逻辑中断处(在解码阶段的一次迭代结束时),它会拉入在队列中等待的其他请求,同时当前批次仍在处理中(因此名称 滚动批次)。 它在解码阶段的每次迭代结束时检查待处理的请求。 请记住,对于每个请求,我们需要运行预填充阶段,然后运行顺序解码阶段。 因为我们可以在预填充阶段并行处理请求初始提示中的所有令牌,所以每当拉入新请求时,我们都会暂时暂停该批处理中正在进行的请求的解码阶段 - 我们暂时保存其 KV 缓存并在内存中激活并运行新请求的预填充阶段。

该缓存的大小可以使用以下选项进行配置:

预填充完成后,我们将新请求和旧的暂停请求合并到新的滚动批次中,这可以并行进行解码阶段。 请注意,旧的暂停请求可以从中断处继续其解码阶段,而新请求将从第一个新令牌开始。

连续或迭代批处理视觉

连续或迭代批处理视觉效果 - 请注意,空闲时间已替换为后续请求

您可能已经意识到,连续批处理是一种几乎类似于我们在日常生活中自然并行任务的方法。 我们有随机传入的消息、电子邮件、电话通知(可能是新请求)(类似于 GPU 以随机交错方式传入的多个请求)。 这一切都是在我们完成飞行任务时发生的——撰写电子邮件、编码、参加会议(类似于 GPU 中当前处理的任务)。 在逻辑中断时,我们暂停正在进行的任务并检查通知以确定我们是否需要执行某些操作,如果有,我们将其添加到正在进行的任务(现实生活中的滚动批处理)中,或者将其放入待办事项列表(队列)中。

综合起来:如何考虑 GPU 的内存利用率

建议对您的模型进行负载测试,以了解哪种配置对于您的业务用例来说最具成本效益。 为了加深理解,我们来可视化加载模型以及滚动批量处理连续请求时 GPU 的内存占用情况。 对于本文,我们假设我们将 Falcon-40B 模型加载到安装有 NVIDIA A5G GPU(每个实例具有 10 GB 内存)的 G24 实例类型实例之一上。 请注意,类似的理解适用于 V3、A4 和 H5 GPU 系列附带的 p100、p100 和 p100 实例类型。

以下是获取服务 Falcon-40B 所需总内存近似值的概述:

  • �ͺųߴ� = 模型参数数量(Falcon-40B 为 40 亿)x 每个参数 4 字节(FP32)= 160 GB
  • 加载 Falcon-40B 进行推理所需的大约总内存 = 模型大小 (=160 GB) + KV 缓存(注意力缓存)(=*20 GB) + ML 框架的额外内存开销(大约 2 GB)
记忆视觉

内存视觉 - 了解加载的 Falcon-40B 模型的内存占用

对于 Falcon-40B,如果我们通过将模型量化为 bfloat16(2 字节)数据类型来压缩模型,则模型大小约为 80 GB。 正如你所看到的,这仍然大于一个加速器设备支持的内存,因此我们需要采用一种具有特殊特性的模型分区(分片)技术 张量并行 (TP) 在多个加速器设备上方法和分片模型。 假设我们选择了 g5.24xlarge,它有 4 个 A10G GPU 设备。 如果我们使用以下内容配置 DJLServing (serving.properties),则可以预期 80 GB 的模型权重将平均分配给所有 4 个 GPU:

tensor_parallel_degree 设置为 4 时,即使在处理单个请求之前,20 GB GPU 内存中的约 24 GB(约 84%)也已被使用。 剩余 16% 的 GPU 将用于传入请求的 KV 缓存。 对于您的业务场景及其延迟和吞吐量要求,2-3 GB 的剩余内存可能就足够了。 如果没有,您可以将实例大小增加到 g5.48xlarge,它有 8 个 GPU,并使用设置为 8 的tensor_parallel_ Degree。在这种情况下,每个 GPU 的 10 GB 可用内存中只有大约 24 GB 用于模型权重,我们大约有 60% 的剩余 GPU 用于激活和 KV 缓存。 直观上我们可以看到这种配置可能会让我们拥有更高的吞吐量。 此外,因为我们现在有更大的缓冲区,所以我们可以增加 max_rolling_batch_prefill_tokens最大滚动批量大小 参数以进一步优化吞吐量。 这两个参数将共同控制模型的激活预填充和 KV 缓存的预分配。 假设 GPU 内存中的 KV 缓存有足够的缓冲区,这两个参数的数字越大,吞吐量越大。

使用 PagedAttention 进行连续批处理

PagedAttention是加州大学伯克利分校开发的一种新的优化算法,通过在固定大小的页面或块中分配内存,允许注意力缓存(KV缓存)不连续,从而改进连续批处理过程。 这是受到操作系统使用的虚拟内存和分页概念的启发。

按照 法学硕士 在论文中,每个令牌序列的注意力缓存被划分为块,并通过块表映射到物理块。 在计算注意力期间,PagedAttention 内核可以使用块表来有效地从物理内存中获取块。 这会显着减少内存浪费,并允许更大的批量大小、更高的 GPU 利用率和更高的吞吐量。

性能比较

为了确保部署配置的有效负载测试,建议首先考虑业务场景并明确定义基于 LLM 的应用程序的输入和输出特征。 例如,如果您正在处理呼叫中心摘要用例,输入可能包含较大的文本,例如客户服务代理和客户之间的 500 个令牌的聊天记录,但输出可能相对较小,大约 100 个标记,代表转录本的摘要。 另一方面,如果您正在处理代码生成场景,输入可能短至 15 个标记,例如“用 Python 编写一个高效的实现来描述所有 EC2 资源,包括分页”,但输出可能会很多更大,达到 500 个代币。 同样重要的是要考虑实现较低延迟或最大化吞吐量是否是特定场景的首要任务。

全面了解业务场景后,您可以分析并确定适合您的托管环境的最佳配置。 在这种情况下,托管环境包含各种关键元素,包括实例类型和其他配置参数,例如 张量平行度, 最大滚动批量大小, max_rolling_batch_prefill_tokens, 和更多。 我们的目标是确定最有效的设置来支持我们的响应时间、吞吐量和模型输出质量要求。

在我们的分析中,我们对性能进行了基准测试,以说明连续批处理相对于传统动态批处理的优势。 我们使用 SageMaker 上的 LMI 容器,在serving.properties 中使用下表中详细介绍的配置进行动态批处理和迭代批处理。

动态配料 连续配料 使用 PagedAttention 进行连续批处理

引擎=Python

option.model_id=tiiuae/falcon-40b

选项.tensor_parallel_ Degree = 8

选项.dtype=fp16

批量大小=4

最大批量延迟=100

option.trust_remote_code = true

引擎=MPI

选项.model_id = {{s3_url}}

option.trust_remote_code = true

选项.tensor_parallel_ Degree = 8

选项.max_rolling_batch_size = 32

option.rolling_batch = auto

选项.dtype = fp16

选项.max_rolling_batch_prefill_tokens = 1024

选项.paged_attention = False

引擎=MPI

选项.model_id = {{s3_url}}

option.trust_remote_code = true

选项.tensor_parallel_ Degree = 8

选项.max_rolling_batch_size = 32

option.rolling_batch = auto

选项.dtype = fp16

选项.max_rolling_batch_prefill_tokens = 1024

选项.paged_attention = True

这两种配置针对 Falcon-40B 进行了基准测试,FP16 数据类型部署在 ml.g5.48xlarge 上,在代表实际应用程序的几个不同场景中:

  • 少量输入令牌生成大量令牌 – 在这种情况下,输入令牌的数量固定为 32,并生成 128 个新令牌
批处理策略 吞吐量(令牌/秒) 延迟 p90(秒)
动态配料 5.53 58.34
连续配料 56.04 4.74
使用 PagedAttention 进行连续批处理 59.18 4.76
  • 生成少量令牌的大量输入 – 这里,我们将输入token的数量固定为256,并提示LLM将输入汇总为32个token
批处理策略 吞吐量(令牌/秒) 延迟 p90(秒)
动态配料 19.96 59.31
连续配料 46.69 3.88
使用 PagedAttention 进行连续批处理 44.75 2.67

我们可以看到,与使用 LMI 容器时在 SageMaker 上使用动态批处理相比,使用 PagedAttention 进行连续批处理在场景 10 中将吞吐量提高了 1 倍,在场景 2.3 中提高了 2 倍。

结论

在这篇文章中,我们研究了 LLM 如何使用内存,并解释了连续批处理如何使用 SageMaker 上的 LMI 容器提高吞吐量。 我们通过显示基准测试结果,展示了在 SageMaker 上使用 LMI 容器对 Falcon-40B 进行连续批处理的优势。 您可以在以下位置找到代码 GitHub回购.


作者简介

阿比吉安·希瓦蒂亚阿比希瓦蒂亚 是 AWS 的高级解决方案架构师,与战略性全球企业组织合作,促进 AWS 服务在人工智能、分布式计算、网络和存储等领域的采用。 他的专长在于自然语言处理 (NLP) 和计算机视觉领域的深度学习。 Abhi 协助客户在 AWS 生态系统中高效部署高性能机器学习模型。

使用 Amazon SageMaker 提高 Falcon 模型的性能 |亚马逊网络服务柏拉图区块链数据智能。垂直搜索。人工智能。达瓦尔·帕特尔 是 AWS 的首席机器学习架构师。 他曾与从大型企业到中型初创公司的组织合作,解决与分布式计算和人工智能相关的问题。 他专注于深度学习,包括 NLP 和计算机视觉领域。 他帮助客户在 SageMaker 上实现高性能模型推理。

使用 Amazon SageMaker 提高 Falcon 模型的性能 |亚马逊网络服务柏拉图区块链数据智能。垂直搜索。人工智能。皮纳克帕尼格拉希 与客户合作构建机器学习驱动的解决方案,以解决 AWS 上的战略业务问题。 当不忙于机器学习时,他会去远足、读书或观看体育比赛。

使用 Amazon SageMaker 提高 Falcon 模型的性能 |亚马逊网络服务柏拉图区块链数据智能。垂直搜索。人工智能。阿比索达尼 担任 AWS 高级 AI/ML 解决方案架构师,专门为客户提供有关生成式 AI 和 ML 解决方案的技术专业知识和指导。 他的主要工作重点是协助数字原生企业充分发挥生成式人工智能和机器学习技术的潜力,使他们能够有效地实现其业务目标。 除了他的专业努力之外,阿比还对阅读等智力追求以及参与瑜伽、冥想等促进身心健康的活动表现出强烈的热情。

使用 Amazon SageMaker 提高 Falcon 模型的性能 |亚马逊网络服务柏拉图区块链数据智能。垂直搜索。人工智能。青岚 是 AWS 的一名软件开发工程师。 他一直在亚马逊开发几个具有挑战性的产品,包括高性能 ML 推理解决方案和高性能日志记录系统。 清的团队以极低的延迟成功推出了亚马逊广告中的第一个十亿参数模型。 青对基础设施优化和深度学习加速有深入的了解。

时间戳记:

更多来自 AWS机器学习