更新时间:2024-09-14 GMT+08:00
分享

分离部署推理服务

本章节介绍如何使用vLLM 0.5.0框架部署并启动推理服务。

什么是分离部署

大模型推理是自回归的过程,有以下两阶段:

  • Prefill阶段(全量推理)

    将用户请求的prompt传入大模型,进行计算,中间结果写入KVCache并推出第1个token,属于计算密集型。

  • Decode阶段(增量推理)

    将请求的前1个token传入大模型,从显存读取前文产生的KVCache再进行计算,属于访存密集型。

分离部署场景下,全量推理和增量推理在不同的容器上进行,用于提高资源利用效率。

分离部署的实例类型启动分为以下三个阶段:
  1. Step6 启动全量推理实例:必须为NPU实例,用于启动全量推理服务,负责输入的全量推理。全量推理占用至少1个容器。
  2. Step7 启动增量推理实例:必须为NPU实例,用于启动增量推理服务,负责输入的增量推理。增量推理占用至少1个容器。
  3. Step8 启动scheduler实例:可为CPU实例,用于启动api-server服务,负责接收推理请求,向全量或增量推理实例分发请求,收集推理结果并向客户端返回推理结果。服务调度实例不占用显卡资源,建议增加1个容器,也可以在全量推理或增量推理的容器上启动。

前提条件

  • 已准备好DevServer环境,具体参考资源规格要求。推荐使用“西南-贵阳一”Region上的DevServer和昇腾Snt9b资源。
  • 安装过程需要连接互联网git clone,确保容器可以访问公网。

Step1 检查环境

  1. SSH登录机器后,检查NPU设备检查。运行如下命令,返回NPU设备信息。
    npu-smi info                    # 在每个实例节点上运行此命令可以看到NPU卡状态
    npu-smi info -l | grep Total    # 在每个实例节点上运行此命令可以看到总卡数,用来确认对应卡数已经挂载
    npu-smi info -t board -i 1 | egrep -i "software|firmware"   #查看驱动和固件版本

    如出现错误,可能是机器上的NPU设备没有正常安装,或者NPU镜像被其他容器挂载。请先正常安装固件和驱动,或释放被挂载的NPU。

    驱动版本要求是23.0.6。如果不符合要求请参考安装固件和驱动章节升级驱动。

  2. 检查docker是否安装。
    docker -v   #检查docker是否安装

    如尚未安装,运行以下命令安装docker。

    yum install -y docker-engine.aarch64 docker-engine-selinux.noarch docker-runc.aarch64
  3. 配置IP转发,用于容器内的网络访问。执行以下命令查看net.ipv4.ip_forward配置项的值,如果为1,可跳过此步骤。
    sysctl -p | grep net.ipv4.ip_forward
    如果net.ipv4.ip_forward配置项的值不为1,执行以下命令配置IP转发。
    sed -i 's/net\.ipv4\.ip_forward=0/net\.ipv4\.ip_forward=1/g' /etc/sysctl.conf
    sysctl -p | grep net.ipv4.ip_forward

Step2 获取基础镜像

建议使用官方提供的镜像部署推理服务。镜像地址{image_url}获取请参见表1

docker pull {image_url}

Step3 上传代码包和权重文件

  1. 上传安装依赖软件推理代码AscendCloud-LLM-6.3.908-xxx.zip和算子包AscendCloud-OPP-6.3.908-xxx.zip到主机中,包获取路径请参见表2
  2. 将权重文件上传到DevServer机器中。权重文件的格式要求为Huggface格式。开源权重文件获取地址请参见表3

    如果使用模型训练后的权重文件进行推理,模型训练及训练后的权重文件转换操作可以参考相关文档章节中提供的模型训练文档。

    3.权重要求放在磁盘的指定目录,并做目录大小检查,参考命令如下:

    df -h

Step4 制作推理镜像

