vllm本地台式机运行(3070显存8G)与模型量化
ollama和vllm 的对比
这块对比网上都很多资料了,
这边使用上简单感觉就是ollama很方便部署,占用资料更少,但后续性能会差点,各选项也不一样.
ollama安装和使用和docker很像,就不赘述了,这里是看vllm的安装
硬件情况介绍
3070 8G显存
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 570.133.20 Driver Version: 570.133.20 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 NVIDIA GeForce RTX 3070 Off | 00000000:08:00.0 On | N/A |
| 30% 38C P8 16W / 240W | 5225MiB / 8192MiB | 0% Default |
| | | N/A |
+-----------------------------------------+------------------------+----------------------+
+-----------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=========================================================================================|
| 0 N/A N/A 346687 C ...niconda3/envs/vllm/bin/python 5200MiB |
+-----------------------------------------------------------------------------------------+
安装vllm
vllm的安装, 要选用gpu版本
不同平台的安装说明可以参考官网
https://docs.vllm.ai/en/latest/getting_started/installation/index.html
建议新开一个环境来执行pip, 如conda activate vllm_env
这里用 cuda 128 版本
pip install vllm --extra-index-url https://download.pytorch.org/whl/cu128
pip list 关键的一些版本号:
torch 2.7.0+cu128
torchaudio 2.7.0+cu128
torchvision 0.22.0+cu128
vllm 0.9.2
启动命令
vllm有很多启动方式,这边采用python -m vllm.entrypoints.openai.api_server
python -m vllm.entrypoints.openai.api_server \
--model /home/xxx/data/hf_models/Qwen3-8B \
--served-model-name DQwen3-8B \
--gpu-memory-utilization 0.5 \
--host 0.0.0.0 \
--port 8003 \
--max-num-seqs 2 \
--enable-chunked-prefill \
--trust-remote-code \
--max-model-len 1024
llm()加载模型时可以使用modelscope环境 export VLLM_USE_MODELSCOPE=True
命令的参数很多, 这边简单说明:
model 加载的模型,可以用本地,是huggingface下载的
served-model-name 名称,用于后续外围访问时用
gpu-memory-utilization 只预分配 50 % 的 GPU 显存做 KV Cache/权重缓存,避免一次性占满整卡。 显存不太够时用
--max-num-seqs 2 同一时刻最多并发 2 条序列(含 prompt 与正在生成的 token)。数值越小,显存峰值越低。
--enable-chunked-prefill 把长 prompt 切成小块逐步预填充,减少一次性显存峰值,对长文本尤其有用。
--max-model-len 1024 把模型的最大上下文长度 硬截断到 1024 tokens。超过此长度的输入会被截断或拒绝。
如果加载 Qwen3-8B直接out of memory了,使用1.5B都还是内存不够,但ollama是可以执行8B的,
从huggingface 下载的和ollama的库的大小也是不一样的, 这是因为ollama对挂在他们上在的模型做了一些处理,如4BIT的量化,所以这边要执行也要对模型量化一下(quantization)
实测在3070,做8B还是有点勉强,所以这里使用Qwen3-4B
显存占用太高,量化4Bit
- 量化有几种方式,这边试了下,用bitsandbytes
# 把精度调下来,给vllm 加载(官方例子)
# https://huggingface.co/docs/bitsandbytes/installation#cuda-pip
# https://huggingface.co/docs/transformers/v4.53.3/en/quantization/bitsandbytes?bnb=4-bit#bitsandbytes
model_name = "Qwen3-4B"
model_path = f"/home/xxx/data/hf_models/{model_name}"
quant_path = f"/home/xxx/data/hf_models/{model_name}-quantizated"
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
quantization_config = BitsAndBytesConfig(load_in_4bit=True)
model = AutoModelForCausalLM.from_pretrained(
model_path,
device_map="auto",
quantization_config=quantization_config
)
model.save_pretrained(quant_path)
print(f'done--------------------{quant_path}')
- 另外awq库也可以,不过这边不成功, 应该是版本不太对 ,
# 把精度调下来,给vllm 加载(官方例子)
# https://docs.vllm.ai/en/latest/features/quantization/auto_awq.html
from awq import AutoAWQForCausalLM
from transformers import AutoTokenizer
ultrachat_200k_path = "/home/xxx/data/hf_datasets/ultrachat_200k"
model_path = "/home/xxx/data/hf_models/Qwen1.5-1.8B-Chat"
quant_path = "/home/xxx/data/hf_models/model-quantized-1"
# model_path = 'mistralai/Mistral-7B-Instruct-v0.2'
# quant_path = 'mistral-instruct-v0.2-awq'
quant_config = { "zero_point": True, "q_group_size": 128, "w_bit": 4, "version": "GEMM" }
# Load model
model = AutoAWQForCausalLM.from_pretrained(
model_path, **{"low_cpu_mem_usage": True, "use_cache": False}
)
tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
# Quantize
model.quantize(tokenizer, quant_config=quant_config)
# Save quantized model
model.save_quantized(quant_path)
tokenizer.save_pretrained(quant_path)
print(f'Model is quantized and saved at "{quant_path}"')
启动与测试情况
python -m vllm.entrypoints.openai.api_server \
--model /home/xxx/data/hf_models/Qwen3-4B-quantized \
--served-model-name DQwen3-4B-quantized \
--gpu-memory-utilization 0.5 \
--host 0.0.0.0 \
--port 8003 \
--max-num-seqs 2 \
--enable-chunked-prefill \
--trust-remote-code \
--max-model-len 1024
如果直接启动抛错可能看不到错误栈,把日志级别改一下再启动
export VLLM_LOGGING_LEVEL=DEBUG
测试:
print(1111)
from openai import OpenAI
# client = OpenAI(
# base_url="http://localhost:11434/v1", # 关键:指向 Ollama
# api_key="ollama" # 随意填,Ollama 不校验
# )
client = OpenAI(
base_url="http://localhost:8003/v1", # 关键:指向 vllm 的端口
api_key="ollama" # 随意填
)
resp = client.chat.completions.create(
# model="deepseek-r1:7b", # 本地已 pull 的模型名
model="DQwen3-4B-awq", # 本地已 pull 的模型名 (vllm指定的served-model-name)
messages=[
{"role": "system", "content": "你是一个科学家,用一个简短的话语回答问题。"},
{"role": "user", "content": "天空为什么是蓝色的?用简短的话回答。"}
],
temperature=0.7,
max_tokens=512
)
print(resp.choices[0].message.content)
返回
1111
<think>
好的,用户问天空为什么是蓝色的。我需要简短回答,所以得抓住关键点。首先,瑞利散射,对吧?太阳光由不同颜色的光组成,波长短的蓝光散射更多。大气中的分子会散射这些光,导致我们看到蓝色。不过,可能需要更简洁的表达。
用户可能想了解基本原理,不需要太深入。可能需要提到散射和颜色。比如,"因为瑞利散射,蓝光被散射得更多,所以天空呈现蓝色。" 但可能需要更简练。或者,"太阳光中的蓝光被大气分子散射,使天空呈现蓝色。" 这样更直接。
检查有没有更简短的表达。比如,"蓝光散射多,所以天空是蓝的。" 但可能不够准确。需要确保术语正确。瑞利散射是关键,但用户可能不需要知道术语。所以可能需要用更通俗的说法。
可能用户是学生或者普通爱好者,需要基础解释。所以,正确的科学解释是瑞利散射导致蓝光散射,所以天空是蓝的。但可能需要更简短,比如"因蓝光散射强,天空呈蓝色。" 或者"蓝光被散射,所以天空是蓝的。"
确定答案是否正确。是的,正确。所以最终回答应该是这个。
</think>
因蓝光散射强,天空呈蓝色。
一些进程简单情况
================= 进程 346687 运行指标 =================
进程名 : python
启动时间 : 2025-07-24 11:49:03
完整命令 : /home/xxx/miniconda3/envs/vllm/bin/python -c from multiprocessing.spawn import spawn_mai
n; spawn_main(tracker_fd=36, pipe_handle=38) --multiprocessing-fork
-----------------------------------------------------
物理内存(RSS) : 2884.8 MB
虚拟内存(VSZ) : 19977.9 MB
Swap 占用 : 0.0 MB
OOM Score : 774
显存 : 5200MiB
-----------------------------------------------------
已打开 FD 数 : 92
线程数 : 63
子进程数 : 0
-----------------------------------------------------
UDP 套接字数 : 7
RX 总字节 : 5.36829e+10
TX 总字节 : 2.29815e+10
-----------------------------------------------------
cgroup : 0::/user.slice/user-1000.slice/session-338.scope
pid namespace: pid:[4026531836]
pid:[4026531836]
net namespace: net:[4026531840]
=====================================================
linux limit 的问题
运行久以后可能会出现 limit 的问题,fd开不了了,这里可以配置下limit 即进程可开的fd数
gradio也遇到过:
The global thread pool has not been initialized.: ThreadPoolBuildError { kind: IOError(Os { code: 11, kind: WouldBlock, message: "Resource temporarily unavailable" }) }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
查看限制
ulimit -n // 查看限制open file
查看当前用户的 soft/hard nofile 限制
ulimit -Sn # soft nofile
ulimit -Hn # hard nofile
查看系统全局默认值(所有用户)
cat /proc/sys/fs/file-max # 系统总 FD 上限
cat /proc/sys/fs/nr_open # 单个进程最大 FD 上限
对应的配置
(1) /security/limits.conf // 对应的全局配置
加上限制:
open files (-n)
针对所有用户(不推荐)
* soft nofile 65536
* hard nofile 65536
针对某个用户
xxx soft nofile 65536 # 默认是1024
xxx hard nofile 65536
(2) 如果是systemctl 配置的
编辑服务文件
sudo nano /etc/systemd/system/vllm-api.service
添加以下配置
[Service]
LimitNOFILE=65535
然后执行:
sudo systemctl daemon-reload
sudo systemctl restart vllm-api
(3) 如果是supervisor, supervisor里有对应的配置
(4) 如果想临时在当前会话设置一下
ulimit -n 65535 # 将 soft nofile 改为 65535
查看当前进程的fd情况
# 查看当前进程的 FD 限制
cat /proc/<PID>/limits | grep "Max open files"
# 统计进程当前使用的 FD 数量
ls -l /proc/<PID>/fd | wc -l
更多推荐
所有评论(0)