Xinference 的內部結構#

概述#

Xinference 利用我們設計的 actor 程式設計框架 Xoscar 作為其核心元件,以管理機器、裝置和模型推理程序。每個 actor 都是模型推理的基本單元,各種推理後端可以整合到 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 分配的任務。

每條命令都配有 optionflag,可自訂其行為,如指定日誌級別、主機地址、通訊埠號碼和其他相關設定。

Python 專案會在 setup.cfgsetup.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_promptroles 用於指定模型的指令和個性。

程式碼指南#

主要程式碼位於 xinference/

  • api/restful_api.py 是設定與執行 RESTful API 的核心部分。它整合了一項身份驗證服務(具體程式碼位於 oauth2/),因為部分或所有端口需要使用者身份驗證。

  • client/:這是 Xinference 的客戶端。

    • oscar/ 定義了 Actor 客戶端,這是一個客戶端介面,用於與 Xinference 中的模型進行互動。

    • restful/ 實作與 Xinference 服務互動的 RESTful 客戶端。

  • core/:這是 Xinference 的核心部分。

    • metrics.pyresource.py 定義了一套用於收集和報告指標以及節點資源狀態的工具,包括模型吞吐量、延遲、CPU 和 GPU 使用率、記憶體使用率等。

    • image_interface.pychat_interface.py 分別為圖像和聊天模型實作了 Gradio 介面。這些介面允許使用者透過 Web 界面與模型進行互動,例如生成圖像或進行聊天。程式碼使用 Gradio 套件建構使用者界面,並透過我們的 RESTful API 與後端模型通訊。

    • worker.pysupervisor.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 翻譯檔案,即可支援更多語言,改善使用者體驗。

  • model/:它為模型描述、建立和快取提供了一個框架。請參閱 Model 以取得更多資訊。

  • web/ui/:前端(使用者介面)的 JavaScript 程式碼。