Skip to content

Fine-tuning

Fine-tuning (微调)

  • SFT (Supervised Fine-Tuning): 传统的微调,给数据对。
  • PEFT (LoRA, Adapter): 怎么省钱地微调。
  • Alignment (对齐技术):
    • RLHF: 用强化学习微调(ChatGPT的核心)。
    • DPO (Direct Preference Optimization): 最近很火的去掉了强化学习的简化版 RLHF。

迁移学习

迁移学习的核心思想是:将一个任务(源领域)中学到的知识,应用到另一个相关任务(目标领域)中。 迁移学习通常通过如下方式进行:

  • 预训练(Pre-training):在大规模数据集上训练一个通用模型
  • 微调(Fine-tuning):更新模型的全部或者部分参数
  • Zero-Shot / Few-shot Learning
  • Domain Adaptation,领域自适应,处理源数据和目标数据“分布不同”的问题。例如:用合成照片训练的模型,迁移到现实世界的照片中。

迁移学习适用于几乎所有的深度学习架构:

架构类型 迁移的具体对象 典型应用
CNN (视觉) 卷积核(提取边缘、形状、纹理的过滤器) 医学影像识别、自动驾驶物体检测
Transformer (NLP) 注意力机制权重、语言表征能力 翻译、情感分析、代码生成、法律文档理解
RNN (序列) 隐藏状态的时间序列逻辑 语音识别、股票预测微调
GNN (图神经网络) 节点和边的结构特征嵌入 药物分子发现、社交网络推荐

迁移学习是现代AI的基石,因为数据是稀缺的、算力是昂贵的、预训练模型的泛化能力是更强大的。

全量微调

假设预训练模型参数为 \(\Theta\),我们将网络分为两部分:

  • \(\theta_{backbone}\) :特征提取部分(如 ResNet 的卷积层)。
  • \(\theta_{head}\) :分类输出部分(最后的全连接层)。

全量微调 (Full Fine-tuning)将整个模型的预训练权重作为初始值,并在新任务上更新所有参数:

\[ \theta_{t+1} = \theta_t - \eta \cdot \nabla_{\theta} L(\theta_t) \]

(注:这里 \(\theta = \{\theta_{backbone}, \theta_{head}\}\),所有参数都参与梯度 \(\nabla\) 的计算)

底层逻辑 :认为源领域和目标领域存在较大差异,或者数据量足够大,允许模型“全身心”改变以适配新任务。

后端微调

后端微调 (Partial Fine-tuning)认为底层特征(边缘、纹理)是通用的,只需微调靠近输出的高层语义特征。

更新公式

\[ \begin{cases} \theta_{low} = \text{Constant} & (\text{冻结底层}) \\ \theta_{high, t+1} = \theta_{high, t} - \eta \cdot \nabla_{\theta_{high}} L & (\text{更新高层}) \end{cases} \]

底层逻辑 :通过设置 \(\frac{\partial L}{\partial \theta_{low}} = 0\)(手动阻断梯度流),强制保留通用特征提取能力,减少训练开销。

差分学习率微调

差分学习率微调 (Differential Learning Rates)对不同层应用不同的学习步长 \(\eta\)。通常:\(\eta_{backbone} \ll \eta_{head}\)

更新公式

\[ \begin{cases} \theta_{backbone, t+1} = \theta_{backbone, t} - \eta_{small} \cdot \nabla_{\theta_{backbone}} L \\ \theta_{head, t+1} = \theta_{head, t} - \eta_{large} \cdot \nabla_{\theta_{head}} L \end{cases} \]

底层逻辑 :这是一种加权信任机制。我们极度信任基座已有的知识(所以改得极慢),同时允许新加的输出层快速适应新类别。

固定特征提取器

固定特征提取器 (Fixed Feature Extractor)完全不改变预训练层的权重,仅将模型视作一个“黑盒”转换器,只训练新接的分类头。

