前面记录了三篇笔记:
本地部署Qwen2大模型之一:Ollma方式部署
第一篇记录了通过Ollama方式在本地部署Qwen2大模型的过程,操作很顺利,看到大模型反应的那一刻很是激动,大大增强了我继续探索的信心。
本地部署Qwen2大模型之二:vLLm方式部署
第二篇记录了通过vLLM方式在本地部署Qwen2大模型的过程,费了很多周折,包括在本地编译vLLM框架代码后安装等,虽然最后都以失败告终,但过程中做的各种尝试,加深了我对大模型和vLLM的认识。
本地部署Qwen2大模型之三:编译CPU版vLLM
第三篇记录了通过vLLM方式在本地部署Qwen2大模型的进一步尝试过程,也是历经艰辛但最后仍未能成功。这次换到了阿里云服务器上部署——个人做技术试验的服务器,配置非常有限,过程中确实也遇到因为内存不足而功败垂成的问题,其中最有价值的是通过各种调试方式,最后单步跟踪代码,终于搞清楚了vLLM部署大模型所涉及到的各种版本与硬件类型的对应关系,知道了我之前部署不成功的底层原因。
事情要做到底,一定要用vLLM把大模型玩转起来!所以,这一篇,我继续干。先还是在我的阿里云服务器上尝试,再来编译一把CPU版的vLLM。
再次编译vLLM源码
先把之前安装的vllm和torch都卸载了:
$ pip uninstall vllm torch
Found existing installation: vllm 0.6.5
Uninstalling vllm-0.6.5:
Would remove:
/home/zhangsan/.local/bin/vllm
/home/zhangsan/.local/lib/python3.10/site-packages/vllm-0.6.5.dist-info/*
/home/zhangsan/.local/lib/python3.10/site-packages/vllm/*
Would not remove (might be manually added):
/home/zhangsan/.local/lib/python3.10/site-packages/vllm/vllm.tar
Proceed (Y/n)? y
Successfully uninstalled vllm-0.6.5
Found existing installation: torch 2.5.1
Uninstalling torch-2.5.1:
Would remove:
/home/zhangsan/.local/bin/convert-caffe2-to-onnx
/home/zhangsan/.local/bin/convert-onnx-to-caffe2
/home/zhangsan/.local/bin/torchfrtrace
/home/zhangsan/.local/bin/torchrun
/home/zhangsan/.local/lib/python3.10/site-packages/functorch/*
/home/zhangsan/.local/lib/python3.10/site-packages/torch-2.5.1.dist-info/*
/home/zhangsan/.local/lib/python3.10/site-packages/torch/*
/home/zhangsan/.local/lib/python3.10/site-packages/torchgen/*
Proceed (Y/n)? y
Successfully uninstalled torch-2.5.1
.local/lib/python3.10/site-packages/vllm/vllm.tar是我之前打包的vllm的源码,手工删除就行。
接着下载最新的vLLM的源码,下载链接 在这里,用wget下载到本地目录,然后解压。
$ wget -c https://files.pythonhosted.org/packages/0c/2b/ce6f381d484d7d998f6540f6368c3ebca5452cb5f5be36c48d746f1c0f91/vllm-0.6.5.tar.gz
--2024-12-24 07:07:06-- https://files.pythonhosted.org/packages/0c/2b/ce6f381d484d7d998f6540f6368c3ebca5452cb5f5be36c48d746f1c0f91/vllm-0.6.5.tar.gz
Resolving files.pythonhosted.org (files.pythonhosted.org)... 146.75.112.223, 2a04:4e42:8c::223
Connecting to files.pythonhosted.org (files.pythonhosted.org)|146.75.112.223|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 4814359 (4.6M) [application/octet-stream]
Saving to: ‘vllm-0.6.5.tar.gz’
vllm-0.6.5.tar.gz 100%[========================================>] 4.59M 7.54KB/s in 13m 24s
2024-12-24 07:20:33 (5.84 KB/s) - ‘vllm-0.6.5.tar.gz’ saved [4814359/4814359]
$ tar -xvf vllm-0.6.5.tar.gz
vllm-0.6.5/
vllm-0.6.5/.buildkite/
。。。。。。
vllm-0.6.5/vllm.egg-info/requires.txt
vllm-0.6.5/vllm.egg-info/top_level.txt
$ cd vllm-0.6.5/
然后按照 vLLM官网上的编译步骤,先安装编译工具链,完成前两部操作:
第二步完成之后的结果显示:
Successfully installed datasets-3.2.0 dill-0.3.8 fsspec-2024.9.0 multiprocess-0.70.16 pandas-2.2.3 pyarrow-18.1.0 python-dateutil-2.9.0.post0 pytz-2024.2 requests-2.32.3 torch-2.5.1+cpu tzdata-2024.2 xxhash-3.5.0
在第三步之前,参考 本地部署Qwen2大模型之二:vLLM方式部署中的经验,需要先更新setuptools,安装python的build模块,然后启用build模块编译(替代第三步的动作):
$ pip install --upgrade setuptools
$ pip install build
$ VLLM_TARGET_DEVICE=cpu python -m build
第一次启动编译比较慢,要创建隔离编译环境,在隔离环境中安装各种依赖,等了一会开始有输出。这次仍然遇到了之前已经遇到过的问题:
CMake Error at /tmp/build-env-im41wc4k/lib/python3.10/site-packages/torch/share/cmake/Caffe2/Caffe2Config.cmake:90 (message):
Your installed Caffe2 version uses CUDA but I cannot find the CUDA
libraries. Please set the proper CUDA prefixes and / or install CUDA.
Call Stack (most recent call first):
/tmp/build-env-im41wc4k/lib/python3.10/site-packages/torch/share/cmake/Torch/TorchConfig.cmake:68 (find_package)
CMakeLists.txt:84 (find_package)
提示说系统安装了使用CUDA的Caffe2工具包,但是实际找不到CUDA。前面的尝试中我采取的办法是安装CUDA,这次要改变方向——安装不用CUDA的Caffe2工具包。怎么安装? 问豆包,有办法,但是又要从源码编译!
好吧,那先把现有的Caffe2卸载了。但神奇的是,系统提示我并没有安装caffe2软件包!
$ pip uninstall caffe2
WARNING: Skipping caffe2 as it is not installed.
奇怪吧!那问题就应该是在隔离的python build环境中安装了它,这怎么搞?
在豆包和kimi的帮助下仔细研究了一把,又增长知识了。原来vLLM官网告诉我们的编译指令是"VLLM_TARGET_DEVICE=cpu python setup.py install",这是传统的编译方式,是靠运行setup.py脚本来执行编译步骤,编译的动作都写在这个python脚本文件中了,而编译时使用的系统环境就是当前用户平时的工作环境,因此它是非隔离的,编译过程中安装的各种依赖包会一直影响当前用户(甚至影响到所有用户)。我们在上面第一步和第二步中所做的工作就是事先准备编译环境,其中就包括安装CPU版本的torch,所以严格来说我们已经准备好了编译环境。但问题是,我当前的实际系统环境比vLLM官方文档假定的环境新得多,python、pip、setuptools都已经更新了,可能其他很多软件也是新的,而新的setuptools已经不允许采用执行setup.py脚本的方式来编译了,要求采用build模块来编译。
为什么要用build模块来编译呢?因为build模块就是setuptools的组成部分,它经过演进,在编译的过程中会先构建一个临时的隔离虚拟环境,在这个隔离的虚拟环境中来安装各种依赖软件,并把要编译的源文件都拷贝到这个隔离环境中来,这样,编译产生的中间文件,包括安装的依赖等都是临时的,等编译完后就会自动清理干净,不影响用户平时的工作环境。这样做确实有很多好处,可以防止各种软件依赖的冲突,也为多种不同的编译环境和不同软件版本的共存创造了条件,可以存在很多种编译配置,相互之间不受影响,也能维持源代码的干净整洁。
明白了原理,就知道我又多做了无用功,我先是按传统方式安装了CPU版本vLLM的依赖,后面又启动build模块来编译,它又重新创建了临时的虚拟环境,在这个虚拟环境中它还是用的CUDA版本的依赖!由此,解决问题的思路是,怎么让build模块在创建虚拟编译环境时也安装CPU版本的依赖?
答案在pyproject.toml文件中,该文件在vllm源码包根目录下,其开头部分的内容:
[build-system]
# Should be mirrored in requirements-build.txt
requires = [
“cmake>=3.26”,
“ninja”,
“packaging”,
“setuptools>=61”,
“setuptools-scm>=8.0”,
“torch == 2.5.1”,
“wheel”,
“jinja2”,
]
build-backend = “setuptools.build_meta”
这就是虚拟编译环境中对软件依赖的约定,其中就包括了"torch == 2.5.1"。经过这几天反复折腾,已经知道了torch的普通版本默认是要用CUDA库的,这就是问题的症结所在!那我们如何指定CPU版本的torch呢?记得前面我们在手动安装依赖时,执行了如下指令:
pip install -v -r requirements-cpu.txt --extra-index-url https://download.pytorch.org/whl/cpu
也就是说,从requirements-cpu.txt中读取依赖,然后增加了一个–extra-index-url参数,指向CPU版本的torch安装路径。requirements-cpu.txt中有一行
torch==2.5.1+cpu; platform_machine != “ppc64le” and platform_machine != “aarch64”
这里就是指定了cpu版本的torch,–extra-index-url告诉它去哪里找,这就是机窍!
依葫芦画瓢,我们在pyproject.toml文件中将 “torch == 2.5.1” 改为 “torch == 2.5.1+cpu”。注意到pyproject.toml中有"Should be mirrored in requirements-build.txt"的注释,所以在requirements-build.txt文件中也改成"torch == 2.5.1+cpu"。
然后在~/.pip/pip.conf文件中添加一行extra-index-url配置:
[global]
# default index source url.
index-url=https://pypi.tuna.tsinghua.edu.cn/simple
# extra index source urls, there could be several extra urls.
extra-index-url=https://download.pytorch.org/whl/cpu
这个方法是我自创的,不是用豆包或kimi搜到的。确实是搜了很久怎么添加extra-index-url的方法,有说在setup.py文件的setup()方法中添加dependency_links属性,或者在pyproject.toml中添加[project.urls]属性组等等,试了,但都不行。然而我发现,build模块在安装依赖包时,都是到我之前设置的国内pypi镜像源去下载的,而且明确打印出了"index-url="字样,我就联想起来,能不能在pip.conf文件里再设置个url呢?试了下,index-url只能有一个,但可以有多个extra-index-url!哈哈,是不是很爽?!
环境设置问题都解决了,再次执行编译指令,中间出现两次报错中断,原因都是github上的依赖包下载失败,多试两次就成功了。但是编译执行到:
-- Primitive cache is enabled
-- CPU extension compile flags: -mf16c;-fopenmp;-DVLLM_CPU_EXTENSION;-mavx512f;-mavx512vl;-mavx512bw;-mavx512dq
-- Enabling C extension.
-- Configuring done (39.6s)
-- Generating done (0.1s)
-- Build files have been written to: /tmp/build-via-sdist-na2f9h9f/vllm-0.6.5+cpu/build/temp.linux-x86_64-cpython-310
[0/416] Building CXX object CMakeFiles/_C.dir/csrc/cpu/activation.cpp.o
在这里卡住不动了,等了很久。推断是系统资源不足了,毕竟只有4GB的内存啊。(后来补充:直到我睡了一觉起来,发现这里只是从[0/416]变成了[1/416],其他啥都没动,包括其编译的文件名。又过了一个白天,它失败退出了。我再次启动编译,它又卡在了同样的地方,反正是编不动!)
马上换道吧,已经是凌晨12点,我是在自己家里头,个人的笔记本可以编啊。于是迅速行动,因为周末在家里弄的时候,以及安装过编译工具了,只要照上面的方法,修改torch的名称,并在pip.conf加入extra-index-url就可以了。把之前安装的vllm和torch先卸载掉,然后执行编译指令:VLLM_TARGET_DEVICE=cpu python -m build
几分钟就编完了(差别好大啊),成功输出结果:
$ ll dist/
总计 12276
drwxrwxr-x 2 zhangsan zhangsan 4096 12月 24 16:14 ./
drwx------ 15 zhangsan zhangsan 4096 12月 24 16:13 ../
-rw-rw-r-- 1 zhangsan zhangsan 7743157 12月 24 16:14 vllm-0.6.5+cpu.cpu-cp310-cp310-linux_x86_64.whl
-rw-rw-r-- 1 zhangsan zhangsan 4815436 12月 24 16:13 vllm-0.6.5+cpu.tar.gz
用pip安装编出来的wheel文件,很顺利,然后检查vllm的版本:
$ pip install dist/vllm-0.6.5+cpu.cpu-cp310-cp310-linux_x86_64.whl
Defaulting to user installation because normal site-packages is not writeable
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple, https://download.pytorch.org/whl/cpu
Processing ./dist/vllm-0.6.5+cpu.cpu-cp310-cp310-linux_x86_64.whl
。。。。。。
Requirement already satisfied: six>=1.5 in /usr/lib/python3/dist-packages (from python-dateutil>=2.8.2->pandas->datasets->vllm==0.6.5+cpu.cpu) (1.16.0)
Installing collected packages: torch, vllm
Successfully installed torch-2.5.1+cpu vllm-0.6.5+cpu.cpu
$ which vllm
/home/zhangsan/.local/bin/vllm
$ vllm -v
0.6.5+cpu
又到了激动人心的时刻!来,运行一把测试程序。。。但是,又一次跌倒了谷底:
$ python test.py
WARNING 12-24 16:48:33 config.py:604] Async output processing is not supported on the current platform type cpu.
WARNING 12-24 16:48:33 cpu.py:56] CUDA graph is not supported on CPU, fallback to the eager mode.
WARNING 12-24 16:48:33 cpu.py:71] Environment variable VLLM_CPU_KVCACHE_SPACE (GB) for CPU backend is not set, using 4 by default.
INFO 12-24 16:48:33 llm_engine.py:249] Initializing an LLM engine (v0.6.5+cpu) with config: model='Qwen/Qwen2-7B-Instruct', speculative_config=None, tokenizer='Qwen/Qwen2-7B-Instruct', skip_tokenizer_init=False, tokenizer_mode=auto, revision=None, override_neuron_config=None, tokenizer_revision=None, trust_remote_code=False, dtype=torch.bfloat16, max_seq_len=32768, download_dir=None, load_format=auto, tensor_parallel_size=1, pipeline_parallel_size=1, disable_custom_all_reduce=False, quantization=None, enforce_eager=True, kv_cache_dtype=auto, quantization_param_path=None, device_config=cpu, decoding_config=DecodingConfig(guided_decoding_backend='xgrammar'), observability_config=ObservabilityConfig(otlp_traces_endpoint=None, collect_model_forward_time=False, collect_model_execute_time=False), seed=0, served_model_name=Qwen/Qwen2-7B-Instruct, num_scheduler_steps=1, multi_step_stream_outputs=True, enable_prefix_caching=False, chunked_prefill_enabled=False, use_async_output_proc=False, mm_cache_preprocessor=False, mm_processor_kwargs=None, pooler_config=None, compilation_config={
"splitting_ops":["vllm.unified_attention","vllm.unified_attention_with_output"],"candidate_compile_sizes":[],"compile_s