【速写】多LoRA并行衍生的一些思考

迁移学习上的一个老问题,怎么做多领域的迁移?以前的逻辑认为领域迁移属于是对参数做方向性的调整,如果两个领域方向相左,实际上不管怎么加权相加都是不合理的。

目前一些做法想着去观察LoRA权重矩阵中的稠密块与稀疏块,选择稠密的部分予以保留,稀疏的部分予以舍弃,然后有选择地进行合并,这是一种很模糊的做法,实际上也缺乏理论保证,而且,低秩与稀疏通常并不等价。

假定是做秩一分解:

h 1 = W 0 x + ( B 1 A 1 ) x = W 0 x + ( ∑ i = 1 r 1 d 1 i v i v i ⊤ ) x = W 0 x + ∑ i = 1 r 1 ( d 1 i v i ⊤ x ) v i = W 0 x + ∑ i = 1 r 1 k 1 i v i h 2 = W 0 x + ( B 2 A 2 ) x = W 0 x + ( ∑ i = 1 r 2 d 2 i u i u i ⊤ ) x = W 0 x + ∑ i = 1 r 2 ( d 2 i v i ⊤ x ) v i = W 0 x + ∑ i = 1 r 2 k 2 i v i h_1 = W_0 x + (B_1A_1) x = W_0 x + \left(\sum_{i=1}^{r_1} d_{1i} v_iv_i^\top\right) x = W_0 x + \sum_{i=1}^{r_1} (d_{1i} v_i^\top x) v_i = W_0 x + \sum_{i=1}^{r_1} k_{1i} v_i \\ h_2 = W_0 x + (B_2A_2) x = W_0 x + \left(\sum_{i=1}^{r_2} d_{2i} u_iu_i^\top\right) x = W_0 x + \sum_{i=1}^{r_2} (d_{2i} v_i^\top x) v_i = W_0 x + \sum_{i=1}^{r_2} k_{2i} v_i h1=W0x+(B1A1)x=W0x+(i=1r1d1ivivi)x=W0x+i=1r1(d1ivix)vi=W0x+i=1r1k1ivih2=W0x+(B2A2)x=W0x+(i=1r2d2iuiui)x=W0x+i=1r2(d2ivix)vi=W0x+i=1r2k2ivi

调整的其实就是rank数量的单位向量的加权和。

这里面的 u i , v i u_i,v_i ui,vi都是单位向量, d 1 i d_{1i} d1i d 2 i d_{2i} d2i表示奇异值。

k 1 i k_{1i} k1i k 2 i k_{2i} k2i都是标量。

那么我们可以在每一层的输出时,选择需要保留的若干个单位向量的加权和作为这层的输出,保留的依据可以根据 k 1 i k_{1i} k1i k 2 i k_{2i} k2i的大小来确定(保大去小)。

比如在合并的时候从 r 1 + r 2 r_1+r_2 r1+r2个秩一矩阵中取 r 1 + r 2 2 \frac{r_1+r_2}{2} 2r1+r2个出来作为融合后的LoRA

这样的调整本身关于输入 x x x是动态的,复杂度很差。

另一件事就是白盒压缩、或者说模型压缩的时候,为什么不直接用SVD进行降维处理呢,重新训练一个小模型出来,可能连模型结构都不一样的模型出来替代原模型,难道还能比跟原模型结构相同的东西有更令人信服的性能吗?

题外话,以及做INT量化与用SVD进行降维处理,两种方法截然不同,对精度的影响有何区别呢?两者都对隐层权重的数值,从而影响每个隐层的输出,但是直觉上,INT量化产生的误差的方差在point-wise上是处处相等的(即均匀误差),但是SVD似乎并非如此,因为SVD给出的误差其实是若干个比较小的奇异值所对应的秩一矩阵的加权和,而秩一矩阵值的分布显然不可能是均匀分布,这取决于奇异向量的分布:

