vLLM: 加速AI推理的利器

2024-07-22 21:22:28 浏览数 (2)

为什么LLM服务如此具有挑战性?

计算资源

由于LLM需要处理大量的参数来进行预测,这可能从70亿参数增加到3210亿,部署这样的模型可能需要大量的资源和优化,而不是使用传统的方法来部署机器学习模型。

延迟

当句子或令牌复杂时,处理结果需要几分钟时间,这可能在大规模或真实世界的业务中造成问题。例如,一家公司可能在产品Q&A聊天机器人中应用LLM,缓慢的响应可能会让用户感到沮丧。因此,应用一些方法来降低延迟是一个好的实践。

成本

在大规模系统中或系统中有多个LLM时,会消耗大量预算,因为LLMs使用大量资源进行处理,作为一个MLE,找到一种利用资源的方法将为系统带来财务效益。例如,降低每次请求的成本。

什么是vLLM?

这个项目来自于加州大学伯克利分校的学生们,他们热衷于优化服务LLMs的性能。许多系统在服务LLMs时花费了大量的资源,然而,使用简单的方法部署时响应时间却很差。因此,vLLM团队提出了一种新方法来解决这个问题,通过使用操作系统的虚拟内存设计,可提升LLM服务性能约24倍,同时相比传统方法使用的GPU内存减半。为了集成到您的系统中,vLLM提供了一个简单的接口,让机器学习工程师通过Python接口进行开发,您可以在不使用复杂包或依赖的情况下将其集成到您的系统中。

vLLM的秘密武器是什么?

为了理解vLLM如何实现降低延迟和优化系统总体性能的目标,我们应该了解vLLM的瓶颈以及如何解决这个问题。

内存使用问题

大型语言模型(LLM)本质上是一个注意力神经网络的分支,或者有些人将其称为变压器,具有基于模型的自定义解码。因此,我们需要理解一个关键概念:LLM是如何生成令牌的。

内存分片

本质上,请求的KV缓存是存储在连续的内存空间中的,因为许多深度学习框架计算都需要将张量值存储在连续的内存中。然而,根据模型架构的不同,KV缓存可能会随时间增长或缩小,这种存储格式可能会导致问题,并且对于计算来说并不实用。

如何克服这个问题

vLLM团队开发了一种新的注意力算法,称为PageAttention,其灵感来自于操作系统的虚拟内存概念。可以将块想象为页面,令牌想象为字节,请求想象为进程。

使用PageAttention的另一好处是,它允许系统共享KV缓存,因为它将令牌存储在非连续的内存中。这使得LLM在许多应用程序中得以利用。

vLLM的OpenAI兼容服务器

如果你希望快速的使用vLLM启动一个OpenAI兼容的服务器,可以如下执行:

命令行安装:

代码语言:bash复制
pip3 install vllm==0.5.1 -i https://pypi.tuna.tsinghua.edu.cn/simple

正常启动(以Qwen2-7B为例):

代码语言:bash复制
python -m vllm.entrypoints.openai.api_server --model Qwen/Qwen2-7B-Instruct

其他启动参数详解:

