LoRA大模型微调技术深度解析:从原理到vLLM框架实战全攻略
本文详细介绍了LoRA(Low Rank Adaptation)低秩微调技术的原理及在vLLM框架中的实现。文章通过替换原始模型层、预分配显存、动态加载LoRA权重等技术,实现了在不修改原始模型的情况下,用少量额外参数高效微调大模型的能力。详细解析了LoRA的加载、切分和推理过程,为开发者提供了完整的LoRA技术实现指南。
本文详细介绍了LoRA(Low Rank Adaptation)低秩微调技术的原理及在vLLM框架中的实现。文章通过替换原始模型层、预分配显存、动态加载LoRA权重等技术,实现了在不修改原始模型的情况下,用少量额外参数高效微调大模型的能力。详细解析了LoRA的加载、切分和推理过程,为开发者提供了完整的LoRA技术实现指南。
前排提示,文末有大模型AGI-CSDN独家资料包哦!
这个季度做了一些关于 LoRA 的工作,写一篇文档记录一下,不足与错误的地方请大佬们多指点。
LoRA(Low Rank Adaptation),一种基于低秩的微调优化方法。
01
LoRA 原理
首先我们需要理解,什么是模型的微调?
本质上是当我们发现一个模型在某一方面的能力不够时通过微调的方法把这个模型更新,模型的参数都是由矩阵构成的,一般的 llm 都是由上亿的参数构成,本例中以 3×3 矩阵代替。
如上图所示,很明显,微调就是把矩阵 A 的形态,变成矩阵 B 的形态。
延伸到 a+b=c 这个公式中,其中 b 这个改动的量,也就是微调的这个矩阵。对 b 这个矩阵的学习更新,则是全量微调。
目前针对 LLM 数十亿起步的参数,许多工作已经表明,深度学习的矩阵往往过参数化(overparametrized),特征的内在维度(intrinsic dimension)指的是在深度学习中的真实或潜在的低维结构或信息的维度。
这个内在维度指的是我们解决这个问题实际上需要的参数空间的维度,我们对模型的微调通常调整的也是这些低秩的内在维度。
也就是说我们对模型进行微调时候,是可以通过提出秩,来压缩参数空间的。
那么这时候,就需要用到最常见的一种技术 LoRA,下面以图例方式看一下 LoRA 的核心思想:
02
vLLM 框架 LoRA 逻辑
(1)LoRA Layer 替换处理
上文已经基本理清了 LoRA 的原理,那么接下来我们学习下在 vLLM 中,LoRA 是如何加载并且做推理的?
首先在加载 model 阶段,把原始的 Linear/ColumnParallelLinear/RowParallelLinear 换成对应的带 LoRA 功能的类,并且为每一层 LoRA 做初始化,分配显存 buffer。
让模型结构具备支持 LoRA 的能力,并开好存储空间。
先从 load_model 为入口,以下是一个主要调用流程:
self.model_runner.load_model()
可以看到在加载模型阶段,会调用 **create_lora_manager()**方法,创建一个 LoRA adapter,并将其作用于模型,返回挂载 LoRA 后的模型。
而如何更改的这个模型结构,则是通过 LoRAModelManager 这个类实现的,这个类主要管理了 activate_adapter()、_create_lora_modules() 等方法。
具体如何将 base linear 更改成了带 LoRA 的 linear 呢,主要通过 _create_lora_modules() 方法实现的。
def from_layer(layer: nn.Module,
lora_cls 为具体的 LoRA linear 层的某个类, 遍历 _all_lora_classes
中注册的所有 **LoRA 包装层类,**然后调用 can_replace_layer 方法,返回一个 bool 类型值,确认是否进行符合替换条件。
然后通过调用 create_lora_weights() 方法,进行 LoRA 权重的初始化,给权重开出具体的 buffer, 提前准备好显存空间,方便后续动态加载多个 LoRA adapter。
以下代码则是一个基类,上述提到的一些带 lora 的 linear 类,都是继承并重写了这个基类的方法,完成了一些权重加载等操作:
classBaseLayerWithLoRA(nn.Module):
以上是在 load_model 阶段的时候做的事情,这时候我们可以看到已经把 nn.module 中的一些 linear 层替换成了带 LoRA 的 linear 层。
并且已经将 LoRA adpter 挂载到了 model 上,后续 dummy_run 或者是真正推理的时候,都会跑到对应的带 LoRA 的 linear 类中。
而对 LoRA 权重的处理我们可以看到只是为 LoRA 权重预分配了内存空间(即分配了对应形状的零张量),并没有对 LoRA 权重做任何实际的赋值和加载,也是为了后续动态配置 LoRA 权重准备。
真实的 LoRA 权重会在之后的加载步骤(activate_adapter
)中被读取、切分(如果有分片)并写入这块预分配的空间。
(2)LoRA 权重加载和切分
在这部分过程中,我们结合 worker_busy_loop()
(也就是一个 worker 持续读取输入、进行推理、写入输出)的过程来看在 LoRA 部分如何对权重做的处理。
从 dummy_run 阶段去看,dummy_run 是只走一遍模型 forward 的初始化:
classLoRAModelRunnerMixin:
在 maybe_select_dummy_loras 函数中主要模拟 prompt → LoRA 的映射,模拟 token → LoRA 映射例如:
prompt_lora_mapping = [1, 2] # 第一个 prompt 用 LoRA ID 1,第二个用 LoRA ID 2
并且构造出一个临时的 LoRA adapter 请求列表,例如:
{
临时数据构造完成后调用 LoRA 管理器,激活这些 dummy adapter。
把传进来的 LoRA 请求和 prompt、token 映射表注册到 lora_manager
,让模型在 forward 时按这些映射使用对应的 LoRA adapter。
加载并激活 adapter 权重到模型模块里并且记录每个 prompt 和 token 使用哪个 adapter 的映射表。
最后对适配器的激活,其实也是通过 LoRAModelManager 这个类去管理的,调用 module.set_lora()
,把这些权重写入到该 module 内部的 buffer 中。
index 则是选用哪个 lora 适配器,lora 的 id 是全局唯一的,所以他的索引全局也只有唯一一个:
classLoRAModelManager(AdapterModelManager):
(3)LoRA 适配器服务中加载
这部分背景是当我们已经启动了在线服务的情况下,还想在请求阶段挂载一个新的 LoRA 适配器:
可以看到是在 model_runner 阶段可以添加 lora 适配器:
classWorker(WorkerBase):
返回的是 lora_manager 实例下的 add_adapter 方法。
defadd_lora(self, lora_request: LoRARequest) -> bool:
这部分代码可以看到将 lora 的适配器做了 load,注册之后。又调用了上面提到的 activate_adapter() 函数,对 lora 适配器进行加载激活,也就是加载他的权重信息。(上文已经提到具体加载的细节)
classLRUCacheWorkerLoRAManager(WorkerLoRAManager):
(4)执行 model
前面已经完成了 nn.module 的替换和 weight 的加载分配,还是从 worker_busy_loop 函数入口,在 def _dummy_run 的时候,加载完权重会执行推理,主要实现如下:
classGPUModelRunner(LoRAModelRunnerMixin):
由于在 nn.mudule 部分已经对网络的结构做了 lora 的替换,所以在走到具体 model forward 中时,则会调到对应的带 lora 的 linear 层中。
classQwen2Attention(nn.Module):
此例中则会调用 RowParallelLinearWithLoRA 类中的 forward:
defapply(self,
深入 add_shrink 这个函数去看可以发现已经调用到了底层算子,也就是前面提到的降维和升维矩阵那部分,底层算子由 triton 生成:
_lora_shrink_kernel[grid](
至此 vLLM LoRA 推理已经全部完成,可以很明显的看到,vLLM 会通过动态注入方式,将 LoRA adapter 挂载到模型模块上。
通俗解释就是 LoRA 是一种给大模型“加外挂”的方法,让我们在不修改原始模型的情况下,用极少的额外参数就能让模型学会新任务。
读者福利:倘若大家对大模型感兴趣,那么这套大模型学习资料一定对你有用。
针对0基础小白:
如果你是零基础小白,快速入门大模型是可行的。
大模型学习流程较短,学习内容全面,需要理论与实践结合
学习计划和方向能根据资料进行归纳总结
包括:大模型学习线路汇总、学习阶段,大模型实战案例,大模型学习视频,人工智能、机器学习、大模型书籍PDF。带你从零基础系统性的学好大模型!
😝有需要的小伙伴,可以保存图片到wx扫描二v码免费领取【保证100%免费
】🆓
👉AI大模型学习路线汇总👈
大模型学习路线图,整体分为7个大的阶段:(全套教程文末领取哈)
第一阶段: 从大模型系统设计入手,讲解大模型的主要方法;
第二阶段: 在通过大模型提示词工程从Prompts角度入手更好发挥模型的作用;
第三阶段: 大模型平台应用开发借助阿里云PAI平台构建电商领域虚拟试衣系统;
第四阶段: 大模型知识库应用开发以LangChain框架为例,构建物流行业咨询智能问答系统;
第五阶段: 大模型微调开发借助以大健康、新零售、新媒体领域构建适合当前领域大模型;
第六阶段: 以SD多模态大模型为主,搭建了文生图小程序案例;
第七阶段: 以大模型平台应用与开发为主,通过星火大模型,文心大模型等成熟大模型构建大模型行业应用。
👉大模型实战案例👈
光学理论是没用的,要学会跟着一起做,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。
👉大模型视频和PDF合集👈
这里我们能提供零基础学习书籍和视频。作为最快捷也是最有效的方式之一,跟着老师的思路,由浅入深,从理论到实操,其实大模型并不难。
👉学会后的收获:👈
• 基于大模型全栈工程实现(前端、后端、产品经理、设计、数据分析等),通过这门课可获得不同能力;
• 能够利用大模型解决相关实际项目需求: 大数据时代,越来越多的企业和机构需要处理海量数据,利用大模型技术可以更好地处理这些数据,提高数据分析和决策的准确性。因此,掌握大模型应用开发技能,可以让程序员更好地应对实际项目需求;
• 基于大模型和企业数据AI应用开发,实现大模型理论、掌握GPU算力、硬件、LangChain开发框架和项目实战技能, 学会Fine-tuning垂直训练大模型(数据准备、数据蒸馏、大模型部署)一站式掌握;
• 能够完成时下热门大模型垂直领域模型训练能力,提高程序员的编码能力: 大模型应用开发需要掌握机器学习算法、深度学习框架等技术,这些技术的掌握可以提高程序员的编码能力和分析能力,让程序员更加熟练地编写高质量的代码。
👉获取方式:
😝有需要的小伙伴,可以保存图片到wx扫描二v码免费领取【保证100%免费
】🆓
更多推荐
所有评论(0)