(1) 高度结构化

  • 所有行成比例:矩阵的每一行是向量 v v v的标量倍数(系数为 u i u_i ui)。
    第 i 行 = u i ⋅ [ v 1 , v 2 , … , v n ] \text{第} i \text{行} = u_i \cdot [v_1, v_2, \dots, v_n] i=ui[v1,v2,,vn]
  • 所有列成比例:每一列是向量 u u u的标量倍数(系数为 v j v_j vj)。
    第 j 列 = v j ⋅ [ u 1 , u 2 , … , u m ] T \text{第} j \text{列} = v_j \cdot [u_1, u_2, \dots, u_m]^T j=vj[u1,u2,,um]T

(2) 数值分布依赖基向量

  • 矩阵元素的值完全由 u u u v v v的分布决定:
    • u u u v v v服从高斯分布,则 M i j M_{ij} Mij是高斯变量的乘积(分布可能复杂,但通常呈现尖峰、重尾特性)。
    • u u u v v v是稀疏的,则 M M M也会稀疏。

(3) 特征值与奇异值

  • 非零特征值:秩1矩阵仅有1个非零特征值(等于 u T v u^T v uTv v T u v^T u vTu)。
  • 奇异值:唯一非零奇异值为 ∥ u ∥ ⋅ ∥ v ∥ \|u\| \cdot \|v\| uv,其余奇异值为0。

至少从误差的分布上来说,量化要更稳定可控一些。

总是觉得现在人做事太简单粗暴了,没有理论分析的支撑,全凭拍脑袋。

下面简单看一看DeepSeek对于多LoRA合并的论述:


多LoRA并行(Multiple LoRA Adapters Parallel)的底层逻辑涉及在模型运行时动态组合多个低秩适配器的权重,其核心是通过并行计算权重叠加的方式将不同LoRA模块的影响同时作用于基座模型(Base Model)。


1. 基本概念回顾

  • LoRA的本质
    在原始模型权重 W 0 ∈ R d × k W_0 \in \mathbb{R}^{d \times k} W0Rd×k 旁注入低秩矩阵 A ∈ R d × r A \in \mathbb{R}^{d \times r} ARd×r B ∈ R r × k B \in \mathbb{R}^{r \times k} BRr×k,其中 r ≪ min ⁡ ( d , k ) r \ll \min(d,k) rmin(d,k)
    前向传播时,输出为:
    h = W 0 x + ( B A ) x h = W_0 x + (BA) x h=W0x+(BA)x
  • 多LoRA并行
    同时激活多个LoRA模块(如 B A ( 1 ) + B A ( 2 ) + … BA^{(1)} + BA^{(2)} + \dots BA(1)+BA(2)+),输出变为:
    h = W 0 x + ∑ i = 1 N ( B ( i ) A ( i ) ) x h = W_0 x + \sum_{i=1}^N (B^{(i)} A^{(i)}) x h=W0x+i=1N(B(i)A(i))x

2. 运行时计算的两种实现方式

方式1:权重直接叠加(静态合并)

步骤

  1. 离线合并:在加载模型时,将所有激活的LoRA的增量权重 Δ W i = B ( i ) A ( i ) \Delta W_i = B^{(i)}A^{(i)} ΔWi=B(i)A(i) 相加:
    Δ W merged = ∑ i = 1 N B ( i ) A ( i ) \Delta W_{\text{merged}} = \sum_{i=1}^N B^{(i)}A^{(i)} ΔWmerged=i=1NB(i)A(i)
  2. 前向计算:仅需计算一次合并后的增量:
    h = W 0 x + Δ W merged x h = W_0 x + \Delta W_{\text{merged}} x h=W0x+ΔWmergedx

底层逻辑

  • 优点:计算量与单LoRA相同,无额外开销。
  • 缺点:静态合并后无法动态调整适配器组合。
  • 适用场景:推理时需固定融合多个LoRA。

代码示例(PyTorch):

# 假设 lora_A 和 lora_B 是两个LoRA模块的增量权重
delta_W = lora_A @ lora_B + lora_C @ lora_D  # 低秩矩阵乘法
h = base_model_W @ x + delta_W @ x
方式2:动态并行计算(运行时逐适配器计算)

