vllm的model_executor
经过前面scheduler一部分代码的解读,了解到scheduler会对当前的batch_requests打包成一整个SchedulerOutput传递给Engine中的ModelExecutor,本节我们继续沿着EngineCore中的step()方法进入模型推理阶段。
1
| future = self.model_executor.execute_model(scheduler_output, non_block=True)
|
1. ModelExecutor
直接进到execute_model(),直接调用了一个RPC来启动模型推理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| def execute_model( self, scheduler_output: SchedulerOutput, non_block: bool = False ) -> ModelRunnerOutput | None | Future[ModelRunnerOutput | None]: output = self.collective_rpc( "execute_model", args=(scheduler_output,), non_block=non_block ) return output[0]
--- 接着搜索下execute_model()调用链是这样的
Executor.execute_model └─ collective_rpc("execute_model", args=(scheduler_output,)) └─ [UniProcExecutor] run_method(driver_worker, "execute_model", ...) └─ [MultiprocExecutor] 通过 IPC 消息队列发送给 WorkerProc └─ Worker.execute_model(scheduler_output) └─ self.model_runner.execute_model(scheduler_output, intermediate_tensors) └─ GPUModelRunner.execute_model(...)
|
在Wroker.execute_model中,对于PP(PiplineParallel)做了一些条件判断,这个图简单的解释了以下PP的工作原理(每一个方框代表了一个GPU Worker):

由于在PP中模型的推理具有先后的依赖关系,所以在每一层都需要等待前一循环的Tensor发送完成才可以,从代码中也可以验证这个设计:
1 2 3 4
| if self._pp_send_work: for handle in self._pp_send_work: handle.wait() self._pp_send_work = []
|
当前一轮的发送任务完成了之后,才会执行本轮的任务。