在 vLLM Ascend 中的补丁#
vLLM Ascend 是 vLLM 的一个平台插件。由于 vLLM 和 vLLM Ascend 的发布周期不同,并且在某些情况下存在硬件限制,我们需要对 vLLM 进行一些代码补丁,以使其能够兼容 vLLM Ascend。
在 vLLM Ascend 代码中,我们提供了一个补丁模块 vllm_ascend/patch 用于应对 vLLM 的变更。
原理#
我们需要记住,Patch 不是让 vLLM 兼容 Ascend 的最佳方式,这只是一个临时的解决方案。最好的方法是将修改贡献到 vLLM 项目中,从而让 vLLM 原生支持 Ascend。对于 vLLM Ascend,我们对 Patch 策略有一个基本原则:
少即是多。请不要打补丁,除非这是目前唯一的方法。
一旦补丁被添加,必须说明将来移除该补丁的计划。
任何时候,欢迎清理补丁代码。
工作原理#
在 vllm_ascend/patch 目录中,你可以看到如下代码结构:
vllm_ascend
├── patch
│ ├── platform
│ │ ├── patch_0_9_2
│ │ ├── patch_common
│ │ ├── patch_main
│ ├── worker
│ │ ├── patch_0_9_2
│ │ ├── patch_common
│ │ ├── patch_main
└───────────
platform:此目录下的补丁代码用于修补 vLLM 主进程中的代码。当 vLLM 初始化时,会在很早的阶段由
vllm_ascend/platform::NPUPlatform::pre_register_and_update调用。对于在线模式,vLLM 进程在解析命令行参数时,会在
vllm/vllm/engine/arg_utils.py::AsyncEngineArgs.add_cli_args这里调用平台补丁。对于离线模式,vLLM 进程在解析输入参数时,会在此处调用平台补丁
vllm/vllm/engine/arg_utils.py::EngineArgs.create_engine_config。
worker:此目录中的补丁代码用于修补 vLLM worker 进程中的代码。在初始化 vLLM worker 进程时,会被
vllm_ascend/worker/worker_v1::NPUWorker::__init__调用。无论是在线还是离线模式,vLLM 引擎核心进程在初始化 worker 进程时,都会在这里调用 worker 补丁:
vllm/vllm/worker/worker_base.py::WorkerWrapperBase.init_worker。
在 platform 和 worker 文件夹中都有一些补丁模块。它们用于修补不同版本的 vLLM。
patch_0_10_0: This module is used for patching vLLM 0.10.0. The version is always the nearest version of vLLM. Once vLLM is released, we will drop this patch module and bump to a new version. For example,patch_0_10_0is used for patching vLLM 0.10.0.patch_main:该模块用于修补 vLLM 主分支代码。patch_common: This module is used for patching both vLLM 0.10.0 and vLLM main branch.
如何撰写补丁#
在编写补丁之前,遵循上述原则,我们应尽量修改最少的代码。如果有必要,我们可以修改 platform 和 worker 文件夹中的代码。下面是一个在 vLLM 中修改 distributed 模块的示例。
Decide which version of vLLM we should patch. For example, after analysis, here we want to patch both 0.10.0 and main of vLLM.
决定我们应该修补哪个进程。例如,这里
distributed属于 vLLM 主进程,所以我们应该修补platform。在正确的文件夹中创建补丁文件。文件应命名为
patch_{module_name}.py。此处的示例是vllm_ascend/patch/platform/patch_common/patch_distributed.py。在新文件中编写你的补丁代码。以下是一个示例:
import vllm def patch_destroy_model_parallel(): # your patch code ... vllm.distributed.parallel_state.destroy_model_parallel = patch_destroy_model_parallel
在
__init__.py中导入补丁文件。在这个示例中,将import vllm_ascend.patch.platform.patch_common.patch_distributed添加到vllm_ascend/patch/platform/patch_common/__init__.py中。在
vllm_ascend/patch/__init__.py中添加补丁的描述。描述格式如下:# ** File: <The patch file name> ** # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # 1. `<The target patch module in vLLM>` # Why: # <Describe the reason why we need to patch> # How: # <Describe the way to patch> # Related PR (if no, explain why): # <Add a link to the related PR in vLLM. If there is no related PR, explain why> # Future Plan: # <Describe the future plan to remove the patch>
添加单元测试和端到端(E2E)测试。在 vLLM Ascend 中新增的任何代码也应包含单元测试和端到端测试。更多详情请参见 测试指南。
限制#
在 V1 引擎中,vLLM 会启动三种类型的进程:主进程、EngineCore 进程和 Worker 进程。现在 vLLM Ascend 默认只支持在主进程和 Worker 进程中打补丁代码。如果你想要在 EngineCore 进程中打补丁,你需要在设置阶段对 EngineCore 进程整体打补丁,入口代码在
vllm.v1.engine.core。请完全重写EngineCoreProc和DPEngineCoreProc。If you are running an edited vLLM code, the version of the vLLM may be changed automatically. For example, if you runs an edited vLLM based on v0.9.n, the version of vLLM may be change to v0.9.nxxx, in this case, the patch for v0.9.n in vLLM Ascend would not work as expect, because that vLLM Ascend can't distinguish the version of vLLM you're using. In this case, you can set the environment variable
VLLM_VERSIONto specify the version of vLLM you're using, then the patch for v0.10.0 should work.