阅前说明

本文档主要介绍采用MindIE镜像的方式在离线环境下给服务器部署大模型,因在离线环境前需要准备好软件包以及模型,因此也同样适用有线环境,如有其他的问题请参考示例文档:

https://www.hiascend.com/software/modelzoo/models/detail/11aa2a48479d4d229a9830b8e41fc011

1.安装驱动以及固件

在准备进行部署大模型前需要确认服务器是否安装了驱动以及固件。可以通过以下指令来判断当前命令是否安装驱动,若返回驱动信息则证明已安装成功,则可以跳过第一章

npm-smi info

说明:

首次安装场景:硬件设备刚出厂时未安装驱动,或者硬件设备前期安装过驱动固件但是当前已卸载,上述场景属于首次安装场景,需按照“驱动->固件”的顺序安装驱动固件。

覆盖安装场景:硬件设备前期安装过驱动固件且未卸载,当前要再次安装驱动固件,此场景属于覆盖安装场景,需按照“固件->驱动”的顺序安装固件驱动。

本文仅主要介绍首次安装的场景,因首次安装的场景是大部分人会遇到的情况,覆盖安装场景请前往华为昇腾社区查询方法

1.1准备用户

指导用户创建安装和运行用户,若用户已存在,请跳过本节内容。

组件 安装用户 运行用户
NPU驱动和固件 root 由于安装驱动固件时,运行用户和用户组默认指定为HwHiAiUser,需在安装软件包前自行创建HwHiAiUser的运行用户和用户组。若创建的用户和用户组是非HwHiAiUser,安装驱动和固件时必须指定运行用户。

执行命令创建HwHiAiUer用户和用户组:

groupadd HwHiAiUser
useradd -g HwHiAiUser -d /home/HwHiAiUser -m HwHiAiUser -s /bin/bash

1.2首次安装

1.以root用户登录安装环境,之后将驱动包和固件包放置在任意目录下,或者可以自己新建文件夹进行放置比如:/root/data/npu

2.进入软件包所在的目录下,执行以下命令给驱动包还有固件包增加权限

chmod +x Ascend-hdk-<chip_type>-npu-driver_<version>_linux-<arch>.run
chmod +x Ascend-hdk-<chip_type>-npu-firmware_<version>.run

3.接下来进行驱动固件的安装,软件包的默认安装路径为"/usr/local/Ascend"。

a.执行如下命令进行安装驱动

./Ascend-hdk-<chip_type>-npu-driver_<version>_linux-<arch>.run --full --install-for-all

若系统出现以下信息则表示安装成功

Driver package installed successfully!

说明:假设执行命令时出现缺失部分Linux工具,请根据安装过程中的会先信息提示自行安装

b.执行如下命令进行安装固件

./Ascend-hdk-<chip_type>-npu-firmware_<version>.run --full

若系统出现如下关键回显信息,表示固件安装成功。

Firmware package installed successfully! Reboot now or after driver installation for the installation/upgrade to take effect

说明:如果驱动和固件运行用户和运行用户组未按照示例步骤创建为HwHiAiUser时,则在安装驱动和固件包时必须指定运行用户和用户组,示例命令如下:

./Ascend-hdk-<chip_type>-npu-driver_<version>_linux-<arch>.run --full --install-username=<username> --install-usergroup=<usergroup>

4.根据系统提示信息决定是否重启系统,若需要重启,请执行以下命令;否则,请跳过此步骤。

boot

5.执行如下命令查看驱动加载是否成功

npu-smi info

若返回驱动相关信息说明加载成功。否则,说明加载失败

2.模型及镜像传输

在准备实现部署大模型的过程需要进行配置好docker环境还有下载好大模型以及适配的mindie镜像。因此需要外部存储设备来进行挂载来获取所需要的文件,将外部存储设备插入服务器之后进行设备的识别

2.1挂载外部存储设备

在对系统进行任何存储操作前,首要任务是精确识别目标设备。此步骤至关重要,可有效防止对系统盘或其他关键数据盘的误操作。推荐使用 lsblk 命令来查看系统中所有块设备的信息,该命令能以树状结构清晰地展示设备及其分区。

lsblk

执行后终端会出现以下内容:

NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
sda           8:0    0   1.8T  0 disk
├─sda1        8:1    0   512M  0 part /boot/efi
└─sda2        8:2    0   1.8T  0 part /
sdb           8:16   0 931.5G  0 disk
└─sdb1        8:17   0 931.5G  0 part

分析与判断:

  • 设备名称 (NAME): 系统内置硬盘通常被识别为 sda。新接入的外部设备会按字母顺序依次命名为 sdbsdc 等。

  • 设备容量 (SIZE): 通过对比设备的标称容量与命令输出的 SIZE 值,可以快速定位目标设备。上例中,931.5Gsdb 设备即为目标外部硬盘。

  • 目标分区: 操作的核心对象是设备的分区,即带有数字后缀的名称,如 sdb1请准确记录此分区标识符(例如 /dev/sdb1),后续操作将使用此路径。

作为备选,sudo fdisk -l 命令可提供更详尽的分区表信息,同样可用于设备识别。

2.2创建挂载点

挂载点 (Mount Point) 是 Linux 文件系统中的一个目录,作为访问外部设备文件系统的入口。在挂载操作完成后,对此目录的读写即是对外部设备内数据的读写。

通常,挂载点创建于 /mnt/media 目录下。

mkdir /mnt/mydev

2.3执行挂载操作

此步骤是将已识别的设备分区与创建的挂载点进行关联。

使用 mount 命令完成此操作:

mount /dev/sdb1 /mnt/mydev

命令格式为: mount [设备分区路径] [挂载点路径]

2.4文件传输

设备成功挂载后,即可通过挂载点路径 /mnt/mydev 对其进行文件操作。因为我们要从外部存储设备取文件,执行以下命令:

cp /mnt/mydev/data.zip /path/to/server/destination/

命令格式为: cp [挂载点路径] [想要放置文件的路径]

3.docker环境部署

3.1确认架构

再将需要的文件取过来之后我们需要进行docker环境的安装,再进行安装之前需要查看docker的安装包是否与系统的架构是否匹配:

查看系统架构,确认架构

[root@localhost ~]uname -p
x86_64
服务器如果是鲲鹏,架构是aarch64
aarch64

之后去对应的官网获取相对应的架构包,此方法同样适用于任何镜像,不单单是docker,假设系统是aarch64的话,下载mysql可以去官网获取相应的架构包

3.2开始安装docker

再确认无误之后我们进入到对应的文件目录,执行命令进行解压

tar -zxvf docker-20.10.7.tgz

将二进制文件复制到/usr/bin/下进行配置