代码语言:bash复制
python3 -m vllm.entrypoints.openai.api_server -h
用法: api_server.py [-h] [--host HOST] [--port PORT] [--uvicorn-log-level {debug,info,warning,error,critical,trace}] [--allow-credentials] [--allowed-origins ALLOWED_ORIGINS] [--allowed-methods ALLOWED_METHODS] [--allowed-headers ALLOWED_HEADERS]
[--api-key API_KEY] [--lora-modules LORA_MODULES [LORA_MODULES ...]] [--chat-template CHAT_TEMPLATE] [--response-role RESPONSE_ROLE] [--ssl-keyfile SSL_KEYFILE] [--ssl-certfile SSL_CERTFILE] [--ssl-ca-certs SSL_CA_CERTS]
[--ssl-cert-reqs SSL_CERT_REQS] [--root-path ROOT_PATH] [--middleware MIDDLEWARE] [--model MODEL] [--tokenizer TOKENIZER] [--skip-tokenizer-init] [--revision REVISION] [--code-revision CODE_REVISION]
[--tokenizer-revision TOKENIZER_REVISION] [--tokenizer-mode {auto,slow}] [--trust-remote-code] [--download-dir DOWNLOAD_DIR] [--load-format {auto,pt,safetensors,npcache,dummy,tensorizer,bitsandbytes}]
[--dtype {auto,half,float16,bfloat16,float,float32}] [--kv-cache-dtype {auto,fp8,fp8_e5m2,fp8_e4m3}] [--quantization-param-path QUANTIZATION_PARAM_PATH] [--max-model-len MAX_MODEL_LEN]
[--guided-decoding-backend {outlines,lm-format-enforcer}] [--distributed-executor-backend {ray,mp}] [--worker-use-ray] [--pipeline-parallel-size PIPELINE_PARALLEL_SIZE] [--tensor-parallel-size TENSOR_PARALLEL_SIZE]
[--max-parallel-loading-workers MAX_PARALLEL_LOADING_WORKERS] [--ray-workers-use-nsight] [--block-size {8,16,32}] [--enable-prefix-caching] [--disable-sliding-window] [--use-v2-block-manager]
[--num-lookahead-slots NUM_LOOKAHEAD_SLOTS] [--seed SEED] [--swap-space SWAP_SPACE] [--gpu-memory-utilization GPU_MEMORY_UTILIZATION] [--num-gpu-blocks-override NUM_GPU_BLOCKS_OVERRIDE]
[--max-num-batched-tokens MAX_NUM_BATCHED_TOKENS] [--max-num-seqs MAX_NUM_SEQS] [--max-logprobs MAX_LOGPROBS] [--disable-log-stats]
[--quantization {aqlm,awq,deepspeedfp,fp8,marlin,gptq_marlin_24,gptq_marlin,gptq,squeezellm,compressed-tensors,bitsandbytes,None}] [--rope-scaling ROPE_SCALING] [--rope-theta ROPE_THETA] [--enforce-eager]
[--max-context-len-to-capture MAX_CONTEXT_LEN_TO_CAPTURE] [--max-seq-len-to-capture MAX_SEQ_LEN_TO_CAPTURE] [--disable-custom-all-reduce] [--tokenizer-pool-size TOKENIZER_POOL_SIZE] [--tokenizer-pool-type TOKENIZER_POOL_TYPE]
[--tokenizer-pool-extra-config TOKENIZER_POOL_EXTRA_CONFIG] [--enable-lora] [--max-loras MAX_LORAS] [--max-lora-rank MAX_LORA_RANK] [--lora-extra-vocab-size LORA_EXTRA_VOCAB_SIZE] [--lora-dtype {auto,float16,bfloat16,float32}]
[--long-lora-scaling-factors LONG_LORA_SCALING_FACTORS] [--max-cpu-loras MAX_CPU_LORAS] [--fully-sharded-loras] [--device {auto,cuda,neuron,cpu,openvino,tpu,xpu}] [--image-input-type {pixel_values,image_features}]
[--image-token-id IMAGE_TOKEN_ID] [--image-input-shape IMAGE_INPUT_SHAPE] [--image-feature-size IMAGE_FEATURE_SIZE] [--image-processor IMAGE_PROCESSOR] [--image-processor-revision IMAGE_PROCESSOR_REVISION]
[--disable-image-processor] [--scheduler-delay-factor SCHEDULER_DELAY_FACTOR] [--enable-chunked-prefill] [--speculative-model SPECULATIVE_MODEL] [--num-speculative-tokens NUM_SPECULATIVE_TOKENS]
[--speculative-draft-tensor-parallel-size SPECULATIVE_DRAFT_TENSOR_PARALLEL_SIZE] [--speculative-max-model-len SPECULATIVE_MAX_MODEL_LEN] [--speculative-disable-by-batch-size SPECULATIVE_DISABLE_BY_BATCH_SIZE]
[--ngram-prompt-lookup-max NGRAM_PROMPT_LOOKUP_MAX] [--ngram-prompt-lookup-min NGRAM_PROMPT_LOOKUP_MIN] [--model-loader-extra-config MODEL_LOADER_EXTRA_CONFIG] [--preemption-mode PREEMPTION_MODE]
[--served-model-name SERVED_MODEL_NAME [SERVED_MODEL_NAME ...]] [--qlora-adapter-name-or-path QLORA_ADAPTER_NAME_OR_PATH] [--otlp-traces-endpoint OTLP_TRACES_ENDPOINT] [--engine-use-ray] [--disable-log-requests]
[--max-log-len MAX_LOG_LEN]

