vLLM、ollama方式部署本地大模型(单机)
1.安装显卡驱动
1.1 查看显卡类型
- PCI/PCIe 总线的硬件设备信息:
[root@localhost ~]# lspci | grep -E "NVIDIA|VGA"
02:00.0 VGA compatible controller: Huawei Technologies Co., Ltd. Hi171x Series [iBMC Intelligent Management system chip w/VGA support] (rev 01)
3b:00.0 3D controller: NVIDIA Corporation TU104GL [Tesla T4] (rev a1)
3c:00.0 3D controller: NVIDIA Corporation TU104GL [Tesla T4] (rev a1)
5e:00.0 3D controller: NVIDIA Corporation TU104GL [Tesla T4] (rev a1)
86:00.0 3D controller: NVIDIA Corporation TU104GL [Tesla T4] (rev a1)
87:00.0 3D controller: NVIDIA Corporation TU104GL [Tesla T4] (rev a1)
af:00.0 3D controller: NVIDIA Corporation TU104GL [Tesla T4] (rev a1)
d8:00.0 3D controller: NVIDIA Corporation TU104GL [Tesla T4] (rev a1)
可以看到显卡类型:NVIDIA Corporation TU104GL [Tesla T4] (rev a1)
- 查看系统类型
cat /etc/os-release
终端输出信息:
NAME="Kylin Linux Advanced Server"
VERSION="V10 (Halberd)"
ID="kylin"
VERSION_ID="V10"
PRETTY_NAME="Kylin Linux Advanced Server V10 (Halberd)"
ANSI_COLOR="0;31"
- 查看系统架构
lscpu
1.2 下载显卡驱动
NVIDIA
显卡下载官网地址:Download The Official NVIDIA Drivers | NVIDIA
根据显卡类型
、系统平台
下载显卡驱动,下载页面选择的下载配置参考如下:
名称 | 选择值 |
---|---|
Select Product Category | 选择 Data Center /Tesla |
Select Product Series | 选择 T-Series |
Select Product | 选择 Tesla T4 |
Select Operating System | 选择 Linux 64-bit |
Any CUDA Toolkit Version | (可)选择 12.8 |
English(US) | 默认就选英文(不推荐中文) |
注意:Operating System
请选择Linux 64-bit
,下载后的文件名称:NVIDIA-Linux-x86_64-570.86.15 .run
,是.run格式的
1.3 kernel-devel
安装与当前内核版本匹配的 kernel-devel 包:
yum install "kernel-devel-uname-r == $(uname -r)"
重启:
reboot
1.4 禁用Nouveau驱动
参考:禁用nouveau驱动 - 华为鲲鹏服务器 GPU卡操作指导书 03 - 华为
防止冲突,禁用Nouveau驱动;查看命令:
lsmod | grep nouveau
如果终端输出信息中包含Nouveau
驱动信息,说明Nouveau
驱动已安装,则需要禁用Nouveau
驱动,禁用步骤如下:
- 编辑
blacklist.conf
文件
vi /etc/modprobe.d/blacklist.conf
编辑内容:
# 注释掉blacklist nvidiafb (# blacklist nvidiafb)
# 添加下面2行
blacklist nouveau
options nouveau modeset=0
执行以下命令,备份并新建一个initramfs
:
mv /boot/initramfs-$(uname -r).img /boot/initramfs-$(uname -r).img.bak
dracut -v /boot/initramfs-$(uname -r).img $(uname -r)
重启:
reboot
1.5 禁用GUI (图形化)
命令:
systemctl set-default multi-user.target
设置为 multi-user.target
后,系统将启动到命令行界面,多个用户可以同时登录,但不启动图形桌面环境。这个模式适用于服务器环境或需要稳定命令行操作的场景,不需要图形用户界面的干扰。
重启:
reboot
其他命令:
# 如果有需要,执行下面命令恢复默认图形界面
systemctl set-default graphical.target
1.6 安装显卡驱动
参考:
手动安装GPU加速型ECS的Tesla驱动_弹性云服务器 ECS_华为云
在Centos上为Tesla T4显卡安装NVIDIA驱动以及cuda和cudnn_t4显卡驱动-CSDN博客
命令:
# 添加可运行权限
chmod +x NVIDIA-Linux-x86_64-570.86.15.run
# 安装
sh NVIDIA-Linux-x86_64-570.86.15.run
安装后,重启:
reboot
查看显卡信息:
nvidia-smi
# watch -n 1 nvidia-smi (终端每秒刷新显卡信息)
输出信息参考如下:
(vllm) [root@localhost bin]# nvidia-smi
Thu Feb 20 23:52:41 2025
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 570.86.15 Driver Version: 570.86.15 CUDA Version: 12.8 |
|-----------------------------------------+------------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+========================+======================|
| 0 Tesla T4 Off | 00000000:3B:00.0 Off | 0 |
| N/A 69C P0 30W / 70W | 1MiB / 15360MiB | 0% Default |
| | | N/A |
+-----------------------------------------+------------------------+----------------------+
| 1 Tesla T4 Off | 00000000:3C:00.0 Off | 0 |
| N/A 70C P0 28W / 70W | 1MiB / 15360MiB | 0% Default |
| | | N/A |
+-----------------------------------------+------------------------+----------------------+
| 2 Tesla T4 Off | 00000000:5E:00.0 Off | 0 |
| N/A 69C P0 31W / 70W | 1MiB / 15360MiB | 0% Default |
| | | N/A |
+-----------------------------------------+------------------------+----------------------+
| 3 Tesla T4 Off | 00000000:86:00.0 Off | 0 |
| N/A 73C P0 32W / 70W | 1MiB / 15360MiB | 0% Default |
| | | N/A |
+-----------------------------------------+------------------------+----------------------+
| 4 Tesla T4 Off | 00000000:87:00.0 Off | 0 |
| N/A 75C P0 33W / 70W | 1MiB / 15360MiB | 0% Default |
| | | N/A |
+-----------------------------------------+------------------------+----------------------+
| 5 Tesla T4 Off | 00000000:AF:00.0 Off | 0 |
| N/A 67C P0 30W / 70W | 1MiB / 15360MiB | 0% Default |
| | | N/A |
+-----------------------------------------+------------------------+----------------------+
| 6 Tesla T4 Off | 00000000:D8:00.0 Off | 0 |
| N/A 73C P0 32W / 70W | 1MiB / 15360MiB | 5% Default |
| | | N/A |
+-----------------------------------------+------------------------+----------------------+
+-----------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=========================================================================================|
| No running processes found |
+-----------------------------------------------------------------------------------------+
1.7 cuda-toolkit安装
下载地址: https://developer.nvidia.com/cuda-toolkit-archive
根据系统信息选择,参考选择如下:
Operating System --> 选择`Linux`
Architecture --> 选择`x86_64`
Distribution --> 选择`KylinOS`
Version --> 选择`10`
Installer Type --> 选择`runfile(local)`
安装命令:
wget https://developer.download.nvidia.com/compute/cuda/12.8.0/local_installers/cuda_12.8.0_570.86.10_linux.run
chmod +x cuda_12.8.0_570.86.10_linux.run
sudo sh cuda_12.8.0_570.86.10_linux.run
安装成功结果:
[root@localhost nvidia_driver]# ./cuda_12.8.0_570.86.10_linux.run
===========
= Summary =
===========
Driver: Not Selected
Toolkit: Installed in /usr/local/cuda-12.8/
Please make sure that
- PATH includes /usr/local/cuda-12.8/bin
- LD_LIBRARY_PATH includes /usr/local/cuda-12.8/lib64, or, add /usr/local/cuda-12.8/lib64 to /etc/ld.so.conf and run ldconfig as root
To uninstall the CUDA Toolkit, run cuda-uninstaller in /usr/local/cuda-12.8/bin
***WARNING: Incomplete installation! This installation did not install the CUDA Driver. A driver of version at least 570.00 is required for CUDA 12.8 functionality to work.
To install the driver using this installer, run the following command, replacing <CudaInstaller> with the name of this run file:
sudo <CudaInstaller>.run --silent --driver
Logfile is /var/log/cuda-installer.log
添加环境变量:
vim ~/.bashrc
编辑内容如下:
# cuda-toolkit
export PATH=/usr/local/cuda-12.8/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/cuda-12.8/lib64:$LD_LIBRARY_PATH
export CUDA_HOME=/usr/local/cuda-12.8
生效配置的环境变量:
source ~/.bashrc
验证安装:
nvcc --version
# 输出内容有 Cuda compilation tools, release 12.8, V12.8.61 类似这种的,代表安装好了。
1.8 cuDNN安装
下载地址:https://developer.nvidia.com/rdp/cudnn-archive
解压文件:
tar -xvf cudnn-linux-x86_64-8.9.7.29_cuda11-archive.tar.xz
将解压后的头文件和库复制到cuda目录中:
# 切换到 cudnn 安装目录
cd cudnn-linux-x86_64-8.9.7.29_cuda11-archive
# 将 cuDNN 的头文件复制到 CUDA 的 include 目录下
sudo cp include/cudnn* /usr/local/cuda/include
# 将 cuDNN 的库文件复制到 CUDA 的 lib64 目录下
sudo cp lib/libcudnn* /usr/local/cuda/lib64
# 修改文件权限,确保所有用户都可以读取 cudnn 头文件和库文件
sudo chmod a+r /usr/local/cuda/include/cudnn* /usr/local/cuda/lib64/libcudnn*
cuDNN安装完成,查看安装的版本:
# 查看 cudnn_version.h 文件中的 CUDNN_MAJOR 宏定义,并显示该行以及后续的两行
cat /usr/local/cuda/include/cudnn_version.h | grep CUDNN_MAJOR -A 2
终端显示:
#define CUDNN_MAJOR 8
#define CUDNN_MINOR 9
#define CUDNN_PATCHLEVEL 7
--
#define CUDNN_VERSION (CUDNN_MAJOR * 1000 + CUDNN_MINOR * 100 + CUDNN_PATCHLEVEL)
1.9 torch-CUDA虚拟环境安装
2. 下载离线模型
如果已经用迅雷或者其他方式已经下载好了离线的模型库文件,或者有更好的下载离线模型方式,可以略过下载离线模型步骤。
2.1 配置镜像加速
编辑文件:
vim /etc/profile
添加如下内容:
# huggingface.co 加速
export HF_ENDPOINT=https://hf-mirror.com
生效:
source /etc/profile
2.2 创建虚拟环境
venv
是 Python 的内置模块,用于创建虚拟环境。虚拟环境允许你在项目中隔离依赖包,避免与全局环境中的其他项目产生冲突。使用虚拟环境可以确保项目的依赖独立,易于管理和部署。以下步骤请在python3虚拟环境中执行。
创建虚拟环境:
# 切换路径
cd /usr/local/python3/bin
# 退出conda环境
conda deactivate
# 创建虚拟环境
python3 -m venv my-environment
2.3 下载模型到本地
激活虚拟环境:
source my-environment/bin/activate
虚拟环境中执行:
pip install -U huggingface_hub
利用huggingface-cli
下载模型语法:
huggingface-cli download --resume-download {填写huggingface.co官网的model name} --local-dir {模型的保存路径}
创建模型保存目录:
mkdir -p /home/data/models/DeepSeek-R1-Distill-Qwen-1.5B
下载模型到本地:
huggingface-cli download --resume-download deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B --local-dir /home/data/models/DeepSeek-R1-Distill-Qwen-1.5B
退出虚拟环境命令:
deactivate
3. 安装Deepseek
3.1 ollama方式
3.1.1 安装
Linux平台安装命令:
curl -fsSL https://ollama.com/install.sh | sh
脚本内容在线参考:ollama/docs/linux.md at main · ollama/ollama · GitHub
3.1.2 配置ollama自启动
编辑systemd自启动文件:
vim /etc/systemd/system/ollama.service
编辑参考内容:
[Unit]
Description=ollama Service
After=network-online.target
[Service]
ExecStart=/usr/bin/ollama serve
Environment="PATH=/usr/local/sbin:/usr/sbin:/usr/local/bin:/usr/bin:/bin:/root/bin"
Environment="OLLAMA_MODELS=/home/data/ollama/models"
[Install]
WantedBy=default.target
3.1.3 运行Deepseek
3.1.3.1 方式一
直接使用使用ollama
命令,运行Deepseek:
ollama run deepseek-r1:{参数数量}b
3.1.3.2 方式二
使用下载到本地的模型进行部署
3.1.3.2.1 配置加速
# 编辑文件
vim /etc/profile
# huggingface加速
export HF_ENDPOINT=https://hf-mirror.com
# 生效
source /etc/profile
3.1.3.2.2 下载模型库
创建模型保存的目录:
mkdir -p /home/data/models/deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B
创建虚拟环境:
python3 -m venv my-environment
激活虚拟环境:
source my-environment/bin/activate
虚拟环境中执行:
# 进入虚拟环境中执行
pip install -U huggingface_hub
虚拟环境中执行:
# 下载模型库
huggingface-cli download --resume-download {复制huggingface.co模型的名称} --local-dir /home/data/models/deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B
3.1.3.2.3 转换并运行
把离线下载好的deepseek
本地模型转换成ollama能用的,操作步骤如下:
切换到模型库下载目录:
cd /home/yyj/data/models/deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B
创建ollama构建镜像的文件:
vim /home/yyj/data/models/deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B/Modelfile
Modelfile
内容如下:
# Modelfile generated by "ollama show"
# To build a new Modelfile based on this, replace FROM with:
# FROM {需要替换成离线模型库保存的位置}
FROM /home/yyj/data/models/deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B
TEMPLATE """{{- if .System }}{{ .System }}{{ end }}
{{- range $i, $_ := .Messages }}
{{- $last := eq (len (slice $.Messages $i)) 1}}
{{- if eq .Role "user" }}<|User|>{{ .Content }}
{{- else if eq .Role "assistant" }}<|Assistant|>{{ .Content }}{{- if not $last }}<|end▁of▁sentence|>{{- end }}
{{- end }}
{{- if and $last (ne .Role "assistant") }}<|Assistant|>{{- end }}
{{- end }}"""
PARAMETER stop <|begin▁of▁sentence|>
PARAMETER stop <|end▁of▁sentence|>
PARAMETER stop <|User|>
PARAMETER stop <|Assistant|>
运行:
ollama create DeepSeek-R1-Distill-Qwen-1.5B -f /home/yyj/data/models/deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B/Modelfile
3.1.4 检验Deepseek状态
检验ollama安装deepseek是否成功,命令如下:
curl http://127.0.0.1:11434
3.1.5 ollama命令
常用命令如下:
# 列出可用的模型
ollama list
# 加载并运行模型
ollama run <model_name>
# 获取模型的信息
ollama info <model_name>
# 列出所有已安装的模型
ollama installed
# 安装特定的模型
ollama pull <model_name>
# 卸载模型
ollama remove <model_name>
# 显示帮助信息
ollama --help
3.2 vLLM方式
3.2.1 安装conda
官网地址:Download Anaconda Distribution | Anaconda (下载精简的Miniconda版本)
查看平台架构:
lscpu
根据平台架构下架(x86_64
):
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
安装:
chmod +x Anaconda3-2024.10-1-Linux-x86_64.sh
sh Anaconda3-2024.10-1-Linux-x86_64.sh
配置环境变量:
vim ~/.bashrc
参考内容:
export PATH="$PATH:{conda安装路径}/bin"
生效配置的环境变量:
source ~/.bashrc
查看版本:
conda -V
# 初始化 Conda 运行环境
# 适用于 bash 终端用户(如 Ubuntu、CentOS、WSL 等)
conda init bash
# 适用于 zsh 终端用户(如 macOS 默认的终端 shell)
conda init zsh
配置镜像加速:
# vim ~/.condarc
vim /{conda安装目录}/.condarc
.condarc
参考内容:
channels:
- defaults
show_channel_urls: true
default_channels:
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/pytorch/
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/msys2/
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
custom_channels:
conda-forge: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
msys2: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
bioconda: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
menpo: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
pytorch: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
simpleitk: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
备用加速参考内容:
channels:
- http://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
- http://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/
- http://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/msys2/
show_channel_urls: true
default_channels:
- http://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main
- http://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/r
- http://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/msys2
custom_channels:
conda-forge: http://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
msys2: http://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
bioconda: http://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
menpo: http://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
pytorch: http://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
pytorch-lts: http://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
simpleitk: http://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
查看conda信息:
conda info
其他命令(有需求执行):
# 退出当前的 Conda 环境
conda deactivate
# 退出 base 环境并不再自动激活
conda config --set auto_activate_base false
3.2.2 创建虚拟环境
You can create a new Python environment using conda
:
# 创建conda虚拟环境
conda create -n vllm python=3.12 -y
# 激活
conda activate vllm
3.2.3 安装pytorch
切换conda虚拟环境:
conda activate vllm
配置pip
加速:
vim /etc/pip.conf
添加如下内容:
[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple
timeout = 600
测试生效:
pip config list
下载地址:download.pytorch.org/whl/torch/
根据显卡信息中的CUDA版本下载,因为显卡信息中的CUDA是CUDA Version: 12.8
,这里需要下载低于12.8版本的。
下载:torch-2.4.0+cu124-cp312-cp312-linux_x86_64.whl (cu124
指的是CUDA版本是12.4、cp312
指的是python 3.12环境),下载后保存到路径/usr/local
下
安装:
# 安装
pip install /usr/local/torch-2.4.0+cu124-cp312-cp312-linux_x86_64.whl
验证安装:
pip show torch
# 或者
pip list | grep torch
3.2.4 安装vllm
参考vllm官方文档:Installation — vLLM
命令:
# 切环境
conda activate vllm
# 安装
pip install vllm
查看版本:
vllm --version
输出内容参考:
(vllm) [root@localhost bin]# vllm --version
INFO 02-21 08:41:14 __init__.py:207] Automatically detected platform cuda.
0.7.3
升级vllm命令:
pip install --upgrade vllm
3.2.5 vllm运行deepseek
进入虚拟环境:
conda activate vllm
运行命令:
CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6 vllm serve /home/data/models/DeepSeek-R1-Distill-Qwen-32B \
--pipeline-parallel-size 7 \
--tensor-parallel-size 1 \
--host 0.0.0.0 \
--port 8000 \
--max_model_len 2048 \
--gpu-memory-utilization 0.9 \
--max-num-seqs 32 \
--served-model-name "DeepSeek-R1-Distill-Qwen-32B" \
--dtype=half
参数的详细解释:
-
CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6
含义: 指定使用哪些 GPU 设备。这个环境变量告诉 CUDA 运行时只使用编号为 0 到 4 的 GPU(共 7 个 GPU)。
作用: 限制模型运行在指定的 GPU 上,而不是系统中的所有 GPU。
例子: 如果系统中还有其他 GPU(比如 7、8),它们不会被这个进程使用。 -
vllm serve
含义: 调用 vLLM 的服务启动命令,用于部署模型并提供推理服务。
作用: 启动一个服务器,允许通过网络请求(比如 HTTP API)对模型进行推理。 -
/home/data/models/DeepSeek-R1-Distill-Qwen-32B
含义: 指定要加载的模型路径。在 FP16 精度下(--dtype=half),每个参数占 2 字节,模型权重大约需要 64GB 显存。加上激活值、KV 缓存等,显存需求可能接近或超过 80GB。
作用: 告诉 vLLM 使用这个目录下的模型文件(DeepSeek-R1-Distill-Qwen-32B)进行推理。这通常是一个预训练的大型语言模型。 -
--pipeline-parallel-size 7
含义: 设置管道并行的大小为 7。
作用: 将模型的计算任务分成 7 个阶段,每个阶段分配给一个 GPU。这种方式利用多个 GPU 并行处理模型的不同层或部分,适合超大模型推理。
注意: 这里 7 对应于 CUDA_VISIBLE_DEVICES 中指定的 7 个 GPU。 -
--tensor-parallel-size 1
含义: 设置张量并行的大小为 1。
作用: 张量并行是将模型的张量(比如权重矩阵)分割到多个 GPU 上并行计算。这里设为 1,意味着不使用张量并行,每个 GPU 完整持有模型的一部分(配合管道并行使用)。
对比: 如果设为大于 1,会在多个 GPU 间分割同一层的计算。 -
--host 0.0.0.0
含义: 指定服务器监听的主机地址。
作用: 0.0.0.0 表示服务器监听所有网络接口,允许外部设备通过网络访问服务。
例子: 如果设为 127.0.0.1,则只能本地访问。 -
--port 8000
含义: 指定服务器监听的端口号。
作用: 服务将运行在 8000 端口,客户端可以通过这个端口发送推理请求。
例子: 你可以用 http://<服务器IP>:8000 来访问服务。 -
--max_model_len 2048
含义: 设置模型支持的最大序列长度为 2048 个 token。
作用: 限制输入和输出的总长度(包括上下文和生成内容),避免内存溢出。
注意: 如果输入超过这个长度,可能会被截断或报错。 -
--gpu-memory-utilization 0.9
含义: 设置 GPU 内存利用率为 90%。
作用: 控制每个 GPU 上分配给模型的显存比例(这里是 90%),剩余部分留给系统或其他开销。
例子: 如果一块 GPU 有 24GB 显存,这里会分配约 21.6GB 给模型。 -
--max-num-seqs 32
指定 vLLM 在一次批处理中最多处理的序列数(即最大 batch size)。它限制了并发请求的上限,直接影响吞吐量和显存使用。
vLLM 默认可能是 256(视版本而定),但会受显存和 --max_model_len 限制。
-
--served-model-name 'DeepSeek-R1-Distill-Qwen-32B'
含义: 指定服务中模型的名称。
作用: 客户端请求时可以用这个名字来标识模型,通常用于区分多个部署的模型。
例子: 在 API 请求中可能会用 "model": "DeepSeek-R1-Distill-Qwen-32B" 来调用。 -
--dtype=half
含义: 指定模型的数据类型为半精度浮点数(FP16)。
作用: 使用 FP16(而不是默认的 FP32)来减少显存占用并加速计算,同时保持合理的精度。
注意: 需要 GPU 支持 FP16 计算(比如 NVIDIA 的 Volta、Turing、Ampere 架构)。
其他说明:
pipeline-parallel-size
和tensor-parallel-size
这两个参数相乘就是总的GPU需求数量,相乘的积需要小于总的可用的GPU数量,注意配置合理。
实际生产过程中发现(7张T4):pipeline-parallel-size * tensor-parallel-size的积为偶数最佳,单独的一个显存用来分配给嵌入模型使用。
3.2.6 配置启动脚本
创建文件夹
mkdir -p /usr/local/deepseek
3.2.6.1 普通脚本
编辑脚本文件
vim /usr/local/deepseek/start_DeepSeek-R1-Distill-Qwen-32B_By_vLLM.sh
脚本内容参考如下:
#!/bin/bash
# 加载 conda 环境
source /usr/local/miniconda3/etc/profile.d/conda.sh
conda activate vllm
# 启动 vllm 服务
CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6 vllm serve /home/data/models/DeepSeek-R1-Distill-Qwen-32B \
--pipeline-parallel-size 7 \
--tensor-parallel-size 1 \
--host 0.0.0.0 \
--port 8000 \
--max_model_len 4096 \
--gpu-memory-utilization 0.9 \
--max-num-seqs 32 \
--served-model-name 'DeepSeek-R1-Distill-Qwen-32B' \
--dtype=half
注意:如果需要显示Think标签,可以追加如下内容到start_DeepSeek-R1-Distill-Qwen-32B_By_vLLM.sh
脚本中:
#!/bin/bash
# 加载 conda 环境
source /usr/local/miniconda3/etc/profile.d/conda.sh
conda activate vllm
# 启动 vllm 服务
CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6 vllm serve /home/data/models/DeepSeek-R1-Distill-Qwen-32B \
--pipeline-parallel-size 7 \
--tensor-parallel-size 1 \
--host 0.0.0.0 \
--port 8000 \
--max_model_len 4096 \
--gpu-memory-utilization 0.9 \
--max-num-seqs 32 \
--served-model-name 'DeepSeek-R1-Distill-Qwen-32B' \
--dtype=half \
--chat-template /home/data/models/DeepSeek-R1-Distill-Qwen-32B/template_deepseek_r1.jinja
编辑systemd
启动文件:
vim /etc/systemd/system/deepseek.service
内容参考如下:
[Unit]
Description=DeepSeek-R1-Distill-Qwen-32B
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/usr/local/deepseek
ExecStart=/bin/bash /usr/local/deepseek/start_DeepSeek-R1-Distill-Qwen-32B_By_vLLM.sh
Restart=always
[Install]
WantedBy=multi-user.target
生效配置:
systemctl daemon-reload
启动、自启动:
systemctl start deepseek
systemctl enable deepseek
3.2.6.2 高级脚本
#!/bin/bash
# 脚本用途说明
echo "Starting vLLM server for DeepSeek-R1-Distill-Qwen-1.5B..."
# 定义所有需要检查的路径和环境变量
CONDA_BASE="/usr/local/conda" # Miniconda 安装路径
CONDA_ENV="vllm" # Conda环境名称
MODEL_PATH="/home/yyj/data/models/DeepSeek-R1-Distill-Qwen-1.5B" # 模型路径
PORT=8000 # vLLM 服务端口
LOG_FILE="/usr/local/deepseek/vllm_server_for_deepseek_1.5B.log" #日志文件路径
# 设置错误处理:脚本在遇到错误时退出
set -e
# 检查 Conda 路径是否存在
if [ ! -d "$CONDA_BASE" ]; then
echo "Error: Miniconda not found at $CONDA_BASE. Please update CONDA_BASE in the script."
exit 1
fi
# 加载 Conda 环境
source "$CONDA_BASE/etc/profile.d/conda.sh"
conda activate "$CONDA_ENV" || {
echo "Error: Failed to activate conda environment '$CONDA_ENV'. Please ensure it exists."
exit 1
}
# 检查 NVIDIA GPU 是否可用
if ! command -v nvidia-smi &> /dev/null; then
echo "Warning: nvidia-smi not found. GPU might not be available."
else
echo "GPU detected: $(nvidia-smi --query-gpu=name --format=csv,noheader)"
fi
# 检查模型路径是否存在
if [ ! -d "$MODEL_PATH" ]; then
echo "Error: Model path $MODEL_PATH does not exist. Please update MODEL_PATH in the script."
exit 1
fi
# 启动 vLLM 服务
echo "Launching vLLM server on port $PORT..."
CUDA_VISIBLE_DEVICES=0 vllm serve "$MODEL_PATH" \
--pipeline-parallel-size 1 \
--tensor-parallel-size 1 \
--host 0.0.0.0 \
--port "$PORT" \
--max_model_len 1024 \
--gpu-memory-utilization 0.85 \
--max-num-seqs 32 \
--served-model-name "DeepSeek-R1-Distill-Qwen-1.5B" \
2>&1 | tee "$LOG_FILE"
# 保存进程 ID 并等待几秒检查是否启动成功
VLLM_PID=$!
sleep 5
if ps -p $VLLM_PID > /dev/null; then
echo "vLLM server started successfully with PID $VLLM_PID. Logs are saved to $LOG_FILE."
else
echo "Error: vLLM server failed to start. Check $LOG_FILE for details."
exit 1
fi
echo "Server is running in the background. Access it at http://0.0.0.0:$PORT."
编辑systemd
启动文件:
[Unit]
Description=DeepSeek-R1-Distill-Qwen-1.5B
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/deepseek/start_DeepSeek-R1-Distill-Qwen-1.5B_By_vLLM.sh
ExecStop=/bin/kill -TERM $MAINPID
#Restart=on-failure
#RestartSec=5s
# 设置为脚本或模型所在的目录。
WorkingDirectory=/usr/local/deepseek
#User=
#Group=yyj
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
3.2.7 优化
3.2.7.1 think思考标签
如果需要弃用think思考标签,需要添加--chat-template
,修改启动脚本,内容参考如下:
#!/bin/bash
# 加载 conda 环境
source /usr/local/miniconda3/etc/profile.d/conda.sh
conda activate vllm
# 启动 vllm 服务
CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6 vllm serve /home/data/models/DeepSeek-R1-Distill-Qwen-32B \
--pipeline-parallel-size 7 \
--tensor-parallel-size 1 \
--host 0.0.0.0 \
--port 8000 \
--max_model_len 4096 \
--gpu-memory-utilization 0.9 \
--max-num-seqs 32 \
--served-model-name 'DeepSeek-R1-Distill-Qwen-32B' \
--dtype=half \
--chat-template /home/data/models/DeepSeek-R1-Distill-Qwen-32B/template_deepseek_r1.jinja
template_deepseek_r1.jinja
内容如下:
{% if not add_generation_prompt is defined %}{% set add_generation_prompt = false %}{% endif %}{% set ns = namespace(is_first=false, is_tool=false, is_output_first=true, system_prompt='') %}{%- for message in messages %}{%- if message['role'] == 'system' %}{% set ns.system_prompt = message['content'] %}{%- endif %}{%- endfor %}{{bos_token}}{{ns.system_prompt}}{%- for message in messages %}{%- if message['role'] == 'user' %}{%- set ns.is_tool = false -%}{{'<|User|>' + message['content']}}{%- endif %}{%- if message['role'] == 'assistant' and message['content'] is none %}{%- set ns.is_tool = false -%}{%- for tool in message['tool_calls']%}{%- if not ns.is_first %}{{'<|Assistant|><|tool▁calls▁begin|><|tool▁call▁begin|>' + tool['type'] + '<|tool▁sep|>' + tool['function']['name'] + '\\n' + '```json' + '\\n' + tool['function']['arguments'] + '\\n' + '```' + '<|tool▁call▁end|>'}}{%- set ns.is_first = true -%}{%- else %}{{'\\n' + '<|tool▁call▁begin|>' + tool['type'] + '<|tool▁sep|>' + tool['function']['name'] + '\\n' + '```json' + '\\n' + tool['function']['arguments'] + '\\n' + '```' + '<|tool▁call▁end|>'}}{{'<|tool▁calls▁end|><|end▁of▁sentence|>'}}{%- endif %}{%- endfor %}{%- endif %}{%- if message['role'] == 'assistant' and message['content'] is not none %}{%- if ns.is_tool %}{{'<|tool▁outputs▁end|>' + message['content'] + '<|end▁of▁sentence|>'}}{%- set ns.is_tool = false -%}{%- else %}{% set content = message['content'] %}{% if '</think>' in content %}{% set content = content.split('</think>')[-1] %}{% endif %}{{'<|Assistant|>' + content + '<|end▁of▁sentence|>'}}{%- endif %}{%- endif %}{%- if message['role'] == 'tool' %}{%- set ns.is_tool = true -%}{%- if ns.is_output_first %}{{'<|tool▁outputs▁begin|><|tool▁output▁begin|>' + message['content'] + '<|tool▁output▁end|>'}}{%- set ns.is_output_first = false %}{%- else %}{{'\\n<|tool▁output▁begin|>' + message['content'] + '<|tool▁output▁end|>'}}{%- endif %}{%- endif %}{%- endfor -%}{% if ns.is_tool %}{{'<|tool▁outputs▁end|>'}}{% endif %}{% if add_generation_prompt and not ns.is_tool %}{{'<|Assistant|>'}}{% endif %}
参考:本地部署DeepSeek-R1-Distill-Qwen-32B,输出仅有,没有 · Issue #352 · deepseek-ai/DeepSeek-R1
- QwQ-32B Think标签优化
参考:Tutorial: How to Run QwQ-32B effectively | Unsloth Documentation
{%- if tools %} {{- '<|im_start|>system\n' }} {%- if messages[0]['role'] == 'system' %} {{- messages[0]['content'] }} {%- else %} {{- '' }} {%- endif %} {{- "\n\n# Tools\n\nYou may call one or more functions to assist with the user query.\n\nYou are provided with function signatures within <tools></tools> XML tags:\n<tools>" }} {%- for tool in tools %} {{- "\n" }} {{- tool | tojson }} {%- endfor %} {{- "\n</tools>\n\nFor each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:\n<tool_call>\n{\"name\": <function-name>, \"arguments\": <args-json-object>}\n</tool_call><|im_end|>\n" }} {%- else %} {%- if messages[0]['role'] == 'system' %} {{- '<|im_start|>system\n' + messages[0]['content'] + '<|im_end|>\n' }} {%- endif %} {%- endif %} {%- for message in messages %} {%- if (message.role == "user") or (message.role == "system" and not loop.first) %} {{- '<|im_start|>' + message.role + '\n' + message.content + '<|im_end|>' + '\n' }} {%- elif message.role == "assistant" and not message.tool_calls %} {%- set content = message.content.split('</think>')[-1].lstrip('\n') %} {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>' + '\n' }} {%- elif message.role == "assistant" %} {%- set content = message.content.split('</think>')[-1].lstrip('\n') %} {{- '<|im_start|>' + message.role }} {%- if message.content %} {{- '\n' + content }} {%- endif %} {%- for tool_call in message.tool_calls %} {%- if tool_call.function is defined %} {%- set tool_call = tool_call.function %} {%- endif %} {{- '\n<tool_call>\n{"name": "' }} {{- tool_call.name }} {{- '", "arguments": ' }} {{- tool_call.arguments | tojson }} {{- '}\n</tool_call>' }} {%- endfor %} {{- '<|im_end|>\n' }} {%- elif message.role == "tool" %} {%- if (loop.index0 == 0) or (messages[loop.index0 - 1].role != "tool") %} {{- '<|im_start|>user' }} {%- endif %} {{- '\n<tool_response>\n' }} {{- message.content }} {{- '\n</tool_response>' }} {%- if loop.last or (messages[loop.index0 + 1].role != "tool") %} {{- '<|im_end|>\n' }} {%- endif %} {%- endif %} {%- endfor %} {%- if add_generation_prompt %} {{- '<|im_start|>assistant\n' }} {%- endif %}
3.2.7.2 优化提示词
参考1:
先思考,然后按照以下格式回答用户的问题:
<think>推理内容</think>
内容
参考2:
先从语义分析用户问题,若无法回答,再检索知识库;回答格式如下:
<think>推理内容</think>
内容
3.2.8 调用测试
查看部署的模型:
curl http://localhost:8000/v1/models
对话测试:
curl http://localhost:8000/v1/completions \
-H "Content-Type: application/json" \
-d '{"model": "DeepSeek-R1-Distill-Llama-70B", "prompt": "1+1=", "max_tokens": 20}'
4.open-webui安装
采用docker
方式安装:
docker run -d \
-p 3000:8080 \
--add-host=host.docker.internal:host-gateway \
-v /home/data/open-webui:/app/backend/data \
--restart always \
--name open-webui \
ghcr.nju.edu.cn/open-webui/open-webui:main
注意:将ghcr.io
换成 ghcr.nju.edu.cn
加速下载,使用教育网镜像加速超级快。
5.嵌入模型安装
参考地址:
5.1 本地方式安装
下载text-embeddings-inference
源码,下载地址:Releases · huggingface/text-embeddings-inference · GitHub
解压:
unzip text-embeddings-inference-1.6.0.zip -C /usr/local/
进入源码目录:
cd /usr/local/text-embeddings-inference-1.6.0
卸载Rust:
rustup self uninstall
然后install Rust:
# 配置加速
# export RUSTUP_DIST_SERVER=https://mirrors.ustc.edu.cn/rust-static
# export RUSTUP_UPDATE_ROOT=https://mirrors.ustc.edu.cn/rust-static/rustup
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# 阿里云脚本 curl --proto '=https' --tlsv1.2 -sSf https://mirrors.aliyun.com/repo/rust/rustup-init.sh | sh
然后重新加载环境变量, 使 rustup 命令生效.
source $HOME/.cargo/env
查看Rust版本:
rustc --version
配置cargo
加速:
vim ~/.cargo/config.toml
参考内容:
[source.crates-io]
replace-with = 'tuna'
[source.tuna]
registry = "https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git"
指定rust版本:
vim /usr/local/text-embeddings-inference-1.6.0/rust-toolchain.toml
修改如下:
[toolchain]
# 这里指定 1.85.0版本
channel = "1.85.0"
components = ["rustfmt", "clippy"]
接着操作如下:
# 安装
cargo install --path router -F mkl
# 这一步做好心里准备,网络不好可能也会弄个几个小时;如果网络有问题,试试命令:curl -I https://github.com,检查下github的网络可达性
安装文本处理工具:
text-embeddings-router --model-id /usr/local/{本地下载好的模型} --port 8080
可能会面临的问题:
- how to launch a service using downloaded model weights? · Issue #2113 · huggingface/text-generation-inference
- Is it possible to use the local model directly without downloading it? · Issue #207 · huggingface/text-embeddings-inference
5.2 Docker方式安装
5.2.1 安装容器依赖
安装docker容器的NVIDIA Container Toolkit
的依赖,
参考:
Installing the NVIDIA Container Toolkit — NVIDIA Container Toolkit
1. Introduction — Installation Guide for Linux 12.8 documentation
Ubuntu 22.04离线安装Docker和NVIDIA Container Toolkit - 知乎
如果以来下载慢/下载不下来,直接迅雷本地下载上传Linux后手动离线安装,我这里就离线安装了:
https://nvidia.github.io/libnvidia-container/stable/rpm/x86_64/nvidia-container-toolkit-base-1.17.4-1.x86_64.rpm
Github仓库地址:libnvidia-container/stable/rpm/x86_64 at gh-pages · NVIDIA/libnvidia-container
安装:
rpm -ivh nvidia-container-toolkit-base-1.17.5-1.x86_64.rpm
检验是否安装成功:
rpm -qa | grep nvidia-container-toolkit
5.2.2 下载模型
创建模型模型保存目录:
mkdir -p /usr/local/nomic-embed-text/model
去huggingface.co下载嵌入模型nomic-ai/nomic-embed-text-v1.5
,然后保存到路径/usr/local/nomic-embed-text/model
5.2.2 安装嵌入模型
参考:GPTs-0071-部署 text-embeddings-inference:cpu-1.5 - 知乎
创建嵌入模型的基础目录:
mkdir -p /usr/local/embedding-model/
创建模型保存目录:
mkdir -p /usr/local/embedding-model/{你需要安装的嵌入模型的目录}
# 示例 mkdir -p /usr/local/embedding-model/nomic-embed-text-v1.5
下载模型模型保存目录中,下载后的模型路径示例:/usr/local/embedding-model/nomic-embed-text-v1.5/nomic-embed-text-v1.5
注意:模型保存目录下需要保存模型的原有的目录(2个一样的目录才行),这个是需要挂载到容器内部的。
- CPU部署参考命令如下:
docker run -itd \
-p 9003:80 \
-v /usr/local/embedding-model/nomic-embed-text-v1.5:/data \
--name nomic-embed-text-v1.5 \
--restart=always \
ghcr.nju.edu.cn/huggingface/text-embeddings-inference:cpu-1.6 \
--model-id /data/nomic-embed-text-v1.5
参数解释:
--model-id /data/nomic-embed-text-v1.5
- 这是传递给容器内应用程序的一个参数。
- 结合前面的 -v 挂载选项,这实际上是告诉容器使用宿主机上挂载到 /data 的模型文件(可能是 nomic-embed-text-v1.5 模型)。
注意:
- 注意:将
ghcr.io
换成ghcr.nju.edu.cn
加速下载,使用教育网镜像加速超级快。 - 这里安装的是CPU处理类型(ghcr.nju.edu.cn/huggingface/text-embeddings-inference:
cpu
-1.6),非利用GPU计算类型;
也可以参考:Using TEI locally with CPU
可能面临的问题:
- Hosted LM throws ReadTimeout error · Issue #942 · huggingface/text-generation-inference
- Serving Private & Gated Models
可能面临的报错:
Caused by:
0: request error: error sending request for url (https://huggingface.co/nomic-embed-text-v1.5/resolve/main/config.json): error trying to connect: tcp connect error: Connection timed out (os error 110)
1: error sending request for url (https://huggingface.co/nomic-embed-text-v1.5/resolve/main/config.json): error trying to connect: tcp connect error: Connection timed out (os error 110)
2: error trying to connect: tcp connect error: Connection timed out (os error 110)
3: tcp connect error: Connection timed out (os error 110)
4: Connection timed out (os error 110)
# 如果你出现了上述报错,你一定是没仔细阅读本文档;需要采用离线方式下载模型后,保存到指定的目录下,请按照文档操作
- GPU 部署参考命令如下:
docker run -itd \
--gpus '"device=4"' \
-p 9003:80 \
-v /home/embedding-models/bge-m3-model:/data \
--name bge-m3 \
--restart=always \
ghcr.nju.edu.cn/huggingface/text-embeddings-inference:89-1.6 \
--model-id /data/bge-m3
# /home/embedding-models/bge-m3-model路径下放了bge-m3下载下来的模型
其他:
在RAG中应用中,BGE-M3可以替代商业的embedding模型,实现低成本、可控的解决方案。它具备的两个重要的功能:
多语言,可以支持100多种工作语言
可输入最长8192个token的长文本。
在进行生成应用时,我们除了关注模型本身的能力外,还需要关注其服务化的性能。
5.2.4 调用测试
BGE-M3
调用测试命令:
curl -w "\n总时间: %{time_total}s\n名称解析时间: %{time_namelookup}s\n连接时间: %{time_connect}s\nTLS握手时间: %{time_appconnect}s\n等待时间: %{time_starttransfer}s\n数据传输时间: %{time_total}s\nHTTP状态码: %{http_code}\n" \
--location '10.0.10.251:9003/embeddings' \
--header 'Content-Type: application/json' \
--data '{
"input":["橘子洲,位于湖南省长沙市区中湘江江心,北纬28°10′23.40″、东经112°57′18.36″,是湘江下游众多冲积沙洲之一。橘子洲西望岳麓山,东临长沙城,四面环水,长达5千米,狭处横约40米,宽处横约140米,最宽处仅300余米,岛形狭长,形似长龙。橘子洲大桥从上横跨而过,离长沙市中心1千米。面积0.614平方千米。从自然演变过程来看,橘子洲为第四纪全新世时期形成的、典型的一级阶地地层,地貌属高河漫滩,主要由以下三方面因素作用而成:一是江心基岩凸起,湘江主流至此分流,分流携带的泥沙通过回流,淤落在江心突起之基岩上形成心滩;二是湘江长沙段江面变宽,江水流速减小,泥沙易于淤落;三是受下游浏阳河、捞刀河以及洞庭湖水顶托,泥沙易于淤落,天长地久,日积月累,“心滩”经新构造运动上升露出水面而形成一座江心岛。橘子洲上生长着数千种花草藤蔓植物,其中名贵植物有143种。有鹤、鹭、鸥、狐、獾等珍稀动物。2012年,长沙市岳麓山-橘子洲旅游区被评为国家AAAAA级景区,橘子洲是其重要组成部分。"],
"model":"bge-m3"
}'
这段curl会统计请求的各个阶段的耗时,将其在服务器上直接运行,避免网络带来的影响。如果需要对比CPU耗时,请部署CPU架构后测试,再对比数据。
bge-reranker-large
调用测试命令:
curl -X 'POST' \
'http://10.0.10.251:9004/rerank' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{ "query": "What is Deep Learning?", "texts": [ "Deep Learning is ...", "hello"]}'