Skip to main content

微调

LLM 微调 (Fine-tuning): 概述

在预训练阶段,大语言模型(LLM)通过在海量通用文本数据上进行训练,学习到了广泛的语言知识、语法结构、世界常识以及一定的推理能力。然而,这些预训练模型是“通才”,它们并不针对任何特定的下游任务或特定的行为模式进行优化。

微调 (Fine-tuning) 的核心目标是:在预训练模型的基础上,使用特定任务或领域的数据集进行进一步训练,从而使模型能够更好地适应这些特定需求,表现出期望的行为或在特定任务上达到更高的性能。

可以把预训练模型想象成一个已经完成了大学通识教育的学生,而微调则像是针对特定专业方向进行的深造或职业培训。

微调的类型与目标

根据在微调过程中更新模型参数的范围和方式,主要可以将微调分为两大类:

  1. 全参数微调 (Full Fine-tuning): 更新模型的所有参数。
  2. 参数高效微调 (Parameter-Efficient Fine-Tuning, PEFT): 只更新模型中一小部分参数,或者增加少量新的可训练模块,而保持大部分预训练参数冻结。

让我们详细探讨这两种类型:


1. 全参数微调 (Full Fine-tuning)

  • 核心思想: 在微调过程中,预训练模型的所有权重(包括词嵌入层、Transformer 层中的注意力权重和前馈网络权重等)都会参与梯度计算和参数更新。

  • 如何操作:

    1. 加载预训练模型: 获取一个已经预训练好的 LLM (例如,从 Hugging Face Hub 加载一个 BERT, GPT, Llama 模型)。
    2. 准备特定任务的数据集: 针对你想要解决的下游任务(如情感分析、文本摘要、问答、代码生成等),准备一个标注好的数据集。
    3. (可选) 修改模型头部: 对于某些任务(尤其是分类任务或序列标注任务),可能需要在预训练模型的顶部添加一个新的、特定于任务的层(称为“头部”,Head)。例如,在 BERT 模型之上添加一个线性分类层来进行情感分析。对于生成式任务,通常不需要修改头部,直接用模型的语言模型头部进行生成。
    4. 训练: 使用特定任务的数据集,以较小的学习率继续训练整个模型(包括预训练部分和新添加的头部)。损失函数根据具体任务定义(如交叉熵损失)。
  • 优点:

    • 潜力巨大: 由于所有参数都参与训练,模型有最大的自由度去适应新的数据和任务,理论上可以达到最佳的性能。
    • 概念简单: 比较直观,就是继续训练。
  • 缺点:

    • 计算成本高:
      • 训练时间长: 更新所有参数需要大量的计算资源 (GPU/TPU 时间)。
      • 显存占用大: 需要存储所有参数的梯度和优化器状态(例如 Adam 优化器会为每个参数存储其一阶和二阶矩估计,这会使得显存占用约为模型参数量的 3-4 倍,如果使用混合精度可能更多)。对于大型 LLM (数十亿甚至上百亿参数),即使是微调,单张 GPU 的显存也可能无法承受。
    • 存储成本高: 如果你需要为多个不同的任务微调同一个基础模型,每个任务都需要存储一份完整的、经过微调的模型副本。这对于拥有大量参数的 LLM 来说,存储开销非常巨大。
    • 灾难性遗忘 (Catastrophic Forgetting): 当模型在一个新任务上进行全参数微调时,它可能会“忘记”在预训练阶段学到的一些通用知识,或者在之前微调过的其他任务上的能力。这是因为所有参数都在向新任务的目标优化。
    • 部署复杂性: 为每个任务维护和部署一个完整的模型副本,管理和更新会比较麻烦。
  • 适用场景:

    • 当计算资源充足,且追求在特定任务上达到极致性能时。
    • 当目标任务与预训练任务差异较大,需要模型进行大幅度调整时。
    • 当模型规模相对较小,全参数微调的成本尚可接受时。

