做二手车有哪些网站有哪些手续费,龙岩网站设计大概价格,信息技术网站建设,电子商务智能建站Ch2 Lora微调原理详解 1.为什么需要Lora 全参微调的难点#xff1a; 大型语言模型的微调成本高昂#xff1a;完整微调需要存储和更新所有模型参数的副本部署困难#xff1a;每个任务都需要存储完整的模型副本,占用大量存储空间计算资源要求高#xff1a;完整微调需要大量计…Ch2 Lora微调原理详解1.为什么需要Lora全参微调的难点大型语言模型的微调成本高昂完整微调需要存储和更新所有模型参数的副本部署困难每个任务都需要存储完整的模型副本,占用大量存储空间计算资源要求高完整微调需要大量计算资源和GPU内存LoRA的核心思想假设模型权重的更新可以通过低秩分解来表示不直接更新原始权重矩阵,而是训练两个更小的矩阵(低秩分解)通过这种方式大大减少了需要训练和存储的参数数量LoRA的优势显著减少可训练参数数量降低GPU内存需求加快训练速度多个任务可以共享基础模型,只需存储小型任务特定适配器训练稳定性好,性能接近完整微调假设一个在线客服场景:公司有一个基础的大语言模型用于客服对话需要为不同产品线(如手机、电脑、家电等)定制专门的客服机器人传统方法需要为每个产品线存储一个完整模型副本使用LoRA后:只需维护一个基础模型为每个产品线训练小型LoRA适配器运行时动态加载对应产品线的适配器大大节省存储空间和训练成本方便快速增加新产品线的支持这样不仅降低了部署和维护成本,还提高了模型更新和扩展的灵活性。2.Lora微调方法讲解2.1 Lora的介绍LoRA来源于微软在2021年发布的Paper《LORA: LOW-RANK ADAPTATION OF LARGE LANGUAGE MODELS》 低秩矩阵微调地址https://arxiv.org/pdf/2106.09685.pdf 同时也在Github上开源了LoRA的技术实现过程其Github地址https://github.com/microsoft/LoRA 。适配器微调Adapter Tuning是在模型中引入了计算模块本质还是要在模型本身增加层次会让模型推理走更长的路径。LORA的核心思想基准模型不进行变化额外引入一部分参数来做专属内容处理同时加上原有模型的推理能力这部分新增加的的内容就是要训练出来的参数矩阵。新的矩阵 $ h $ 可以表示为$ h W_0 x \Delta W x $其中$ W_0 $ 是原始的权重矩阵。$ x $ 是输入向量。$ \Delta W $ 是新增的权重矩阵用于增加训练的特色。$ x $ 经过原有矩阵计算和现在新增$ \Delta W $ 是矩阵计算后权重给出一个期望的值。新增这部分参数矩阵我期望不要太大不然和全参数微调没什么区别了我想参数量小一点节约点资源。不然就成了全参数微调了线性代数上讲一个参数矩阵可以由两个矩阵相乘得出来同理$ \Delta W $ 就可以将本身的矩阵拆成矩阵A和矩阵BA*B$ \Delta W $原有算法 $ h W_0 x \Delta W x $ 变成hW0xΔWxW0xBAxh W_0x \Delta Wx W_0x BAxhW0​xΔWxW0​xBAx( $ x $ 做为向量入参不需要改变只需要跟随即可)这里引入了一个概念本征维度Intrinsic Dimension是指数据或空间中所需的最小维度以便充分描述其中的结构或特征。换句话说尽管数据可能存在于高维空间中但其实际所包含的信息可能集中在一个更低维度的子空间内本征维度就是描述这个低维子空间的维度。LoRA与本征维度的关系LoRA的核心假设是神经网络的权重更新矩阵通常具有较低的本征秩这意味着虽然模型权重是高维的,但实际的任务相关更新可能位于一个低维子空间中LoRA正是利用了这一特性,使用低秩分解来捕获权重更新![](https://i-blog.csdnimg.cn/img_convert/f47e0e596a86013ac0b48da6543cff3c.png) ![](https://i-blog.csdnimg.cn/img_convert/9a09229ffbdda643d7cafc5407406eff.png)例如一张苹果图片展示很精细有光线斑点、叶子脉络、细微的色差等等。 但是我想要的就是能让我看出苹果才是最关键的点所以上边的描述是没用的仅仅用右边最普通的像素点展示就可以了。这个像素极低的几个点才是我最关键的信息。同理引入到矩阵中如果将$ \Delta W $ 拆成矩阵A和矩阵B这两个矩阵的秩与原矩阵相同那就没有意义了因为想要训练某一个方向专属技能就代表其他技能的参数在想要输出的方向上没那么重要是不是提炼最相关的那部分业务数据相对更重要。就会有个关键信息低秩矩阵低秩是什么[2∗32∗2101∗33∗293∗31∗211][2∗31∗281∗31∗25][1∗31∗25] \begin{bmatrix} 2*3 2*2 10 \\ 1*3 3*2 9 \\ 3*3 1*2 11 \end{bmatrix} \quad \begin{bmatrix} 2*3 1*2 8 \\ 1*3 1*2 5 \\ \end{bmatrix} \quad \begin{bmatrix} 1*3 1*2 5 \\ \end{bmatrix}​2∗31∗33∗3​2∗23∗21∗2​10911​​[2∗31∗3​1∗21∗2​85​][1∗3​1∗2​5​]一个矩阵的秩是指矩阵中线性独立行或列的最大数目第一个矩阵A、B、C分别各自表示花了多少钱谁也不能替代谁第二个矩阵C买的东西花的钱是A和B的和那么C就可以被替代就不属于秩的概念第三个矩阵C买的东西花的钱是A3的倍数那么C就不用表示B买的东西花的钱是A2的倍数那么B也就不用表示对应的秩(Rank) 分别为 3 、2 、1 我们是不是可以理解同秩越低占用空间越小忽略严谨的数学概念定义就可以理解一个矩阵的秩越大信息含量就越大对应占用空间也就越大。也就是为什么要用低秩具体体现# 假设原始权重矩阵 W ∈ R^{d×k}# LoRA将权重更新分解为:ΔWBA# 其中B ∈ R^{d×r}, A ∈ R^{r×k}, r min(d,k)r 是LoRA的秩(rank),通常远小于原始维度r 实际上反映了任务适配所需的本征维度较小的r就足够表达任务所需的权重更新,说明更新确实存在于低维子空间矩阵是什么呢怎么表示小明想去三个地方距离分别是10、20、30km他可以步行、自行车、骑摩托去 分别花费了多少时间。[]与[]能够表达[]矩阵的数量 \begin{bmatrix} \\ \\ \\ \end{bmatrix} 与 \begin{bmatrix} \\ \end{bmatrix} 能够表达 \begin{bmatrix} \\ \\ \end{bmatrix} 矩阵的数量​​​与[​​​]能够表达​​​​​矩阵的数量 符号仅作为数字占位符使用不做实际意义仅用来表达两组数据可以表达一个n*n的矩阵相比于一开始矩阵9个参数当前替换后的两个小矩阵参数就是336对比之前就是9-6少了3个参数量的位置与空间。 如果是一个100w的矩阵的规模就可以拆成1000*1000的两个矩阵假设秩8那么参数量就是1000*81000*816000这个参数量占原有100w惨数量的16000/10000001.6%对于动辄10亿的参数节约的空间就很大了过参数化模型Over-parametrized models是指参数数量远超训练数据样本数量的模型。换句话说模型中可调参数的数量大于用于训练的样本数量。如GPT系列模型和transformer模型均为此类模型。采用这种策略可以带来性能上的大幅提升。同样的如此大的参数量一定是有冗余的也就是说如此多的参数对于很多下游任务不一定都是有用的。垂直领域的知识所需要的参数一定远小于全量参数对这样的任务可能仅仅一部分重要的参数就可以做的足够好。实际上存在于一个较低的内在维度上。假设模型适应过程中权重的变化也具有较低的“内在秩”基于此这导致了低秩适应LoRA方法的灵感。LoRA允许我们通过优化适应过程中密集层变化的秩分解矩阵来间接训练神经网络中的一些密集层同时保持预先训练的权值冻结以实现微调效果并节省了计算资源。# 假设一个客服机器人场景# 原始模型过参数化-通用语言理解能力-基础对话能力-大量冗余参数# 特定任务适配如手机客服-只需要学习-手机相关专业词汇-特定问答模式-服务流程通俗来讲LoRA的策略是通过使用较小规模的矩阵来近似模拟大模型的原始矩阵。实现的方式是基于低秩分解的数学原理通过较少的参数更新实现对大模型复杂功能的有效捕捉和适配在减少计算资源消耗和提升微调效率的同时保持或甚至提升模型对特定任务的适应性和性能。…代码较长已省略输入序列 ↓ Linear投影层 ↓ Q、K、V矩阵变换 ↓ 注意力计算 ↓ O矩阵变换输出投影 ↓ 输出结果具体作用Q矩阵将输入转换为查询形式K矩阵将输入转换为可被查询的键V矩阵存储实际的信息内容O矩阵将注意力机制的输出转换为所需的表示在LoRA中的应用LoRA主要应用在这些权重矩阵的更新上对每个权重矩阵(Wq,Wk,Wv,Wo)都可以应用LoRA# 以Q为例 原始: Q input × Wq LoRA: Q input × (Wq BA) # B和A是低秩矩阵LoRA的选择性应用可以只对部分矩阵应用LoRA常见组合仅Q和VQ、K、V全部Q、K、V、O全部LORA 的作用在于ΔW\Delta WΔW$ W_0 Q \Delta W q$$ W_0 K \Delta W k$$ W_0 V \Delta W v$…代码较长已省略import numpy as np import torch import matplotlib.pyplot as plt # 1. 创建一个模拟的原始权重矩阵 def create_original_matrix(d512, k512): 创建一个模拟的原始权重矩阵 d: 输入维度 k: 输出维度 original_weight torch.randn(d, k) # 随机初始化一个权重矩阵 return original_weight # 2. 实现LoRA分解 class LoRALayer: def __init__(self, d, k, r): d: 输入维度 k: 输出维度 r: LoRA秩 (rank) self.d d self.k k self.r r # 初始化A和B矩阵 self.lora_A torch.randn(d, r) / np.sqrt(r) # 缩放初始化 self.lora_B torch.zeros(r, k) # B初始化为0 # 使其需要梯度 self.lora_A.requires_grad_(True) self.lora_B.requires_grad_(True) def forward(self, x): 前向传播 return (self.lora_A self.lora_B) x def get_weight_update(self): 获取权重更新矩阵 return self.lora_A self.lora_B # 3. 演示训练过程 def train_lora(original_weight, lora_layer, num_iterations1000): 训练LoRA来近似原始权重矩阵 Adam是一种优化器用于更新模型参数 [lora_layer.lora_A, lora_layer.lora_B]指定需要优化的参数 lr0.01是学习率控制每次更新的步长 优化器的作用是根据梯度更新A和B矩阵使得BA的乘积逐渐接近原始权重矩阵 optimizer torch.optim.Adam([lora_layer.lora_A, lora_layer.lora_B], lr0.01) losses [] for i in range(num_iterations): # 计算当前LoRA权重 current_weight lora_layer.get_weight_update() # 计算与原始权重的差异 # 计算当前LoRA权重与原始权重的差异 # 使用均方误差损失函数MSE来衡量差异 # 损失函数越小表示当前LoRA权重越接近原始权重 loss torch.nn.functional.mse_loss(current_weight, original_weight) # 反向传播 optimizer.zero_grad() # 清除之前的梯度 loss.backward() # 计算梯度 optimizer.step() # 根据梯度更新参数 if i % 100 0: losses.append(loss.item()) print(fIteration {i}, Loss: {loss.item():.6f}) return losses # 4. 可视化结果 # 修改可视化函数 def visualize_results(original_weight, lora_approximation, losses): plt.figure(figsize(15, 5)) # 绘制损失曲线 plt.subplot(131) plt.plot(losses) plt.title(Training Loss) plt.xlabel(Iterations (x100)) plt.ylabel(MSE Loss) # 绘制原始权重矩阵 plt.subplot(132) plt.imshow(original_weight.detach().numpy(), cmapviridis) plt.title(Original Weight Matrix) plt.colorbar() # 绘制LoRA近似后的矩阵 plt.subplot(133) plt.imshow(lora_approximation.detach().numpy(), cmapviridis) plt.title(LoRA Approximation) plt.colorbar() plt.tight_layout() plt.show() # 打印矩阵数值 print(\n原始权重矩阵的一部分(5x5):) print(original_weight.detach().numpy()[:5, :5]) print(\nLoRA近似后的矩阵的一部分(5x5):) print(lora_approximation.detach().numpy()[:5, :5]) # 计算误差矩阵 error_matrix original_weight.detach().numpy() - lora_approximation.detach().numpy() print(\n误差矩阵的一部分(5x5):) print(error_matrix[:5, :5]) # 计算一些统计指标 print(\n统计指标:) print(f最大误差: {np.abs(error_matrix).max():.6f}) print(f平均误差: {np.abs(error_matrix).mean():.6f}) print(f误差标准差: {np.abs(error_matrix).std():.6f}) # 计算相似度 from scipy.stats import pearsonr orig_flat original_weight.detach().numpy().flatten() lora_flat lora_approximation.detach().numpy().flatten() correlation, _ pearsonr(orig_flat, lora_flat) print(f矩阵相似度(相关系数): {correlation:.6f}) # 5. 主函数 def main(): # 设置维度 d, k 10, 10 # 使用较小的维度便于演示 r 2 # LoRA秩 # 创建原始权重 original_weight create_original_matrix(d, k) # 创建LoRA层 lora_layer LoRALayer(d, k, r) # 训练LoRA losses train_lora(original_weight, lora_layer) # 获取最终的LoRA近似 final_approximation lora_layer.get_weight_update() # 计算参数量的节省 original_params d * k lora_params r * (d k) reduction (1 - lora_params/original_params) * 100 print(f\n原始参数量: {original_params}) print(fLoRA参数量: {lora_params}) print(f参数减少: {reduction:.2f}%) # 可视化结果 visualize_results(original_weight, final_approximation, losses) if __name__ __main__: main()