S-LoRA:同时应用多个LoRA模块并行推理

写在前面:当base大模型在垂类任务上表现一般,需要少量参数微调时,流行的做法就是对其进行少量参数(LoRA)微调时。这样难免存在每个任务有个单独的adapter ,推理时需要把adapter与base model参数加到一起再推理。这样做的结果是,在推理时依然是一任务一模型,仿佛又回到了BERT时代,但是每个模型的参数却大得多,推理需要的显存更多。既然base模型一样,有没有什么方法能够节省推理的GPU显存,构造一个统一的推理模型,能够满足所有的业务场景呢?S-LoRA为我们提供了一种很好的工程上的解决方案。

0. 快速复习LoRA

论文:LORA : LOW-RANK ADAPTATION OF LARGE LANGUAGE MODELS

LoRA:Low-Rank Adaptation,LoRA冻结预训练模型权重并将可训练的秩分解矩阵注入到 Transformer 架构的每一层中,大大减少了下游任务的可训练参数的数量(推理参数不变)。它基于的假设就是,下游任务需要修改的特征空间是低秩的,即只要针对优化少量参数即可。类似是传统的Adapter思想,但是它的设计比较巧妙,就是用d×r和r×d(r远小于d,r一般又被称为秩)的参数矩阵A×B来做自适应学习的那部分(如下图所示),推理时只要跟base模型的d×d参数矩阵加起来就可以了,不会有额外的推理需求增加。但是这样做有个隐患就是,依然是一任务一模型。之前的解决方案是通过对参数矩阵的加减实现一个base模型加载多个adapter,但是这样依然不能实现在一个batch里同时使用多个lora。

1. S-LoRA解决了什么问题?

论文:S-LoRA: Serving Thousands of Concurrent LoRA Adapters

S-LoRA实现了同时用多个LoRA的Adapters并行推理,即1 base model + n Adapters(A×B的部分),相比于n models,在推理时就可以减少显存占用。

2. S-LoRA为什么能做到的?

S-LoRA在具体实现上有很多细致的设计,能够真正支持多Adapters并行化推理,又能尽量减少推理显存消耗,并减少相比一任务一模型的结构的中间的性能损失。论文主要从3大方面来解释它的做法的,分别是:推理请求的并行化处理、内存管理和张量并行。

2.1 请求的并行化处理

为了减少base model的数量,本文将base模型和adapter分开计算(如下图所示),而不是直接把参数合在一起了,是在分别计算后再把两个模型输出的结果加起来。

道理看起来简单,实际操作却暗含很多需要优化的问题:lora的每个adapter的秩不一定一样,就导致每个批次里请求的adapter参数矩阵大小不一,如何并行化处理?每批次请求用到的adapter都不一样,如何调度?等等问题

2.1.1 token-level的批处理调度方法

为了实现显存的尽可能高的利用率,这里的batch request调度采用了orca(Yu@OSDI2022, ORCA: A Distributed Serving System for Transformer-Based Generative Models)调度方法,实现token-level的迭代调度。详细讲解可以看作者自己的报告视频(一般的批处理调度-视频第6分钟左右; orca批处理调度-第8分钟左右):Orca: A Distributed Serving System for Transformer-Based Generative Models | USENIX

简要来说,就是orca构造了一个请求池,每并行处理完所有序列的一个token长度就把没结束生成的requests放回池子里,新来的requests也按照来的顺序放在一起,等下次生成再从请求池里调度不超过最大batch-size的请求进行处理。

2.1.2 对请求按照Adapter聚在一起

为了尽量降低推理显存占用,就需要在每个batch的请求里尽量用最少的Adapters,即尽量把相同Adapter的请求放在一个batch里,这样每次需要从内存中取出的adapter的数量就会比较少,减少并行推理时的显存。

2.1.3 准入控制

S-LoRA还介绍了它在请求高并发状态的处理方式。对于每个请求,S-LoRA会预先衡量这个请求在当前状态下的处理时延用户是否能够接受,不能被接受的话,就会被直接抛弃掉。如果一下来的请求过多,它会选择只处理时间顺序相对靠后的满足时延的请求。相比于超时才显示请求失败这种硬性门槛,可以提高响应效率,对于完不成的请求就会直接显示失败,不需要用户等了指定时间超时了才显示。

2.1.4 新的GPU算子

