详细介绍:vLLM - GPUModelRunner

news/2025/10/4 16:43:16/文章来源:https://www.cnblogs.com/yxysuanfa/p/19125719

GPUModelRunner是真正执行模型前向传播的组件,主要的功能:

  • load_model:模型加载与初始化。
  • execute_model :模型执行,负责驱动模型的执行并输出结果。
  • capture_model :图捕获。
  • LORA:主要靠继承的LoRAModelRunnerMixin实现。

load_model

load_model完成模型的加载:

  • 通过get_model_loader获取model_loader,再调用model_loader.load_model加载模型。
  • 调用self.load_lora_model加载LORA部分,包括:模型转换,权重注入,调度器适配。
  • 调用self.drafter.load_model(self.model)加载drafter模型,用于Speculative Decoding。
  • 如果是MOE模型,则创建EplbState,用于后续专家并行负载均衡。
def load_model(self, eep_scale_up: bool = False) -> None:
...
with DeviceMemoryProfiler() as m:  # noqa: SIM117
time_before_load = time.perf_counter()
model_loader = get_model_loader(self.load_config)
if not hasattr(self, "model"):
self.model = model_loader.load_model(
vllm_config=self.vllm_config,
model_config=self.model_config)
else:
model_loader.load_weights(self.model,
model_config=self.model_config)
if self.lora_config:
self.model = self.load_lora_model(self.model,
self.model_config,
self.scheduler_config,
self.lora_config,
self.device)
if hasattr(self, "drafter"):
self.drafter.load_model(self.model)
if self.use_aux_hidden_state_outputs:
self.model.set_aux_hidden_state_layers(
self.model.get_eagle3_aux_hidden_state_layers())
prepare_communication_buffer_for_model(self.model)
if is_mixture_of_experts(
self.model) and self.parallel_config.enable_eplb:
logger.info("EPLB is enabled for model %s.",
self.model_config.model)
self.eplb_state = EplbState.build(
self.model,
self.device,
self.parallel_config,
global_expert_load,
old_global_expert_indices,
rank_mapping,
)

execute_model

execute_model完成模型的执行:

  • 状态更新:调用self._update_states更新状态。
  • 输入准备:调用self._prepare_inputs根据调度器的输出准备模型的输入数据和相关元数据,包括:
    1)attn_metadata: dict[str, Any]: 映射每一层到其对应的注意力元数据。
    2)attention_cuda_graphs: bool: attention是否使用cugraph。
    3)logits_indices: torch.Tensor: logits 的索引。
    4)spec_decode_metadata: Optional[SpecDecodeMetadata]: 推测解码的元数据。
    5)num_scheduled_tokens: np.ndarray: 每个request的调度token数。
    6)spec_decode_common_attn_metadata: Optional[CommonAttentionMetadata]: 推测解码的通用注意力元数据。
  • Padding num_input_tokens:
    1)如使用CUDA图,则padding到对应分档的Graph Size。
    2)如使能序列并行,需要padding到tp_size的整数倍(vllm中sp_size == tp_size)。
    3)DP Padding:DP Group内的所有RANK的num_input_tokens对齐到最大值。
  • 多模态Encode:如果是多模态模型,调用self._execute_mm_encoder生成多模态的tokens:mm_embeds。
  • 多模态Embedding:如果是多模态模型,调用self.model.get_input_embeddings生成输入的embedding(多模态需要处理不同来源的输入,且图像和视频适合预计算)。
  • PP并行intermediate_tensors:PP并行下,非第一个RANK调用self.sync_and_slice_intermediate_tensors处理前级RANK输入的intermediate_tensors。
  • KV Cache加载:调用self.maybe_setup_kv_connector(scheduler_output)加载KV Cache。
  • 模型前向传播:调用self.model执行一次前向传播。
  • KV Cache存储:调用self.maybe_wait_for_kv_save()等待新生成的KV Cache写入完成。
  • 计算Logits:调用self.model.compute_logits(sample_hidden_states, None)计算新生成token的Logits。
  • 文法约束:调用self.apply_grammar_bitmask清零的不符合文化的token Logits。
  • Sampling:调用self.sampler进行token采样,生成新token id(考虑temperature,top-p,top-k,repetition penalty等)。
  • Reject Sampling:调用self.rejection_sampler对投机推理的结果进行拒绝采样,最后生成的output tokens = accepted tokens + recovered tokens + bonus tokens。
  • Discard Tokens:在Partial Prefill等场景下,可能存在Prompt的token还未处理完的情况,所以这时要丢弃生成的token,并回退torch.Generator的状态。
  • Parse Valid Tokens:如果不存在投机推理,则所有token都有效,否则则调用self.rejection_sampler.parse_output获取输出中有效的tokens。
  • 投机推理:调用self.propose_draft_token_ids进行下一轮的投机推理。
  • EPLB:调用self.eplb_step()处理EP的Load Balance步。
  • 返回结果:ModelRunnerOutput