步骤

  1. 独立保留LoRA权重:保持每个LoRA的 A ( i ) A^{(i)} A(i) B ( i ) B^{(i)} B(i) 矩阵独立存储。
  2. 前向传播时逐适配器计算
    h = W 0 x + ∑ i = 1 N ( B ( i ) ( A ( i ) x ) ) h = W_0 x + \sum_{i=1}^N (B^{(i)} (A^{(i)} x)) h=W0x+i=1N(B(i)(A(i)x))
    • 先计算所有 A ( i ) x A^{(i)} x A(i)x,再与对应的 B ( i ) B^{(i)} B(i) 相乘,最后累加结果。

底层逻辑

  • 优点:支持动态开关适配器(如根据输入选择不同的LoRA组合)。
  • 缺点:计算量随LoRA数量线性增长(需 N N N 次低秩矩阵乘法和累加)。
  • 适用场景:需要运行时灵活切换适配器的场景(如多任务推理)。

代码示例(PEFT库实现逻辑):

# 伪代码:动态多LoRA计算
h = base_layer(x)
for adapter in active_adapters:lora_A = adapters[adapter].A  # 形状 (d, r)lora_B = adapters[adapter].B  # 形状 (r, k)h += (lora_B @ (lora_A @ x)) * adapter.scaling  # 缩放系数

3. 关键优化技术

为了减少多LoRA并行的计算开销,框架(如PEFT)通常会采用以下优化:

(1) 共享基座模型权重
  • 所有LoRA复用同一份 W 0 W_0 W0,仅额外存储增量部分 Δ W i \Delta W_i ΔWi
(2) 批处理低秩计算
  • 将多个LoRA的 A ( i ) A^{(i)} A(i) 拼接为大矩阵 A stack ∈ R N ⋅ r × d A_{\text{stack}} \in \mathbb{R}^{N \cdot r \times d} AstackRNr×d,通过一次矩阵乘法和分割结果加速计算:
    [ A ( 1 ) x ; A ( 2 ) x ; … ] = A stack x [A^{(1)}x; A^{(2)}x; \dots] = A_{\text{stack}} x [A(1)x;A(2)x;]=Astackx
    再分别与对应的 B ( i ) B^{(i)} B(i) 相乘。
(3) 延迟缩放(Scaling)
  • 将LoRA的缩放系数 α r \frac{\alpha}{r} rα 合并到 B ( i ) B^{(i)} B(i) 中,避免重复乘法:
    B ′ ( i ) = B ( i ) ⋅ α r B'^{(i)} = B^{(i)} \cdot \frac{\alpha}{r} B(i)=B(i)rα

4. 数学形式对比

假设有两个LoRA( Δ W 1 = B 1 A 1 \Delta W_1 = B_1A_1 ΔW1=B1A1, Δ W 2 = B 2 A 2 \Delta W_2 = B_2A_2 ΔW2=B2A2):

方法计算过程FLOPs
静态合并 h = W 0 x + ( B 1 A 1 + B 2 A 2 ) x h = W_0 x + (B_1A_1 + B_2A_2) x h=W0x+(B1A1+B2A2)x O ( d k + d r + r k ) O(dk + dr + rk) O(dk+dr+rk)
动态并行 h = W 0 x + B 1 ( A 1 x ) + B 2 ( A 2 x ) h = W_0 x + B_1(A_1 x) + B_2(A_2 x) h=W0x+B1(A1x)+B2(A2x) O ( d k + 2 ( d r + r k ) ) O(dk + 2(dr + rk)) O(dk+2(dr+rk))
批处理优化 h = W 0 x + [ B 1 , B 2 ] ⋅ [ A 1 ; A 2 ] x h = W_0 x + [B_1, B_2] \cdot [A_1; A_2] x h=W0x+[B1,B2][A1;A2]x O ( d k + d ( 2 r ) + ( 2 r ) k ) O(dk + d(2r) + (2r)k) O(dk+d(2r)+(2r)k)

5. 实际框架中的实现