这一小节主要介绍的是S-LoRA采用的CUDA算子。论文中是放在了内存管理里介绍的,笔者认为这部分对于实现并行推理也很重要,就放在前面了。

为什么要用新的CUDA算子?原来我们在GPU中一般用到的矩阵计算算子是GEMM,GEMM是并行化处理矩阵的,我们在推理时,通过paddding把一个batch的所有序列填充到一样长度之后,每批次的输入,模型的各部分计算的矩阵大小是固定的,GEMM就可以实现各部分的并行计算。但是这样GPU的本身利用率就不高,再加上LoRA的Adapter的异构性(秩r的大小不一致),就导致原来的矩阵算子(GEMM)不能实现并行计算。于是,S-LoRA采用的是MBGMM和MBGMV算子,具体介绍读者可以参考下一段。

GEMM(通用矩阵乘法,动态计算图)->MBGMM(输入编码部分,sequence-level,triton)+MBGMV(解码部分,token-level,punica

上图是Punica论文中的SGMV算子(即这里的MBGMV算子),相比于GEMM的固定矩阵相乘,这里是先把矩阵Gather到一起后,再相乘,即外层的Y+=X@W是一样的逻辑,但是内部的具体参数会随着请求对应的Adapter发生变化。

2.2 内存管理

S-LoRA的内存管理是延续了vLLM的Paged-Attention的页管理思想,用每个block table将逻辑地址和物理地址联系起来。S-LoRA就在Paged-Attention的基础上,在cache中除了Key和Value之外,还增加了对Adapter的参数的管理,如下图所示。

之所以可以这么设计,作者主要是认为LoRA的Adapters和Key&Value向量有着两点相似之处:

  • 两者都是动态的,KV-cache是序列根据请求动态输入,请求结束就被销毁;adapter是每个请求如果用到了某个adapter就加载,下个batch没用到就移除;
  • 两者的矩阵有一维是一样的,KV的矩阵形状是sequence-length×hidden-size,adapter的矩阵形状是rank-size×hidden-size,所以就算合在一起,也相对规整,可以减少显存碎片。

于是,增加Adapter weights之后的cache如下图所示。

此外,为了减少adapter weight从内存到显存的load时间,s-lora有个prefetch机制,就是会根据下一个batch的request中用到adapter,提前取出到cache里,减少loading的时间。

2.3 张量并行

为了在显存不够的情况下,实现能够在多GPU上并行推理,又尽量减少通信损失,作者提出了张量并行的方案(类Megatron-LM)如下图所示。

3. S-LoRA怎么用?

调用代码如下:github.com/vllm-projec... 通过代码可以看出,S-LoRA的调用很简单,处理base模型的常用参数温度等,只要在每个request的时候加上lora地址即可。目前仅支持LLaMa和mistral模型,在vLLM项目上是实验性集成,等待支持更多的大模型以及正式发布~

相关推荐
火山引擎边缘云40 分钟前
2025 全球分布式云大会演讲实录 | 沈建发:智启边缘,畅想未来:边缘计算新场景落地与 Al 趋势新畅想
人工智能·llm·边缘计算
OpenBayes贝式计算1 小时前
教程上新丨媲美 o3-mini,开源代码推理模型 DeepCoder-14B-Preview 狂揽 3k stars
人工智能·开源·llm
Apifox2 小时前
Apifox 全面支持 LLMs.txt:让 AI 更好地理解你的 API 文档
llm·ai编程·cursor
Dlimeng3 小时前
OpenAI发布GPT-4.1系列模型——开发者可免费使用
人工智能·ai·chatgpt·openai·ai编程·agents·gpt-41
机器之心3 小时前
刚刚,OpenAI发布最强推理模型o3!图像深度思考首秀,开源编程智能体已揽5k+star
人工智能·chatgpt
SHIPKING3934 小时前
【LangChain核心组件】Memory:让大语言模型拥有持续对话记忆的工程实践
数据库·python·langchain·llm·memory
Loving_enjoy4 小时前
【用ChatGPT学编程】让AI成为你的编程外脑:注释生成与Debug实战秘籍
chatgpt·ai编程
星鹿XINGLOO4 小时前
ChatGPT语音功能在iPad上支持吗?全面解答!
人工智能·安全·ios·ai·chatgpt·语音识别·ipad
亚马逊云开发者5 小时前
利用大模型实现地理领域文档中英文自动化翻译
机器学习·llm