解压AscendCloud压缩包及该目录下的推理代码AscendCloud-LLM-6.3.908-xxx.zip和算子包AscendCloud-OPP-6.3.908-xxx.zip,并执行build_image.sh脚本制作推理镜像。安装过程需要连接互联网git clone,请确保机器环境可以访问公网。
unzip AscendCloud-*.zip -d ./AscendCloud && unzip ./AscendCloud/AscendCloud-OPP-*.zip -d ./AscendCloud/AscendCloud-OPP && unzip ./AscendCloud/AscendCloud-LLM-*.zip -d ./AscendCloud/AscendCloud-LLM && cd ./AscendCloud/AscendCloud-LLM/llm_inference/ascend_vllm/ && sh build_image.sh --base-image=${base_image} --image-name=${image_name}

参数说明:

  • ${base_image}为基础镜像地址。
  • ${image_name}为推理镜像名称,可自行指定。

运行完后,会生成推理所需镜像。

Step5 生成ranktable

介绍如何生成ranktable,以1p1d-tp2分离部署模式为例。当前1p1d分离部署模式,全量节点和增量节点分别占用2张卡,一共使用4张卡。

  • 配置tools工具根目录环境变量

    使用AscendCloud-LLM发布版本进行推理,基于AscendCloud-LLM包的解压路径配置tool工具根目录环境变量:

    export LLM_TOOLS_PATH=${root_path_of_AscendCloud-LLM}/llm_tools

    其中,`${root_path_of_AscendCloud-LLM}`为AscendCloud-LLM包解压后的根路径。

    当使用昇腾云的官方指导文档制作推理镜像时,可直接基于该固定路径配置环境变量:

    export LLM_TOOLS_PATH=/home/ma-user/AscendCloud/AscendCloud-LLM/llm_tools
  • 获取每台机器的rank_table

    在每个机器生成global rank_table信息与local rank_table信息。

    python ${LLM_TOOLS_PATH}/PD_separate/pd_ranktable_tools.py --mode gen --prefill-server-list 4,5 --decode-server-list 6,7 --api-server --save-dir ./save_dir

    执行后,会生成一个global_ranktable.json文件和使用实例个数的local_ranktable.json文件;如果指定了`--api-server`,还会生成一个local_ranktable_host.json文件用于确定服务入口实例。

    ./save_dir 生成ranktable文件如下(假设本地主机ip为10.**.**.18)。

    global_ranktable_10.**.**.18.json      # global rank_table
    local_ranktable_10.**.**.18_45.json    # 全量节点local rank_table
    local_ranktable_10.**.**.18_67.json    # 增量节点local rank_table
    local_ranktable_10.**.**.18_host.json  # api-server
  • 合并不同机器的global rank_table(可选)

    如果分离部署在多台机器,获取每台机器的rank_table后,合并各个机器的global rank_table得到完整的global rank_table。

    python ${LLM_TOOLS_PATH}/PD_separate/pd_ranktable_tools.py --mode merge --global-ranktable-list ./ranktable/global_ranktable_0.0,0,0.json ./ranktable/global_ranktable_1.1.1.1.json --save-dir ./save_dir

    pd_ranktable_tools.py的入参说明如下。

    • --mode:脚本的处理模式,可选值为`gen`或者`merge`。`gen`模式表示生成rank_table文件,`merge`模式表示合并global rank_table文件。
    • --save-dir:保存生成的rank_table文件的根目录,默认为当前目录。
    • --api-server:仅在`gen`模式有效,可选输入,当存在该输入时,表示分离部署的服务入口在该机器。注意,在多台机器启动分离部署时,只能有一台机器存在服务入口。当存在该输入时,会生成local_ranktable_xx_host.json文件,用于在启动推理服务时确定服务入口实例。
    • --prefill-server-list:仅在`gen`模式有效,可选输入,后续入参表示若干个vllm全量实例,使用空格隔开,每个vllm实例的数字表示使用的昇腾卡device_id,使用多个昇腾卡时,device_id之间使用`,`分隔开。当存在该输入时,会生成对应全量实例个数的local_ranktable_xx_yy.json文件,用于在启动推理服务时确定全量实例。
    • --decode-server-list:仅在`gen`模式有效,可选输入,后续入参表示若干个vllm增量实例,使用空格隔开,每个vllm实例的数字表示使用的昇腾卡device_id,使用多个昇腾卡时,device_id之间使用`,`分隔开。当存在该输入时,会生成对应增量实例个数的local_ranktable_xx_yy.json文件,用于在启动推理服务时确定增量实例。
    • --global-ranktable-list:仅在`gen`模式有效,必选输入,后续入参表示需要合并的global rank_table,使用空格分隔开。

    执行后,会生成完成合并的global_ranktable_merge.json文件。

  • global_rank_table.json格式说明

    server_group_list的长度必须为3,第一个元素(group_id="0")代表Scheduler实例的ip信息,只能有一个实例。

    第二个元素(group_id="1")代表全量实例信息,长度即为全量实例个数。其中需要配置每个全量实例的ip信息以及使用的device信息。rank_id为逻辑卡号,必然从0开始计算,device_id为物理卡号,device_ip则通过上面的hccn_tool获取。

    第三个元素(group_id="2")代表增量实例信息,长度即为增量实例个数。其余信息和全量类似。

    global_rank_table.json具体示例如下:
    {
        "version": "1.0",
        "status": "completed",
        "server_group_list": [
            {
                "group_id": "0",
                "server_count": "1",
                "server_list": [
                    {
                        "server_id": "localhost", 
                        "server_ip": "localhost"
                    }
                ]
            },
            {
                "group_id": "1",
                "server_count": "1",
                "server_list": [
                    {
                        "server_id": "localhost", 
                        "server_ip": "localhost",
                        "device": [
                            {
                                "device_id": "4",
                                "device_ip": "10.**.**.22",
                                "rank_id": "0"
                            },
                            {
                                "device_id": "5",
                                "device_ip": "10.**.**.23",
                                "rank_id": "1"
                            }
                        ]
                    }
                ]
            },
            {
                "group_id": "2",
                "server_count": "1",
                "server_list": [
                    {
                        "server_id": "localhost",
                        "server_ip": "localhost",
                        "device": [
                            {
                                "device_id": "6",
                                "device_ip": "29.**.**.56",
                                "rank_id": "0"
                            },
                            {
                                "device_id": "7",
                                "device_ip": "29.**.**.72",
                                "rank_id": "1"
                            }
                        ]
                    }
                ]
            }
        ]
    }
    ```
  • local_rank_table.json格式说明
    每个全量/增量实例都需要local_rank_table.json。下面以某一个增量实例为例,需要和global_rank_table.json中的全量信息完全对应,group_id为0。
    ```
    {
        "version": "1.0",
        "status": "completed",
        "group_id": "0",
        "server_count": "1",
        "server_list": [
            {
                "server_id": "localhost",
                "server_ip": "localhost",
                "device": [
                    {
                        "device_id": "6",
                        "device_ip": "29.**.**.56",
                        "rank_id": "0"
                    },
                    {
                        "device_id": "7",
                        "device_ip": "29.**.**.72",
                        "rank_id": "1"
                    }
                ]
            }
        ]
    }
    ```

Step6 启动全量推理实例

以下介绍如何启动全量推理实例。

  1. 启动容器镜像前请先按照参数说明修改${}中的参数。docker启动失败会有对应的error提示,启动成功会有对应的docker id生成,并且不会报错。
    docker run -itd \
    --device=/dev/davinci4 \
    --device=/dev/davinci5 \
    -v /etc/localtime:/etc/localtime  \
    -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \
    -v /etc/ascend_install.info:/etc/ascend_install.info \
    --device=/dev/davinci_manager \
    --device=/dev/devmm_svm \
    --device=/dev/hisi_hdc \
    -v /var/log/npu/:/usr/slog \
    -v /usr/local/sbin/npu-smi:/usr/local/sbin/npu-smi \
    -v /sys/fs/cgroup:/sys/fs/cgroup:ro \
    -v ${dir}:${container_work_dir} \
    --net=host \
    --name ${container_name} \
    ${image_id} \
    /bin/bash

    参数说明:

    • --device=/dev/davinci0,..., --device=/dev/davinci7:挂载NPU设备,示例中挂载了2张卡davinci4、davinci5。
    • -v ${dir}:${container_work_dir} 代表需要在容器中挂载宿主机的目录。宿主机和容器使用不同的大文件系统,dir为宿主机中文件目录,${container_work_dir}为要挂载到的容器中的目录。为方便两个地址可以相同。
      • 容器不能挂载到/home/ma-user目录,此目录为ma-user用户家目录。如果容器挂载到/home/ma-user下,拉起容器时会与基础镜像冲突,导致基础镜像不可用。
      • driver及npu-smi需同时挂载至容器。
      • 不要将多个容器绑到同一个NPU上,会导致后续的容器无法正常使用NPU功能。
    • --name ${container_name}:容器名称,进入容器时会用到,此处可以自己定义一个容器名称。
    • {image_id} 为docker镜像的ID,即第四步中生成的新镜像id,在宿主机上可通过docker images查询得到。
  2. 进入容器。
    docker exec -it -u ma-user ${container-name} /bin/bash
  3. 启动全量推理实例,命令如下。
    export GLOBAL_RANK_TABLE_FILE_PATH=global_ranktable_10.**.**.18.json
    export RANK_TABLE_FILE_PATH=local_rank_table_10.**.**.18_45.json
    export NODE_PORTS=8088,8089
    export USE_OPENAI=1
    
    sh AscendCloud-LLM/llm_tools/PD_separate/start_servers.sh \
        --model=${model} \
        --tensor-parallel-size=2 \
        --max-model-len=4096 \
        --max-num-seqs=256 \
        --max-num-batched-tokens=4096 \
        --host=0.0.0.0 \
        --port=8088 \
        --served-model-name ${served-model-name}

    其中环境变量说明如下:

    • GLOBAL_RANK_TABLE_FILE_PATH:global rank_table的路径,必选。不同实例类型的global rank_table均一致。
    • RANK_TABLE_FILE_PATH:local rank_table的路径,必选。当实例类型为全量推理实例或者增量推理实例,local rank_table配置local_ranktable_xx_yy.json文件,其中xx表示当前实例的IP地址,yy表示当前实例使用的device_id信息;当实例类型为服务入口实例,local rank_table配置local_ranktable_xx_host.json文件,其中xx表示当前实例的IP地址。
    • NODE_PORTS:仅在服务入口实例生效,用于与全量推理实例、增量推理实例的信息交互。该参数入参为形如{port1},{port2},{portn}的字符串,与全量或增量推理实例启动的--port参数相关。--port表示服务部署的端口。每个全量/增量推理实例基于配置的端口号(`--port`)启动服务,并按照global rank_table中的全量实例、增量实例的顺序,对全量推理实例、增量推理实例启动的端口号进行排序,端口之间用`,`分隔开作为该环境变量的输入。
    • USE_OPENAI:仅在服务入口实例生效,用于配置api-server服务是否使用openai服务,默认为1。当配置为1时,启动服务为openai服务;当配置为0时,启动服务为vllm服务。

    其中常见的参数如下:

    • --host:服务部署的IP
    • --port:服务部署的端口,注意如果不同实例部署在一台机器上,不同实例需要使用不同端口号
    • --model:HuggingFace下载的官方权重
    • --max-num-seqs:同时处理的最大句子数量
    • --max-model-len:模型能处理的请求输入+输出的token长度
    • --max-num-batched-tokens:最多会使用多少token,必须大于或等于--max-model-len,推荐使用4096或8192
    • --tensor-parallel-size:模型并行数量
    • --served-model-name:openai服务的model入参名称,仅在环境变量`USE_OPENAI=1`时候生效。
    • --quantization:如果需要增加模型量化功能,启动推理服务前,先参考使用AWQ量化使用SmoothQuant量化使用GPTQ量化章节对模型做量化处理。

    参数定义和使用方式与vLLM0.5.0版本一致,此处介绍关键参数。详细参数解释请参见https://github.com/vllm-project/vllm/blob/main/vllm/engine/arg_utils.py

Step7 启动增量推理实例

  1. 启动增量推理容器

    启动容器镜像前请先按照参数说明修改${}中的参数。docker启动失败会有对应的error提示,启动成功会有对应的docker id生成,并且不会报错。

    docker run -itd \
    --device=/dev/davinci6 \
    --device=/dev/davinci7 \
    -v /etc/localtime:/etc/localtime  \
    -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \
    -v /etc/ascend_install.info:/etc/ascend_install.info \
    --device=/dev/davinci_manager \
    --device=/dev/devmm_svm \
    --device=/dev/hisi_hdc \
    -v /var/log/npu/:/usr/slog \
    -v /usr/local/sbin/npu-smi:/usr/local/sbin/npu-smi \
    -v /sys/fs/cgroup:/sys/fs/cgroup:ro \
    -v ${dir}:${container_work_dir} \
    --net=host \
    --name ${container_name} \
    ${image_id} \
    /bin/bash

    参数说明:

    • --device=/dev/davinci0,..., --device=/dev/davinci7:挂载NPU设备,示例中挂载了2张卡davinci6、davinci7。
    • -v ${dir}:${container_work_dir} 代表需要在容器中挂载宿主机的目录。宿主机和容器使用不同的大文件系统,dir为宿主机中文件目录,${container_work_dir}为要挂载到的容器中的目录。为方便两个地址可以相同。
      • 容器不能挂载到/home/ma-user目录,此目录为ma-user用户家目录。如果容器挂载到/home/ma-user下,拉起容器时会与基础镜像冲突,导致基础镜像不可用。
      • driver及npu-smi需同时挂载至容器。
      • 不要将多个容器绑到同一个NPU上,会导致后续的容器无法正常使用NPU功能。
    • --name ${container_name}:容器名称,进入容器时会用到,此处可以自己定义一个容器名称。
    • {image_id} 为docker镜像的ID,即第四步中生成的新镜像id,在宿主机上可通过docker images查询得到。
  2. 进入容器
    docker exec -it -u ma-user ${container-name} /bin/bash
  3. 启动增量推理实例,命令如下。
    export GLOBAL_RANK_TABLE_FILE_PATH=global_ranktable_10.**.**.18.json
    export RANK_TABLE_FILE_PATH=local_rank_table_10.**.**.18_67.json
    
    export NODE_PORTS=8088,8089
    export USE_OPENAI=1
    
    sh AscendCloud-LLM/llm_tools/PD_separate/start_servers.sh \
        --model=${model} \
        --tensor-parallel-size=2 \
        --max-model-len=4096 \
        --max-num-seqs=256 \
        --max-num-batched-tokens=4096 \
        --host=0.0.0.0 \
        --port=8089 \
        --served-model-name ${served-model-name}

    其中环境变量说明如下:

    • GLOBAL_RANK_TABLE_FILE_PATH:global rank_table的路径,必选。不同实例类型的global rank_table均一致。
    • RANK_TABLE_FILE_PATH:local rank_table的路径,必选。当实例类型为全量推理实例或者增量推理实例,local rank_table配置local_ranktable_xx_yy.json文件,其中xx表示当前实例的IP地址,yy表示当前实例使用的device_id信息;当实例类型为服务入口实例,local rank_table配置local_ranktable_xx_host.json文件,其中xx表示当前实例的IP地址。
    • NODE_PORTS:仅在服务入口实例生效,用于与全量推理实例、增量推理实例的信息交互。该参数入参为形如{port1},{port2},{portn}的字符串,与全量/增量推理实例启动的--port参数相关,--port表示服务部署的端口。每个全量/增量推理实例基于配置的端口号(--port)启动服务,并按照global rank_table中的全量实例、增量实例的顺序,对全量推理实例、增量推理实例启动的端口号进行排序,端口之间用,(英文逗号)分隔开作为该环境变量的输入。
    • USE_OPENAI:仅在服务入口实例生效,用于配置api-server服务是否使用openai服务,默认为1。当配置为1时,启动服务为openai服务;当配置为0时,启动服务为vllm服务。

    其中常见的参数如下:

    • --host:服务部署的IP地址
    • --port:服务部署的端口,注意如果不同实例部署在一台机器上,不同实例需要使用不同端口号
    • --model:HuggingFace下载的官方权重
    • --max-num-seqs:同时处理的最大句子数量
    • --max-model-len:模型能处理的请求输入+输出的token长度
    • --max-num-batched-tokens:最多会使用多少token,必须大于或等于--max-model-len,推荐使用4096或8192
    • --tensor-parallel-size:模型并行数量
    • --served-model-name:openai服务的model入参名称,仅在环境变量`USE_OPENAI=1`时候生效。
    • --quantization:如果需要增加模型量化功能,启动推理服务前,先参考使用AWQ量化使用SmoothQuant量化使用GPTQ量化章节对模型做量化处理。

Step8 启动scheduler实例

建议在PD服务(即全量推理和增量推理服务)启动后,再启动scheduler服务。

  1. 启动scheduler容器。启动容器镜像前请先按照参数说明修改${}中的参数。docker启动失败会有对应的error提示,启动成功会有对应的docker id生成,并且不会报错。
    docker run -itd \
    -v /etc/localtime:/etc/localtime  \
    -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \
    -v /etc/ascend_install.info:/etc/ascend_install.info \
    --device=/dev/davinci_manager \
    --device=/dev/devmm_svm \
    --device=/dev/hisi_hdc \
    -v /var/log/npu/:/usr/slog \
    -v /usr/local/sbin/npu-smi:/usr/local/sbin/npu-smi \
    -v /sys/fs/cgroup:/sys/fs/cgroup:ro \
    -v ${dir}:${container_work_dir} \
    --net=host \
    --name ${container_name} \
    ${image_id} \
    /bin/bash

    参数说明:

    • --device=/dev/davinci0,..., --device=/dev/davinci7:挂载NPU设备,示例中挂载了0张卡。
    • -v ${dir}:${container_work_dir} 代表需要在容器中挂载宿主机的目录。宿主机和容器使用不同的大文件系统,dir为宿主机中文件目录,${container_work_dir}为要挂载到的容器中的目录。为方便两个地址可以相同。
      • 容器不能挂载到/home/ma-user目录,此目录为ma-user用户家目录。如果容器挂载到/home/ma-user下,拉起容器时会与基础镜像冲突,导致基础镜像不可用。
      • driver及npu-smi需同时挂载至容器。
      • 不要将多个容器绑到同一个NPU上,会导致后续的容器无法正常使用NPU功能。
    • --name ${container_name}:容器名称,进入容器时会用到,此处可以自己定义一个容器名称。
    • {image_id} 为docker镜像的ID,即第四步中生成的新镜像id,在宿主机上可通过docker images查询得到。
  2. 进入容器。
    docker exec -it -u ma-user ${container-name} /bin/bash
  3. 启动scheduler实例,命令如下。
    export GLOBAL_RANK_TABLE_FILE_PATH=global_ranktable_10.**.**.18.json
    export RANK_TABLE_FILE_PATH=local_rank_table_10.**.**.18_host.json
    export NODE_PORTS=8088,8089
    export USE_OPENAI=1
    
    sh AscendCloud-LLM/llm_tools/PD_separate/start_servers.sh \
        --model=${model} \
        --tensor-parallel-size=2 \
        --max-model-len=4096 \
        --max-num-seqs=256 \
        --max-num-batched-tokens=4096 \
        --host=0.0.0.0 \
        --port=9000 \
        --served-model-name ${served-model-name}
    
    # 当前schduler端口port对外提供推理服务,故使用该端口进行性能验证和精度对齐

    其中环境变量说明如下:

    • GLOBAL_RANK_TABLE_FILE_PATH:global rank_table的路径,必选。不同实例类型的global rank_table均一致。
    • NODE_PORTS:仅在服务入口实例生效,用于与全量推理实例、增量推理实例的信息交互。该参数入参为形如{port1},{port2},{portn}的字符串,与全量/增量推理实例启动的--port参数相关,--port表示服务部署的端口。每个全量/增量推理实例基于配置的端口号(--port)启动服务,并按照global rank_table中的全量实例、增量实例的顺序,对全量推理实例、增量推理实例启动的端口号进行排序,端口之间用`,`分隔开作为该环境变量的输入。当前端口9000是对外服务端口,而8088、8089则为scheduler调度推理服务端口。
    • USE_OPENAI:仅在服务入口实例生效,用于配置api-server服务是否使用openai服务,默认为1。当配置为1时,启动服务为openai服务;当配置为0时,启动服务为vllm服务。

    其中常见的参数如下,

    • --host:服务部署的IP
    • --port:服务部署的端口,注意如果不同实例部署在一台机器上,不同实例需要使用不同端口号
    • --model:HuggingFace下载的官方权重
    • --max-num-seqs:同时处理的最大句子数量
    • --max-model-len:模型能处理的请求输入+输出的token长度
    • --max-num-batched-tokens:最多会使用多少token,必须大于或等于--max-model-len,推荐使用4096或8192
    • --tensor-parallel-size:模型并行数量
    • --served-model-name:openai服务的model入参名称,仅在环境变量USE_OPENAI=1时候生效。
    • --quantization:如果需要增加模型量化功能,启动推理服务前,先参考使用AWQ量化使用SmoothQuant量化使用GPTQ量化章节对模型做量化处理。
    • 全量和增量节点的local rank table必须一一对应。
    • 全量和增量节点不能使用同一个端口。
    • scheduler实例中NODE_PORTS=8088,8089;端口设置顺序必须与global rank table文件中各全量和增量节点顺序一致,否则会报错。

Step9 推理请求

使用命令测试推理服务是否正常启动。服务启动命令中的参数设置请参见表1

通过OpenAI服务API接口启动服务使用以下推理测试命令。${docker_ip}替换为实际宿主机的IP地址。如果启动服务未添加served-model-name参数,${container_model_path}的值请与model参数的值保持一致,如果使用了served-model-name参数,${container_model_path}请替换为实际使用的模型名称。
curl -X POST http://${docker_ip}:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
    "model": "${container_model_path}",
    "messages": [
        {
            "role": "user",
            "content": "hello"
        }
    ],
    "max_tokens": 100,
    "top_k": -1,
    "top_p": 1,
    "temperature": 0,
    "ignore_eos": false,
    "stream": false
}'

服务的API与vLLM官网相同,此处介绍关键参数。详细参数解释请参见官网https://docs.vllm.ai/en/stable/dev/sampling_params.html

表1 请求服务参数说明

参数

是否必选

默认值

参数类型

描述

model

Str

通过OpenAI服务API接口启动服务时,推理请求必须填写此参数。取值必须和启动推理服务时的model ${container_model_path}参数保持一致。

通过vLLM服务API接口启动服务时,推理请求不涉及此参数。

prompt

-

Str

请求输入的问题。

max_tokens

16

Int

每个输出序列要生成的最大tokens数量。

top_k

-1

Int

控制要考虑的前几个tokens的数量的整数。设置为-1表示考虑所有tokens。

适当降低该值可以减少采样时间。

top_p

1.0

Float

控制要考虑的前几个tokens的累积概率的浮点数。必须在 (0, 1] 范围内。设置为1表示考虑所有tokens。

temperature

1.0

Float

控制采样的随机性的浮点数。较低的值使模型更加确定性,较高的值使模型更加随机。0表示贪婪采样。

stop

None

None/Str/List

用于停止生成的字符串列表。返回的输出将不包含停止字符串。

例如:["你","好"],生成文本时遇到"你"或者"好"将停止文本生成。

stream

False

Bool

是否开启流式推理。默认为False,表示不开启流式推理。

n

1

Int

返回多条正常结果。

约束与限制:

不使用beam_search场景下,n取值建议为1≤n≤10。如果n>1时,必须确保不使用greedy_sample采样。也就是top_k > 1; temperature > 0。

使用beam_search场景下,n取值建议为1<n≤10。如果n=1,会导致推理请求失败。

说明:

n建议取值不超过10,n值过大会导致性能劣化,显存不足时,推理请求会失败。

use_beam_search

False

Bool

是否使用beam_search替换采样。

约束与限制:使用该参数时,如下参数需按要求设置:

n>1

top_p = 1.0

top_k = -1

temperature = 0.0

presence_penalty

0.0

Float

presence_penalty表示会根据当前生成的文本中新出现的词语进行奖惩。取值范围[-2.0,2.0]。

frequency_penalty

0.0

Float

frequency_penalty会根据当前生成的文本中各个词语的出现频率进行奖惩。取值范围[-2.0,2.0]。

length_penalty

1.0

Float

length_penalty表示在beam search过程中,对于较长的序列,模型会给予较大的惩罚。

如果要使用length_penalty,必须添加如下三个参数,并且需将use_beam_search参数设置为true,best_of参数设置大于1,top_k固定为-1。

"top_k": -1

"use_beam_search":true

"best_of":2

ignore_eos

False

Bool

ignore_eos表示是否忽略EOS并且继续生成token。

guided_json

None

Union[str, dict, BaseModel]

使用openai启动服务,如果需要使用JSON Schema时要配置guided_json参数。

JSON Schema使用专门的关键字来描述数据结构,例如标题title、 类型type、属性properties,必须属性required 、定义definitions等,JSON Schema通过定义对象属性、类型、格式的方式来引导模型生成一个包含用户信息的JSON对象。

如果希望使用JSON Schema,guided_json的写法可参考outlines: Structured Text Generation中的“Efficient JSON generation following a JSON Schema”样例,如下图所示。

图1 guided_json样例
如果想在发送的请求中包含上述guided_json架构,可参考以下代码。如果prompt未提供充足信息可能导致返回的json文件部分结果为空。
curl -X POST http://${docker_ip}:8080/v1/completions \
-H "Content-Type: application/json" \
-d '{
    "model": "${container_model_path}",
    "prompt": "Meet our valorous character, named Knight, who has reached the age of 32. Clad in impenetrable plate armor, Knight is well-prepared for any battle. Armed with a trusty sword and boasting a strength score of 90, this character stands as a formidable warrior on the field.Please provide details for this character, including their Name, Age, preferred Armor, Weapon, and Strength",
    "max_tokens": 200,
    "temperature": 0,
    "guided_json": "{\"title\": \"Character\", \"type\": \"object\", \"properties\": {\"name\": {\"title\": \"Name\", \"maxLength\": 10, \"type\": \"string\"}, \"age\": {\"title\": \"Age\", \"type\": \"integer\"}, \"armor\": {\"$ref\": \"#/definitions/Armor\"}, \"weapon\": {\"$ref\": \"#/definitions/Weapon\"}, \"strength\": {\"title\": \"Strength\", \"type\": \"integer\"}}, \"required\": [\"name\", \"age\", \"armor\", \"weapon\", \"strength\"], \"definitions\": {\"Armor\": {\"title\": \"Armor\", \"description\": \"An enumeration.\", \"enum\": [\"leather\", \"chainmail\", \"plate\"], \"type\": \"string\"}, \"Weapon\": {\"title\": \"Weapon\", \"description\": \"An enumeration.\", \"enum\": [\"sword\", \"axe\", \"mace\", \"spear\", \"bow\", \"crossbow\"], \"type\": \"string\"}}}"
}'

相关文档