更新公式

\[ \begin{cases} \theta_{backbone} = \Theta_{pretrained} & (\text{完全不更新}) \\ \theta_{head, t+1} = \theta_{head, t} - \eta \cdot \nabla_{\theta_{head}} L & (\text{仅训练随机初始化的层}) \end{cases} \]

底层逻辑 :在 PyTorch 中通过 param.requires_grad = False 实现。此时,计算图在反向传播时到分类头截止,不再向后传播梯度,计算效率最高。

LLM PEFT

LLM PEFT指的是2026年主流的LLM的高效微调(Parameter-Efficient Fine-Tuning, PEFT)。

大多数开发不再从零开始,而是基于现有模型进行:

  1. 预训练(Pretraining - 学生阶段): 学习通用语法和常识,具备预测下一个词的能力。
  2. 指令微调(SFT - 专家阶段): 让模型学会“听从指令”,通过问答对训练使其适应特定领域(如电子工程)。
  3. 对齐(Alignment - 抛光阶段): 使用 RLHF 等技术使回复更安全、更有用、更符合人类偏好。

技术工具栈

PEFT的技术栈和工具包括:

  • 硬件层:CUDA,NVIDIA提供的引擎,可以将python代码翻译为GPU运算指令,并经过GPU完成矩阵乘法等深度学习计算任务。
  • 计算引擎:PyTorch,当下主流的深度学习框架,可以自动求导等。
  • 优化层:Unsloth,一个专门为 LoRA(低秩自适应) 优化的加速库。它通过手写更高效的数学算子,让显存占用降低 70% 以上,速度提升 2-3 倍。它让在普通消费级显卡(如 RTX 4090)上微调 7B 甚至 70B 模型成为可能。
  • 管理层:Hugging Face Transformers: 它提供了一个统一的接口,无论你想用 Meta 的 Llama、Google 的 Gemma 还是阿里的 Qwen,代码几乎是一样的。
  • Hugging Face Datasets: 提供了标准化的数据加载方式。不管你的原始数据是 JSON 还是 CSV,它都能快速转化成模型需要的格式。
  • Python/Jupyter Notebook: 应用层。

训练流程

计算机无法理解文字,只能处理数字。因此,分词(Tokenization) 成为首要步骤,它通过算法将句子拆解为名为“Token”的最小单元(如将 "Learning" 拆分为 "Learn" 与 "ing"),并为每个单元分配唯一的数字 ID。不同模型的分词效率直接影响其对长文本的处理能力。

在训练阶段,损失函数(Loss) 充当了衡量模型表现的“标尺”。它利用数学公式计算预测结果与标准答案之间的差距。如果模型预测离谱(如将“电阻单位”预测为“香蕉”),Loss 就会大幅上升。训练的核心目标就是通过梯度下降算法,不断调整参数以最小化 Loss,使预测趋于准确。

当模型完成学习并投入使用时,这一过程称为 推理(Inference) 。与训练不同,推理无需更新参数或计算梯度,因此对计算资源和显存的需求更低。

为了让庞大的模型能在普通硬件甚至移动设备上运行,量化(Quantization) 技术至关重要。它将模型原有的高精度参数(如 16 位浮点数)压缩至 4 位甚至更低。虽然这会带来极微小的精度损失,但能显著降低显存占用,使原本需要高端显卡支持的大模型得以在平价硬件上流畅运行。

LoRA

LoRALow-Rank Adaptation 的缩写。

  • Low-Rank (低秩):这是数学概念。指的是我们不需要更新模型那个巨大的、全功率的矩阵,而是将其简化为两个“窄”矩阵(Rank \(r\) 很小)。
  • Adaptation (适配/微调):指的是它的用途。它不是为了从头训练一个模型,而是为了让已经训练好的模型去“适配”特定的新任务或新风格。