@torch.inference_mode()
def execute_model(
self,
scheduler_output: "SchedulerOutput",
intermediate_tensors: Optional[IntermediateTensors] = None,
) -> Union[ModelRunnerOutput, IntermediateTensors]:
self._update_states(scheduler_output)
...
(attn_metadata, attention_cuda_graphs, logits_indices,
spec_decode_metadata, num_scheduled_tokens_np,
spec_decode_common_attn_metadata) = (
self._prepare_inputs(scheduler_output))
num_scheduled_tokens = scheduler_output.total_num_scheduled_tokens
if (self.use_cuda_graph
and num_scheduled_tokens <= self.cudagraph_batch_sizes[-1]):
num_input_tokens = self.vllm_config.pad_for_cudagraph(
num_scheduled_tokens)
else:
tp_size = self.vllm_config.parallel_config.tensor_parallel_size
if self.compilation_config.pass_config. \
enable_sequence_parallelism and tp_size > 1:
num_input_tokens = round_up(num_scheduled_tokens, tp_size)
else:
num_input_tokens = num_scheduled_tokens
num_pad, num_tokens_across_dp = self.get_dp_padding(num_input_tokens)
num_input_tokens += num_pad
if self.is_multimodal_model:
self._execute_mm_encoder(scheduler_output)
mm_embeds = self._gather_mm_embeddings(scheduler_output)
else:
mm_embeds = []
if self.is_multimodal_model and get_pp_group().is_first_rank:
input_ids = self.input_ids[:num_scheduled_tokens]
inputs_embeds = self.model.get_input_embeddings(
input_ids=input_ids,
multimodal_embeddings=mm_embeds or None,
)
self.inputs_embeds[:num_scheduled_tokens].copy_(inputs_embeds)
inputs_embeds = self.inputs_embeds[:num_input_tokens]
input_ids = None
else:
input_ids = self.input_ids[:num_input_tokens]
inputs_embeds = None
...
if get_pp_group().is_first_rank:
intermediate_tensors = None
else:
intermediate_tensors = self.sync_and_slice_intermediate_tensors(
num_input_tokens, intermediate_tensors, True)
...
skip_cuda_graphs = self.full_cuda_graph and not attention_cuda_graphs
with set_forward_context(
attn_metadata,
self.vllm_config,
num_tokens=num_input_tokens,
num_tokens_across_dp=num_tokens_across_dp,
skip_cuda_graphs=skip_cuda_graphs,
):
self.maybe_setup_kv_connector(scheduler_output)
model_output = self.model(
input_ids=input_ids,
positions=positions,
intermediate_tensors=intermediate_tensors,
inputs_embeds=inputs_embeds,
)
self.maybe_wait_for_kv_save()
finished_sending, finished_recving = (
self.get_finished_kv_transfers(scheduler_output))
if self.use_aux_hidden_state_outputs:
hidden_states, aux_hidden_states = model_output
else:
hidden_states = model_output
aux_hidden_states = None
broadcast_pp_output = \
self.parallel_config.distributed_executor_backend \
== "external_launcher" and len(get_pp_group().ranks) > 0
if not get_pp_group().is_last_rank:
...
else:
...
sample_hidden_states = hidden_states[logits_indices]
logits = self.model.compute_logits(sample_hidden_states, None)
...
if scheduler_output.grammar_bitmask is not None:
self.apply_grammar_bitmask(scheduler_output, logits)
sampling_metadata = self.input_batch.sampling_metadata
if spec_decode_metadata is None:
sampler_output = self.sampler(
logits=logits,
sampling_metadata=sampling_metadata,
)
else:
bonus_logits = logits[spec_decode_metadata.bonus_logits_indices]
sampler_output = self.sampler(
logits=bonus_logits,
sampling_metadata=sampling_metadata,
)
bonus_token_ids = sampler_output.sampled_token_ids
target_logits = logits[spec_decode_metadata.target_logits_indices]
output_token_ids = self.rejection_sampler(
spec_decode_metadata,
None,  # draft_probs
target_logits,
bonus_token_ids,
sampling_metadata,
)
sampler_output.sampled_token_ids = output_token_ids
discard_sampled_tokens_req_indices = []
for i, req_id in enumerate(self.input_batch.req_ids):
req_state = self.requests[req_id]
seq_len = (req_state.num_computed_tokens +
scheduler_output.num_scheduled_tokens[req_id])
if seq_len < req_state.num_tokens:
generator = self.input_batch.generators.get(i)
if generator is not None:
generator.set_offset(generator.get_offset() - 4)
discard_sampled_tokens_req_indices.append(i)
...
sampled_token_ids = sampler_output.sampled_token_ids
max_gen_len = sampled_token_ids.shape[-1]
if max_gen_len == 1:
valid_sampled_token_ids = sampled_token_ids.tolist()
else:
valid_sampled_token_ids = self.rejection_sampler.parse_output(
sampled_token_ids,
self.input_batch.vocab_size,
)
...
if not self.speculative_config:
# Speculative decoding is not enabled.
spec_token_ids = None
else:
assert spec_decode_common_attn_metadata is not None
spec_token_ids = self.propose_draft_token_ids(
scheduler_output,
valid_sampled_token_ids,
sampling_metadata,
hidden_states,
sample_hidden_states,
aux_hidden_states,
spec_decode_metadata,
spec_decode_common_attn_metadata,
)
self.eplb_step()
return ModelRunnerOutput(
req_ids=self.input_batch.req_ids,
req_id_to_index=self.input_batch.req_id_to_index,
sampled_token_ids=valid_sampled_token_ids,
spec_token_ids=spec_token_ids,
logprobs=logprobs_lists,
prompt_logprobs_dict=prompt_logprobs_dict,
pooler_output=[],
finished_sending=finished_sending,
finished_recving=finished_recving,
num_nans_in_logits=num_nans_in_logits,
)