cp docker/* /usr/bin/

这时候配置添加 systemd

vi /usr/lib/systemd/system/docker.service

在这个文件添加

[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service
Wants=network-online.target
[Service]
Type=notify
ExecStart=/usr/bin/dockerd
ExecReload=/bin/kill -s HUP $MAINPID
LimitNOFILE=infinity
LimitNPROC=infinity
TimeoutStartSec=0
Delegate=yes
KillMode=process
Restart=on-failure
StartLimitBurst=3
StartLimitInterval=60s
[Install]
WantedBy=multi-user.target

注意想要推出点击Esc键,输入:wq就可以保存推出了,之后加载重启docker

systemctl daemon-reload
systemctl restart docker

同时我们设置docker开机自启动来确保下次再进入服务器依旧能识别docker命令

systemctl enable docker

这时候我们可以通过输入以下命令查看docker是否能开机自启动了,假设能看到回显enable就代表成功了

systemctl is-enabled docker

输入下面的指令,弹出信息就代表安装成功了

docker info

4.加载镜像

进入mindie的文件路径下,执行命令进行加载

docker load -i mindie:1.0.0-800I-A2-py311-openeuler24.03-lts(下载的镜像名称与标签)

完成加载镜像后,请使用docker images命令确认查找具体镜像名称与标签。

docker images

5.新建容器

如果您使用的是root用户镜像(例如从Ascend Hub上取得),并且可以使用特权容器,请使用以下命令启动容器:

docker run -it -d --net=host --shm-size=1g \
    --privileged \
    --name <container-name> \
    --device=/dev/davinci_manager \
    --device=/dev/hisi_hdc \
    --device=/dev/devmm_svm \
    -v /usr/local/Ascend/driver:/usr/local/Ascend/driver:ro \
    -v /usr/local/sbin:/usr/local/sbin:ro \
    -v /path-to-weights:/path-to-weights:ro \
    mindie:1.0.0-800I-A2-py311-openeuler24.03-lts bash

如果您希望使用自行构建的普通用户镜像,并且规避容器相关权限风险,可以使用以下命令指定用户与设备:

docker run -it -d --net=host --shm-size=1g \
    --name <container-name> \
    --device=/dev/davinci_manager \
    --device=/dev/hisi_hdc \
    --device=/dev/devmm_svm \
    --device=/dev/davinci0 \
    --device=/dev/davinci1 \
    --device=/dev/davinci2 \
    --device=/dev/davinci3 \
    --device=/dev/davinci4 \
    --device=/dev/davinci5 \
    --device=/dev/davinci6 \
    --device=/dev/davinci7 \
    -v /usr/local/Ascend/driver:/usr/local/Ascend/driver:ro \
    -v /usr/local/sbin:/usr/local/sbin:ro \
    -v /path-to-weights:/path-to-weights:ro \
    mindie:1.0.0-800I-A2-py311-openeuler24.03-lts bash

说明:在这里我们需要变动的是<container-name>,这个是我们自定义的容器名称,

两个一样/path-to-weights,这是你模型的文件的路径,第一个是你服务器上的文件的路径,第二个是创建容器的模型存放的路径,如果担心出问题或者不是很清楚的话,都把这两个路径改成服务器上的模型文件的路径就好了

mindie:1.0.0-800I-A2-py311-openeuler24.03-lts 这个是mindie的镜像名称,也可以使用docker images命令来获取镜像的id来进行替换

6.进入容器

这时候执行命令进入容器

docker exec -it ${容器名称} bash

7.服务化推理

说明当我们建立容器之后是需要进行一个基本的推理来判断模型是否成功部署,推理有服务化推理以及纯模型推理,本文主要介绍服务化推理,想试试纯模型推理的话请前往上方的链接

ps:这时候你已经进入容器了需要推出的话执行exit来进行推出,有的时候需要执行多次才能退出容器回到服务器

exit

当我们进入到容器之后我们需要编辑文件进行配置:

vim /usr/local/Ascend/mindie/latest/mindie-service/conf/config.json

打开之后配置如下(#后面的备注如有自定义一定要修改,实际情况的话看着修改):

{
    "Version": "1.0.0",
    "LogConfig" :
    {
        "logLevel" : "Info",
        "logFileSize" : 20,
        "logFileNum" : 20,
        "logPath" : "logs/mindservice.log"
    },

    "ServerConfig" :
    {
        "ipAddress" : "127.0.0.1",   #请求ip地址,根据实际情况设置
        "managementIpAddress": "127.0.0.2",#根据实际情况进行修改(新手的话建议把这两个ip都改成服务器的ip)
        "port" : 1025, #端口号,根据实际情况修改
        "managementPort" : 1026,
        "metricsPort" : 1027,
        "allowAllZeroIpListening" : false, 
        "maxLinkNum" : 1000,
        "httpsEnabled" : false, # https通信安全认证,测试环境下建议设置为false
        "fullTextEnabled" : false,
        "tlsCaPath" : "security/ca/",
        "tlsCaFile" : ["ca.pem"],
        "tlsCert" : "security/certs/server.pem",
        "tlsPk" : "security/keys/server.key.pem",
        "tlsPkPwd" : "security/pass/key_pwd.txt",
        "tlsCrlPath" : "security/certs/",
        "tlsCrlFiles" : ["server_crl.pem"],
        "managementTlsCaFile" : ["management_ca.pem"],
        "managementTlsCert" : "security/certs/management/server.pem",
        "managementTlsPk" : "security/keys/management/server.key.pem",
        "managementTlsPkPwd" : "security/pass/management/key_pwd.txt",
        "managementTlsCrlPath" : "security/management/certs/",
        "managementTlsCrlFiles" : ["server_crl.pem"],
        "kmcKsfMaster" : "tools/pmt/master/ksfa",
        "kmcKsfStandby" : "tools/pmt/standby/ksfb",
        "inferMode" : "standard",
        "interCommTLSEnabled" : true,
        "interCommPort" : 1121,
        "interCommTlsCaPath" : "security/grpc/ca/",
        "interCommTlsCaFiles" : ["ca.pem"],
        "interCommTlsCert" : "security/grpc/certs/server.pem",
        "interCommPk" : "security/grpc/keys/server.key.pem",
        "interCommPkPwd" : "security/grpc/pass/key_pwd.txt",
        "interCommTlsCrlPath" : "security/grpc/certs/",
        "interCommTlsCrlFiles" : ["server_crl.pem"],
        "openAiSupport" : "vllm"
    },

    "BackendConfig": {
        "backendName" : "mindieservice_llm_engine",
        "modelInstanceNumber" : 1,
        "npuDeviceIds" : [[0,1,2,3]], #要使用的npu编号,根据实际情况进行配置
        "tokenizerProcessNumber" : 8,
        "multiNodesInferEnabled": false,
        "multiNodesInferPort": 1120,
        "interNodeTLSEnabled": true,
        "interNodeTlsCaPath": "security/grpc/ca/",
        "interNodeTlsCaFiles": ["ca.pem"],
        "interNodeTlsCert": "security/grpc/certs/server.pem",
        "interNodeTlsPk": "security/grpc/keys/server.key.pem",
        "interNodeTlsPkPwd": "security/grpc/pass/mindie_server_key_pwd.txt",
        "interNodeTlsCrlPath" : "security/grpc/certs/",
        "interNodeTlsCrlfiles" : ["server_crl.pem"],
        "interNodeKmcKsfMaster": "tools/pmt/master/ksfa",
        "interNodeKmcKsfStandby": "tools/pmt/standby/ksfb",
        "ModelDeployConfig":
        {
            "maxSeqLen" : 2560,
            "maxInputTokenLen" : 2048, 
            "truncation" : false,
            "ModelConfig" : [
                {
                    "modelInstanceType": "Standard",
                    "modelName" : "llama_65b",  # 模型名称,用于标识,后面做测试的时候会用到,自定义
                    "modelWeightPath" : "/data/atb_testdata/weights/llama1-65b", #容器内模型路径,自定义
                    "worldSize" : 4, # 该参数要求与npu卡的数量同步
                    "cpuMemSize" : 5,
                    "npuMemSize" : -1,
                    "backendType": "atb",
                    "trustRemoteCode": false
                }
            ]
        },

        "ScheduleConfig":
        {
            "templateType": "Standard",
            "templateName" : "Standard_LLM",
            "cacheBlockSize" : 128,

            "maxPrefillBatchSize" : 50,
            "maxPrefillTokens" : 8192,
            "prefillTimeMsPerReq" : 150,
            "prefillPolicyType" : 0,

            "decodeTimeMsPerReq" : 50,
            "decodePolicyType" : 0,

            "maxBatchSize" : 200, # 最大BatchSize
            "maxIterTimes" : 512, # 输出序列长度
            "maxPreemptCount" : 0,
            "supportSelectBatch" : false,
            "maxQueueDelayMicroseconds" : 5000
        }
    }
}

7.拉起服务化

输入:

cd /usr/local/Ascend/mindie/latest/mindie-service/bin
./mindieservice_daemon

这时候等会就会看到Success的消息,表示离成功不远了

8.新建窗口

这时候我们再新建一个连接服务器的窗口

curl 127.0.0.1:1025/generate -d '{ #127.0.0.1是我们请求的ip,1025自定义的端口
"prompt": "What is deep learning?",#提问的问题
"max_tokens": 32,#输出的最大内容token
"stream": false,#是否流式输出
"do_sample":true,
"repetition_penalty": 1.00,
"temperature": 0.01,
"top_p": 0.001,
"top_k": 1,
"model": "qwen"#模型名称
}'

这时候就能看到模型的回答了

9.卸载外部设备

最后进行卸载设备就好了

umount /mnt/mydev
#或者
umount /dev/sdb1

若系统返回 target is busy 错误,表示设备仍被占用。可使用 lsof | grep /mnt/mydev 等命令检查并终止相关进程。

9.常见问题

9.1权限问题

当你在拉起服务化的时候发现权限问题的情况时

请你退出容器在服务器里进入到模型路径下,使用指令修改文件权限再新建容器即可

chmod 640 config.json

9.2transformers问题

ImportError: cannot import name 'shard_checkpoint' from 'transformers.modeling_utils'. 

降低transformers版本可解决。输入

pip install transformers==4.46.3 --force-reinstall
pip install numpy==1.26.4 --force-reinstall
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