2. 参数高效微调 (Parameter-Efficient Fine-Tuning, PEFT)

  • 核心思想: 保持预训练 LLM 的绝大部分(甚至全部)参数冻结不变,只引入和训练一小部分新的参数,或者只微调模型中已有的一小部分参数。

  • 目标/动机:

    • 降低计算成本: 由于只训练少量参数,训练所需的计算资源和时间显著减少。梯度计算和优化器状态的存储需求也大大降低,使得在单张消费级 GPU 上微调大型 LLM 成为可能。
    • 减少存储成本: 对于每个特定任务,只需要存储那一小部分被修改或新增的参数,而不是整个模型的副本。基础的预训练模型可以被多个任务共享。例如,一个 7B 参数的模型,其 PEFT 模块可能只有几 MB 到几十 MB。
    • 缓解灾难性遗忘: 由于大部分预训练参数被冻结,模型在预训练阶段学到的通用知识和能力能够得到更好的保留,从而减少在适应新任务时对原有能力的损害。
    • 更容易管理多个任务的模型: 可以为每个任务训练一个轻量级的 PEFT 模块,在推理时根据任务加载对应的模块到共享的基础模型上。
    • 提高数据效率: 有研究表明,在数据量较少的情况下,PEFT 方法有时能比全参数微调取得更好的效果,因为它们限制了模型的自由度,减少了过拟合的风险。
  • 常见的 PEFT 方法 (我们后续会逐个详细学习):

    • Adapter Tuning: 在 Transformer 层的固定预训练参数之间插入小型可训练的 "Adapter" 模块。
    • Prefix Tuning: 在输入序列的嵌入层前添加可学习的连续向量前缀。
    • Prompt Tuning (Soft Prompts): 类似 Prefix Tuning,但通常更轻量,只在输入嵌入前添加可学习的提示向量。
    • LoRA (Low-Rank Adaptation): 通过学习低秩矩阵来近似预训练模型权重在微调时的变化。这是目前非常流行且效果显著的一种 PEFT 方法。
    • (IA)^3 (Infused Adapter by Inhibiting and Amplifying Inner Activations): 通过学习缩放因子来调整预训练模型的内部激活。
    • BitFit: 只微调模型中的偏置项 (bias terms)。
  • 如何操作 (以 LoRA 为例的简化概念):

    1. 加载预训练模型并冻结其参数。
    2. 为模型中的某些层 (通常是注意力层或前馈网络层) 引入 LoRA 模块。 这些 LoRA 模块包含少量可训练的参数 (低秩分解矩阵 A 和 B)。
    3. 准备特定任务的数据集。
    4. 训练: 只训练这些 LoRA 模块的参数,而预训练模型的原始权重保持不变。
    5. 推理/部署: 可以将训练好的 LoRA 权重与原始预训练权重合并(对于某些方法如 LoRA),或者在推理时动态加载 LoRA 模块。
  • 优点: (即 PEFT 的主要目标)

    • 显著降低计算和存储成本。
    • 有效缓解灾难性遗忘。
    • 便于多任务模型的管理和部署。
    • 在某些情况下性能接近甚至超过全参数微调,尤其是在低资源场景下。
  • 缺点:

    • 性能上限可能略低于全参数微调: 由于可训练参数的限制,在某些非常复杂的任务或需要模型进行根本性转变的情况下,PEFT 的性能上限可能略低于精心调整的全参数微调。
    • 引入新的超参数: 不同的 PEFT 方法会引入各自的超参数 (例如 LoRA 中的秩 ralpha 值,Adapter 的瓶颈维度等),需要进行调整。
    • 并非所有 PEFT 方法效果都一样好: 不同 PEFT 方法在不同模型、不同任务上的表现可能存在差异。
  • 适用场景:

    • 计算资源有限,尤其是显存受限的场景。
    • 需要为大量不同任务微调同一个基础模型。
    • 希望快速迭代和实验不同任务。
    • 关注模型的便携性和部署效率。
    • 希望尽可能保留预训练模型的通用能力。

总结与对比:

特性 全参数微调 (Full Fine-tuning) 参数高效微调 (PEFT)
可训练参数 模型所有参数 少量新增参数或模型中一小部分已有参数 (通常 <1% of total)
计算成本 高 (训练时间长,显存占用大) 低 (训练时间短,显存占用小)
存储成本 高 (每个任务一个完整模型副本) 低 (每个任务一个小型 PEFT 模块)
灾难性遗忘 风险较高 风险较低
性能潜力 理论上最高 通常接近全参数微调,有时甚至更好 (尤其低资源时),但上限可能略低
部署管理 复杂 (管理多个大模型) 简单 (共享基础模型,加载不同 PEFT 模块)
适用场景举例 追求极致性能且资源充足;任务与预训练差异大 资源有限;多任务场景;快速迭代;希望保留通用能力

理解这两种微调范式是进行 LLM 应用开发的基础。在实践中,PEFT 由于其巨大的优势,在当前的 LLM 领域变得越来越流行和重要。