当前位置: 首页 > news >正文

怎么编写网站美轮美奂的网站建设

怎么编写网站,美轮美奂的网站建设,汕头互联网公司,做外贸网站服务修改内容时间2.4.1处理请求的流程#xff0c;引用更好的流程图2025.02.11首发2025.02.08 深入解析 vLLM#xff1a;高性能 LLM 服务框架的架构之美#xff08;一#xff09;原理与解析 深入解析 vLLM#xff1a;高性能 LLM 服务框架的架构之美#xff08;二#xff09;…修改内容时间2.4.1处理请求的流程引用更好的流程图2025.02.11首发2025.02.08 深入解析 vLLM高性能 LLM 服务框架的架构之美一原理与解析 深入解析 vLLM高性能 LLM 服务框架的架构之美二调度管理 1. vLLM 整体代码架构 1.1 vLLM 的设计目标与特点 vLLM 是一个高性能的大语言模型服务框架。在大语言模型日益普及的今天如何高效地提供推理服务成为一个重要挑战。传统的服务框架在处理并发请求时往往会遇到性能瓶颈、内存管理效率低下等问题。vLLM 正是为解决这些关键挑战而生。 在性能优化方面vLLM 最大的创新在于引入了突破性的 PagedAttention 机制。这项技术巧妙地将传统的连续注意力计算改造为基于页的形式使得 GPU 内存的利用效率得到极大提升。通过精心设计的连续批处理机制vLLM 能够充分利用 GPU 算力显著提升推理速度。 说到内存效率vLLM 采用了独特的动态内存管理方案。通过对 KV Cache 的动态管理和页式存储它能够有效减少内存碎片提高内存利用率。这就像是在有限的空间里实现了完美俄罗斯方块让每一块内存都物尽其用。 在并发处理能力上vLLM 表现同样出色。它采用灵活的调度策略能够同时处理大量并发请求并通过动态负载均衡确保资源的最优分配。这种设计让 vLLM 能够轻松应对高并发场景就像一个经验丰富的交通指挥官让所有请求都能高效有序地通行。 作为一个服务框架vLLM 的架构设计非常灵活。它不仅支持单机部署还能轻松扩展到分布式环境。框架兼容主流的 LLM 模型并提供简洁的 API 接口大大降低了开发者的使用门槛。 在实际应用中vLLM 展现出了令人印象深刻的性能表现。相比传统方案它能够将推理服务的吞吐量提升 2-4 倍同时显著降低请求延迟。这种性能提升不仅体现在数据上更为用户带来了明显的体验改善。 对开发者而言vLLM 提供了完善的工具支持。从简单的集成方式到丰富的监控指标和调优选项都体现了框架在易用性方面的深思熟虑。这使得开发者能够快速上手并根据实际需求进行灵活调整。 1.2 核心组件概览 vLLM 的系统架构由几个关键组件构成它们各司其职又相互协作共同支撑起整个服务框架。让我们深入了解每个组件的核心功能 Engine 是整个系统的中枢负责协调其他组件的工作。它就像一个指挥家统筹管理着模型加载、请求分发、结果收集等核心流程。Engine 接收用户请求后会将其转化为内部任务并交由其他组件处理。 Worker 是实际执行推理计算的工作单元。每个 Worker 都可以独立处理分配给它的计算任务就像工厂中的熟练工人。在分布式部署时多个 Worker 可以并行工作大大提升系统的处理能力。 Scheduler 是 vLLM 的调度大脑它的主要职责是合理分配计算资源和管理请求队列。通过精心设计的调度算法Scheduler 能够权衡不同请求的优先级、资源需求和系统负载确保系统高效运转。 BlockManager 负责内存资源的精细化管理。它采用块式管理策略将 GPU 内存划分为多个块并通过智能的分配和回收机制最大化内存使用效率。这就像是一个经验丰富的仓库管理员让每一寸空间都得到充分利用。 PagedAttention 是 vLLM 最具创新性的组件。它重新设计了注意力机制的实现方式引入页式管理的概念使得 KV Cache 的管理更加灵活高效。这项技术显著提升了推理性能是 vLLM 性能优势的关键所在。 CacheEngine 专注于缓存策略的实现。它通过智能的缓存机制减少重复计算提升响应速度。就像是系统的记忆库能够快速调用常用的计算结果。 这些组件通过精心设计的接口相互配合形成了一个高效协同的整体。每个组件都可以独立优化和扩展这种模块化的设计既保证了系统的灵活性也便于维护和升级。 1.3 系统架构与工作流程 vLLM 的系统架构采用了模块化设计各个组件之间通过清晰的接口进行交互。下面这张架构图展示了各个核心组件及其关系 当用户发起一个推理请求时整个处理流程是这样的首先请求会经由 Engine 接收和解析。Engine 会对请求进行初步处理包括参数验证、格式转换等。这就像是前台接待员确保所有进入系统的请求都是规范的。 接下来Engine 会将请求交给 Scheduler 进行调度分析。Scheduler 会根据当前系统的负载状况、可用资源情况为这个请求制定处理计划。它会考虑多个因素是否有空闲的 Worker内存资源是否充足是否需要进行批处理优化这个过程就像是一个经验丰富的项目经理在有限的资源下做出最优的任务分配。 在执行阶段Worker 承担着最重要的计算任务。它们在 Scheduler 的指挥下有条不紊地进行模型推理计算。这时BlockManager 会密切配合确保所需的内存资源能够及时到位。如果发现内存不足BlockManager 会启动交换机制像变魔术一样腾出空间来。 PagedAttention 在这个过程中发挥着关键作用。它创新性地使用页式管理方式处理注意力计算使得长序列推理变得更加高效。这就像是给计算过程装上了加速器显著提升了处理速度。 CacheEngine 则在整个过程中不断优化性能。它会智能地缓存一些计算结果在遇到相似请求时直接复用避免重复计算。这就像是系统的备忘录能够快速提供历史经验。 最后处理结果会再次回到 Engine由它负责结果的整理和返回。整个过程环环相扣每个组件都各司其职又紧密协作共同确保了请求处理的高效性。 在分布式部署场景下这个架构还能轻松扩展。多个 Worker 节点可以并行工作Scheduler 会自动协调它们的任务分配就像是一个指挥交响乐团的指挥家让所有乐器都能配合得天衣无缝。 2. vLLM 处理请求的流程 一个请求在 vLLM 中的生命周期是一个精心编排的过程涉及多个组件的协同工作。主要实现在 vllm/engine/llm_engine.py 和 vllm/engine/ray_worker.py 中。 2.1 初始化并加载模型权重 如上图所示vLLM 的初始化过程包括模型加载、模型参数初始化、KV Cache 预分配等关键步骤。 vLLM需要初始化并加载模型权重支持从HF Hub加载模型也支持从本地加载模型。在加载过程中vLLM将模型权重加载到GPU中以便后续推理在GPU运行。 2.2 估计KV Cache的物理块数量 在模型部署的初始化阶段vLLM 会通过一个模拟实验步骤来决定 GPU 和 CPU 上可以分配的 KV cache 物理块数量确保后续推理时的内存分配不会导致显存溢出。这个步骤在 vLLM 中被称为 determine_num_available_blocks。 首先在启动 LLMEngine 时系统会进行一个 “假数据模拟” 来测量模型的内存使用情况。它通过构造假数据并执行一次模拟前向推理来观察 GPU 上模型运行时的峰值内存需求。在这次前向推理中系统不使用 KV cache而是单纯地模拟模型推理所需的基本内存。这种方式可以帮助确定整个推理过程会占用多少显存从而为后续的内存分配提供依据。 在完成内存需求的测量后vLLM 会使用测得的内存数据来计算可分配给 KV cache 的显存总量。具体来说分配给 KV cache 的显存等于 GPU 总显存减去在不使用 KV cache 时推理所占用的显存包括模型本身和推理过程中的中间数据。这样可以确保显存分配合理不会因为内存不足而导致 OOMOut Of Memory错误。 接下来通过计算显存中可以分配的物理块数量vLLM 会确定 GPU 上可以使用的 KV cache 数量。物理块的大小由用户定义包括多个参数例如 block_size、num_heads、head_size、num_layers 以及数据类型的大小如 fp16 对应的字节数是 2。计算公式会依据这些参数来估算单个物理块的大小然后根据剩余显存估算出可以分配的物理块总数。 2.3 预分配 KV Cache 在确定好 KV cache 块的大小之后vLLM 会进行显存的预分配以确保后续推理过程中有足够的内存来存储 KV cache。这一过程的核心是创建空的张量empty tensor并将它们直接分配到 GPU 上从而锁定一定的显存空间专门用于 KV cache。这种显存预分配的方式能够避免推理过程中频繁的动态内存分配提升系统的稳定性和推理效率。 预分配的显存专门用于 KV cache因此在 vLLM 初始化后你可能会注意到显存的占用比单纯加载模型时要多一些。这是因为这些额外的显存已经被预先分配给了 KV cache确保它们在推理时不会受到其他任务的影响。通过这种显存的预先规划和锁定系统在处理推理请求时能够更高效地管理内存资源避免了推理阶段因显存分配不足而出现的瓶颈。 2.4 处理请求 2.4.1 请求到达 LLMEngine 这种图展示了 vLLM 引起国内的工作流程可以把它理解为一些列处理请求的步骤。我们分成两部分来看异步(async)和同步(sync)流程。 异步流程 API-Server 接受请求当用户发送请求时API 服务器首先会接收到这些请求并解析其中的参数。这些参数告诉系统后续进行什么样的处理。生成请求参数(async_args)API-Server 会根据请求参数生成一个 async_args 对象它包含了请求的详细信息比如模型 ID、输入文本、推理参数等。请求加入队列请求加入队列后会等待调度器调度。引擎主循环开始(run_engine_loop)在异步流程中引擎主循环会不断从队列中获取请求并进行处理。处理请求(get_new_and_abort_requests)在处理过程中系统会检查新的请求以及是否有请求被终止确保每个请求被及时处理。执行推理步骤(engine_step): engine 开始处理请求决定哪个请求可以执行。异步步骤完成(add_request_async): 将请求传递到 LLMEngine请求加入调度(add_seq_group): 将请求包装为 seq_group 对象并加入调度器返回调度结果(sche_output): 调度执行对 waiting,running, swapped 队列中的请求进行调度返回调度结果等待模型推理。单步推理(step_async): 模型推理生成一个step 的输出结果。引擎推理(engine_step): 引擎推理处理请求生成一个step 的输出结果。模型推理(execute_model_req): model_executor 执行推理生成一个step 的输出结果。结果返回(return_output): 将结果返回给 AsyncLLMEngine包装为 request_output 对象。返回结果(return_output_async): 回抛结果流式输出(stream_output): 流式输出结果请求完成(request_done): 请求完成流式将结果返回API-Server。 同步流程 同步流程相对简单主要是在执行过程中直接返回结果 初始化(init): 同步流程开始时系统会初始化所有必要的参数和资源。请求处理(add_request): 此时系统直接处理请求并开始执行。推理计算(step): 系统会一步一步地处理推理任务直到完成。生成并返回结果(output): 处理完成后系统会直接返回推理结果。 总体来说vLLM 的工作流程就像一个工厂API 服务器像一个接收原材料的入口它把请求交给引擎进行处理处理的方式有两种一种是异步的一种是同步的。每个请求都会经过一系列步骤最终模型给出答案。 2.4.2 调度器的任务 在请求进入调度器后Scheduler 会根据当前的资源情况如可用的 KV 缓存块来决定如何执行任务。调度器维护了三个请求队列 Waiting Queue等待执行的请求。Running Queue当前正在处理的请求。Swapped Queue由于显存不足而被暂时置换出去的请求。 调度器会判断是否有足够的内存块可以分配给新的 tokens。如果有足够的可用 KV 块则请求从等待队列移动到正在运行的队列waiting → running如果内存不足调度器会将一些运行中的请求交换到 CPU 内存running → swapped以腾出空间让新请求进入运行队列。 2.4.3 Worker 执行推理 当请求进入运行队列后Scheduler 会将任务分发给多个 Worker。每个 Worker 在 GPU 上运行负责实际的推理计算。在这一过程中CacheEngine 会按照调度器的指示管理缓存块包括在 GPU 和 CPU 之间交换内存块确保内存资源得到高效利用。此外CacheEngine 还会对共享缓存块执行写时复制copy-on-write以确保数据的一致性和高效性。 2.4.4 模型的推理过程 每个 Worker 中的 Worker.model 模块负责加载并执行模型推理。在这个过程中它会依赖 PagedAttention 来实现高效的注意力计算。PagedAttention 是优化的注意力机制实现适用于大规模的 Transformer 模型并使用诸如 xformers 或 FlashAttention 等技术来加速推理。 此外模型的其他部分例如线性层、量化层等也进行了优化以便在分布式执行和张量并行的情况下达到最高性能。在推理阶段Sampler 会负责选择下一个生成的 token使用贪心算法、随机采样或者 Beam Search 等策略。 2.4.5 请求的完成和结果返回 推理完成后结果会被发送回 LLMEngine。LLMEngine 会对生成的 tokens 进行 detokenization将它们转换回可读的文本并最终将生成的结果流式地返回给用户。这一流程使得生成的结果可以尽快交付给用户而无需等待整个请求的完全完成。 整个请求的处理流程由 LLMEngine 进行协调调度通过 Scheduler 管理内存和资源的有效利用Worker 在 GPU 上执行具体的推理计算最终将结果流式地返回给用户。 3. vLLM 输入数据的预处理 在 vLLM 处理用户请求之前需要对输入数据进行一系列预处理操作以确保数据能够被模型正确处理。这个过程就像是将原始材料加工成标准化的零件为后续的推理计算做好准备。 3.1 Tokenization 处理 Tokenization 是输入预处理的第一道关卡。vLLM 使用与原始语言模型相同的分词器将输入文本转换为模型可以理解的 token 序列。主要实现在 vllm/engine/llm_engine.py 和 vllm/engine/tokenizer.py 中。 这个过程包含几个关键步骤 文本规范化首先对输入文本进行清理和标准化包括处理特殊字符、统一空白字符等。这就像是将各种形状的原料整理成统一的形态。 分词处理使用模型对应的 tokenizer 将文本切分成 token。这个过程会考虑词频、语义完整性等因素就像是将长木材切割成大小合适的木块。 批处理优化vLLM 创新性地实现了动态批处理机制。它会智能地将多个请求的 token 组合在一起处理就像是将多个订单的相似零件放在一起加工显著提升处理效率。 3.2 Prompt 模板与格式化 vLLM 支持灵活的 prompt 模板系统帮助用户更好地构造输入。相关实现在 vllm/engine/arg_utils.py 和 vllm/engine/sampling_params.py 中 模板定义用户可以预定义不同场景的 prompt 模板包括系统提示、用户输入、历史对话等部分。 变量替换模板中的变量可以动态替换使得同一个模板能够适应不同的输入场景。 格式验证系统会自动检查填充后的 prompt 是否符合预期格式确保输入的规范性。 3.3 输入验证与优化 为了确保系统稳定性和性能vLLM 会对输入进行全面的验证和优化 长度检查验证输入是否超过模型的最大上下文长度必要时进行截断或分段处理。 特殊标记处理自动添加或处理模型所需的特殊标记如开始符、结束符等。 资源评估预估处理该输入所需的计算资源和内存需求为后续调度做准备。(实现在 vllm/engine/llm_engine.py 中的 add_request 方法) 缓存优化分析输入是否能够利用已有的 KV Cache提前进行优化决策。(实现在 vllm/core/block_manager.py 中) 3.4 深入解析 add_request 接下来我们将深入分析 LLMEngine 的请求处理流程。通过 LLMEngine.add_request 方法接收到的请求会经过一系列预处理、调度、执行和输出处理步骤。 def add_request(self,request_id: str,prompt: Optional[PromptType] None,params: Optional[Union[SamplingParams, PoolingParams]] None,arrival_time: Optional[float] None,lora_request: Optional[LoRARequest] None,trace_headers: Optional[Mapping[str, str]] None,prompt_adapter_request: Optional[PromptAdapterRequest] None,priority: int 0,*,inputs: Optional[PromptType] None, # DEPRECATED ) - None: Add a request to the engines request pool.The request is added to the request pool and will be processed by the scheduler as engine.step() is called. The exact scheduling policy is determined by the scheduler.Args:request_id: The unique ID of the request.prompt: The prompt to the LLM. See :class:~vllm.inputs.PromptTypefor more details about the format of each input.params: Parameters for sampling or pooling.:class:~vllm.SamplingParams for text generation.:class:~vllm.PoolingParams for pooling.arrival_time: The arrival time of the request. If None, we usethe current monotonic time.trace_headers: OpenTelemetry trace headers.priority: The priority of the request.Only applicable with priority scheduling.Details:- Set arrival_time to the current time if it is None.- Set prompt_token_ids to the encoded prompt if it is None.- Create n number of :class:~vllm.Sequence objects.- Create a :class:~vllm.SequenceGroup objectfrom the list of :class:~vllm.Sequence.- Add the :class:~vllm.SequenceGroup object to the scheduler.Example: # initialize engine engine LLMEngine.from_engine_args(engine_args) # set request arguments example_prompt Who is the president of the United States? sampling_params SamplingParams(temperature0.0) request_id 0 # add the request to the engine engine.add_request( str(request_id), example_prompt, SamplingParams(temperature0.0)) # continue the request processing ...首先add_request 方法接受了多个参数其中关键的参数包括 request_id每个请求的唯一标识符用于跟踪和调度。prompt请求的提示词通常是用户输入的自然语言文本定义了生成任务的起点。params这是生成任务的参数可能是 SamplingParams采样生成参数或者 PoolingParams池化生成参数这将影响生成的策略比如温度、采样方法等。arrival_time请求到达的时间用于统计和分析请求的延迟。lora_request用于处理 LoRA 模型的特定请求如果模型使用了 LoRA 技术。trace_headers用于跟踪请求的元数据通常用于日志记录和调试。prompt_adapter_request用于处理提示适配器的特定请求如果模型使用了提示适配器。priority请求的优先级用于调度器决定请求的执行顺序。inputs这是一个可选参数用于兼容旧版本通常可以忽略。 3.4.1 preprocess 入口 在 LLMEngine 中当我们使用 add_request 方法添加一个请求时系统首先会调用 InputPreprocessor 对输入进行预处理这一过程确保用户的输入被模型正确处理。InputPreprocessor 类负责解析和处理不同类型的输入包括文本、tokens 等并将其转换为模型可以使用的标准化格式。 def preprocess(self,prompt: PromptType,request_id: str,lora_request: Optional[LoRARequest] None,prompt_adapter_request: Optional[PromptAdapterRequest] None, ) - ProcessorInputs:Preprocess the input prompt.if self.model_config.is_encoder_decoder:# Encoder-decoder model requires special mapping of# input prompts to encoder decoderreturn self._process_encoder_decoder_prompt(prompt,request_idrequest_id,)if is_explicit_encoder_decoder_prompt(prompt):raise ValueError(Cannot pass encoder-decoder prompt to decoder-only models)# Decoder-only operationreturn self._process_decoder_only_prompt(prompt,request_idrequest_id,lora_requestlora_request,prompt_adapter_requestprompt_adapter_request,)对于 encoder-decoder 模型输入需要分为 encoder prompt 和 decoder prompt每一部分都需要分别进行处理。_process_encoder_decoder_prompt 是专门为 encoder-decoder 模型设计的它能够处理同时包含编码器和解码器的 prompt。 现在我们只考虑 decoder-only 模型对于 decoder-only 模型输入处理相对简单仅需要处理单一的解码器 prompt。_process_decoder_only_prompt 的逻辑如下 def _process_decoder_only_prompt(self,prompt: SingletonPrompt,request_id: str,lora_request: Optional[LoRARequest] None,prompt_adapter_request: Optional[PromptAdapterRequest] None, ) - DecoderOnlyInputs:For decoder-only models:Process an input prompt into an :class:DecoderOnlyInputs instance.Arguments:* prompt: input prompt* request_id* lora_request* prompt_adapter_requestReturns:* :class:DecoderOnlyInputs instanceprompt_comps self._prompt_to_llm_inputs(prompt,request_idrequest_id,lora_requestlora_request,)return self._build_decoder_only_llm_inputs(prompt_comps,prompt_adapter_requestprompt_adapter_request,)_prompt_to_llm_inputs 方法负责将输入的 prompt 转换为模型可以理解的格式。它根据 prompt 的类型字符串、tokens 或文本进行不同的处理。 def _prompt_to_llm_inputs(self,prompt: SingletonPrompt,request_id: str,lora_request: Optional[LoRARequest] None,) - SingletonInputs:Extract the singleton inputs from a prompt.Arguments:* request_id* prompt: single encoder or decoder input prompt* lora_request: this is only valid for decoder promptsReturns:* :class:SingletonInputs instanceparsed parse_singleton_prompt(prompt)if parsed[type] str:prompt_text parsed[content]prompt_token_ids self._tokenize_prompt(prompt_text,request_idrequest_id,lora_requestlora_request,)return token_inputs(promptprompt_text,prompt_token_idsprompt_token_ids,)if parsed[type] tokens:tokens_content parsed[content]prompt_token_ids tokens_content[prompt_token_ids]token_type_ids tokens_content.get(token_type_ids)multi_modal_data tokens_content.get(multi_modal_data)mm_processor_kwargs tokens_content.get(mm_processor_kwargs)if multi_modal_data is not None and self._can_process_multimodal():return self._process_multimodal(prompt_token_ids,multi_modal_data,mm_processor_kwargs,lora_requestlora_request,)return token_inputs(prompt_token_idsprompt_token_ids,prompt_embedstokens_content.get(prompt_embeds),token_type_idstoken_type_ids,multi_modal_datamulti_modal_data,mm_processor_kwargsmm_processor_kwargs,)if parsed[type] text:text_content parsed[content]prompt_text text_content[prompt]multi_modal_data text_content.get(multi_modal_data)mm_processor_kwargs text_content.get(mm_processor_kwargs)if multi_modal_data is not None and self._can_process_multimodal():return self._process_multimodal(prompt_text,multi_modal_data,mm_processor_kwargs,lora_requestlora_request,)prompt_token_ids self._tokenize_prompt(prompt_text,request_idrequest_id,lora_requestlora_request,)return token_inputs(promptprompt_text,prompt_token_idsprompt_token_ids,prompt_embedstext_content.get(prompt_embeds),multi_modal_datamulti_modal_data,mm_processor_kwargsmm_processor_kwargs,)assert_never(parsed)_tokenize_prompt 方法负责将输入的文本转换为 token 序列。它使用模型对应的 tokenizer 将文本切分成 token并返回对应的 token ID 列表。 def _tokenize_prompt(self,prompt: str,request_id: str,lora_request: Optional[LoRARequest],) - List[int]:Apply the models tokenizer to a text prompt, returning thecorresponding token IDs.tokenizer self.get_tokenizer_group()add_special_tokens Noneif self.model_config.hf_config.model_type whisper:# For Whisper, special tokens should be provided by the user based# on the task and language of their request. Also needed to avoid# appending an EOS token to the prompt which disrupts generation.add_special_tokens Falsereturn tokenizer.encode(request_idrequest_id,promptprompt,lora_requestlora_request,add_special_tokensadd_special_tokens)获取 Tokenizer通过 get_tokenizer_group() 获取当前模型对应的分词器。这个分词器通常在模型初始化时就已经加载与模型使用相同的词表和分词规则。特殊标记处理 默认情况下add_special_tokens 为 None表示使用模型默认的特殊标记处理方式对于 Whisper 模型等特殊情况会设置 add_special_tokensFalse因为这些模型需要用户根据具体任务和语言来提供特殊标记这样的设计确保了不同模型的特殊标记如开始符、结束符等能够被正确处理 Token 编码调用 tokenizer 的 encode 方法将文本转换为 token ID 序列。这个过程包括 将输入文本分割成子词subwords将每个子词映射到对应的 token ID根据需要添加特殊标记如果 add_special_tokens 为 True处理 LoRA 相关的特殊需求如果提供了 lora_request 请求追踪通过传入 request_id确保能够追踪每个请求的 tokenization 过程这对于调试和性能分析很有帮助。 3.4 创建 sequence 和 sequence_group 通过这些精心设计的预处理步骤vLLM 能够将各种形式的输入转换为标准化、高效的形式为后续的推理计算打下坚实基础。这就像是一个细心的厨师在烹饪之前将所有食材都准备妥当确保整个烹饪过程的顺畅进行。 在预处理之后我们得到了 ProcessorInputs 实例它包含了处理后的输入数据。接下来我们调用 _add_processed_request 方法将处理后的请求添加到引擎的请求池中。 def _add_processed_request(self,request_id: str,processed_inputs: ProcessorInputs,params: Union[SamplingParams, PoolingParams],arrival_time: float,lora_request: Optional[LoRARequest],prompt_adapter_request: Optional[PromptAdapterRequest],trace_headers: Optional[Mapping[str, str]] None,priority: int 0,) - Optional[SequenceGroup]:Add a processed request to the engines request pool.return the created sequence group.if isinstance(params, SamplingParams) and params.n 1:ParallelSampleSequenceGroup.add_request(request_id,self,params,processed_inputsprocessed_inputs,arrival_timearrival_time,lora_requestlora_request,trace_headerstrace_headers,prompt_adapter_requestprompt_adapter_request,prioritypriority,)return Noneself._validate_model_inputs(processed_inputs, lora_request)# Create the sequences.block_size self.cache_config.block_sizeseq_id next(self.seq_counter)eos_token_id self.input_preprocessor.get_eos_token_id(lora_request)if is_encoder_decoder_inputs(processed_inputs):decoder_inputs processed_inputs[decoder]encoder_inputs processed_inputs[encoder]else:decoder_inputs processed_inputsencoder_inputs Noneseq Sequence(seq_id, decoder_inputs, block_size, eos_token_id,lora_request, prompt_adapter_request)encoder_seq (None if encoder_inputs is None else Sequence(seq_id, encoder_inputs, block_size, eos_token_id, lora_request,prompt_adapter_request))# Create a SequenceGroup based on SamplingParams or PoolingParamsif isinstance(params, SamplingParams):seq_group self._create_sequence_group_with_sampling(request_id,seq,params,arrival_timearrival_time,lora_requestlora_request,trace_headerstrace_headers,prompt_adapter_requestprompt_adapter_request,encoder_seqencoder_seq,prioritypriority)elif isinstance(params, PoolingParams):seq_group self._create_sequence_group_with_pooling(request_id,seq,params,arrival_timearrival_time,lora_requestlora_request,prompt_adapter_requestprompt_adapter_request,encoder_seqencoder_seq,prioritypriority)else:raise ValueError(Either SamplingParams or PoolingParams must be provided.)# Add the sequence group to the scheduler with least unfinished seqs.costs [scheduler.get_num_unfinished_seq_groups()for scheduler in self.scheduler]min_cost_scheduler self.scheduler[costs.index(min(costs))]min_cost_scheduler.add_seq_group(seq_group)return seq_groupSequenceGroup 表示的是多个 Sequence 的集合通常是因为这些 Sequence 共享相同的采样参数如温度、采样策略等以及优先级调度策略如 priority。SequenceGroup 的创建是通过 _create_sequence_group_with_sampling 或 _create_sequence_group_with_pooling 方法完成的具体取决于是否采用采样策略或者池化策略。 SamplingParams 是用于控制模型生成文本时的行为的参数比如温度temperature、采样概率top_p等。SamplingParams 会影响生成的策略比如生成的多样性、生成的质量等。 def _create_sequence_group_with_sampling(self,request_id: str,seq: Sequence,sampling_params: SamplingParams,arrival_time: float,lora_request: Optional[LoRARequest],trace_headers: Optional[Mapping[str, str]] None,prompt_adapter_request: Optional[PromptAdapterRequest] None,encoder_seq: Optional[Sequence] None,priority: int 0,) - SequenceGroup:Creates a SequenceGroup with SamplingParams.max_logprobs self.get_model_config().max_logprobsif (sampling_params.logprobsand sampling_params.logprobs max_logprobs) or (sampling_params.prompt_logprobsand sampling_params.prompt_logprobs max_logprobs):raise ValueError(fCannot request more than f{max_logprobs} logprobs.)sampling_params self._build_logits_processors(sampling_params, lora_request)# Defensive copy of SamplingParams, which are used by the sampler,# this doesnt deep-copy LogitsProcessor objectssampling_params sampling_params.clone()sampling_params.update_from_generation_config(self.generation_config_fields, seq.eos_token_id)# Create the sequence group.seq_group SequenceGroup(request_idrequest_id,seqs[seq],arrival_timearrival_time,sampling_paramssampling_params,lora_requestlora_request,trace_headerstrace_headers,prompt_adapter_requestprompt_adapter_request,encoder_seqencoder_seq,prioritypriority)return seq_group3.4.1 深入理解 SequenceGroup SequenceGroup 是 vLLM 中一个核心概念它代表了一组共享相同采样参数和调度优先级的序列集合。让我们通过一个具体的生命周期来理解 SequenceGroup 初始化阶段 每个 SequenceGroup 初始时只包含一个序列(seq)这个序列对应用户输入的 prompt初始序列的状态被设置为 waiting等待调度器分配资源 第一次推理阶段Prefill 当调度器选中该 SequenceGroup 后会首先执行 prefill 操作如果采样参数中设置了 n 1例如 n 4系统会基于初始序列生成 n 个分支所有生成的序列状态都变为 running开始并行生成 tokens 资源竞争阶段Preemption 当 GPU 资源不足时调度器会触发抢占机制。此时根据序列数量采取不同策略 a) Swap 策略 (序列数量 1) 适用于多序列场景将 SequenceGroup 下所有序列的 KV Cache 从 GPU 转移到 CPU所有序列状态变为 swapped保留已计算的 KV Cache避免重复计算 b) Recomputation 策略 (序列数量 1) 适用于单序列场景释放该 SequenceGroup 占用的所有 GPU 内存块将序列重新放入 waiting 队列下次调度时从 prefill 阶段重新开始选择重计算的原因单序列重新计算 KV Cache 的成本相对较低 sequence_group 的属性 seqs_dict self.seqs_dict: Dict[int, Sequence] {}存储序列ID到Sequence对象的映射 使用字典结构实现快速查找和管理 每个 Sequence 对象包含序列的状态、token 历史等信息 sampling_params self.sampling_params: SamplingParams控制文本生成的关键参数 包含温度(temperature)、top_p、top_k等采样策略 影响生成文本的多样性和质量 metrics self.metrics: Dict[str, Any] {arrival_time: float,first_scheduled_time: Optional[float],first_token_time: Optional[float],... }记录序列组的关键时间点和性能指标用于调度器进行决策和性能分析包括到达时间、首次调度时间、首个token生成时间等 max_running_steps def get_max_num_running_steps(self) - int:计算剩余生命周期内的最大并行序列数预估序列组在整个生成过程中需要的最大并行步数帮助调度器进行资源规划和分配考虑了采样参数和当前生成状态 实现细节 class SequenceGroup:A group of sequences that are generated from the same prompt.Args:request_id: The ID of the request.seqs: The list of sequences.sampling_params: The sampling parameters used to generate the outputs.arrival_time: The arrival time of the request.lora_request: LoRA request.pooling_params: The parameters used to generate the poolerfor a pooling model.pooled_data: The extracted hidden states from a pooling model.encoder_seq: Optional, the single encoder sequence. Should be Noneunless you are working with an encoder/decoder model.trace_headers: OpenTelemetry trace headers.prompt_adapter_request: Prompt Adapter request.priority: User-defined priority of the request.def __init__(self,request_id: str,seqs: List[Sequence],arrival_time: float,sampling_params: Optional[SamplingParams] None,lora_request: Optional[LoRARequest] None,pooling_params: Optional[PoolingParams] None,pooled_data: Optional[torch.Tensor] None,encoder_seq: Optional[Sequence] None,trace_headers: Optional[Mapping[str, str]] None,prompt_adapter_request: Optional[PromptAdapterRequest] None,priority: int 0,) - None:self.request_id request_idself.seqs seqsself.first_seq seqs[0]self.arrival_time arrival_timeself.is_single_seq len(seqs) 1self.seqs_dict {seq.seq_id: seq for seq in seqs}self.sampling_params sampling_paramsself.metrics RequestMetrics(arrival_timearrival_time,last_token_timearrival_time,first_scheduled_timeNone,first_token_timeNone,time_in_queueNone)self.last_token_latency 0.0self.lora_request lora_requestself.prompt_logprobs: Optional[PromptLogprobs] Noneself.state SequenceGroupState()self.pooling_params pooling_paramsself.pooled_data pooled_dataself.prompt_adapter_request prompt_adapter_requestself.encoder_seq encoder_seqself.trace_headers trace_headersself.priority priorityself.cached_request_output None4. 小结 在这篇文章中我们踏上了探索 vLLM 架构的旅程就像解构一台精密的机器我们逐层剖析了它的核心组件和运作机制。从整体架构设计开始我们看到了 Engine、Worker、Scheduler 等组件如何协同工作就像一个精心编排的交响乐团每个部分都在演奏着自己的乐章共同谱写出高效服务的乐章。 在深入研究请求处理流程时我们见证了一个请求从诞生到完成的完整生命历程。就像一颗种子从播种到生长每个阶段都经过精心的规划和呵护。从最初的模型初始化到 KV Cache 的预分配再到请求的具体处理vLLM 展现出了令人印象深刻的工程智慧。 特别值得一提的是输入数据的预处理机制这就像是一个细心的厨师在烹饪前的准备工作。通过精心设计的 Tokenization 处理、灵活的 Prompt 模板系统以及严谨的请求验证流程vLLM 确保了每个输入都能被完美处理。而在序列管理方面Sequence 和 SequenceGroup 的设计则展现了框架在处理复杂场景时的优雅解决方案。 这次的探索之旅让我们对 vLLM 的基础架构有了深入的认识但这仅仅是开始。在下一篇文章中我们将继续深入探讨 vLLM 最引人注目的两大核心机制调度器Scheduler的智能调度策略和内存管理器BlockManager的高效内存管理。这两个机制就像是 vLLM 的双翼让它能够在高并发的天空中自由翱翔。我们将看到调度器如何像一个睿智的指挥官统筹安排每个请求的处理时机以及内存管理器如何通过创新的 PagedAttention 机制让有限的显存发挥出最大效能。 5. 参考资料 [1] vLLM Team, “vLLM Documentation,” vLLM Official Documentation, 2024. [Online]. Available: https://docs.vllm.ai/en/latest/ [2] vLLM Project Contributors, “vLLM: Easy, Fast, and Cheap LLM Serving,” GitHub Repository, 2024. [Online]. Available: https://github.com/vllm-project/vllm [3] vLLM Team, “Serving LLMs at Scale with vLLM,” vLLM Blog, Jun. 2023. [Online]. Available: https://blog.vllm.ai/2023/06/20/vllm.html [4] vLLM Community, “vLLM Discussions,” GitHub Discussions, 2024. [Online]. Available: https://github.com/vllm-project/vllm/discussions [5] Y. Feng, “vLLM Diagram Overview,” Personal Blog, Sep. 2024. [Online]. Available: https://fy2462.github.io/2024/09/vllm-diagram-overview/ [6] PaddleJitLab, “vLLM Source Code Analysis: Scheduler,” GitHub Repository, 2024. [Online]. Available: https://github.com/PaddleJitLab/CUDATutorial/blob/develop/docs/16_vllm_source_code/03_scheduler.md
http://www.tj-hxxt.cn/news/140309.html

