Docs Appendix E: LoRA 微调
Appendix 状态:done

Appendix E: LoRA 微调

LoRA (Low-Rank Adaptation) 参数高效微调,用极少参数适配新任务

概述

LoRA (Low-Rank Adaptation) 是一种参数高效微调(PEFT)方法:

  • 冻结原模型所有参数
  • 在目标层旁边添加低秩分解矩阵 A 和 B
  • 只训练 A 和 B,参数量减少 90%+

核心思想

原始全连接层:

y = x @ W      # W: [d_in, d_out]

LoRA 改造后:

y = x @ W + (alpha/rank) * x @ A @ B
    ─────     ──────────────────────
    冻结的           LoRA 旁路
矩阵形状参数量训练?
W[d_in, d_out]d_in * d_out冻结
A[d_in, rank]d_in * rank训练
B[rank, d_out]rank * d_out训练

rank = 8, d_in = d_out = 768 时:

  • W: 589,824 参数
  • A + B: 12,288 参数(仅 2%)

初始化

A ← Kaiming 均匀初始化(随机)
B ← 全零初始化(关键!)

B 初始化为零确保训练开始时 A @ B = 0,LoRA 旁路不改变原模型输出。训练过程中 B 逐渐学习到有用的适配。


C# 实现

LoraLayer

// src/Shared/.../Nn/LoraLayer.cs
public class LoraLayer : Module
{
    Tensor _a;  // [inDim, rank] — Kaiming init
    Tensor _b;  // [rank, outDim] — Zero init

    Forward(x) => (alpha / rank) * MatMul(MatMul(x, A), B)
}

LinearWithLora

// src/Shared/.../Nn/LinearWithLora.cs
public class LinearWithLora : Module
{
    Linear _original;   // 冻结
    LoraLayer _lora;    // 可训练

    Forward(x) => original.Forward(x) + lora.Forward(x)
}

应用到模型

// src/Chapter06.Classification/.../LayerFreezer.cs

// 方式 1: 一键应用(替换所有注意力层的 Q/V)
LayerFreezer.ApplyLora(model, rank: 8, alpha: 16);

// 查看参数量变化
var (total, trainable) = LayerFreezer.CountParameters(model);
Console.WriteLine($"Total: {total}, Trainable: {trainable} ({100.0*trainable/total:F1}%)");

为什么只替换 Q 和 V?

原论文实验表明:

  • W_queryW_value 加 LoRA 效果最好
  • W_key 的影响较小
  • out_proj 也有一定效果,但增加参数量

本实现遵循原论文推荐,只在 Q 和 V 上加 LoRA。


文件索引

文件说明
Shared/.../Nn/LoraLayer.csLoRA 低秩分解层(A @ B 矩阵)
Shared/.../Nn/LinearWithLora.cs包装器: original + LoRA 旁路
Chapter06/.../LayerFreezer.csApplyLora() + CountParameters()