我们都很清楚,在深度学习中,模型其实就是一堆巨大的 权重矩阵 (Matrix)。当你训练一个大模型时,传统的微调(Fine-tuning)需要更新这些矩阵里的每一个数字。然而,现在的模型太大了。比如 Llama 3 70B,哪怕只是更新 1% 的参数,普通显卡也根本跑不动(因为训练时需要储存每个参数的“梯度”和“动量”,显存消耗是参数本身的数倍)。

人们很快发现,为了让模型学会一个新技能(比如学会写诗或写代码),其实并不需要改变所有的参数方向。模型修改的实质是低秩(Low-Rank)的。比如说,虽然模型有 1 万个维度,但真正起作用的可能只有那 8 个核心维度。LoRA 就是只去捕捉这核心的 8 个维度,而不去碰剩下的 9992 个。

数学原理

假设模型中有一个原始的权重矩阵 \(W_0\),它的维度是 \(d \times k\)。你要计算一个新的 \(\Delta W\)(权重变化量),然后得到训练后的权重 \(W = W_0 + \Delta W\)。这里 \(\Delta W\) 的大小和 \(W_0\) 一模一样。如果 \(W_0\)\(4096 \times 4096\),那么 \(\Delta W\) 也有 1600 万个参数

LoRA 假设这个 \(\Delta W\) 可以被分解为两个极小的矩阵相乘:

\[ \Delta W = A \times B \]

其中:

  • 矩阵 A 的维度是 \(d \times r\)
  • 矩阵 B 的维度是 \(r \times k\)

这个 \(r\) 就是所谓的 LoRA Rank(秩)。


例如,假设 \(d=4096, k=4096\),我们取 \(r=8\)

  • 传统微调: 参数量 \(= 4096 \times 4096 = 16,777,216\)
  • LoRA: 参数量 \(= (4096 \times 8) + (8 \times 4096) = 65,536\)

如果你把 \(r\) 从 8 增加到 64 甚至更高,显存占用增加 (Training Overhead 增加)是最直接的变化。\(r\) 越大,矩阵 \(A\)\(B\) 就越宽,包含的参数就越多。

  • 你需要更多的显存来存储这些参数的 梯度(Gradients)优化器状态(Optimizer States)
  • 如果你在 24GB 的卡上跑,原本 \(r=8\) 能跑,调到 \(r=256\) 可能就直接提示 OOM (Out of Memory) 了。

\(r\) 越高,意味着 \(\Delta W\) 能够捕捉到的细节越多。如果你的任务非常复杂(比如让模型学习一种完全不同的新语言),高 \(r\) 会更有帮助。如果任务简单(比如只是调整一下说话语气),低 \(r\) 就足够了。

\(r\) 越高,训练时间越长。虽然 LoRA 很快,但参数量翻倍后,GPU 每一轮计算所需的浮点运算次数(FLOPs)也会随之增加,训练会变慢。

\(r\) 越高,过拟合风险越大:这像是在一张小纸条上写不下太多东西,所以你只能记重点(泛化性好);但如果给你一块巨大的黑板(高 \(r\)),你可能会把训练集里一些没意义的噪声也背下来,导致模型在实际使用时变笨(过拟合)。

r的选择

\(r\) 增加时,LoRA 矩阵 \(A\)\(B\) 的参数量变多,导致上述的梯度和优化器状态占用的空间也随之增大。不过,即使你把 \(r\) 开到 128 或 256,其显存占用通常依然比 Full Parameter Tuning(全参数微调) 低得多。因为全参数微调是针对每一个原始参数都要存梯度和优化器状态,而 LoRA 只针对那两个窄窄的矩阵。

虽然 LoRA 效果很好且省钱,但在以下三种核心场景下,全参数微调(即你图中 Scenario A 那种模式)依然是不可替代的:

  1. 注入全新的、大量的垂直领域知识
  2. 改变模型的输出格式或任务范式
  3. 数据量极大且算力极其充足

评论 #