相关文章:

  • 一级a做爰片不卡免费网站广东网站建设报价如何
  • 黑糖不苦还做网站么网站的后台怎么做
  • 织梦 音乐网站网站页面禁止访问
  • 百度宣传做网站多少钱做网站卖大闸蟹
  • 甘肃省建设厅执业资格注册中心网站手机怎么查看网站代码实现的
  • 做网站建设的合同范本企业网站后台模板
  • 什么网站可以做外贸网页设计网站建设
  • 知名的建站公司免费网站外链推广
  • 做网站协议怎么签成都建工路桥建设有限公司网站
  • 重庆市工程建设招投标交易中心网站制作网站可用性监控
  • 杭州的服装网站建设mysql导入wordpress
  • 商务网站的分类网站建站的技术解决方案
  • 北京建设网站的公司兴田德润简介企业微信app下载安装官网电脑版
  • 做网站都有那些步骤网站群建设情况
  • 用搬瓦工做储存网站免费招商加盟
  • 新学校网站建设成果wordpress禁用主题更新
  • 做彩平的网站模板网传奇手游
  • 专业的网站开发团队需要哪些人黄金网站下载免费
  • 网站建设的基本知识资料网站怎么做
  • 无锡网站优化排名推广哪个网站做废旧好
  • 微信注册网站入口医院网站素材
  • 河北网站优化公司网上商城都有哪些平台
  • 开发网站最新注册公司流程及费用
  • 如何注册网站主办者秦皇岛市城乡建设局网站
  • 竞价托管多少钱西安seo站内优化
  • 天津百度整站优化服务请问如何做网站
  • 大良营销网站建设公司网站开发职位介绍
  • 英文网站建静宁门户网站
  • 网站开发便宜大图网
  • 工信部网站备案系统影视 网站建设 新媒体