_calc_spec_decode_metadata

在execute_model中,会调用_calc_spec_decode_metadata计算投机推理的SpecDecodeMetadata。
以代码中的注释为例:

Inputs:
cu_num_scheduled_tokens:  [  4, 104, 107, 207, 209]
num_draft_tokens:         [  3,   0,   2,   0,   1]
Outputs:
cu_num_draft_tokens:      [  3,   3,   5,   5,   6]
logits_indices:           [  0,   1,   2,   3, 103, 104, 105, 106, 206, 207, 208]
target_logits_indices:    [  0,   1,   2,   5,   6,   9]
bonus_logits_indices:     [  3,   4,   7,   8,  10]

输入:
累积的调度token数:cu_num_scheduled_tokens = [4, 104, 107, 207, 209]
在上一个Step每个Request已经通过draft model投机推理产生的token数:[3, 0, 2, 0, 1]
所以输入的5个Request:

  • Request 0:从位置4开始,有3个draft token,本轮推理要Sample 4个(3+1)token。
  • Request 1:从位置104开始,有0个draft token,本轮推理要Sample 1个token。
  • Request 2:从位置107开始,有2个draft token,本轮推理要Sample 3个token。
  • Request 3:从位置207开始,有0个draft token,本轮推理要Sample 1个token。
  • Request 4:从位置209开始,有1个draft token,本轮推理要Sample 2个token。

