分享主题为:使用 OpenLLM 快速构建和部署大语言模型的应用。OpenLLM 是一个开源的大语言模型(LLM)开发框架。它支持多种开源的 LLM 模型,并且具有内建的两个关键的 LLM 优化,能够优化内存使用。此外,它与 LangChain 和 BentoML 都有很好的集成,可以快速地构建和部署大语言模型的应用。
今天的分享会围绕下面五点展开:
1. BentoML 公司简介
2. OpenLLM 产品背景
3. OpenLLM 介绍、应用举例与使用优势
4. BentoML 介绍与应用举例
5. OpenLLM 总结
分享嘉宾|明希 BentoML 高级软件工程师
编辑整理|张阳
内容校对|李瑶
出品社区|DataFun
BentoML专注于提供机器学习基础设施。核心产品是与公司同名的开源框架BentoML。公司总部位于旧金山湾区,在国内也有众多远程工作的同事。通过不断努力,公司获得了众多客户的认可。
首先来分享一下我们开发 OpenLLM 的背景。
1. LLM 爆发
相信即将过去的 2023 年对大家来说都是非常奇妙的一年。2022 年 11 月的时候 ChatGPT 刚刚发布,过了一年到现在,我们已经见证了各种各样的大语言模型横空出世:有商用的大语言模型,比如 Claude 和 GPT;也有很多开源的小模型,其参数量可能从几个 B 到几百个 B 不等。可以说这是一个大语言模型繁荣发展的时代,新型语言模型的层出不穷。
BentoML 在与一些客户互动时发现,他们在开发过程中可能会利用 OpenAI 的能力进行开发,将数据输入到 prompt 中,然后测试推理结果。在将模型部署到生产环境上线时,他们希望在自己的服务器或云服务器上进行部署。
2. 属于自己的 LLM
大部分客户有以下诉求:
3. 生产环境中部署 LLMs 的挑战
如果我们自己去部署大语言模型,可能会遇到以下挑战:
1. OpenLLM 介绍
下面介绍我们的开源产品 OpenLLM 是如何解决上述问题的。
OpenLLM 于 2023 年 6 月开源,是一个用于部署大语言模型的框架。目前,该项目在 GitHub 上已经获得了 6800 多个星标。其最初的口号是通过一行代码或相对轻松地在不同的大语言模型之间切换,为个人用户提供方便。无论是想要尝试不同模型的个人用户,还是想要部署自己的 AI 应用的用户,OpenLLM 都可以提供便捷的解决方案。
OpenLLM 目前支持几乎所有常用的开源大语言模型。对于每个模型,框架都提供了多个不同的参数量和不同部署模型 ID 可供选择。目前包括 ChatGLM、百川、Dolly-V2 等模型。
2. OpenLLM 应用举例
接下来通过演示来介绍 OpenLLM 是如何加速大语言模型应用的开发和部署的。
首先,启动一个 LLM 服务。
启动 LLM 服务非常简单,只需在安装 LLM 工具后运行以下命令:"start dolly-v2" 即可启动应用。如果你的计算机上之前未下载过该模型,它将自动帮你下载。这可能需要一些时间,应用启动后,可以通过命令行直接与该服务交互,提出一个问题,比如"地球的重量是多少"。我们使用的是 Dolly-V2 模型,它给出了一个回答。由于这个模型相对较弱,因此回答可能不太准确。
我们尝试使用另一个模型,LlaMA,来看看是否可以提升准确度。在这里,我们选择使用 LlaMA2 模型,但由于 LlaMA2 不是 LlaMA 的默认模型,我们需要指定一下模型 ID。和之前一样,使用方法完全相同,只是切换了模型。
因此,使用我们的框架,用户可以轻松在不同的模型之间切换。尽管使用方法一样,但不同模型的回答可能会有所不同。这次使用 LlaMA2 模型,可以看到给出的答案相对更准确。
我们使用命令行与服务进行交互,这在测试阶段非常方便和实用。然而,在实际部署应用时,我们可能希望应用提供一个 HTTP 或 gRPC 接口,以便前端或外部系统能够调用。
OpenLLM 框架支持内置的开箱即用的 HTTP API。在服务的首页,显示一个 Swagger 页面,列出了所有服务支持的 HTTP 端点。你甚至可以在这里直接与服务进行交互和测试,输入提示并获取 JSON 格式的响应体,就像我们之前在命令行中演示的一样。
由于我们暴露了 HTTP 接口,因此无论使用 Python、Node 还是 Curl 等任何能够访问 HTTP 的客户端,都可以调用这个接口。这为应用的灵活性和可访问性提供了更多的选择。
我们还提供了一个 Python SDK,使用户能够在 Python 代码中直接与服务进行交互。只需导入 Client,指定服务的地址,就可以直接向服务提出问题,它将正确地给出答案。这样就可以在 Python 环境中更加便捷地集成和使用 OpenLLM 的服务。
3. OpenLLM 使用优势
使用 OpenLLM 有以下优势:
下面重点讨论一下 Continuous Batching(持续批跑),因为我们使用了 VLM 的后端,它为我们带来了很好的优化。
在大型语言模型的推理中,输入的强度并不相同,有些输入可能更快产生结果,而有些可能需要更长时间。如果不进行优化,当其中一个输入(比如 S2)先完成推理时,整个过程就会等待其他输入完成才能进入下一轮。这会导致 GPU 时间的浪费,因为有一段时间没有推理任务在进行。
Continuous Batching 的优化可以在一个推理结束时立即引入下一个推理任务。以一个例子来说明,假设 S3 先完成了推理,那么 S5 就会立即加入,接着 S1 完成了推理,S6 就会立即加入。这样可以确保在每个时间片上都有一个模型推理任务在运行,从而最大程度地利用 GPU 资源。这是一个有效的优化策略,减少了空闲时间,提高了整体推理效率。
介绍了时间优化之后,再来看一下空间优化,尤其是关于 KVcache 的优化。首先简要介绍一下大语言模型的工作原理。它基于 Transformer 框架,模型通过一系列输入的 token,返回下一个 token 的最大概率。然而,由于输入可能存在重复计算,例如在输入"我是一只"后,模型返回"我是一只猫",在输入"我是一只猫"时,又返回"我是一只猫,",这导致了 Transformer 框架中有许多重复的计算。为了解决这个问题,我们使用 KVcache 缓存计算结果。
KVcache 带来了一个新问题,就是在计算机内存分配时,无法准确知道需要分配多少内存。我们只能先估算一个大致的范围。通过图表演示可以看到,当一个任务完成后,本来可以释放的内存却可能由于下一个任务的加入而无法充分利用。这样就会产生很多内存碎片,影响内存的使用效率。
为了优化这个问题,引入了 Paged Attention。Paged Attention 的优化思想是将所有内存拆分成一个个 block,然后在内存分配时按 block 分配。如果一个任务完成后,发现内存不够,需要再增加时,框架会在另一个地方(可能不是连续的地方)分配另一个 block。任务完成后,这个 block 可能会被释放,供下一个任务使用。通过这种方式,可以有效减少内存碎片。需要注意的是,内存不是连续的,因此需要一个 block table 来存储内存的物理位置和实际序号的映射关系,使得在大模型中看起来是获得了一个逻辑上连续的内存。
1. BentoML 介绍
完成了以上优化后,开始部署大语言模型。然而,大多数 AI 应用不仅仅是将一个模型部署上去,否则没有哪个公司能够与 OpenAI 竞争。因此,除了模型推理之外,我们的 AI 应用还可能包含许多其他方面的工作。例如,需要考虑如何收集数据、验证数据、配置部署指标以及如何进行模型推理,包括服务指标的观测。这些问题在研究阶段,可能不需要考虑,但在部署和工程化之后,必须考虑这些杂项问题。
BentoML 与 OpenLLM 集成带来了许多优势。BentoML 是一个专注于解决部署后事项的开源 AI 部署框架,具体如下:
BentoML 模型是对机器学习模型的一种抽象。在机器学习领域,有许多不同的框架,每个框架都有自己的模型概念。BentoML 允许将这些不同框架的模型导入为 BentoML 模型。这种抽象化的设计有几个优点:
BentoML 的 Runner 具有以下特点:
上图中展示了 BentoML API Server 的工作流程:应用从外部接收 HTTP 请求,可能是通过 POST 方法发送的 JSON 数据。接收到的 HTTP 请求数据可能需要进行预处理,以便转换为模型能够接受的格式。这个步骤通常涉及数据格式转换、验证等操作,确保输入数据符合模型的要求。IO Descriptors 定义了输入和输出数据的结构和类型,起到了数据格式转换桥梁的作用。经过 IO Descriptors 的转换后,数据被传递给模型进行推理。模型利用输入数据生成相应的预测或输出。模型的输出可能需要进行一些后置处理,以便将其转换为 HTTP 响应的格式。这个步骤包括将 Tensor 或 Numpy 数组转换为 JSON 格式等。处理完后的数据以 HTTP 响应的形式返回给请求方,完成了整个推理过程。这是应用与外部系统通信的出口。
BentoML 的请求处理流程经过了负载均衡层、API 服务器和 Runner 的多个层次:
这里介绍一下 BentoML 中 Bento 的概念,Bento 是打包好的最小的部署的单元,包括机器学习的依赖、环境的 Dockerfile、源代码、需要的模型等各种部署的配置。
2. BentoML 应用举例
接下来通过一个实例来演示如何使用 BentoML 开发和部署 AI 应用。我们将创建一个应用,利用 LangChain 和 OpenLLM 实现广告词的生成功能,并展示 LangChain 和 OpenLLM 的集成。然后,我们将使用 BentoML 启动一个 HTTP 服务,通过一行代码切换 LLM 模型,并最终生成一个 Bento 包,以演示如何使用 BentoML 进行后续部署。
在前面的代码中,我们导入了一些 LangChain 的模块。如果你对 LangChain 比较熟悉的话,应该对这些模块有所了解,这里不做详细讲解。接下来是 BentoML 的部分。BentoML 主要导入了一些 IO Descriptor,这些描述符用于说明输入输出的类型。在这里,我们导入了两个类型,一个是 JSON,另一个是 Text。现在我们将利用这些导入的模块和描述符,因为我们的输入应该是 JSON 格式,而输出则是一段文字。
接下来,我们将使用 pydantic 的 Model 定义一个结构体,该结构体用于验证输入的有效性。这个 Query 对象包含以下几个参数:industry 表示所在行业,productName 表示产品名称,keywords 表示需要的关键词。这些参数是生成广告词所需的输入。
第二部分是一个 helper 函数,用于快速切换模型 ID。该函数返回一个 LangChain 对象。因此,我们首先使用 opt 模型,如果注释掉上面的一行并使用下面一行,就可以直接切换到使用百川模型。
这是 Prompt 的生成部分,利用 LangChain 的功能,指定一个 Prompt 的模板,然后将刚才输入的参数填充到这个模板中,生成一个完整的 Prompt。
接下来的步骤是定义要公开的接口。通过指定输入和输出的类型,将这个函数作为服务的一个接口。在第 48 行,将 LLM 的 Runner 传递给了这个服务,因为在启动服务时,需要知道有哪些 Runner 需要在分布式环境中远程启动。因此,这里的启动会生成两个独立的服务:一个是 API 接口层(`Service`),另一个是 LLM Runner。它们是相互独立的。
启动之后,可以看到与之前相似的 Swagger 页面,我们可以直接在上面进行测试。在这里,我们将行业设为"SAAS",产品名称设为"BentoML",执行后,它可以为我们生成一段广告词。这个广告词符合我们的需求,看起来像一条推文或者微信的内容。如果我们想生成一个房地产行业的广告,只需切换行业为"房地产",就可以得到一条看起来更符合房地产行业的广告,其中还包含一个房子的表情图标。
开发以及本地的测试完成后,将整个代码和模型打包成一个 Bento。通过使用 BentoML 的 Build 命令,可以轻松制作一个 Bento 包。制作完成后,还有两个后续的可选步骤。
第一个是将其容器化 containerize,打包成一个镜像,为后续的部署使用。
第二种选择是可以直接把这个 Bento push 到我们的 Cloud 平台上,Cloud 平台会自动帮你执行后续的部署操作。
Cloud 平台是一个能够部署你的 Bento 的平台。它会将 Bento 自动转化为一个运行在 Kubernetes 上的容器,并在其上运行。这里的例子包括一个 API 服务器以及多个不同的 runner,包括 LLM 的 runner 和 Text2Image 的 runner 等。此外,在 BentoCloud 上,可以指定扩容的方式,可以分别为 API 指定需要扩容的节点数,或者为每个 runner 指定需要的 GPU 数量或实例数。
OpenLLM 是一个开源的大语言模型(LLM)开发框架。它支持多种开源的 LLM 模型,并且具有内建的两个关键的 LLM 优化,能够优化内存使用。此外,它与 LangChain 和 BentoML 都有很好的集成。
以上就是本次分享的内容,谢谢大家。