在 本地部署Qwen2大模型之二:vLLM方式部署 中,我详细记录了以vLLM方式在本地部署Qwen2大模型的经过,但是最后还是没能运行起来,坑是踩遍了,路熟了,这是其积极意义。但事情还得继续整!
仔细回顾一下,首先vLLM是很容易安装的,vLLM框架,包括它所依赖的PyTorch都默认采用NVIDIA的GPU加速,要依赖CUDA库,而且都会自动的安装上。我开始遇到的是路径问题,如果pypi镜像源、Qwen2大模型发布源的路径都先行解决了的话,接下来遇到的问题只是启动测试用例时LLM引擎初始化失败。失败的原因是"RuntimeError: Failed to infer device type",即无法推断实际的设备类型,也就是无法确定是在CPU上运行,还是在GPU上运行,如果在GPU运行,是加载CUDA包还是加载ROCM包?如此说来,是否我在运行测试用例时,先传入一个参数VLLM_TARGET_DEVICE=cpu,明确是不用GPU加速,即按下面的方式运行:
VLLM_TARGET_DEVICE=cpu python test.py
软件框架可以有CUDA包,但是运行的时候我明确告诉你不用GPU,你用CPU就行了,这样应该也能够运行吧?如果说得通,那就没有必要再强求CPU版本的vLLM,也不需要在本地进行源码编译,也不需要下载和安装不同版本的PyTorch了。实际这样运行会怎么样呢?嗯,至少试试看吧!
新的环境
前面利用周末两天的时间,在家里的个人笔记本上弄的;上班就没得基础环境了,不能在公司的电脑和服务器上乱整吧? 虽然也有Docker、Conda、VirtualBox等隔离环境的工具,但毕竟是公司资源,不能随便动,还是用个人的设备练手吧。想起我还有个阿里云的服务器可以用,不受地点的限制,只要有网就行,于是赶紧去看了下它的配置。这一看,很尴尬啊!
$ sudo lshw -c display
*-display
description: VGA compatible controller
product: GD 5446
vendor: Cirrus Logic
physical id: 2
bus info: pci@0000:00:02.0
logical name: /dev/fb0
version: 00
width: 32 bits
clock: 33MHz
capabilities: vga_controller rom fb
configuration: depth=16 driver=cirrus latency=0 resolution=1024,768
resources: irq:0 memory:fc000000-fdffffff memory:febf0000-febf0fff memory:c0000-dffff
$ cat /proc/cpuinfo
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 85
model name : Intel(R) Xeon(R) Platinum
stepping : 4
microcode : 0x1
cpu MHz : 2500.026
cache size : 33792 KB
physical id : 0
siblings : 2
core id : 0
cpu cores : 1
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 22
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc cpuid tsc_known_freq pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch invpcid_single pti fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat
bugs : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs taa itlb_multihit mmio_stale_data retbleed gds
bogomips : 5000.05
clflush size : 64
cache_alignment : 64
address sizes : 46 bits physical, 48 bits virtual
power management:
processor : 1
vendor_id : GenuineIntel
cpu family : 6
model : 85
model name : Intel(R) Xeon(R) Platinum
stepping : 4
microcode : 0x1
cpu MHz : 2500.026
cache size : 33792 KB
physical id : 0
siblings : 2
$ cat /proc/meminfo
MemTotal: 3662684 kB
MemFree: 438000 kB
MemAvailable: 2352820 kB
Buffers: 37864 kB
Cached: 2014196 kB
SwapCached: 0 kB
Active: 1265412 kB
Inactive: 1594620 kB
Active(anon): 1216 kB
Inactive(anon): 818760 kB
Active(file): 1264196 kB
Inactive(file): 775860 kB
Unevictable: 29152 kB
Mlocked: 27616 kB
SwapTotal: 0 kB
SwapFree: 0 kB
$ df -h
Filesystem Size Used Avail Use% Mounted on
tmpfs 358M 1.1M 357M 1% /run
/dev/vda3 99G 5.9G 88G 7% /
tmpfs 1.8G 0 1.8G 0% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
/dev/vda2 197M 6.1M 191M 4% /boot/efi
tmpfs 358M 4.0K 358M 1% /run/user/1000
$ cat /etc/os-release
PRETTY_NAME="Ubuntu 22.04.5 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.5 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
虚拟的Intel Xeon双核CPU,2.5GHz;
4GB的内存;
100GB的SSD硬盘,还有88GB可用;
VGA显卡,没得GPU。
平时当个文件中转站,跑个Web服务器也还行,想跑AI大模型,是不是感觉有点像做梦?!
但它终究是台云服务器啊,也对吧?反正能跑程序,不管最后AI大模型能不能跑得起来,先跑一把试试看呗~
走捷径
路是已经熟了,先把镜像源给配置起来,包括pypi镜像源,hf-mirror镜像源,具体方法参阅 上一篇文章。然后就安装vllm,最简单的方式,直接执行pip install vllm指令,等安装完成后检查结果:
$ vllm -h
usage: vllm [-h] [-v] {serve,complete,chat} ...
vLLM CLI
positional arguments:
{serve,complete,chat}
serve Start the vLLM OpenAI Compatible API server
complete Generate text completions based on the given prompt via the running API server
chat Generate chat completions via the running API server
options:
-h, --help show this help message and exit
-v, --version show program's version number and exit
$ vllm -v
0.6.5
$ pip show torch
Name: torch
Version: 2.5.1
Summary: Tensors and Dynamic neural networks in Python with strong GPU acceleration
Home-page: https://pytorch.org/
Author: PyTorch Team
Author-email: packages@pytorch.org
License: BSD-3-Clause
Location: /home/zhangsan/.local/lib/python3.10/site-packages
Requires: filelock, fsspec, jinja2, networkx, nvidia-cublas-cu12, nvidia-cuda-cupti-cu12, nvidia-cuda-nvrtc-cu12, nvidia-cuda-runtime-cu12, nvidia-cudnn-cu12, nvidia-cufft-cu12, nvidia-curand-cu12, nvidia-cusolver-cu12, nvidia-cusparse-cu12, nvidia-nccl-cu12, nvidia-nvjitlink-cu12, nvidia-nvtx-cu12, sympy, triton, typing-extensions
Required-by: compressed-tensors, outlines, torchvision, vllm, xformers, xgrammar
$ sudo find / -name *cuda*.so* 2>/dev/null
/usr/lib/x86_64-linux-gnu/libicudata.so.70.1
/usr/lib/x86_64-linux-gnu/libicudata.so.70
/home/zhangsan/.local/lib/python3.10/site-packages/nvidia/cuda_runtime/lib/libcudart.so.12
/home/zhangsan/.local/lib/python3.10/site-packages/torch/lib/libc10_cuda.so
/home/zhangsan/.local/lib/python3.10/site-packages/torch/lib/libtorch_cuda_linalg.so
/home/zhangsan/.local/lib/python3.10/site-packages/torch/lib/libtorch_cuda.so
/home/zhangsan/.local/lib/python3.10/site-packages/torchvision.libs/libcudart.41118559.so.12
vllm有了,torch有了,cuda库也有了。下面就直接运行测试程序,在命令行传入cpu参数:
$ VLLM_TARGET_DEVICE=cpu python test.py
tokenizer_config.json: 1.29kB [00:00, 2.67MB/s]
vocab.json: 2.78MB [00:01, 1.67MB/s]
merges.txt: 1.67MB [00:01, 1.03MB/s]
tokenizer.json: 7.03MB [00:04, 1.70MB/s]
Traceback (most recent call last):
File "/usr/work/llm/vllm/test.py", line 12, in <module>
llm = LLM(model="Qwen/Qwen2-7B-Instruct")
File "/home/zhangsan/.local/lib/python3.10/site-packages/vllm/utils.py", line 990, in inner
return fn(*args, **kwargs)
File "/home/zhangsan/.local/lib/python3.10/site-packages/vllm/entrypoints/llm.py", line 230, in __init__
self.llm_engine = self.engine_class.from_engine_args(
File "/home/zhangsan/.local/lib/python3.10/site-packages/vllm/engine/llm_engine.py", line 529, in from_engine_args
engine_config = engine_args.create_engine_config(usage_context)
File "/home/zhangsan/.local/lib/python3.10/site-packages/vllm/engine/arg_utils.py", line 1026, in create_engine_config
device_config = DeviceConfig(device=self.device)
File "/home/zhangsan/.local/lib/python3.10/site-packages/vllm/config.py", line 1433, in __init__
raise RuntimeError("Failed to infer device type")
RuntimeError: Failed to infer device type
Exception ignored in: <function LLM.__del__ at 0x7f6c41214430>
Traceback (most recent call last):
File "/home/zhangsan/.local/lib/python3.10/site-packages/vllm/entrypoints/llm.py", line 236, in __del__
if self.llm_engine and hasattr(self.llm_engine, "shutdown"):
AttributeError: 'LLM' object has no attribute 'llm_engine'
好吧,问题还是一样,熟悉的"RuntimeError: Failed to infer device type"错误!
令人欣喜的是,运行并不慢啊,很快就有输出了,也可能是因为大模型还没加载起来吧。这次没有报告说找不到"Qwen/Qwen2-7B-Instruct"大模型,也没有报告说连接不上"https://huggingface.co",证实了前面的镜像源设置生效了。
死磕到底
我们再来解决这个"RuntimeError: Failed to infer device type"的错误。
用豆包查,回答很明确
问题分析
设备类型推断失败:从报错信息 RuntimeError: Failed to infer device type 来看,在 vLLM 的初始化过程中,程序无法推断出要使用的设备类型(比如是 GPU 还是 CPU 等)。这可能是因为相关的配置参数没有正确设置或者缺失,导致系统不知道该将模型加载到何种设备上去运行。
对象属性异常:后续出现的 AttributeError: ‘LLM’ object has no attribute ‘llm_engine’ 是由于前面初始化 LLM 实例时已经出现错误,没能正确创建 llm_engine 属性,而在 del 方法中尝试访问这个不存在的属性时就引发了该错误。
解决方案
明确指定设备类型:
使用参数指定(推荐):在创建 LLM 实例时,可以通过合适的参数明确指定设备类型。如果想使用 GPU(假设你已经正确安装配置好 GPU 相关环境,比如 CUDA 等),可以这样写:
python
from vllm import LLM
llm = LLM(model=“Qwen/Qwen2-7B-Instruct”, device=“cuda”)
要是希望使用 CPU 来运行,按照如下方式指定:
python
llm = LLM(model=“Qwen/Qwen2-7B-Instruct”, device=“cpu”)
检查环境变量(若适用):
有些情况下,vLLM 可能会读取环境变量来确定设备类型。确保环境变量中关于设备相关的设置是正确的,例如,如果环境变量中设置了错误的 VLLM_TARGET_DEVICE 值(假设 vLLM 会参考这个变量来判断设备),可能会导致设备类型推断出错。可以在终端中通过 echo $VLLM_TARGET_DEVICE (Linux 或 Mac 系统下)这样的命令来查看其值,若值不正确,进行相应修改,或者根据需要添加正确的环境变量设置。例如在 Linux 系统中,若要设置为使用 CPU,可在终端执行 export VLLM_TARGET_DEVICE=“cpu”,然后再运行你的 Python 代码。
检查依赖和配置完整性:
CUDA 及 GPU 驱动(针对 GPU 使用):如果打算使用 GPU,确认 CUDA 已正确安装(可以通过 nvcc --version 命令查看 CUDA 版本来验证安装情况),并且 GPU 驱动是最新且与 CUDA 版本适配的。
vLLM 版本兼容性:检查所使用的 vLLM 版本是否存在已知的与设备类型推断相关的问题或特殊配置要求。若版本较旧,尝试升级到最新版本,通过 pip install --upgrade vllM 命令来升级,看能否解决问题。
查看更多日志和调试信息(可选):
可以尝试在代码中添加更多的打印语句,比如在涉及设备类型推断的相关函数内部(例如 vLLM/config.py 中 DeviceConfig 类的初始化部分等位置),打印出一些关键变量的值,来帮助进一步确定为何无法推断出设备类型,以便更精准地定位和解决问题。不过这需要对代码有一定的熟悉程度以及遵循相应的代码规范来进行调试操作。
可以设置环境变量,我刚刚是通过命令行参数传递的,跟设置环境变量的作用应该差不多,昨天也试过了;另外就是在代码里面传递’device=“cpu” '这个参数,昨天试的是"target-device"参数,结果vllm不认识,今天这个是"device"参数,再试试。改了之后重新执行,还是报错,但错误跟上面的不一样了,跟昨天的也不一样:
$ python test.py
config.json: 663B [00:00, 2.35MB/s]
INFO 12-23 06:47:23 config.py:478] This model supports multiple tasks: {'classify', 'reward', 'generate', 'embed', 'score'}. Defaulting to 'generate'.
Traceback (most recent call last):
File "/usr/work/llm/vllm/test.py", line 12, in <module>
llm = LLM(model="Qwen/Qwen2-7B-Instruct", device="cpu")
File "/home/zhangsan/.local/lib/python3.10/site-packages/vllm/utils.py", line 990, in inner
return fn(*args, **kwargs)
File "/home/zhangsan/.local/lib/python3.10/site-packages/vllm/entrypoints/llm.py", line 230, in __init__
self.llm_engine = self.engine_class.from_engine_args(
File "/home/zhangsan/.local/lib/python3.10/site-packages/vllm/engine/llm_engine.py", line 529, in from_engine_args
engine_config = engine_args.create_engine_config(usage_context)
File "/home/zhangsan/.local/lib/python3.10/site-packages/vllm/engine/arg_utils.py", line 1221, in create_engine_config
config = VllmConfig(
File "<string>", line 18, in __init__
File "/home/zhangsan/.local/lib/python3.10/site-packages/vllm/config.py", line 2991, in __post_init__
self.model_config.verify_async_output_proc(self.parallel_config,
File "/home/zhangsan/.local/lib/python3.10/site-packages/vllm/config.py", line 603, in verify_async_output_proc
if not current_platform.is_async_output_supported(self.enforce_eager):
File "/home/zhangsan/.local/lib/python3.10/site-packages/vllm/platforms/interface.py", line 165, in is_async_output_supported
raise NotImplementedError
NotImplementedError
Exception ignored in: <function LLM.__del__ at 0x7f2198784430>
Traceback (most recent call last):
File "/home/zhangsan/.local/lib/python3.10/site-packages/vllm/entrypoints/llm.py", line 236, in __del__
if self.llm_engine and hasattr(self.llm_engine, "shutdown"):
AttributeError: 'LLM' object has no attribute 'llm_engine'
提示is_async_output_supported()方法未实现,不能判断是否支持异步输出?继续问豆包,答复如下:
问题分析
功能未实现异常:从报错信息 NotImplementedError 来看,在 vLLM 的初始化配置过程中,涉及到了检查异步输出是否被支持的逻辑(通过 is_async_output_supported 方法),而这个方法抛出了 NotImplementedError,意味着相关的功能在当前平台或者代码逻辑里并没有被实现,这可能是因为当前环境不满足某些前置条件或者代码本身存在需要完善的地方。
对象属性异常(后续连带问题):和之前类似,由于前面初始化 LLM 实例时出现错误,导致没能正确创建 llm_engine 属性,所以在 del 方法中访问这个不存在的属性时就产生了 AttributeError。
解决方案
检查平台兼容性:
确认你所使用的平台(操作系统、硬件环境等)是否被 vLLM 完整支持,尤其是涉及到异步输出相关的功能部分。例如,某些特定的操作系统版本或者比较特殊的硬件架构可能存在尚未适配的情况。可以查看 vLLM 的官方文档,确认其支持的平台列表,看是否需要更换到支持的平台环境下运行。
更新 vLLM 版本:
有可能是你正在使用的 vLLM 版本存在这个未实现功能的缺陷,尝试通过 pip install --upgrade vLLM 命令将 vLLM 升级到最新版本,看新版本中是否已经修复了该问题,完善了异步输出相关功能的实现逻辑。
检查相关配置参数(尝试绕过问题):
在 vLLM 的配置过程中,涉及到触发这个未实现功能检查的部分,可能与某些配置参数有关。查看代码中对 VllmConfig 等相关配置类的参数设置情况,例如,对于 enforce_eager 参数(它与异步输出的检查逻辑相关联),可以尝试显式地设置其值,看看能否绕过这个导致 NotImplementedError 的情况。比如像这样(只是示例,需根据实际情况调整):
python
from vllm import LLM, VllmConfig
config = VllmConfig(enforce_eager=True) # 尝试设置 enforce_eager 参数
llm = LLM(model=“Qwen/Qwen2-7B-Instruct”, device=“cpu”, engine_args=config)
不过这样做可能会改变模型运行的一些行为模式,需要进一步测试验证是否满足你的实际需求。
查看代码和提反馈(进阶操作):
如果上述方法都无法解决问题,并且你对 vLLM 的代码结构比较熟悉,可以深入查看 vLLM/platforms/interface.py 中 is_async_output_supported 方法的实现逻辑,分析为何会抛出 NotImplementedError,尝试自己补充相应的实现代码(前提是你有能力且符合项目的开发规范)。或者向 vLLM 的开发团队提交问题反馈,提供详细的报错信息、你的使用环境等情况,等待他们修复和回应。
意思还是兼容问题。有没有什么办法跳过这个检测呢? 明确告知vllm不用异步输出,不用去判断,能不能做到?继续查了下VllmConfig的用法及其可能的参数:
VllmConfig 基本介绍
VllmConfig是 vLLM 库中用于配置语言模型相关参数的一个类。通过设置它的各种参数,可以调整模型的运行行为,如推理策略、资源分配等。
可设置的参数及其取值范围
model参数
描述:指定要使用的语言模型的名称或路径。
取值范围:可以是预训练模型在模型库中的名称(如"Qwen/Qwen2 - 7B - Instruct"),也可以是本地模型文件的路径(例如"/path/to/your/local/model")。
device参数
描述:指定模型运行的设备。
取值范围:常见取值为"cpu"或"cuda"(用于 GPU)。如果有多个 GPU,还可以通过更复杂的设备指定方式(如"cuda:0"表示使用第一个 GPU 设备)来利用特定的 GPU 资源。
dtype参数
描述:设置模型的数据类型,这会影响模型的计算精度和资源占用情况。
取值范围:例如"float32"(单精度浮点数)、“float16”(半精度浮点数,可加速计算但可能损失一些精度)等。使用"float16"通常可以减少内存占用和加速计算,但可能会在某些情况下导致数值精度问题。
max_num_batched_tokens参数
描述:用于控制每次批量处理的最大令牌(token)数量。这个参数与模型的推理性能和资源利用效率有关。
取值范围:它是一个正整数,具体取值取决于模型的大小、硬件资源(如 GPU 内存)等因素。例如,可以设置为1024、2048等。较大的值可能会提高推理效率,但也可能会占用更多的资源。
max_num_seqs参数
描述:控制同时处理的最大序列(sequence)数量。
取值范围:也是一个正整数,比如可以设置为4、8等。这个参数同样会影响模型的性能和资源分配,较多的序列数可以提高并行处理能力,但可能会增加计算开销。
engine_use_ray参数
描述:决定是否使用 Ray(一个用于分布式计算的框架)来优化模型引擎的运行。
取值范围:取值为True或False。如果设置为True,需要确保 Ray 已经正确安装并且环境配置支持 Ray 的使用,这可以帮助在分布式环境或者复杂的计算场景下更好地管理和调度模型推理任务。
tensor_parallel_size参数
描述:用于设置张量并行(tensor parallelism)的大小。张量并行是一种在多个设备(如多个 GPU)上并行处理张量计算的技术,以加速模型的运行。
取值范围:是一个正整数,并且通常不超过可用设备(如 GPU)的数量。例如,如果有 4 个 GPU,这个参数可以设置为1(不进行张量并行)、2(在两个 GPU 上进行张量并行)或4(在全部 4 个 GPU 上进行张量并行)。
pipeline_parallel_size参数
描述:与管道并行(pipeline parallelism)相关的参数,管道并行是另一种模型并行技术,通过将模型分成多个阶段并在不同设备上并行处理来加速计算。
取值范围:也是一个正整数,并且其取值要根据模型结构和可用设备数量合理设置。例如,对于一个适合进行管道并行的模型,这个参数可以根据实际设备情况设置为2、3等,以实现模型在多个设备上的管道式并行计算。
seed参数
描述:用于设置随机种子,这在需要复现模型的输出(例如在调试或者对比实验中)时非常重要。
取值范围:通常是一个整数,任何有效的整数都可以作为种子值。例如,42是一个常用的随机种子数。当设置了相同的种子后,在相同的模型和输入条件下,模型的输出(如生成的文本)应该是相同的。
看下来,这些参数也就是大模型根目录下的config.json文件中的配置啊,似乎没有关于异步输出控制的。继续问豆包,明确地询问可否通过配置跳过异常输出检查,呵呵,还真有哦!
怎么让vllm跳过异步输出检查?明确不采用异步输出,具体实现方式?
理解异步输出检查机制
在 vLLM 中,异步输出检查是在模型配置和初始化阶段进行的,用于判断当前环境是否支持异步输出功能。如果不支持或者想要明确不采用异步输出,可以通过修改相关配置参数来跳过这个检查。
通过配置参数跳过检查(以VllmConfig为例)
设置enforce_eager参数为True:
在创建VllmConfig对象时,可以设置enforce_eager参数为True。这样做会强制模型以同步(非异步)的方式运行,从而跳过异步输出检查。示例代码如下:
python
from vllm import VllmConfig, LLM
config = VllmConfig(enforce_eager=True)
llm = LLM(model=“your_model_name”, config=config)
在LLM初始化时传递配置参数:
如上述代码所示,创建好VllmConfig对象后,将其作为参数传递给LLM类的初始化方法。这样,LLM在初始化过程中会根据配置参数来设置模型的运行方式,当enforce_eager为True时,就不会启用异步输出相关的检查和功能。
检查其他可能相关的配置(深度定制)
查看vllm.config模块中的其他参数:
除了enforce_eager参数外,可能还有其他与异步输出相关的隐藏参数或者配置选项。可以深入研究vllm.config模块中的代码,例如查看VllmConfig类的其他属性和方法,看是否有可以进一步定制以完全禁用异步输出相关逻辑的地方。不过这种方式需要对 vLLM 的代码结构有更深入的理解,并且要注意修改代码可能带来的潜在风险,如破坏其他功能或者导致不兼容问题。
参考官方文档和示例代码(持续关注更新):
vLLM 的官方文档可能会提供关于如何跳过异步输出检查或者禁用异步输出的最新方法。同时,官方提供的示例代码也是很好的参考资源,可以查看是否有类似场景下的配置方式。如果文档和示例中没有明确提及,可以考虑向 vLLM 的开发团队或者社区提问,以获取更准确的信息。
原来VllmConfig是个类,可以用它来设置vllm的参数。实际上在前面的回答中就有这个内容,只是不够明确(或者说是我不懂啊)!那还等什么,增加参数配置(注意:完全可以直接把参数放在LLM类的构造方法中,不用VllmConfig类,当然用它也可以),改完再试。但结果还是不行, 还是提示is_async_output_supported()方法未实现,到底怎么回事呢?
终极大招
只有放终极大招了吧,查看vllm框架源代码!
根据Traceback信息可以看到报错的文件名、方法名和代码行,从网上下载源码包解压,或者在安装vllm后的.local/lib/python3.10/site-packages/vllm目录下,都可找到整个vllm框架的源代码,这就是开源系统的好处啊!
在vllm/config.py文件中查到如下代码:
def verify_async_output_proc(self, parallel_config, speculative_config,
device_config) -> None:
if not self.use_async_output_proc:
# Nothing to check
return
if parallel_config.pipeline_parallel_size > 1:
logger.warning("Async output processing can not be enabled "
"with pipeline parallel")
self.use_async_output_proc = False
return
# Reminder: Please update docs/source/usage/compatibility_matrix.rst
# If the feature combo become valid
if not current_platform.is_async_output_supported(self.enforce_eager):
logger.warning(
"Async output processing is not supported on the "
"current platform type %s.", current_platform.device_type)
self.use_async_output_proc = False
return
if envs.VLLM_USE_RAY_SPMD_WORKER:
logger.warning(
"Async output processing can not be enabled with ray spmd")
self.use_async_output_proc = False
return
# Async postprocessor is not necessary for pooling models
# since there is no token generation
if self.runner_type == "pooling":
self.use_async_output_proc = False
# Reminder: Please update docs/source/usage/compatibility_matrix.rst
# If the feature combo become valid
if speculative_config:
logger.warning("Async output processing is not supported with"
" speculative decoding currently.")
self.use_async_output_proc = False
这里可以看出来,use_async_output_proc这个属性就代表是否采用异步输出,它的默认值设置为True,这里会重新判定它的值,也正是在这里会调用platform类的is_async_output_supported()方法,但当前平台却没有实现这个方法。调用is_async_output_supported()方法时恰是用enforce_eager作为参数,所以即使设置了这个参数也并不能跳过对它的调用。从代码逻辑看,要避免调用,只有两次机会,一个是将use_async_output_proc的初始值设为False,但刚刚已经说了,它的初始值是True;所以剩下的唯一机会是将pipeline_parallel_size设为大于1的值。
记得前面查询VllmConfig类的使用方法时见到过pipeline_parallel_size参数,就是它了。仍然用设置enforce_eager参数一样的方法,将pipeline_parallel_size设置为2,再来试试!但是,再次抛出异常:
$ python test.py
INFO 12-23 13:03:39 config.py:478] This model supports multiple tasks: {'reward', 'generate', 'score', 'classify', 'embed'}. Defaulting to 'generate'.
INFO 12-23 13:03:39 config.py:1216] Defaulting to use mp for distributed inference
WARNING 12-23 13:03:39 config.py:596] Async output processing can not be enabled with pipeline parallel
Traceback (most recent call last):
File "/usr/work/llm/vllm/test.py", line 12, in <module>
llm = LLM(model="Qwen/Qwen2-7B-Instruct", pipeline_parallel_size=2, device="cpu")
File "/home/zhangsan/.local/lib/python3.10/site-packages/vllm/utils.py", line 990, in inner
return fn(*args, **kwargs)
File "/home/zhangsan/.local/lib/python3.10/site-packages/vllm/entrypoints/llm.py", line 230, in __init__
self.llm_engine = self.engine_class.from_engine_args(
File "/home/zhangsan/.local/lib/python3.10/site-packages/vllm/engine/llm_engine.py", line 529, in from_engine_args
engine_config = engine_args.create_engine_config(usage_context)
File "/home/zhangsan/.local/lib/python3.10/site-packages/vllm/engine/arg_utils.py", line 1221, in create_engine_config
config = VllmConfig(
File "<string>", line 18, in __init__
File "/home/zhangsan/.local/lib/python3.10/site-packages/vllm/config.py", line 2997, in __post_init__
self.cache_config.verify_with_parallel_config(self.parallel_config)
File "/home/zhangsan/.local/lib/python3.10/site-packages/vllm/config.py", line 956, in verify_with_parallel_config
raise ValueError("Too large swap space. " + msg)
ValueError: Too large swap space. 4.00 GiB out of the 3.49 GiB total CPU memory is allocated for the swap space.
Exception ignored in: <function LLM.__del__ at 0x7f878ba104c0>
Traceback (most recent call last):
File "/home/zhangsan/.local/lib/python3.10/site-packages/vllm/entrypoints/llm.py", line 236, in __del__
if self.llm_engine and hasattr(self.llm_engine, "shutdown"):
AttributeError: 'LLM' object has no attribute 'llm_engine'
设置了pipeline_parallel_size=2之后,意味着vllm采用并行处理模式,所以要消耗更多的内存,而我的云服务器一共才4GB内存,程序可用的只有3.49GB,哪里有4GB分给交换空间? 哎,结论就是搞不定啊!
进一步挖掘
实际上,查看vllm/platform/interface.py文件中的代码,Platform类是有is_async_output_supported()方法成员的实现的,只是它直接抛出了未实现的异常,传入的enforce_eager参数根本就没用到。
class Platform:
_enum: PlatformEnum
device_name: str
device_type: str
# available dispatch keys:
# check https://github.com/pytorch/pytorch/blob/313dac6c1ca0fa0cde32477509cce32089f8532a/torchgen/model.py#L134 # noqa
# use "CPU" as a fallback for platforms not registered in PyTorch
dispatch_key: str = "CPU"
supported_quantization: list[str] = []
def is_cuda(self) -> bool:
return self._enum == PlatformEnum.CUDA
def is_rocm(self) -> bool:
return self._enum == PlatformEnum.ROCM
def is_tpu(self) -> bool:
return self._enum == PlatformEnum.TPU
def is_hpu(self) -> bool:
return self._enum == PlatformEnum.HPU
def is_xpu(self) -> bool:
return self._enum == PlatformEnum.XPU
def is_cpu(self) -> bool:
return self._enum == PlatformEnum.CPU
。。。。。。
@classmethod
def is_async_output_supported(cls, enforce_eager: Optional[bool]) -> bool:
"""
Check if the current platform supports async output.
"""
raise NotImplementedError
不管是什么平台,都是这个表现,可能最新的v0.6.5版本的vllm就不玩这个了?
还有一种可能,就是Platform是基类,具体的平台类会继承它,然后重载is_async_output_supported()方法,但是我的设备环境未能匹配到合适的重载了这个方法的平台类型。如果逻辑是这样,那问题又出在哪里呢?
果然,我在源码目录vllm下搜索,就出现了各个具体平台的实现代码:
$ grep -rn is_async_output_supported
config.py:603: if not current_platform.is_async_output_supported(self.enforce_eager):
platforms/interface.py:161: def is_async_output_supported(cls, enforce_eager: Optional[bool]) -> bool:
platforms/neuron.py:26: def is_async_output_supported(cls, enforce_eager: Optional[bool]) -> bool:
platforms/hpu.py:28: def is_async_output_supported(cls, enforce_eager: Optional[bool]) -> bool:
platforms/openvino.py:41: def is_async_output_supported(cls, enforce_eager: Optional[bool]) -> bool:
platforms/cpu.py:41: def is_async_output_supported(cls, enforce_eager: Optional[bool]) -> bool:
platforms/cuda.py:96: def is_async_output_supported(cls, enforce_eager: Optional[bool]) -> bool:
platforms/tpu.py:39: def is_async_output_supported(cls, enforce_eager: Optional[bool]) -> bool:
platforms/xpu.py:45: def is_async_output_supported(cls, enforce_eager: Optional[bool]) -> bool:
platforms/rocm.py:76: def is_async_output_supported(cls, enforce_eager: Optional[bool]) -> bool:
其中vllm/platforms/cpu.py中的实现是:
class CpuPlatform(Platform):
_enum = PlatformEnum.CPU
device_name: str = "cpu"
device_type: str = "cpu"
dispatch_key: str = "CPU"
@classmethod
def get_device_name(cls, device_id: int = 0) -> str:
return "cpu"
。。。。。。
@classmethod
def is_async_output_supported(cls, enforce_eager: Optional[bool]) -> bool:
return False
这就是直接用CPU处理,不用GPU的实现,其中至少有实现,虽然传入的enforce_eager=True参数也没用,但不会抛出未实现的异常。也就是说,我虽然传入了device=”cpu“参数,但并未匹配到CPU类型的平台对象,为什么呢?平台类型到底是在哪里确定的?怎么确定的?我的设备环境被判定为什么平台了?
因为LLM引擎初始化就没成功,llm对象都没有创建,即使捕获异常,也没得可输出信息的源头,没办法插入调试代码来输出信息,怎么办呢?
尝试启用日志试试,在test.py中加入
import logging
logging.basicConfig(filename="vllm.log", level=logging.DEBUG)
运行之后,vllm.log文件的内容:
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): hf-mirror.com:443
DEBUG:urllib3.connectionpool:https://hf-mirror.com:443 “HEAD /Qwen/Qwen2-7B-Instruct/resolve/main/tokenizer_config.json HTTP/1.1” 200 0
DEBUG:urllib3.connectionpool:https://hf-mirror.com:443 “HEAD /Qwen/Qwen2-7B-Instruct/resolve/main/config.json HTTP/1.1” 200 0
DEBUG:urllib3.connectionpool:https://hf-mirror.com:443 “HEAD /Qwen/Qwen2-7B-Instruct/resolve/main/config.json HTTP/1.1” 200 0
DEBUG:urllib3.connectionpool:https://hf-mirror.com:443 “HEAD /Qwen/Qwen2-7B-Instruct/resolve/main/sentence_bert_config.json HTTP/1.1” 404 0
DEBUG:urllib3.connectionpool:https://hf-mirror.com:443 “HEAD /Qwen/Qwen2-7B-Instruct/resolve/main/sentence_roberta_config.json HTTP/1.1” 404 0
DEBUG:urllib3.connectionpool:https://hf-mirror.com:443 “HEAD /Qwen/Qwen2-7B-Instruct/resolve/main/sentence_distilbert_config.json HTTP/1.1” 404 0
DEBUG:urllib3.connectionpool:https://hf-mirror.com:443 “HEAD /Qwen/Qwen2-7B-Instruct/resolve/main/sentence_camembert_config.json HTTP/1.1” 404 0
DEBUG:urllib3.connectionpool:https://hf-mirror.com:443 “HEAD /Qwen/Qwen2-7B-Instruct/resolve/main/sentence_albert_config.json HTTP/1.1” 404 0
DEBUG:urllib3.connectionpool:https://hf-mirror.com:443 “HEAD /Qwen/Qwen2-7B-Instruct/resolve/main/sentence_xlm-roberta_config.json HTTP/1.1” 404 0
DEBUG:urllib3.connectionpool:https://hf-mirror.com:443 “HEAD /Qwen/Qwen2-7B-Instruct/resolve/main/sentence_xlnet_config.json HTTP/1.1” 404 0
DEBUG:urllib3.connectionpool:https://hf-mirror.com:443 “HEAD /Qwen/Qwen2-7B-Instruct/resolve/main/preprocessor_config.json HTTP/1.1” 404 0
DEBUG:urllib3.connectionpool:https://hf-mirror.com:443 “HEAD /Qwen/Qwen2-7B-Instruct/resolve/main/modules.json HTTP/1.1” 404 0
这是获取大模型配置文件的过程,对我们的问题分析没有帮助。
尝试以verbose方式启动测试,执行python -v test.py指令,屏幕快速滚动,打印出大量的文件和对象引入信息,就只是反映出涉及到的文件和对象引用顺序,对抛出异常问题的分析也没有帮助。
尝试以调试模式运行,先用pip安装ipdb模块,然后修改测试程序文件test.py,在LLM引擎初始化之前启动调式,具体改动如下:
import ipdb
# Initialize the tokenizer
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2-7B-Instruct")
# Pass the default decoding hyperparameters of Qwen2-7B-Instruct
# max_tokens is for the maximum length for generation.
sampling_params = SamplingParams(temperature=0.7, top_p=0.8, repetition_penalty=1.05, max_tokens=512)
ipdb.set_trace()
# Input the model name or path. Can be GPTQ or AWQ models.
llm = LLM(model="Qwen/Qwen2-7B-Instruct", enforce_eager=True, device="cpu")
再次运行test.py,进入pdb模式:
$ python test.py
> /usr/work/llm/vllm/test.py(15)<module>()
14 # Input the model name or path. Can be GPTQ or AWQ models.
---> 15 llm = LLM(model="Qwen/Qwen2-7B-Instruct", enforce_eager=True, device="cpu")
16
ipdb>
然后按如下的参考指令进行调试:
ipdb 是 pdb 的增强版,提供了更友好的交互式调试体验,它可以打印对象的信息,以下是其详细使用方法:
- 安装
在使用 ipdb 之前,需要先进行安装,使用如下命令:
收起
plaintext
pip install ipdb- 命令行启动
与 pdb 类似,可以在命令行通过 -m ipdb 来启动一个脚本的调试,假设你有一个 test.py 的脚本:
收起
bash
python -m ipdb test.py
脚本启动后,代码会停在第一行,进入 ipdb 的交互式界面,显示提示符 ipdb>- 代码内嵌启动
在 Python 代码中,你可以插入 ipdb.set_trace() 语句来启动调试。例如:
python
import ipdb
def add_numbers(a, b):
ipdb.set_trace()
result = a + b
return result
if name == “main”:
sum_value = add_numbers(3, 5)
print(sum_value)
当代码运行到 ipdb.set_trace() 时,就会暂停,进入 ipdb 调试界面。- 使用调试命令
执行下一行代码:使用 n(next),代码会执行当前行的下一行,不会进入函数内部。
进入函数:s(step)用于进入函数内部,逐行执行函数里的代码,便于查看函数内部的运算逻辑。
继续执行:c(continue)会让代码持续运行,直到遇到下一个断点,或者程序结束。
查看代码上下文:l(list)可以列出当前行附近的代码片段,默认展示当前行前后的几行代码,方便了解代码位置。
打印变量:直接输入变量名,就能查看变量的值,例如,如果有变量 x,输入 x 即可查看其当前的值。
打印对象信息:对于对象,可以使用 pp(pretty print) 命令。假设你有一个列表对象 my_list = [1, 2, 3],在 ipdb 界面输入 pp my_list,它会以更美观、易读的格式打印出列表的内容,比直接输入 my_list 输出的格式要好得多,尤其适用于复杂的嵌套对象,如字典嵌套列表这类数据结构。
设置断点:b(break)用来设置断点,你可以指定行号、函数名等。例如,b 10 会在第 10 行设置一个断点,b my_function 则会在 my_function 函数的开头设置断点。
退出调试:使用 q(quit)可以直接退出调试,终止程序的运行。
发现这个调试非常有用,比如我调试到vllm/entrypoint/llm.py:227行时,可以打印出engine_args的内容:
ipdb> pp(engine_args)
EngineArgs(model='Qwen/Qwen2-7B-Instruct',
served_model_name=None,
tokenizer='Qwen/Qwen2-7B-Instruct',
task='auto',
skip_tokenizer_init=False,
tokenizer_mode='auto',
trust_remote_code=False,
allowed_local_media_path='',
download_dir=None,
load_format='auto',
config_format=<ConfigFormat.AUTO: 'auto'>,
dtype='auto',
kv_cache_dtype='auto',
quantization_param_path=None,
seed=0,
max_model_len=None,
worker_use_ray=False,
distributed_executor_backend=None,
pipeline_parallel_size=1,
tensor_parallel_size=1,
max_parallel_loading_workers=None,
block_size=None,
enable_prefix_caching=False,
disable_sliding_window=False,
use_v2_block_manager=True,
swap_space=4,
cpu_offload_gb=0,
gpu_memory_utilization=0.9,
max_num_batched_tokens=None,
max_num_seqs=256,
max_logprobs=20,
disable_log_stats=True,
revision=None,
code_revision=None,
rope_scaling=None,
rope_theta=None,
hf_overrides=None,
tokenizer_revision=None,
quantization=None,
enforce_eager=True,
max_seq_len_to_capture=8192,
disable_custom_all_reduce=False,
tokenizer_pool_size=0,
tokenizer_pool_type='ray',
tokenizer_pool_extra_config=None,
limit_mm_per_prompt=None,
mm_processor_kwargs=None,
mm_cache_preprocessor=False,
enable_lora=False,
enable_lora_bias=False,
max_loras=1,
max_lora_rank=16,
enable_prompt_adapter=False,
max_prompt_adapters=1,
max_prompt_adapter_token=0,
fully_sharded_loras=False,
lora_extra_vocab_size=256,
long_lora_scaling_factors=None,
lora_dtype='auto',
max_cpu_loras=None,
device='cpu',
num_scheduler_steps=1,
multi_step_stream_outputs=True,
ray_workers_use_nsight=False,
num_gpu_blocks_override=None,
num_lookahead_slots=0,
model_loader_extra_config=None,
ignore_patterns=None,
preemption_mode=None,
scheduler_delay_factor=0.0,
enable_chunked_prefill=None,
guided_decoding_backend='xgrammar',
logits_processor_pattern=None,
speculative_model=None,
speculative_model_quantization=None,
speculative_draft_tensor_parallel_size=None,
num_speculative_tokens=None,
speculative_disable_mqa_scorer=False,
speculative_max_model_len=None,
speculative_disable_by_batch_size=None,
ngram_prompt_lookup_max=None,
ngram_prompt_lookup_min=None,
spec_decoding_acceptance_method='rejection_sampler',
typical_acceptance_sampler_posterior_threshold=None,
typical_acceptance_sampler_posterior_alpha=None,
qlora_adapter_name_or_path=None,
disable_logprobs_during_spec_decoding=None,
otlp_traces_endpoint=None,
collect_detailed_traces=None,
disable_async_output_proc=False,
scheduling_policy='fcfs',
override_neuron_config=None,
override_pooler_config=None,
compilation_config=None,
worker_cls='auto',
kv_transfer_config=None)
ipdb>
这就很好玩了,继续!进入到vllm/engine/arg_utils.py: create_engine_config()方法后,在1221行设置断点,然后直接运行到这个位置:
> /home/zhangsan/.local/lib/python3.10/site-packages/vllm/engine/arg_utils.py(1008)create_engine_config()
1007 # so we make sure the quant method and the load format are consistent
-> 1008 if (self.quantization == "bitsandbytes" or
1009 self.qlora_adapter_name_or_path is not None) and \
ipdb> pp(envs.VLLM_USE_V1)
False
ipdb> b 1221
Breakpoint 1 at /home/zhangsan/.local/lib/python3.10/site-packages/vllm/engine/arg_utils.py:1221
ipdb> c
INFO 12-23 16:14:13 config.py:478] This model supports multiple tasks: {'classify', 'score', 'embed', 'generate', 'reward'}. Defaulting to 'generate'.
> /home/zhangsan/.local/lib/python3.10/site-packages/vllm/engine/arg_utils.py(1221)create_engine_config()
1220
1> 1221 config = VllmConfig(
1222 model_config=model_config,
ipdb>
继续单步执行进入到VllmConfig()构造方法,直到运行到__post_init__(self),这里可以打印出VllmConfig实例对象的值:
> /home/zhangsan/.local/lib/python3.10/site-packages/vllm/config.py(2987)__post_init__()
2986
-> 2987 def __post_init__(self):
2988 """Verify configs are valid & consistent with each other.
ipdb> pp(self)
VllmConfig(model_config=<vllm.config.ModelConfig object at 0x7f5a058dab30>,
cache_config=<vllm.config.CacheConfig object at 0x7f5a059b2050>,
parallel_config=ParallelConfig(pipeline_parallel_size=1,
tensor_parallel_size=1,
worker_use_ray=False,
max_parallel_loading_workers=None,
disable_custom_all_reduce=False,
tokenizer_pool_config=None,
ray_workers_use_nsight=False,
placement_group=None,
distributed_executor_backend=None,
worker_cls='auto',
sd_worker_cls='auto',
world_size=1,
rank=0),
scheduler_config=SchedulerConfig(runner_type='generate',
max_num_batched_tokens=32768,
max_num_seqs=256,
max_model_len=32768,
num_lookahead_slots=0,
delay_factor=0.0,
enable_chunked_prefill=False,
is_multimodal_model=False,
preemption_mode=None,
num_scheduler_steps=1,
multi_step_stream_outputs=True,
send_delta_data=False,
policy='fcfs',
chunked_prefill_enabled=False),
device_config=<vllm.config.DeviceConfig object at 0x7f5a0628d120>,
load_config=LoadConfig(load_format=<LoadFormat.AUTO: 'auto'>,
download_dir=None,
model_loader_extra_config=None,
ignore_patterns=['original/**/*']),
lora_config=None,
speculative_config=None,
decoding_config=DecodingConfig(guided_decoding_backend='xgrammar'),
observability_config=ObservabilityConfig(otlp_traces_endpoint=None,
collect_model_forward_time=False,
collect_model_execute_time=False),
prompt_adapter_config=None,
quant_config=None,
compilation_config=None,
kv_transfer_config=None,
instance_id='')
ipdb>
继续单步运行,直到进入verify_async_output_proc()方法:
ipdb> s
> /home/zhangsan/.local/lib/python3.10/site-packages/vllm/config.py(2990)__post_init__()
2989 """
-> 2990 if self.model_config is not None:
2991 self.model_config.verify_async_output_proc(self.parallel_config,
ipdb> s
> /home/zhangsan/.local/lib/python3.10/site-packages/vllm/config.py(2991)__post_init__()
2990 if self.model_config is not None:
-> 2991 self.model_config.verify_async_output_proc(self.parallel_config,
2992 self.speculative_config,
ipdb> s
> /home/zhangsan/.local/lib/python3.10/site-packages/vllm/config.py(2992)__post_init__()
2991 self.model_config.verify_async_output_proc(self.parallel_config,
-> 2992 self.speculative_config,
2993 self.device_config)
ipdb> s
> /home/zhangsan/.local/lib/python3.10/site-packages/vllm/config.py(2993)__post_init__()
2992 self.speculative_config,
-> 2993 self.device_config)
2994 self.model_config.verify_with_parallel_config(self.parallel_config)
ipdb> s
> /home/zhangsan/.local/lib/python3.10/site-packages/vllm/config.py(2991)__post_init__()
2990 if self.model_config is not None:
-> 2991 self.model_config.verify_async_output_proc(self.parallel_config,
2992 self.speculative_config,
ipdb> s
--Call--
> /home/zhangsan/.local/lib/python3.10/site-packages/vllm/config.py(589)verify_async_output_proc()
588
--> 589 def verify_async_output_proc(self, parallel_config, speculative_config,
590 device_config) -> None:
ipdb> s
> /home/zhangsan/.local/lib/python3.10/site-packages/vllm/config.py(591)verify_async_output_proc()
590 device_config) -> None:
--> 591 if not self.use_async_output_proc:
592 # Nothing to check
在这里先打印self和self.use_async_output_proc的值:
ipdb> pp(self)
<vllm.config.ModelConfig object at 0x7f5a058dab30>
ipdb> pp(self.use_async_output_proc)
True
确实use_async_output_proc的值为True,确认它初始化时就是True,在前面我们也看到了parallel_config.pipeline_parallel_size的值是1,所以,必然地,下一步就要执行下面的代码:
if not current_platform.is_async_output_supported(self.enforce_eager):
logger.warning(
"Async output processing is not supported on the "
"current platform type %s.", current_platform.device_type)
self.use_async_output_proc = False
return
这就是前面抛出异常的地方了,在这里仔细检查所有可疑对象的值。
ipdb> pp(current_platform)
<vllm.platforms.interface.UnspecifiedPlatform object at 0x7f5a0a7d20e0>
current_platform的类型原来是UnspecifiedPlatform,这就是为什么它的is_async_output_supported()方法抛出异常的原因了,因为它根本就没有重载这个方法,直接继承的基类Platform的默认实现,啥都没干就抛出了NotImplementedError。
current_platform是哪里来的呢? 它怎么初始化的?vllm/config.py:25行有代码:
from vllm.platforms import current_platform
所以它可能是类对象或者是全局对象,既然是从vllm.platforms中引入,platforms又显然是个包,对应vllm/platforms源代码目录,那首先查看该目录下的__init__.py文件,果然,它就是个全局的Platform类型的对象!将__init__.py文件的完整内容抄录如下:
from .interface import _Backend # noqa: F401
from .interface import CpuArchEnum, Platform, PlatformEnum, UnspecifiedPlatform
current_platform: Platform
# NOTE: we don't use `torch.version.cuda` / `torch.version.hip` because
# they only indicate the build configuration, not the runtime environment.
# For example, people can install a cuda build of pytorch but run on tpu.
is_tpu = False
try:
# While it's technically possible to install libtpu on a non-TPU machine,
# this is a very uncommon scenario. Therefore, we assume that libtpu is
# installed if and only if the machine has TPUs.
import libtpu # noqa: F401
is_tpu = True
except Exception:
pass
is_cuda = False
try:
import pynvml
pynvml.nvmlInit()
try:
if pynvml.nvmlDeviceGetCount() > 0:
is_cuda = True
finally:
pynvml.nvmlShutdown()
except Exception:
# CUDA is supported on Jetson, but NVML may not be.
import os
def cuda_is_jetson() -> bool:
return os.path.isfile("/etc/nv_tegra_release") \
or os.path.exists("/sys/class/tegra-firmware")
if cuda_is_jetson():
is_cuda = True
is_rocm = False
try:
import amdsmi
amdsmi.amdsmi_init()
try:
if len(amdsmi.amdsmi_get_processor_handles()) > 0:
is_rocm = True
finally:
amdsmi.amdsmi_shut_down()
except Exception:
pass
is_hpu = False
try:
from importlib import util
is_hpu = util.find_spec('habana_frameworks') is not None
except Exception:
pass
is_xpu = False
try:
# installed IPEX if the machine has XPUs.
import intel_extension_for_pytorch # noqa: F401
import oneccl_bindings_for_pytorch # noqa: F401
import torch
if hasattr(torch, 'xpu') and torch.xpu.is_available():
is_xpu = True
except Exception:
pass
is_cpu = False
try:
from importlib.metadata import version
is_cpu = "cpu" in version("vllm")
except Exception:
pass
is_neuron = False
try:
import transformers_neuronx # noqa: F401
is_neuron = True
except ImportError:
pass
is_openvino = False
try:
from importlib.metadata import version
is_openvino = "openvino" in version("vllm")
except Exception:
pass
if is_tpu:
# people might install pytorch built with cuda but run on tpu
# so we need to check tpu first
from .tpu import TpuPlatform
current_platform = TpuPlatform()
elif is_cuda:
from .cuda import CudaPlatform
current_platform = CudaPlatform()
elif is_rocm:
from .rocm import RocmPlatform
current_platform = RocmPlatform()
elif is_hpu:
from .hpu import HpuPlatform
current_platform = HpuPlatform()
elif is_xpu:
from .xpu import XPUPlatform
current_platform = XPUPlatform()
elif is_cpu:
from .cpu import CpuPlatform
current_platform = CpuPlatform()
elif is_neuron:
from .neuron import NeuronPlatform
current_platform = NeuronPlatform()
elif is_openvino:
from .openvino import OpenVinoPlatform
current_platform = OpenVinoPlatform()
else:
current_platform = UnspecifiedPlatform()
__all__ = ['Platform', 'PlatformEnum', 'current_platform', 'CpuArchEnum']
进一步解读之前,先统一学习下vllm支持的所有设备类型知识:
TPU 指的是张量处理单元(Tensor Processing Unit,简称 TPU),它是谷歌专门为加速机器学习工作负载而设计开发的一种专用集成电路(ASIC)芯片 ,与传统的 CPU、GPU 有所不同,TPU针对深度学习算法中的张量运算做了高度优化,拥有极高的能效比,能够在运行大规模深度学习模型训练与推理任务时,实现远超常规硬件的速度与更低的能耗。将多个TPU 芯片集成到一台服务器或者计算设备上,就构成了 TPU machine,这类设备常被用于处理海量数据的 AI项目,例如大型语言模型的预训练阶段。
CUDA(Compute Unified Device Architecture),即计算统一设备架构,是 NVIDIA 推出的一种并行计算平台和编程模型,于 2007 年首次发布,它在加速深度学习和高性能计算任务方面发挥着关键作用。CUDA 与 NVIDIA的 GPU 紧密相连,NVIDIA 生产的 GPU 芯片包含了大量的 CUDA 核心,这些核心专门设计用于高效处理大规模并行计算任务。常见的 GeForce、Quadro、Tesla 系列 GPU,都配备数量不等的 CUDA
核心。NVIDIA 还提供了一系列丰富的 CUDA 库,像是 CUDA Toolkit 自带的cuBLAS(用于线性代数运算,如矩阵乘法、向量加法)、cuFFT(快速傅里叶变换)、cuDNN(深度神经网络库,优化神经网络的前向传播、反向传播计算)等,这些库封装好了高效算法,开发者无需从零开发,直接调用就能加速对应类型的计算任务。pynvml是 NVIDIA Management Library (NVML) 的 Python 绑定,它提供了一组用于与 NVIDIA GPU 进行交互的函数和类。
Jetson 系列产品均搭载了 NVIDIA 的 GPU,Jetson Nano、Jetson Xavier NX、Jetson AGX Xavier 等不同型号的 Jetson 设备,都配备了相应数量的 CUDA 核心。
AMD SMI 通常指 AMD System Management Interface,是适用于 Linux 的 C 语言库,为应用程序提供了用户空间接口,用于监控和控制 AMD 设备,如 AMD GPU 等。
XPU 可以指代将多种不同类型的处理器集成在一个芯片或系统中的架构,这些处理器包括但不限于 CPU、GPU、FPGA、ASIC 等 ,旨在综合不同处理器的优势,以适应更广阔的超级计算市场和复杂多样的计算任务需求。英特尔的 Falcon Shores XPU混合搭配了 CPU 和 GPU,英特尔正在开发的新一代数据中心 XPU 产品。
Transformers NeuronX 是由亚马逊云科技开发的一个开源库,主要用于在 AWS Inferentia 和 Trainium 等第二代 Neuron 硬件上,使用 PyTorch 对大型语言模型进行推理。
OpenVINO(Open Visual Inference & Neural Network Optimization),即开放视觉推理与神经网络优化工具包,是英特尔推出的一款用于加速深度学习模型推理的开源软件套件,旨在帮助开发者更高效地将深度学习算法部署到英特尔架构的硬件平台上。
有了设备类型的概念,再对照__init__.py文件中的代码就比较容易理解了。vLLM对设备平台的判定是在程序加载的时候就已经完成了,这很大程度上取决于vllm软件包编译的时候选定的支持,针对不同设备类型编译成了不同的版本(更多集中在其依赖的PyTorch的版本上)。相应地在安装时就要根据设备类型选定对应的python依赖包,vllm加载时进而根据安装的python依赖包,以及其他相应的信息来判定设备类型。
比较特殊的一个情况是,对于没有GPU硬件,或者不支持GPU加速的设备,其判定方式比较直接,就是确认vllm的版本号中是否带有cpu字样,有cpu字样就表示用CPU处理,不支持GPU加速,简单粗暴!
is_cpu = False
try:
from importlib.metadata import version
is_cpu = "cpu" in version("vllm")
except Exception:
pass
好了,现在可以总结了:
没得GPU硬件,不支持GPU加速的设备,必须安装CPU版本的vllm包;
有AMD GPU的显卡,可以安装ROCM版本的vllm包;
有NVIDIA的显卡或者它专门设计的机器学习硬件设备,就安装CUDA版本的vllm包;
其他特殊的硬件类型则根据各自情况选择。
至此算是彻底搞清楚了吧?!呵呵,三天了,可以先上床睡个安稳觉了。

4520

被折叠的 条评论
为什么被折叠?