vLLM与OpenAI兼容的RESTful API服务器。

可选参数:
  -h, --help            显示此帮助信息并退出
  --host HOST           主机名
  --port PORT           端口号
  --uvicorn-log-level {debug,info,warning,error,critical,trace}
                        uvicorn的日志等级
  --allow-credentials   允许凭证
  --allowed-origins ALLOWED_ORIGINS
                        允许的来源
  --allowed-methods ALLOWED_METHODS
                        允许的方法
  --allowed-headers ALLOWED_HEADERS
                        允许的头信息
  --api-key API_KEY     如果提供,服务器将要求在头信息中提供此密钥。
  --lora-modules LORA_MODULES [LORA_MODULES ...]
                        LoRA模块配置,格式为name=path。可以指定多个模块。
  --chat-template CHAT_TEMPLATE
                        聊天模板的文件路径,或为指定模型的单行形式的模板
  --response-role RESPONSE_ROLE
                        如果`request.add_generation_prompt=true`,则返回的角色名称。
  --ssl-keyfile SSL_KEYFILE
                        SSL密钥文件的文件路径
  --ssl-certfile SSL_CERTFILE
                        SSL证书文件的文件路径
  --ssl-ca-certs SSL_CA_CERTS
                        CA证书文件
  --ssl-cert-reqs SSL_CERT_REQS
                        是否需要客户端证书(参考标准库ssl模块)
  --root-path ROOT_PATH
                        当应用程序位于基于路径的路由代理之后时的FastAPI root_path
  --middleware MIDDLEWARE
                        应用于应用的附加ASGI中间件。我们接受多个--middleware参数。其值应为一个导入路径。如果提供了函数,vLLM会将其添加到服务器使用@app.middleware('http')。如果提供了类,则vLLM会使用app.add_middleware()添加它。
  --model MODEL         使用的huggingface模型名称或路径。
  --tokenizer TOKENIZER
                        使用的huggingface分词器名称或路径。如果未指定,则使用模型名称或路径。
  --skip-tokenizer-init
                        跳过分词器和反分词器的初始化
  --revision REVISION   要使用的特定模型版本。它可以是一个分支名称、一个标签名称或一个提交id。如果未指定,将使用默认版本。
  --code-revision CODE_REVISION
                        用于模型代码在Hugging Face Hub的特定修订版本。它可以是一个分支名称、一个标签名称或一个提交id。如果未指定,将使用默认版本。
  --tokenizer-revision TOKENIZER_REVISION
                        要使用的huggingface分词器的修订版本。它可以是一个分支名称、一个标签名称或一个提交id。如果未指定,将使用默认版本。
  --tokenizer-mode {auto,slow}
                        分词器模式。* "auto"将使用快速分词器(如果可用)。* "slow"将总是使用慢分词器。
  --trust-remote-code   信任来自huggingface的远程代码。
  --download-dir DOWNLOAD_DIR
                        下载并加载权重的目录,默认为huggingface的默认缓存目录。
  --load-format {auto,pt,safetensors,npcache,dummy,tensorizer,bitsandbytes}
                        用于加载模型权重的格式。* "auto"将尝试以safetensors格式加载权重,并在safetensors格式不可用时回退到pytorch bin格式。* "pt"将以pytorch bin格式加载权重。* "safetensors"将以safetensors格式加载权重。* "npcache"将以pytorch格式加载权重并存储numpy缓存以加速加载。* "dummy"将以随机值初始化权重,主要用于性能分析。* "tensorizer"将使用来自CoreWeave的tensorizer加载权重。有关更多信息,请参见示例部分中的Tensorize vLLM模型脚本。* "bitsandbytes"将使用bitsandbytes量化加载权重。
  --dtype {auto,half,float16,bfloat16,float,float32}
                        模型权重和激活的数据类型。* "auto"将对FP32和FP16模型使用FP16精度,对BF16模型使用BF16精度。* "half"用于FP16。推荐用于AWQ量化。* "float16"与"half"相同。* "bfloat16"用于平衡精度和范围。* "float"是FP32精度的简写。* "float32"用于FP32精度。
  --kv-cache-dtype {auto,fp8,fp8_e5m2,fp8_e4m3}
                        kv缓存存储的数据类型。如果为"auto",将使用模型数据类型。CUDA 11.8 支持fp8(=fp8_e4m3)和fp8_e5m2。ROCm(AMD GPU)支持fp8(=fp8_e4m3)
  --quantization-param-path QUANTIZATION_PARAM_PATH
                        包含KV缓存比例因子的JSON文件路径。当KV缓存数据类型为FP8时,通常应当提供此文件。否则,KV缓存比例因子默认为1.0,可能导致准确性问题。FP8_E5M2(未缩放)仅在CUDA版本大于11.8时支持。在ROCm(AMD GPU)上,相反,支持FP8_E4M3以满足常见的推理标准。
  --max-model-len MAX_MODEL_LEN
                        模型上下文长度。如果未指定,将从模型配置自动派生。
  --guided-decoding-backend {outlines,lm-format-enforcer}
                        哪个引擎将默认用于指导解码(JSON架构/正则表达式等)。当前支持https://github.com/outlines-dev/outlines 和 https://github.com/noamgat/lm-format-enforcer。可通过请求中的guided_decoding_backend参数覆盖。
  --distributed-executor-backend {ray,mp}
                        用于分布式服务的后端。当使用多于1个GPU时,如果安装了"ray"将自动设置为"ray",否则设置为"mp"(多进程)。
  --worker-use-ray    已弃用,请使用--distributed-executor-backend=ray。
  --pipeline-parallel-size PIPELINE_PARALLEL_SIZE, -pp PIPELINE_PARALLEL_SIZE
                        管道阶段的数量。
  --tensor-parallel-size TENSOR_PARALLEL_SIZE, -tp TENSOR_PARALLEL_SIZE
                        张量并行副本的数量。
  --max-parallel-loading-workers MAX_PARALLEL_LOADING_WORKERS
                        分多批次顺序加载模型,以避免在使用张量并行和大型模型时发生RAM OOM。
  --ray-workers-use-nsight
                        如果指定,使用nsight对Ray工作节点进行分析。
  --block-size {8,16,32}
                        连续token块的token块大小。
  --enable-prefix-caching
                        启用自动前缀缓存。
  --disable-sliding-window
                        禁用滑动窗口,设置为滑动窗口大小
  --use-v2-block-manager
                        使用BlockSpaceMangerV2。
  --num-lookahead-slots NUM_LOOKAHEAD_SLOTS
                        实验性调度配置,必要用于对初始解码的推测。这将被推测配置在未来替代;它目前的存在是为了直到那时启用正确性测试。
  --seed SEED           操作的随机种子。
  --swap-space SWAP_SPACE
                        每GPU的CPU交换空间大小(GiB)。
  --gpu-memory-utilization GPU_MEMORY_UTILIZATION
                        用于模型执行器的GPU内存的使用比例,可以从0到1的范围。例如,0.5的值将意味着50%的GPU内存利用率。如果未指定,将使用0.9的默认值。
  --num-gpu-blocks-override NUM_GPU_BLOCKS_OVERRIDE
                        如果指定,忽略GPU性能测试结果并使用这个数字的GPU块。用于测试抢占。
  --max-num-batched-tokens MAX_NUM_BATCHED_TOKENS
                        每次迭代的最大批处理token数。
  --max-num-seqs MAX_NUM_SEQS
                        每次迭代的最大序列数。
  --max-logprobs MAX_LOGPROBS
                        返回logprobs的最大数量,如果在SamplingParams中指定了logprobs。
  --disable-log-stats   禁用日志统计。
  --quantization {aqlm,awq,deepspeedfp,fp8,marlin,gptq_marlin_24,gptq_marlin,gptq,squeezellm,compressed-tensors,bitsandbytes,None}, -q {aqlm,awq,deepspeedfp,fp8,marlin,gptq_marlin_24,gptq_marlin,gptq,squeezellm,compressed-tensors,bitsandbytes,None}
                        用于量化权重的方法。如果None,我们首先检查模型配置文件中的`quantization_config`属性。如果那是None,我们假设模型权重未量化,并使用`dtype`确定权重的数据类型。
  --rope-scaling ROPE_SCALING
                        RoPE缩放配置的JSON格式。例如,{"type":"dynamic","factor":2.0}
  --rope-theta ROPE_THETA
                        使用`rope_scaling`的RoPE theta。在某些情况下,改变RoPE theta可以提高缩放模型的性能。
  --enforce-eager       总是使用PyTorch的急切模式。如果为False,将使用急切模式和CUDA图的混合以获得最大的性能和灵活性。
  --max-context-len-to-capture MAX_CONTEXT_LEN_TO_CAPTURE
                        由CUDA图覆盍的最大上下文长度。当序列的上下文长度大于此长度时,我们将回退到急切模式。(已弃用。请改用--max-seq-len-to-capture)
  --max-seq-len-to-capture MAX_SEQ_LEN_TO_CAPTURE
                        由CUDA图覆盖的最大序列长度。当序列的上下文长度大于此长度时,我们将回退到急切模式。
  --disable-custom-all-reduce
                        参见ParallelConfig。
  --tokenizer-pool-size TOKENIZER_POOL_SIZE
                        用于异步分词的分词器池的大小。如果为0,将使用同步分词。
  --tokenizer-pool-type TOKENIZER_POOL_TYPE
                        用于异步分词的分词器池的类型。如果tokenizer_pool_size为0,则忽略。
  --tokenizer-pool-extra-config TOKENIZER_POOL_EXTRA_CONFIG
                        分词器池额外配置。这应当是一个将被解析成字典的JSON字符串。如果tokenizer_pool_size为0,则忽略。
  --enable-lora         如果为True,启用LoRA适配器的处理。
  --max-loras MAX_LORAS
                        单个批次中LoRAs的最大数量。
  --max-lora-rank MAX_LORA_RANK
                        LoRA秩的最大值。
  --lora-extra-vocab-size LORA_EXTRA_VOCAB_SIZE
                        LoRA适配器中可以存在的额外词汇表的最大大小(添加到基础模型词汇表中)。
  --lora-dtype {auto,float16,bfloat16,float32}
                        LoRA的数据类型。如果为auto,将默认为基础模型的dtype。
  --long-lora-scaling-factors LONG_LORA_SCALING_FACTORS
                        指定多个缩放因子(可以与基础模型的缩放因子不同-参见例如Long LoRA),以允许同时使用训练有这些缩放因子的多个LoRA适配器。如果未指定,仅允许使用基础模型缩放因子训练的适配器。
  --max-cpu-loras MAX_CPU_LORAS
                        在CPU内存中存储的LoRAs的最大数量。必须大于等于max_num_seqs。默认为max_num_seqs。
  --fully-sharded-loras
                        默认情况下,仅使用张量并行对LoRA计算的一半进行分片。启用此选项将使用完全分片的层。在高序列长度、最大秩或张量并行大小下,这可能更快。
  --device {auto,cuda,neuron,cpu,openvino,tpu,xpu}
                        vLLM执行的设备类型。
  --image-input-type {pixel_values,image_features}
                        传入vLLM的图像输入类型。
  --image-token-id IMAGE_TOKEN_ID
                        图像令牌的输入id。
  --image-input-shape IMAGE_INPUT_SHAPE
                        给定输入类型的最大图像输入形状(对内存占用最不利)。仅用于vLLM的profile_run。
  --image-feature-size IMAGE_FEATURE_SIZE
                        图像特征沿上下文维度的大小。
  --image-processor IMAGE_PROCESSOR
                        要使用的huggingface图像处理器的名称或路径。如果未指定,将使用模型名称或路径。
  --image-processor-revision IMAGE_PROCESSOR_REVISION
                        要使用的huggingface图像处理器的修订版本。它可以是一个分支名称、一个标签名称或一个提交id。如果未指定,将使用默认版本。
  --disable-image-processor
                        即使为模型在huggingface上定义了图像处理器,也禁用图像处理器的使用。
  --scheduler-delay-factor SCHEDULER_DELAY_FACTOR
                        在调度下一个提示之前应用延迟(以先前提示的延迟乘以延迟因子)。
  --enable-chunked-prefill
                        如果设置,prefill请求可以根据max_num_batched_tokens进行分块。
  --speculative-model SPECULATIVE_MODEL
                        在推测解码中使用的草案模型的名称。
  --num-speculative-tokens NUM_SPECULATIVE_TOKENS
                        从草案模型在推测解码中采样的推测token数。
  --speculative-draft-tensor-parallel-size SPECULATIVE_DRAFT_TENSOR_PARALLEL_SIZE, -spec-draft-tp SPECULATIVE_DRAFT_TENSOR_PARALLEL_SIZE
                        在推测解码中草案模型的张量并行副本数。
  --speculative-max-model-len SPECULATIVE_MAX_MODEL_LEN
                        草案模型支持的最大序列长度。序列超过此长度将跳过推测。
  --speculative-disable-by-batch-size SPECULATIVE_DISABLE_BY_BATCH_SIZE
                        如果入队请求的数量大于此值,则禁用新进入请求的推测解码。
  --ngram-prompt-lookup-max NGRAM_PROMPT_LOOKUP_MAX
                        在推测解码中ngram提示查找的最大窗口大小。
  --ngram-prompt-lookup-min NGRAM_PROMPT_LOOKUP_MIN
                        在推测解码中ngram提示查找的最小窗口大小。
  --model-loader-extra-config MODEL_LOADER_EXTRA_CONFIG
                        模型加载器的额外配置。这将传递给对应于所选load_format的模型加载器。这应当是一个将被解析成字典的JSON字符串。
  --preemption-mode PREEMPTION_MODE
                        如果为‘recompute’,引擎通过块交换执行抢占;如果为‘swap’,引擎通过块交换执行抢占。
  --served-model-name SERVED_MODEL_NAME [SERVED_MODEL_NAME ...]
                        API中使用的模型名称。如果提供了多个名称,服务器将响应任何提供的名称。响应中的模型字段中的模型名称将是此列表中的第一个名称。如果未指定,模型名称将与`--model`参数相同。注意,此名称也将用于prometheus度量中的`model_name`标签内容,如果提供了多个名称,度量标签将采用第一个。
  --qlora-adapter-name-or-path QLORA_ADAPTER_NAME

总结

vLLM展示了使用我们已经应用了十年的简单概念,就能做出令人惊叹的东西。这个框架在GPU内存使用和利用PageAttention技术的各种优势方面取得了巨大的改进。通过减少KV缓存的使用,系统能够处理更大的负载并更快地进行推理。

0 人点赞