以PEFT(Hugging Face)为例:

  1. 注册多个适配器
    model.add_adapter("adapter1", lora_config_A)
    model.add_adapter("adapter2", lora_config_B)
    
  2. 动态激活组合
    model.set_active_adapters(["adapter1", "adapter2"])
    
  3. 底层计算
    • PEFT自动选择动态并行计算(方式2),按需累加所有激活适配器的输出。

6. 总结:多LoRA并行的本质

  • 静态合并:算术叠加权重,适合固定组合的轻量推理。
  • 动态并行:独立计算后求和,适合灵活适配但计算成本较高。
  • 优化方向:通过批处理和共享基座权重减少冗余计算。

如果需要进一步分析具体框架(如PEFT、AdaLoRA)的实现细节,可以提供更多上下文!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/77945.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Delphi 基础知识 44】接口interface的应用

目录 1. 前言2. 接口有哪些优势2.1. 实现多态性2.2 实现多重(解决单继承限制)2.3 解耦代码(依赖注入)2.4 便于测试(模拟接口)2.5 跨语言互操作性(COM支持)1. 前言 总结为一句话就是:接口只告诉你要做什么,而类会告诉你应该怎么做 下面是最简单的接口实现 typeIMyIn…

09.传输层协议 ——— TCP协议

文章目录 TCP协议 谈谈可靠性TCP协议格式 序号与确认序号窗口大小六个标志位 确认应答机制(ACK)超时重传机制连接管理机制 三次握手四次挥手 流量控制滑动窗口拥塞控制延迟应答捎带应答面向字节流粘包问题TCP异常情况TCP小结基于TCP的应用层协议 TCP协…

NLP高频面试题(五十一)——LSTM详解

长短期记忆网络(LSTM)相较于传统循环神经网络(RNN)的核心改进在于通过引入记忆单元(cell state)和门机制(gating mechanism)来有效缓解梯度消失与梯度爆炸问题,从而更好地捕捉长距离依赖关系 。在其网络结构中,信息通过输入门(input gate)、遗忘门(forget gate)和…

SpringCloud组件—Eureka

一.背景 1.问题提出 我们在一个父项目下写了两个子项目,需要两个子项目之间相互调用。我们可以发送HTTP请求来获取我们想要的资源,具体实现的方法有很多,可以用HttpURLConnection、HttpClient、Okhttp、 RestTemplate等。 举个例子&#x…

无需花钱购买域名服务器!使用 VuePress + Github 30分钟搭建属于自己的博客网站(保姆级教程)

前言 GitHub Pages 提供免费全球加速的服务器资源,VuePress 将 Markdown 变成艺术品级的网页,仅需 30 分钟,你便可以像提交代码一样发布文章,过程完全免费。 博客搭建好的效果如下:https://honorsong.github.io/exam…

提交到Gitee仓库