输出:
累积的草稿token数cu_num_draft_tokens: [3, 3, 5, 5, 6]

需要Sample的token在输出的logits中的位置logits_indices:

  • Request 0:[0(4-3-1), 1, 2, 3]
  • Request 1:[103(104-0-1)]
  • Request 2:[104(107-2-1), 105, 106]
  • Request 3:[206(207-0-1)]
  • Request 4:[207(209-1-1), 208]

target model生成的用于验证draft token在logits_indices中的位置target_logits_indices:

  • Request 0:[0, 1, 2]
  • Request 1:[]
  • Request 2:[5, 6]
  • Request 3:[]
  • Request 4:[9]

所有的draft token都被接受后,next token在logits_indices中的位置bonus_logits_indices:

  • Request 0:[3]
  • Request 1:[4]
  • Request 2:[7]
  • Request 3:[8]
  • Request 4:[10]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/927350.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Rewind: Codeforces Round 1055 (Div.1+Div.2)

E. Monotone Subsequence \(\text{time limit: 2000 ms}\\\text{memory limit: 1024 MB}\) 这是一道交互题 题意: 由 \(\text{Thm. Erdős–Szekeres}\) ,我们知道对任意长为 \(n^2+1\) 的排列必有一个长为 \(n+1\) …

10.4模拟赛总结

2025-2026 赛季 OIFHA 第三十四场 NOIP 模拟赛总结 一休尼(forever) 原题:CF5E Bindian Signalizing 长度为 \(n\) 的整数序列 \(a\) 。求整数对 \((i,j)\),\(i,j\in [1,n]\) 的个数,满足 \((i,j)\) 之间存在至少…

做网站动图的软件游戏开发软件有哪些

一、简介 java8新添加了一个特性&#xff1a;流Stream。Stream让开发者能够以一种声明的方式处理数据源&#xff08;集合、数组等&#xff09;&#xff0c;它专注于对数据源进行各种高效的聚合操作&#xff08;aggregate operation&#xff09;和大批量数据操作 (bulk data op…

重庆网站设计建设备案网站服务内容

探索AI图像安全&#xff0c;助力可信AI发展 0. 前言1. 人工智能发展与安全挑战1.1 人工智能及其发展1.2 人工智能安全挑战 2. WAIC 2023 多模态基础大模型的可信 AI2.1 WAIC 2023 专题论坛2.2 走进合合信息 3. AI 图像安全3.1 图像篡改检测3.2 生成式图像鉴别3.3 OCR 对抗攻击技…

01.linux基础

01.linux基础 1.你平时在公司主要做什么?2.你们原来公司的网站架构是怎么样的?3.你对哪一块比较熟练或者精通?4.介绍一下负载均衡?5.lvs 内部原理?6.nginx lvs haproxy 三个有什么区别?7.lvs 主要3种工作模式原…

详细介绍:Kubernetes实战:MariaDB误删恢复与数据持久化

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

我的世界封面制作网站企业网站软件

一&#xff1a;prototype大概概念和用途“prototype”字面翻译是“原型”&#xff0c;是javascript实现继承的主要手段。粗略来说就是&#xff1a;prototype是javascript中的函数(function)的一个保留属性&#xff0c;并且它的值是一个对象&#xff08;我们可以称这个对象为&qu…

