【Bug已解决】Add BoRA to PEFT 解决方案一、现象长什么样社区提议把BoRABottleneck Rank Adaptation瓶颈秩适配加进 PEFT。BoRA 是 LoRA 的一个变体在标准 LoRA 的B·A·x之外再引入一个共享瓶颈来进一步压缩可训练参数、提升跨层一致性。但要把一个新方法接进 PEFT 时使用者会遇到和之前“Add PSOFT”类似的工程问题没有统一的BoRAConfig/BoRAModel/mapping注册自己改写forward容易和 PEFT 的merge_and_unload/load_adapter/print_trainable_parameters冲突BoRA 的“瓶颈”结构共享投影若实现成额外 Module保存时键名和 PEFT 约定不一致跨模型load错配想和 LoRA 组合同一模型一部分层用 LoRA、一部分用 BoRA时发现 PEFT 没有对应扩展点复用save_pretrained时瓶颈参数没有统一的adapter_config.json描述。所以“Add BoRA to PEFT”本质是集成方法论如何按 PEFT 扩展规范把 BoRA 接成一等公民且能与现有方法组合、可被get_peft_model管理。二、背景BoRA 的核心思想以 Bottleneck Rank Adaptation 的通用形式标准 LoRA 是Δ B·A·x其中A ∈ ℝ^{r×in}、B ∈ ℝ^{out×r}。BoRA 在此基础上引入一个跨层共享的瓶颈投影P ∈ ℝ^{r×s}s r把每层的A写成A P·a_layera_layer ∈ ℝ^{s×in}是每层独有的小矩阵于是每层只需训a_layer远小于完整A瓶颈P在所有层间共享Δ B · (P · a_layer) · x好处每层可训练参数从r·in out·r降到s·in out·r r·s共享P只算一次且共享瓶颈起到跨层正则作用缓解过拟合。PEFT 扩展规范回顾仍是三件套BoRAConfig(PeftConfig)超参r、s、alpha、target_modules。BoRAModel(BaseTuner)持有基座 每层a_layer 共享P重写forward。mapping.py注册PEFT_TYPE_TO_MODEL_MAPPING[PeftType.BORA] BoRAModel。下面用可运行代码给出自包含的 BoRA 实现结构对齐 PEFT 规范以及一个把它接到 PEFT 风格的骨架。三、根因这里的“问题”是集成规范缺失导致的重复造轮子三件套不全每个用户自己改forward无法复用 PEFT 生态。瓶颈参数键名不统一跨模型save/load错配。无法与 LoRA 组合缺扩展点。修复方向按 PEFT 规范实现BoRAConfigBoRAModelmapping注册让 BoRA 成为可管理的一等公民且能用add_adapter与 LoRA 并存。四、最小可运行复现下面给一个自包含的 BoRA 实现共享瓶颈P 每层a_layerB离线可验证数学正确。import torch import torch.nn as nn class BoRAConfig: def __init__(self, r8, s2, alpha16, target_modules(fc1,)): self.r, self.s, self.alpha r, s, alpha self.target_modules target_modules class BoRALayer(nn.Module): 单层 BoRAΔ B · (P · a) · xP 共享、a/B 本层独有。 def __init__(self, in_f, out_f, r, s): super().__init__() self.a nn.Parameter(torch.randn(s, in_f) * 0.01) # 每层独有 [s, in] self.B nn.Parameter(torch.zeros(out_f, r)) # 每层独有 [out, r] # 共享瓶颈 P 作为 buffer所有 BoRALayer 共享同一份 self.register_buffer(P, torch.randn(r, s) * 0.01) def forward(self, x, P): # a: [s, in] - Pa: [r, in] - (Pa)x.T: [r, T] - B: [out, T] A_eff P self.a # [r, in] delta (self.B (A_eff x.T)).T # [T, out] return delta class BoRANet(nn.Module): def __init__(self, in_f, out_f, r, s, n_layers): super().__init__() self.P nn.Parameter(torch.randn(r, s) * 0.01) # 共享瓶颈 self.blocks nn.ModuleList() self.base nn.ModuleList([nn.Linear(in_f, out_f) for _ in range(n_layers)]) for _ in range(n_layers): self.blocks.append(BoRALayer(in_f, out_f, r, s)) def forward(self, x): out x for i, blk in enumerate(self.blocks): out self.base[i](out) blk(out, self.P) # 基座 BoRA 增量 return out torch.manual_seed(0) net BoRANet(16, 16, r8, s2, n_layers3) x torch.randn(2, 16) out net(x) # 训练参数共享 P(r*s) 每层 (a: s*in B: out*r) per_layer 2 * 16 16 * 8 total 8 * 2 3 * per_layer tr sum(p.numel() for p in net.parameters() if p.requires_grad) print(输出形状:, tuple(out.shape)) print(实际可训练:, tr, 理论:, total, 一致:, tr total)运行后输出形状正确可训练参数 共享P(8*2) 每层a(2*16)B(16*8)且requires_gradTrue仅限这些——验证了 BoRA 的核心结构与参数节省。五、解决方案第一层最小直接修复修复 1共享瓶颈 P 用 buffer 或 Module 级参数如BoRALayer.register_buffer(P, ...)或放在BoRANet.P确保所有层引用同一份避免重复存、重复训。修复 2冻结基座只训 a / B / Pfor p in net.base.parameters(): p.requires_grad_(False) # a/B/P 保持 requires_grad修复 3键名统一便于 save/load# 每层 a/B 键名: boralayer.{i}.a.weight / boralayer.{i}.B.weight # 共享 P: boralayer.shared_P.weight六、解决方案第二层结构性改进改进 1按 PEFT 规范写 BoRAConfig BoRAModelfrom peft import PeftConfig, PeftType class BoRAConfig(PeftConfig): def __init__(self, r8, s2, alpha16, **kwargs): super().__init__(peft_typePeftType.BORA, **kwargs) self.r, self.s, self.alpha r, s, alpha from peft.tuners import BaseTuner class BoRAModel(BaseTuner): def __init__(self, model, config, adapter_namedefault): super().__init__(model, config, adapter_name) # 注入 BoRALayer、持有共享 P、重写 forward def forward(self, *a, **k): return self.model(*a, **k) # 内部各层调用 BoRALayer改进 2mapping 注册from .bora import BoRAModel PEFT_TYPE_TO_MODEL_MAPPING[PeftType.BORA] BoRAModel改进 3与 LoRA 组合model get_peft_model(base, LoraConfig(r8, target_modules[q_proj])) model.add_adapter(bo1, BoRAConfig(r8, s2, target_modules[v_proj])) model.set_adapter([default, bo1])七、解决方案第三层断言 / CI 守护import torch import torch.nn as nn import pytest class BoRALayer(nn.Module): def __init__(self, in_f, out_f, r, s): super().__init__() self.a nn.Parameter(torch.randn(s, in_f) * 0.01) self.B nn.Parameter(torch.zeros(out_f, r)) self.register_buffer(P, torch.randn(r, s) * 0.01) def forward(self, x, P): return (self.B ((P self.a) x.T)).T def test_bora_delta_shape(): torch.manual_seed(0) layer BoRALayer(16, 16, 8, 2) P torch.randn(8, 2) * 0.01 d layer(torch.randn(2, 16), P) assert d.shape (2, 16) def test_shared_bottleneck_used(): layer BoRALayer(16, 16, 8, 2) assert hasattr(layer, P) and layer.P.shape (8, 2) def test_only_a_B_trainable(): torch.manual_seed(1) base nn.Linear(16, 16) layer BoRALayer(16, 16, 8, 2) for p in base.parameters(): p.requires_grad_(False) tr sum(p.numel() for p in [base, layer] if p.requires_grad) assert tr (2*16 16*8) # 仅 a B def test_bora_adds_to_base(): torch.manual_seed(2) base nn.Linear(16, 16) layer BoRALayer(16, 16, 8, 2) x torch.randn(2, 16) out base(x) layer(x, torch.randn(8, 2)*0.01) base_only base(x) assert not torch.allclose(out, base_only)这四个测试守护“BoRA 增量形状、共享瓶颈存在、仅 a/B 可训练、增量叠加到基座”。八、排查清单把 BoRA 接进 PEFT 时按序查三件套齐全BoRAConfigBoRAModelmapping注册。共享瓶颈 P 唯一用 buffer 或模型级参数所有层引用同一份。基座冻结只训a/B/P。键名统一boralayer.{i}.a/Bshared_P便于 save/load。复用生态接好即可print_trainable_parameters/save_pretrained/load_adapter。与 LoRA 组合用add_adapterset_adapter。参数计数核对total r*s n_layers*(s*in out*r)。测试守护增量形状、共享瓶颈、可训练参数、叠加基座。九、小结Add BoRA to PEFT的本质不是代码崩溃而是集成规范缺失用户各自改写forward、瓶颈参数键名不统一、无法与 LoRA 组合、不能复用 PEFT 生态。最小修复是实现自包含 BoRA每层a/B 共享瓶颈P、冻结基座、键名统一结构性改进是按 PEFT 规范写BoRAConfigBoRAModelmapping注册让 BoRA 成为一等公民并能与 LoRA 组合最后用测试守护“增量形状正确、共享瓶颈存在、仅 a/B 可训练、增量叠加基座”。这样 BoRA 就能像其它 PEFT 方法一样被get_peft_model统一管理。
企业数字化 ERP 产品动态
相关推荐
C++20 Ranges在科学计算中的实战:从向量处理到网格数据分析 1. 项目概述:当科学计算遇上C20 Ranges 如果你写过科学计算相关的C代码,无论是物理仿真、金融建模还是数据处理,大概率经历过这样的场景:为了处理一个向量或矩阵,你写下了层层嵌套的 for 循环,里面塞满了… · 2026/10/20 15:18:01
AI在海鲜电商文案生成中的实践与优化 1. 项目背景与核心价值去年帮一家海鲜电商做内容运营时,发现他们每天要生产200条虾类产品的营销文案,团队6个文案写到头秃还是跟不上进度。这促使我开始思考:在高度垂直的农产品领域,能否用AI实现精准的内容自动化生产?… · 2026/10/20 11:27:46
AI时代论文降重四步法:语义重组与AIGC特征消除实战 1. 项目背景与核心痛点去年帮学弟修改毕业论文时,发现现在的查重系统已经进化到能识别AI生成内容(AIGC)了。当时用传统降重方法处理过的段落,在知网最新检测中依然被标红,这才意识到:高校查重系统已经进入&… · 2026/10/21 15:44:47
桃源县建筑电工证多久拿证 外省证能不能转过来 桃源县建筑电工证多久拿证 外省证能不能转过来 之前考的证在外省能不能转过来?这是很多人在考虑考取桃源县建筑电工证前最关心的问题。如果你也面临这个疑问,恭喜你,这篇文章正好为你解决这个痛点,告诉你桃源县建筑电工证多久拿证,以及如何顺利办理、转… · 2026/11/13 13:14:51
厂里电工证查询外省证怎么转 含金量到底值不值 厂里电工证查询外省证怎么转 含金量到底值不值 之前考的证在外省能不能转过来?这几乎是所有在外地打工、换过几次工作的电工都会问的问题。特别是在洛阳涧西区这种工业集中、水利工程项目多的区域,很多电工都是从老家或外地考的证,到了新单位后才发现… · 2026/11/13 13:14:51
忠县考电工证地址在哪里?通过率揭秘来了 忠县考电工证地址在哪里?通过率揭秘来了 你是不是正愁不知道去哪报名考电工证,又怕被中介坑?现在市面上培训机构五花八门,真假难辨,很多人花了钱还没拿到证,或者拿到了也不符合要求,耽误了上岗和就业。今天就来聊聊 忠县考电工证地址… · 2026/11/13 13:14:51
考电工证多久出结果 郑州报考避坑指南 考电工证多久出结果 郑州报考避坑指南 你是不是也担心学历不高报不了电工证?别急,我来告诉你怎么走,不走弯路,不花冤枉钱。 考电工证多久出结果这个问题,很多人在报考前都问过,结果要么等到报名截止才发现来不及,要么交了钱又被告知不符合条件。其实… · 2026/11/13 13:13:51
电工证丢失还能补吗?千万别踩坑,丢了证等于失业 电工证丢失还能补吗?千万别踩坑,丢了证等于失业 你正在找工作,但手里的电工证突然丢了,这下怎么办?别急,先别慌, 电工证丢失还能补吗 ?答案是肯定的,但 千万别踩坑 ,补办流程如果不了解,可能会耽误你上岗、甚至影响到你的收入。… · 2026/11/12 14:09:01
电力电缆作业证直播报名入口与办理流程良心建议 电力电缆作业证直播报名入口与办理流程良心建议 你是不是也担心学历不高报不了名?别急,今天就给你讲讲 电力电缆作业证直播 的报名流程和那些你必须知道的干货, 良心建议 在这里,别错过。 电力电缆作业证直播报名需要什么条件?… · 2026/11/13 5:40:45
英德电工证报考费多少钱,怕考不过白交培训费?看完这篇别再踩坑 英德电工证报考费多少钱,怕考不过白交培训费?看完这篇别再踩坑 怕考不过白交培训费?英德电工证报考费多少钱,你真的了解吗?现在市面上培训机构五花八门,价格参差不齐,很多人一不小心就花了冤枉钱,结果还考不过。别急,今天就来给你说清楚英德电工证的… · 2026/11/12 23:27:43
维修电公用考电工证吗 在哪考最靠谱 维修电公用考电工证吗 在哪考最靠谱 工地太忙根本没时间复习考试,你是维修电工,天天在项目上跑,连抽个空背个题都难。那问题来了—— 维修电公用考电工证吗 ?答案是: 必须考 。尤其是在当前施工行业,没有电工证,连进场都可能被拦下。而且,… · 2026/11/13 0:00:08
电工证是不是可以登高?含金量和证书范围你必须知道的事 电工证是不是可以登高?含金量和证书范围你必须知道的事 证书过期了不知道怎么复审延期,这事儿很多人遇到过,尤其是像你这样在郑州金水区做劳务班组负责人,手里握着几十个工人的证书,稍微一疏忽,就可能影响工程进度和公司信誉。特别是电工证是不是可以登… · 2026/11/13 0:00:08
鸡西电工证哪家下证快官方报名入口怎么找 鸡西电工证哪家下证快官方报名入口怎么找 你是不是也担心 学历不高怕报不上名 ?别急,今天我就来跟你说说, 鸡西电工证哪家下证快 ,还有 官方报名入口 到底怎么找,别让那些“代办”“代考”耽误了你的机会。… · 2026/11/13 0:00:08
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/13 6:12:21
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/13 6:11:51
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/12 21:15:21