文章目录 注册配置公钥创建空白的码云仓库把本地项目上传到码云对应的空白仓库中 注册 注册并激活码云账号( 注册页面地址:https://gitee.com/signup ) 可以在自己C盘/用户/用户名/.ssh 可以看到 有id_rsa.pub 以前在GitHub注册时搞过&…

如何在 Java 中从 PDF 文件中删除页面(教程)

由于 PDF 文件格式不是 Java 原生支持的,因此要从 PDF 中删除页面,你需要使用外部库。 本教程介绍如何使用 JPedal 来实现这一功能。 开始使用 • 将 JPedal 添加到你的类路径或模块路径中(可从官网下载安装试用版 JAR 文件) •…

机器学习第二篇 多变量线性回归

数据集:世界幸福指数数据集中的变量有幸福指数排名、国家/地区、幸福指数得分、人均国内生产总值、健康预期寿命、自由权、社会支持、慷慨程度、清廉指数。我们选择GDP per Capita和Freedom,来预测幸福指数得分。 文件一:linear,…

位运算,状态压缩dp(算法竞赛进阶指南学习笔记)

目录 移位运算一些位运算的操作最短 Hamilton 路径(状态压缩dp模板,位运算) 0x是十六进制常数的开头;本身是声明进制,后面是对应具体的数; 数组初始化最大值时用0x3f赋值; 移位运算 左移 把二…

Java高频面试之并发编程-05

hello啊,各位观众姥爷们!!!本baby今天来报道了!哈哈哈哈哈嗝🐶 面试官:线程有哪些调度方法? 在Java中,线程的调用方法主要包括以下几种方式,每种方式适用于…

进程的同步和互斥

进程同步(synchronous) ✅通俗理解: 就像在排队买饭,一个一个来,前面的人不走,后面的人就不能干事。 进程同步就是:多个进程之间需要协调,有先后顺序,一个进程要等另一…

PDF处理控件Aspose.PDF指南:使用 Python 将 EPUB 转换为 PDF

EPUB是一种流行的电子书格式,用于可重排内容,而PDF则广泛用于固定版式文档,非常适合共享和打印。如果您想使用 Python 将 EPUB 转换为 PDF,Aspose.PDF for Python 提供了一个简单可靠的解决方案。在本教程中,我们将向您…

day4-小白学习JAVA---开发软件_Scanner键盘录入_Random随机数_流程控制语句

开发软件_Scanner键盘录入_Random随机数_流程控制语句 一、开发软件idea(MAC版)1、软件安装-安装社区版2、中英文设置3、保存时格式化配置4、注释和代码对不齐5、idea快捷键 二、键盘录入--Scanner1、next和nextInt2、next和nextLine区别 三、Random随机…

MySQL基本查询与数据操作全面解析

目录 1. CRUD操作概述 2. Create操作详解 2.1 表的创建 2.2 单行数据插入 2.3 多行数据插入 2.4 插入冲突处理 3. Retrieve操作详解 3.1 基础查询 全列查询(慎用) 指定列查询 表达式查询 结果去重 3.2 条件查询(WHERE子句&#…

01.Python代码Pandas是什么?pandas的简介

01.Python代码Pandas是什么?pandas的简介 提示:帮帮志会陆续更新非常多的IT技术知识,希望分享的内容对您有用。本章分享的是pandas的使用语法。前后每一小节的内容是存在的有:学习and理解的关联性,希望对您有用~ pyth…

(8)ECMAScript语法详解

本系列教程目录:Vue3Element Plus全套学习笔记-目录大纲 文章目录 第2章 ECMAScript2.1 ECMAScript 的发展历史2.2 什么是ES62.3 ES6语法新特性2.3.1 变量声明let2.3.2 常量声明2.3.3 模板字符串2.3.4 函数默认参数2.3.5 箭头函数2.3.6 对象初始化简写2.3.7 解构2.3…

Android JNI开发中头文件引入的常见问题与解决方案​,提示:file not found

Android JNI开发中头文件引入的常见问题与解决方案 问题场景(新手易犯错误) 假设你在开发一个JNI项目,想要实现一个线程安全的队列(SafeQueue),于是直接在cpp目录下创建了safe_queue.h文件,并开…

C++静态与动态联编区别解析

在 C++ 中,静态联编(Static Binding)和动态联编(Dynamic Binding)是两种不同的函数调用绑定机制,核心区别在于确定函数调用的时机和多态性的支持。以下是详细解释: 1. 静态联编(Static Binding) 定义:在编译阶段确定函数调用与具体实现的关系。特点: 由编译器直接确…

如何批量为多个 Word 文档添加水印保护

在日常办公中,Word文档添加水印是一项重要的操作,特别是在需要保护文件内容的安全性和版权时。虽然Office自带了添加水印的功能,但当需要一次性给多个Word文档添加水印时,手动操作显得非常繁琐且低效。为了提高效率,可…

【愚公系列】《Python网络爬虫从入门到精通》057-分布式爬取中文日报新闻数据

🌟【技术大咖愚公搬代码:全栈专家的成长之路,你关注的宝藏博主在这里!】🌟 📣开发者圈持续输出高质量干货的"愚公精神"践行者——全网百万开发者都在追更的顶级技术博主! &#x1f…