首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >vLLM多租户LoRA原理揭秘

vLLM多租户LoRA原理揭秘

原创
作者头像
aaronwjzhao
修改2025-08-07 18:54:41
修改2025-08-07 18:54:41
67710
举报
文章被收录于专栏:AI工程落地AI工程落地

vllm lora的使用

加载基座大模型

首先需要加载模型Llama 3 8b,并向vLLM表明我们将使用LoRA,同时还需要设置max_lora_rank。

from vllm import LLM, SamplingParams from vllm.lora.request import LoRARequest from huggingface_hub import snapshot_download llm = LLM(model="meta-llama/Meta-Llama-3-8B", enable_lora=True, max_lora_rank=16)

创建LoRARequest

chat adapter

sampling_params_oasst = SamplingParams(temperature=0.7, top_p=0.9, max_tokens=500) oasst_lora_id = "kaitchup/Meta-Llama-3-8B-oasst-Adapter" oasst_lora_path = snapshot_download(repo_id=oasst_lora_id) oasstLR = LoRARequest("oasst", 1, oasst_lora_path)

函数adapter

sampling_params_xlam = SamplingParams(temperature=0.0, max_tokens=500) xlam_lora_id = "kaitchup/Meta-Llama-3-8B-xLAM-Adapter" xlam_lora_path = snapshot_download(repo_id=xlam_lora_id) xlamLR = LoRARequest("xlam", 2, xlam_lora_path)

生成token

chat adapter

prompts_oasst = [ "### Human: Check if the numbers 8 and 1233 are powers of two.### Assistant:", "### Human: What is the division result of 75 divided by 1555?### Assistant:", ] outputs = llm.generate(prompts_oasst, sampling_params_oasst, lora_request=oasstLR) for output in outputs: generated_text = output.outputs[0].text print(generated_text) print('------')

函数adapter

prompts_xlam = [ "<user>Check if the numbers 8 and 1233 are powers of two.</user>\n\n<tools>", "<user>What is the division result of 75 divided by 1555?</user>\n\n<tools>", ] outputs = llm.generate(prompts_xlam, sampling_params_xlam, lora_request=xlamLR) for output in outputs: generated_text = output.outputs[0].text print(generated_text) print('------')

基座模型只加载一次,并在内存中也是共享的。每个用户的请求,可以指定使用不同的lora adapter,一个请求只能指定一个lora adapter。

单基础模型可以同时挂载多个LoRA适配器(如聊天/函数调用),不同请求的lora adapter切换延迟低于1ms。

支持5+adapter并行服务。

vllm lora的网络层

以Llama 3 8B的微调模型kaitchup/Meta-Llama-3-8B-oasst-Adapter为例:

网络层

算子名

attention

self_attn.q_proj

self_attn.k_proj

self_attn.v_proj

self_attn.o_proj

mlp

mlp.down_proj

mlp.gate_proj

mlp.up_proj

kaitchup/Meta-Llama-3-8B-oasst-Adapter模型权重
kaitchup/Meta-Llama-3-8B-oasst-Adapter模型权重

从vllm源码来看,可以支持包括embedding、qkv linear、mlp、lmhead相关的几乎所有矩阵乘运算。

vLLM中支持LoRA的层
vLLM中支持LoRA的层

vllm lora实现原理

思想来源

实现思想来自于论文Punica: Multi-Tenant LoRA Serving,该论文主要解决多租户LoRA服务问题,Punica设计原则:

1.GPU很昂贵,因此需要尽量少的使用 GPU,尽量提高 GPU 利用率

2.Batching是提高性能和 GPU 利用率的有效手段

3.Decoding 阶段是模型服务成本的主要因素,因此只需关注 Decoding 性能即可,其他部分可以应用最简单的方案

Punica整体框架图:

Punica框架图
Punica框架图

Frontends:可面向用户提供 RESTful API,并将用户的请求转发给 Punica 调度器(Scheduler)。用户的请求包含 LoRA 模型的标识符和提示(prompt)。

Scheduler:将请求分发给GPU。

Runner:每个 GPU 都会启动一个 Runner,该 Runner 与 Scheduler 通信并控制所有 GPU 的执行。

在Punica中,每个 GPU 都会加载基座模型,很大一部分 GPU 显存保留给 KV cache。只有模型的 LoRA 组件在需要时从远端存储(比如 host 内存、硬盘)中传输到 GPU,这也就允许模型服务的快速冷启动。

Punica关键技术--SGMVM(Segmented Gather Matrix-Vecotr Multiplication):

对于有多个 LoRA 模型的系统,除了基座模型可以batching外,针对同一个LoRA模型的输入也可以batching起来一起处理。

如下图所示,s1表示第一个 LoRA 模型,sn表示第 n 个 LoRA 模型,si表示batch size。

  • 等号右侧第一部分:基座模型,所以 x 都与 W 相乘,也就是一个大的矩阵乘操作,比较简单
  • 等号右侧第二部分:多个 LoRA 模型,相当于多个矩阵乘操作
多个LoRA矩阵乘法
多个LoRA矩阵乘法

对于第二部分计算,作者将其称为SGMV,并实现了一个高效的CUDA kernel来实现。

SGMV实现原理
SGMV实现原理

Expand kernel负责调度不同输入给相应的Ai,计算输出Vi

Shrink kernel负责调度不同的Vi给相应的Bi,计算输出Yi。

SGMV expand/shrink kernels实现
SGMV expand/shrink kernels实现

实现细节

模型加载的时候,只加载正常的权重,loraAB初始化为0,并且初始化LoRAManager管理多个lora模型。

vLLM中QKV Linear初始化lora_a/lora_b值为0
vLLM中QKV Linear初始化lora_a/lora_b值为0

每个请求(prompt)可以使用不同的lora模型,根据请求里带的lora模型,添加到LoRAManager里。

管理用户请求里的LoRA模型
管理用户请求里的LoRA模型

关键优化特性

槽位管理:支持多个LoRA同时加载,通过槽位索引管理 LRU缓存:自动管理LoRA内存,淘汰最少使用的适配器 批处理优化:Punica算法支持高效的批处理LoRA计算 内存优化:支持CPU/GPU内存分层存储 多租户支持:同时服务多个不同LoRA的请求

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • vllm lora的使用
  • vllm lora的网络层
  • vllm lora实现原理
    • 思想来源
    • 实现细节
    • 关键优化特性
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档