微调
LLM 微调 (Fine-tuning): 概述
在预训练阶段,大语言模型(LLM)通过在海量通用文本数据上进行训练,学习到了广泛的语言知识、语法结构、世界常识以及一定的推理能力。然而,这些预训练模型是“通才”,它们并不针对任何特定的下游任务或特定的行为模式进行优化。
微调 (Fine-tuning) 的核心目标是:在预训练模型的基础上,使用特定任务或领域的数据集进行进一步训练,从而使模型能够更好地适应这些特定需求,表现出期望的行为或在特定任务上达到更高的性能。
可以把预训练模型想象成一个已经完成了大学通识教育的学生,而微调则像是针对特定专业方向进行的深造或职业培训。
微调的类型与目标
根据在微调过程中更新模型参数的范围和方式,主要可以将微调分为两大类:
- 全参数微调 (Full Fine-tuning): 更新模型的所有参数。
- 参数高效微调 (Parameter-Efficient Fine-Tuning, PEFT): 只更新模型中一小部分参数,或者增加少量新的可训练模块,而保持大部分预训练参数冻结。
让我们详细探讨这两种类型:
1. 全参数微调 (Full Fine-tuning)
-
核心思想: 在微调过程中,预训练模型的所有权重(包括词嵌入层、Transformer 层中的注意力权重和前馈网络权重等)都会参与梯度计算和参数更新。
-
如何操作:
- 加载预训练模型: 获取一个已经预训练好的 LLM (例如,从 Hugging Face Hub 加载一个 BERT, GPT, Llama 模型)。
- 准备特定任务的数据集: 针对你想要解决的下游任务(如情感分析、文本摘要、问答、代码生成等),准备一个标注好的数据集。
- (可选) 修改模型头部: 对于某些任务(尤其是分类任务或序列标注任务),可能需要在预训练模型的顶部添加一个新的、特定于任务的层(称为“头部”,Head)。例如,在 BERT 模型之上添加一个线性分类层来进行情感分析。对于生成式任务,通常不需要修改头部,直接用模型的语言模型头部进行生成。
- 训练: 使用特定任务的数据集,以较小的学习率继续训练整个模型(包括预训练部分和新添加的头部)。损失函数根据具体任务定义(如交叉熵损失)。
-
优点:
- 潜力巨大: 由于所有参数都参与训练,模型有最大的自由度去适应新的数据和任务,理论上可以达到最佳的性能。
- 概念简单: 比较直观,就是继续训练。
-
缺点:
- 计算成本高:
- 训练时间长: 更新所有参数需要大量的计算资源 (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 为例的简化概念):
- 加载预训练模型并冻结其参数。
- 为模型中的某些层 (通常是注意力层或前馈网络层) 引入 LoRA 模块。 这些 LoRA 模块包含少量可训练的参数 (低秩分解矩阵 A 和 B)。
- 准备特定任务的数据集。
- 训练: 只训练这些 LoRA 模块的参数,而预训练模型的原始权重保持不变。
- 推理/部署: 可以将训练好的 LoRA 权重与原始预训练权重合并(对于某些方法如 LoRA),或者在推理时动态加载 LoRA 模块。
-
优点: (即 PEFT 的主要目标)
- 显著降低计算和存储成本。
- 有效缓解灾难性遗忘。
- 便于多任务模型的管理和部署。
- 在某些情况下性能接近甚至超过全参数微调,尤其是在低资源场景下。
-
缺点:
- 性能上限可能略低于全参数微调: 由于可训练参数的限制,在某些非常复杂的任务或需要模型进行根本性转变的情况下,PEFT 的性能上限可能略低于精心调整的全参数微调。
- 引入新的超参数: 不同的 PEFT 方法会引入各自的超参数 (例如 LoRA 中的秩
r
、alpha
值,Adapter 的瓶颈维度等),需要进行调整。 - 并非所有 PEFT 方法效果都一样好: 不同 PEFT 方法在不同模型、不同任务上的表现可能存在差异。
-
适用场景:
- 计算资源有限,尤其是显存受限的场景。
- 需要为大量不同任务微调同一个基础模型。
- 希望快速迭代和实验不同任务。
- 关注模型的便携性和部署效率。
- 希望尽可能保留预训练模型的通用能力。
总结与对比:
特性 | 全参数微调 (Full Fine-tuning) | 参数高效微调 (PEFT) |
---|---|---|
可训练参数 | 模型所有参数 | 少量新增参数或模型中一小部分已有参数 (通常 <1% of total) |
计算成本 | 高 (训练时间长,显存占用大) | 低 (训练时间短,显存占用小) |
存储成本 | 高 (每个任务一个完整模型副本) | 低 (每个任务一个小型 PEFT 模块) |
灾难性遗忘 | 风险较高 | 风险较低 |
性能潜力 | 理论上最高 | 通常接近全参数微调,有时甚至更好 (尤其低资源时),但上限可能略低 |
部署管理 | 复杂 (管理多个大模型) | 简单 (共享基础模型,加载不同 PEFT 模块) |
适用场景举例 | 追求极致性能且资源充足;任务与预训练差异大 | 资源有限;多任务场景;快速迭代;希望保留通用能力 |
理解这两种微调范式是进行 LLM 应用开发的基础。在实践中,PEFT 由于其巨大的优势,在当前的 LLM 领域变得越来越流行和重要。