泊头做网站的大宗商品交易平台上市公司

Puppeteer 是 Chrome 开发团队在 2017 年发布的一个 Node.js 包&#xff0c;用来模拟 Chrome 浏览器的运行。demo只支持将简单不需要翻页&#xff0c;不需要登陆的页面转换为图片需要node环境&#xff0c;以及npm或cnpm包管理工具(自行百度)开始进入一个新的项目目录&#xff0…

微服务项目->在线oj系统(Java-Spring)--竞赛管理 - 教程

微服务项目->在线oj系统(Java-Spring)--竞赛管理 - 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas…

2025整体橱柜厂家TOP企业品牌推荐排行榜,云南昆明整体橱柜全瓷砖,开放式厨房,经济型,一站式无烟柴火灶,嵌入式,智能,多功能,全屋无烟柴火灶整体橱柜公司推荐

在当前整体橱柜市场中,消费者面临着诸多选择难题。部分产品存在耐用性不足的问题,使用一段时间后柜体易出现受潮、霉变现象,尤其是在潮湿的厨房环境中,这一问题更为突出;有些产品虽然外观设计美观,但环保性能不达…

AutoOps:简化自管理 Elasticsearch 的旅程 - 指南

AutoOps:简化自管理 Elasticsearch 的旅程 - 指南2025-10-04 16:27 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; displ…

巩义网站建设费用龙华品牌网站建设

文章目录 同版本多实例配置部署、启动、连接 不同版本多实例配置初始化initialize-insecure 含义 启动 同版本多实例 配置 mkdir -p /data/330{7..9}/data chown -R mysql.mysql /data/* cat > /data/3307/my.cnf <<EOF [mysqld] usermysql basedir/usr/local/mysql …

vite-vue3脚手架(参考帝莎编程-后台管理系统开发)

一 创建项目vite-vue3-app 项目原型: http://shopadmin.dishawang.com/#/ vite: https://vitejs.cn/vite3-cn/ # npm 7+, extra double-dash is needed: npm create vite@latest vite-vue3-app -- --template vuecd …

上传文件的后端程序handleFileUpload()、getOriginalFilename()、UUID及Yaml配置

handleFileUpload()是Element UI中用于自定义文件上传行为的函数,通过http-request属性绑定实现。该函数会在文件选择后触发,负责处理文件上传逻辑,包括文件格式验证、上传进度控制及服务器交互等。 核心功能‌文件…

【视觉SLAM十四讲】视觉里程计 1 - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

从模拟入侵到渗透测试:我摸清了黑客的套路,也懂了企业的软肋 - 详解

从模拟入侵到渗透测试:我摸清了黑客的套路,也懂了企业的软肋 - 详解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: &q…

网站内容通过服务器会不会被更改没有做icp备案的网站

源码下载&#xff1a;B2弹幕插件.zip 这是b2独有的站点信息弹幕插件&#xff0c;专门用来在首页显示站点动态的一款个性化 WordPress插件。喜欢的可以下载回去进行二次开发&#xff0c;还是蛮不错的 基于wordpress 7B2主题开发的一款弹幕插件/气泡插件 功能一览 插件安装&a…

同样的Python代码,在Windows上运行没有错误,在Linux Centos上运行出行错误。

原因: 两个地方里面的包的版本不一致。 需要一个一个检查版本:比如python的版本,torch的版本。out = F.conv2d(input=x, weight=weights, bias=b, stride=1, padding=1) # out: (1, unit_channel, l, d)RuntimeErro…

网站建设电话营销郑州市建设局官网

本章学习了图的结构及应用&#xff0c; 首先是图的分类&#xff0c;图分为无向图、有向图、完全图、连通图、强连通图、带权图、稀疏图、稠密图等等。 图的存储方式有两大类&#xff0c;以边集合方式的表示法和以链接方式的表示法。其中&#xff0c;以边集合方式表示的为邻接矩…