Xinference 的内部结构#
概述#
Xinference 利用我们设计的 actor 编程框架 Xoscar 作为其核心组件,以管理机器、设备和模型推理进程。每个 actor 都是模型推理的基本单元,各种推理后端可以集成到 actor 中,从而使我们能够支持多种推理引擎和硬件。这些 actor 在 actor 池中托管和调度,actor 池具有资源池的功能,actor 的设计是异步和非阻塞的,。
supervisor 和 worker 都是 actor 实例。需要先在每台服务器上创建一个作为资源池的 actor 池;每个 actor 可以使用一个 CPU 内核或一块 GPU 设备。每台服务器都有自己的地址(IP 地址或主机名),因此不同计算节点上的 actor 可以通过这些地址相互通信。更多信息,请参阅 Actor。
RESTful API#
RESTful API 是利用 FastAPI 实现的,具体代码在 api/restful_api.py。
self._router.add_api_route("/status", self.get_status, methods=["GET"])
这是一个 API 的示例,API /status 对应函数 get_status。您可以在 api/restful_api.py 中添加 RESTful API 和对应后端函数之间的关系。
命令行#
命令行是通过 Click 实现的,具体代码在 deploy/cmdline.py,命令行允许用户直接在终端与 Xinference 进行交互。
入口点#
以我们实现的命令行为例:
xinference:提供命令用于模型管理,包括注册/取消注册模型、列出所有已注册/运行的模型,以及启动或终止特定模型。它还提供生成语言和聊天等交互式命令,用于测试或交互已部署的模型。xinference-local:启动一个本地 Xinference 服务。xinference-supervisor:启动 supervisor 进程,在分布式环境中管理和监控 worker actors。xinference-worker:启动 worker 进程,利用可用计算资源,执行 supervisor 分配的任务。
每条命令都配有 option 和 flag,可自定义其行为,如指定日志级别、主机地址、端口号和其他相关设置。
Python 项目会在 setup.cfg 或 setup.py 中定义命令行控制台入口点。
console_scripts =
xinference = xinference.deploy.cmdline:cli
xinference-local = xinference.deploy.cmdline:local
xinference-supervisor = xinference.deploy.cmdline:supervisor
xinference-worker = xinference.deploy.cmdline:worker
命令行 xinference 可参考 xinference.deploy.cmdline:cli 中的代码。
Click#
我们使用 Click 来实现特定的命令行:
@click.option(
"--host",
"-H",
default=XINFERENCE_DEFAULT_DISTRIBUTED_HOST,
type=str,
help="Specify the host address for the supervisor.",
)
@click.option(
"--port",
"-p",
default=XINFERENCE_DEFAULT_ENDPOINT_PORT,
type=int,
help="Specify the port number for the Xinference web ui and service.",
)
例如,xinference-local 命令允许您定义主机地址和端口。
Actor#
Xinference 以 Xoscar 为基础,Xoscar 是我们的 actor 框架,可以管理计算资源和 Python 进程,支持可扩展的并发编程。下面的伪代码演示了 Worker Actor 的工作原理,实际的 Worker Actor 要比这个复杂得多。
import xoscar as xo
class WorkerActor(xo.Actor):
def __init__(self, *args, **kwargs):
...
async def launch_model(self, model_id, n_gpu, ...):
# launch an inference engine, use specific model class to load model checkpoints
...
async def list_models(self):
# list models on this actor
...
async def terminate_model(self, model_id):
# terminate the model
...
async def __post_create__(self):
# called after the actor instance is created
...
async def __pre_destroy__(self):
# called before the actor instance is destroyed
...
我们以 WorkerActor 为例,说明如何构建 Xinference。每个 actor 类都是继承自 xoscar.Actor 的标准 Python 类。该类的实例就是 actor 池中的一个特定的 actor。
定义 Actor 的行为:每个 actor 都需要定义某些动作或行为来完成特定任务。例如,模型推理
WorkerActor需要启动模型(launch_model)、列出该 actor 中的模型(list_models)、终止模型(termininate_model)。有两个特殊方法值得注意。__post_create__在创建 actor 之前调用,进行必要的初始化。而__pre_destroy__会在 actor 被销毁后调用,执行清理任务。引用 Actor 和调用方法:当创建一个 Actor 时,它会产生一个引用变量,以便其他 Actor 可以引用它。Actor 也可以用 IP 地址来引用。假设创建了
WorkerActor,且引用变量为worker_ref,那么就可以通过调用worker_ref.launch_model()来调用该 Actor 类的launch_model。即使 actor 中的方法原来是一个传统的阻塞式的方法,当我们使用引用变量调用这个方法时,它也变成了一个异步方法。推理引擎:Actor 可以管理进程,而推理引擎也是一种进程。在
WorkerActor的启动模型部分,我们可以根据用户的需要初始化不同的推理引擎。因此,Xinference 可以支持多种推理引擎,并能轻松适应未来的新推理引擎。
请参阅 Xoscar 文档 了解更多 Actor 用例。
异步编程#
Xinference 和 Xoscar 非常依赖异步编程库 asyncio。异步编程是一种非阻塞的编程范式。相比于传统的阻塞式的函数调用,异步编程中的请求或函数调用在后台执行,运行结果在未来某个时刻返回。异步编程的优势是使得可以同时并发进行很多不同的活动或任务。
如果您不熟悉 Python 的 asyncio,可以查看更多教程以获得帮助:
模型#
Xinference 支持不同类型的模型,包括大型语言模型(LLM)、图像模型、音频模型、嵌入模型等。所有模型在 model/ 文件夹下实现。
LLM#
以 model/llm/ 为例,它主要管理和启动 LLM,包括加载、配置和运行大语言模型。
我们支持不同的推理后端,比如 GGML、PyTorch 和 vLLM。我们生成的内容与 OpenAI 的格式兼容,比如支持流式输出(stream),对话模型以 chat completion 格式返回。因此模型输出内容后要做很多适配工作。这些工作并不难,但需要一些时间。编写这部分代码时,请参考 OpenAI 的 API 文档 和各个推理后端的文档,做必要的适配。
JSON#
在 model/llm/llm_family.json 中,我们利用 JSON 文件来管理新出现的开源模型的元数据。添加一个新模型并不需要编写新代码,只需要将新的元数据添加到现有的 JSON 文件中即可。
{
"model_name": "llama-2-chat",
"model_ability": ["chat"],
"model_specs": [
{
"model_format": "ggmlv3",
"model_size_in_billions": 70,
"quantization": ["q8_0", ...],
"model_id": "TheBloke/Llama-2-70B-Chat-GGML",
},
...
],
"prompt_style": {
"style_name": "LLAMA2",
"system_prompt": "<s>[INST] <<SYS>>\nYou are a helpful AI assistant.\n<</SYS>>\n\n",
"roles": ["[INST]", "[/INST]"],
"stop_token_ids": [2],
"stop": ["</s>"]
}
}
这是一个如何定义 Llama-2 聊天模型的示例。model_specs 定义了模型的信息,因为一个模型系列通常有不同的尺寸、量化方法和文件格式。例如,model_format 可以是 pytorch (使用 Hugging Face Transformers 或 vLLM 作为后端)、 ggmlv3 (与 llama.cpp 相关的张量库)或 gptq (训练后量化框架)。 model_id 定义了模型中心的资源库,Xinference 从模型中心下载检查点文件。此外,由于不同的指令调整过程,不同的模型系列有不同的提示风格。JSON 文件中的 prompt_style 指定了该特定模型的提示格式。例如,system_prompt 和 roles 用于指定模型的指令和个性。
代码指南#
主要代码位于 xinference/:
api/:restful_api.py 是设置和运行 RESTful API 的核心部分。它集成了一个身份验证服务(具体代码位于 oauth2/),因为部分或所有端口需要用户身份验证。
client/:这是 Xinference 的客户端。
core/:这是 Xinference 的核心部分。
metrics.py 和 resource.py 定义了一套用于收集和报告指标以及节点资源状态的工具,包括模型吞吐量、延迟、CPU 和 GPU 的使用率、内存使用率等。
image_interface.py 和 chat_interface.py 分别为图像和聊天模型实现了 Gradio 接口。这些接口允许用户通过 Web 界面与模型进行交互,例如生成图像或进行聊天。代码使用 Gradio 软件包构建用户界面,并通过我们的 RESTful API 与后端模型通信。
worker.py 和 supervisor.py 分别定义了 worker actor 和 supervisor actor 的逻辑。worker actor 负责执行特定的模型计算任务,而 supervisor actor 则管理 Worker 节点的生命周期和任务调度,并监控系统状态。
status_guard.py 实现了一个状态监视器,用于跟踪模型的状态(如创建、更新、终止等)。它允许根据模型的 UID 查询模型实例的状态信息
cache_tracker.py 定义了一个缓存跟踪器,用于记录和管理缓存状态和模型版本信息。它支持记录缓存位置和模型版本的状态,并根据模型名称查询模型版本信息。
event.py 定义了一个事件收集器,用于收集和报告各种运行时模型的事件,如信息、警告和错误。model.py 定义了一个模型 Actor,它是与模型直接交互的核心组件。模型 actor 负责执行模型推理请求,处理输入和输出数据流,并支持各种模型操作。这两个部分都使用 Xoscar 用于并发和分布式执行。
deploy/:它提供了一个命令行界面(CLI),用于与 Xinference 框架进行交互,允许用户通过命令行进行操作。更多信息,请参见 Command Line。
locale/:它支持多语言本地化。只需添加和更新 JSON 翻译文件,就可以支持更多语言,改善用户体验。
web/ui/:前端(用户界面)的js代码。