当前位置: 首页 > article >正文

如何在神经网络模型中通过低秩矩阵调整权重,并只训练少量参数

这段代码展示了 LoRA(Low-Rank Adaptation) 的应用,如何在神经网络模型中通过低秩矩阵调整权重,并只训练少量参数。接下来我会详细解释代码中的关键部分,帮助你理解其工作原理。


🔍 1️⃣ 原始模型 BaseModel

class BaseModel(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(BaseModel, self).__init__()
        self.fc1 = nn.Linear(input_size, hidden_size)
        self.fc2 = nn.Linear(hidden_size, output_size)

    def forward(self, x):
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        return x
  • fc1 输入层到隐藏层的线性变换。
  • fc2 隐藏层到输出层的线性变换。
  • F.relu() ReLU 激活函数,增加模型的非线性能力。

这是一个简单的两层全连接神经网络。


2️⃣ LoRA 模块

class LoRA(nn.Module):
    def __init__(self, original_layer, rank=8, alpha=16):
        super(LoRA, self).__init__()
        self.original_layer = original_layer  # 原始全连接层
        self.rank = rank
        self.scaling = alpha / rank
关键参数解释:
  • original_layer 需要调整的原始全连接层(这里是 fc1)。
  • rank 低秩矩阵的秩(维度),控制参数量的压缩程度。
  • alpha 缩放因子,用于平衡 LoRA 影响力,最终缩放系数为 alpha / rank

📐 3️⃣ 低秩矩阵 A 和 B

        # 低秩矩阵 A 和 B
        self.A = nn.Linear(original_layer.in_features, rank, bias=False)  # 降维
        self.B = nn.Linear(rank, original_layer.out_features, bias=False) # 升维
  • A(降维矩阵):

    • 输入维度 → rank 维度,起到信息压缩的作用。
    • 类似于 Adapter 中的降维层。
  • B(升维矩阵):

    • rank 维度 → 输出维度,将压缩后的信息重新扩展。
    • 类似于 Adapter 中的升维层。

这种设计可以有效减少可训练参数的数量。


🚀 4️⃣ 初始化与冻结参数

        # 初始化 A 和 B
        nn.init.kaiming_uniform_(self.A.weight, a=0.01)  # 初始化 A,适用于 ReLU 激活
        nn.init.zeros_(self.B.weight)                    # 初始化 B 为 0

        # 冻结原始层参数
        for param in self.original_layer.parameters():
            param.requires_grad = False
  • 初始化策略:

    • A 的权重 使用 Kaiming 初始化,适合 ReLU 激活函数。
    • B 的权重 初始化为全零,确保初始时不对模型产生影响,后续通过训练逐渐调整。
  • 冻结原始参数:

    • 设置 requires_grad = False,意味着原始层的权重在训练时不会更新,只训练 LoRA 的参数。

🔄 5️⃣ LoRA 前向传播

    def forward(self, x):
        return self.original_layer(x) + self.scaling * self.B(self.A(x))
公式解释:

[
\text{Output} = W x + \alpha \cdot BAx
]
在这里插入图片描述

  • original_layer(x) 代表原始模型的输出 ( W x )。
  • B(A(x)) 通过低秩矩阵 ( A ) 和 ( B ) 进行调整的部分。
  • self.scaling 控制调整部分的影响力。

这种设计确保了模型在初始状态下性能不受影响,训练时逐渐调整。


🔗 6️⃣ 替换 fc1 层,应用 LoRA

class ModelWithLoRA(BaseModel):
    def __init__(self, input_size, hidden_size, output_size):
        super(ModelWithLoRA, self).__init__(input_size, hidden_size, output_size)
        self.fc1 = LoRA(self.fc1, rank=4)  # 低秩矩阵替换 fc1
  • 将原始模型中的 fc1 层替换为 LoRA 模块。
  • 这样,fc1 的权重不再直接更新,而是通过 LoRA 的调整来间接影响。

⚙️ 7️⃣ 训练设置

# 只训练 LoRA 的 A 和 B
optimizer = torch.optim.Adam(
    list(model.fc1.A.parameters()) + list(model.fc1.B.parameters()), 
    lr=0.001
)
  • 只训练 A 和 B:
    • 优化器只更新 LoRA 模块的参数,原始模型的参数保持不变。
    • 这可以显著减少训练所需的计算资源。

🎯 Adapter vs LoRA 对比总结

特点AdapterLoRA
结构降维 → 激活 → 升维 + 残差低秩矩阵分解(A: 降维,B: 升维) + 残差
目的在不改变主模型的基础上,增加微调能力高效调整原始权重,减少参数更新量
参数量少量增加参数更少参数,尤其适用于大模型
适用场景各类微调场景超大模型(如大语言模型)微调,效果更佳
初始化正常随机初始化B 初始化为 0,初始时不影响模型输出

http://www.kler.cn/a/534836.html

相关文章:

  • 2.Mkdocs配置说明(mkdocs.yml)【最新版】
  • new Integer(“127“) 和Integer.valueOf(“128“)
  • Spring 核心技术解析【纯干货版】- IX:Spring 数据访问模块 Spring-Jdbc 模块精讲
  • DeepSeek R1技术报告关键解析(8/10):DeepSeek-R1 的“aha 时刻”,AI 自主学习的新突破
  • 【技海登峰】Kafka漫谈系列(二)Kafka高可用副本的数据同步与选主机制
  • Immutable设计 SimpleDateFormat DateTimeFormatter
  • 蓝桥杯C语言组:进制与整除问题
  • npm-npm ERR! missing script: serve
  • 深入探索 C++ 类型转换的奥秘
  • Conmi的正确答案——Rider中添加icon作为exe的图标
  • 使用java代码操作rabbitMQ收发消息
  • 管理etcd的存储空间配额
  • 汇编JCC条件跳转指令记忆
  • langchain教程-11.RAG管道/多轮对话RAG
  • DeepSeek让 Obsidian 更强大:Text generator与 Copilot 使用指南
  • 【LeetCode: 1004. 最大连续1的个数 III + 滑动窗口】
  • ?和.和*在正则表达式里面的区别
  • 探索进制转换的奥秘/西瓜杯
  • fast-lio代码解析(二)
  • PE/西瓜杯
  • Linux 环境安装 Elasticsearch 8
  • 每日一题——最小的K个数
  • 【蓝桥杯嵌入式】4_key:单击+长按+双击
  • 排序时间的复杂度和稳定性
  • 汽车免拆诊断案例 | 2015款奔驰R320车行驶中偶尔多个故障灯异常点亮
  • 游戏引擎学习第88天