调试技巧#
本文档概述了一些你可以考虑的调试策略。如果你认为你发现了一个错误,请先 搜索现有问题 以查看是否已经报告过。如果没有,请 提交一个新问题 ,并尽可能提供相关的信息。
备注
一旦你调试了一个问题,记得关闭任何定义的调试环境变量,或者简单地启动一个新的shell以避免受到残留调试设置的影响。否则,系统可能会因为调试功能被激活而变慢。
挂起下载模型#
如果模型尚未下载到磁盘,vLLM 将从互联网下载模型,这可能需要时间并取决于您的互联网连接。建议首先使用 huggingface-cli 下载模型,并将模型的本地路径传递给 vLLM。这样,您可以隔离问题。
从磁盘加载模型时挂起#
如果模型很大,从磁盘加载它可能需要很长时间。注意你存储模型的位置。一些集群在节点之间有共享文件系统,例如分布式文件系统或网络文件系统,这可能会很慢。最好将模型存储在本地磁盘上。此外,当模型太大时,可能会占用大量CPU内存,操作系统需要频繁地在磁盘和内存之间交换,从而减慢操作系统的速度。
模型太大#
如果模型太大,无法放入单个GPU中,您可能需要 考虑张量并行 将模型分布在多个GPU上。在这种情况下,每个进程都会读取整个模型并将其分割成块,这使得磁盘读取时间更长(与张量并行的大小成正比)。您可以使用 此示例 将模型检查点转换为分片检查点。转换过程可能需要一些时间,但之后您可以更快地加载分片检查点。无论张量并行的大小如何,模型加载时间应保持不变。
启用更多日志记录#
如果其他策略无法解决问题,可能是 vLLM 实例在某处卡住了。您可以使用以下环境变量来帮助调试问题:
export VLLM_LOGGING_LEVEL=DEBUG
以开启更多日志记录。export CUDA_LAUNCH_BLOCKING=1
以识别哪个CUDA内核导致了问题。export NCCL_DEBUG=TRACE
以开启NCCL的更多日志记录。export VLLM_TRACE_FUNCTION=1
以记录所有函数调用,以便在日志文件中检查,找出哪个函数崩溃或挂起。
网络设置不正确#
如果你有一个复杂的网络配置,vLLM 实例可能无法获取正确的 IP 地址。你可以找到类似 DEBUG 06-10 21:32:17 parallel_state.py:88] world_size=8 rank=0 local_rank=0 distributed_init_method=tcp://xxx.xxx.xxx.xxx:54641 backend=nccl
的日志,IP 地址应该是正确的。如果不是,请使用环境变量 export VLLM_HOST_IP=<your_ip_address>
覆盖 IP 地址。
您可能还需要设置 export NCCL_SOCKET_IFNAME=<your_network_interface>
和 export GLOO_SOCKET_IFNAME=<your_network_interface>
来指定用于IP地址的网络接口。
在 self.graph.replay()
附近发生错误#
如果 vLLM 崩溃并且错误跟踪在 vllm/worker/model_runner.py
中的 self.graph.replay()
附近捕获到它,这是一个 CUDAGraph 内部的 CUDA 错误。要识别导致错误的特定 CUDA 操作,可以在命令行中添加 --enforce-eager
,或者在 LLM
类中添加 enforce_eager=True
以禁用 CUDAGraph 优化并隔离导致错误的精确 CUDA 操作。
不正确的硬件/驱动#
如果无法建立 GPU/CPU 通信,您可以使用以下 Python 脚本,并按照以下说明确认 GPU/CPU 通信是否正常工作。
# Test PyTorch NCCL
import torch
import torch.distributed as dist
dist.init_process_group(backend="nccl")
local_rank = dist.get_rank() % torch.cuda.device_count()
torch.cuda.set_device(local_rank)
data = torch.FloatTensor([1,] * 128).to("cuda")
dist.all_reduce(data, op=dist.ReduceOp.SUM)
torch.cuda.synchronize()
value = data.mean().item()
world_size = dist.get_world_size()
assert value == world_size, f"Expected {world_size}, got {value}"
print("PyTorch NCCL is successful!")
# Test PyTorch GLOO
gloo_group = dist.new_group(ranks=list(range(world_size)), backend="gloo")
cpu_data = torch.FloatTensor([1,] * 128)
dist.all_reduce(cpu_data, op=dist.ReduceOp.SUM, group=gloo_group)
value = cpu_data.mean().item()
assert value == world_size, f"Expected {world_size}, got {value}"
print("PyTorch GLOO is successful!")
# Test vLLM NCCL, with cuda graph
from vllm.distributed.device_communicators.pynccl import PyNcclCommunicator
pynccl = PyNcclCommunicator(group=gloo_group, device=local_rank)
pynccl.disabled = False
s = torch.cuda.Stream()
with torch.cuda.stream(s):
data.fill_(1)
pynccl.all_reduce(data, stream=s)
value = data.mean().item()
assert value == world_size, f"Expected {world_size}, got {value}"
print("vLLM NCCL is successful!")
g = torch.cuda.CUDAGraph()
with torch.cuda.graph(cuda_graph=g, stream=s):
pynccl.all_reduce(data, stream=torch.cuda.current_stream())
data.fill_(1)
g.replay()
torch.cuda.current_stream().synchronize()
value = data.mean().item()
assert value == world_size, f"Expected {world_size}, got {value}"
print("vLLM NCCL with cuda graph is successful!")
dist.destroy_process_group(gloo_group)
dist.destroy_process_group()
如果你在单个节点上进行测试,请调整 --nproc-per-node
为你想要使用的GPU数量:
NCCL_DEBUG=TRACE torchrun --nproc-per-node=<number-of-GPUs> test.py
如果你在多节点上进行测试,根据你的设置调整 --nproc-per-node
和 --nnodes
,并将 MASTER_ADDR
设置为主节点的正确IP地址,该地址应可从所有节点访问。然后,运行:
NCCL_DEBUG=TRACE torchrun --nnodes 2 --nproc-per-node=2 --rdzv_backend=c10d --rdzv_endpoint=$MASTER_ADDR test.py
如果脚本运行成功,你应该会看到消息 sanity check is successful!
。
备注
多节点环境比单节点环境更复杂。如果你遇到诸如 torch.distributed.DistNetworkError
的错误,很可能是网络/DNS设置不正确。在这种情况下,你可以手动分配节点等级并通过命令行参数指定IP:
在第一个节点中,运行
NCCL_DEBUG=TRACE torchrun --nnodes 2 --nproc-per-node=2 --node-rank 0 --master_addr $MASTER_ADDR test.py
。在第二个节点中,运行
NCCL_DEBUG=TRACE torchrun --nnodes 2 --nproc-per-node=2 --node-rank 1 --master_addr $MASTER_ADDR test.py
。
根据您的设置调整 --nproc-per-node
、--nnodes
和 --node-rank
,确保在不同的节点上执行不同的命令(使用不同的 --node-rank
)。