大模型微调实战指南
大模型基础:
相关知识:
1.大模型训练就是对下一个token进行分类预测,
对最后一个token计算不了loss,标签需要左移一位,形成label。
2.使用交叉熵来计算Loss
3.注意每个大模型有自己的输入模板
4.计算损失
completions only 仅针对回答计算损失(一般)
NEFTuning 给embedding层加噪声(数据增强,增加模型的泛化性)
基本流程:
- 加载模型(远程/本地加载,可选:量化加载)+分词器
from transformers import AutoTokenizer, BitsAndBytesConfig, AutoModelForCausalLM
from peft import LoraConfig, get_peft_model, TaskType
import torch
model_path = "Meta-Llama-3.1-8B-Instruct"
tokenizer = AutoTokenizer.from_pretrained(model_path, use_fast=False)
tokenizer.padding_side = "right"
tokenizer.pad_token = tokenizer.eos_token
# 可选:量化加载
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_use_double_quant=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.float16
)
model = AutoModelForCausalLM.from_pretrained(
model_path,
quantization_config=bnb_config,
torch_dtype=torch.float16
)
# 使用Lora冻结部分参数微调
peft_config = LoraConfig(
r=8,
target_modules=["q_proj",
"v_proj",
"k_proj",
"o_proj",
"gate_proj",
"down_proj",
"up_proj"
],
task_type=TaskType.CAUSAL_LM,
lora_alpha=16,
lora_dropout=0.05
)
model = get_peft_model(model, peft_config)
# 模型放入显卡
model.to("cuda")
- 加载以及处理数据
# sft部分数据展示 {"query":xxx, "answer":xxx}
"""
{"query": "保持健康的一个提示。 ", "answer": "以下是保持健康的一个提示:\n\n 保持身体活动。每天做适当的身体运动,如散步、跑步或游泳,能促进心血管健康,增强肌肉力量,并有助于减少体重。"}
{"query": "三原色是什么? ", "answer": "三原色通常指的是红色、绿色和蓝色(RGB)。它们是通过加色混合原理创建色彩的三种基础颜色。在以发光为基础的显示设备中(如电视、计算机显示器、智能手机和平板电脑显示屏), 三原色可混合产生大量色彩。其中红色和绿色可以混合生成黄色,红色和蓝色可以混合生成品红色,蓝色和绿色可以混合生成青色。当红色、绿色和蓝色按相等比例混合时,可以产生白色或灰色。"}
"""
from datasets import Dataset
import json
items = []
with open("./data/sft_data.json", "r", encoding="utf8")as f:
for line in f:
item = json.loads(line)
items.append({"prompt": item["query"], "completion": item["answer"]})
dataset = Dataset.from_list(items)
- 简单训练示例
#把模型放入显卡,定义优化器
model.to("cuda")
optimizer = torch.optim.AdamW(model.parameters())
#输入文本,对文本进行分词,将分词后的input也放入显卡
text = "今天天气不错。"
input = tokenizer(text, return_tensors="pt")
input = {k: v.to("cuda") for k, v in input.items()} #input是一个字典,包括input_ids, mask
#设置labels和inputs一致
input["labels"] = input["input_ids"].clone()
output = model(**input)
#获取模型的loss
loss = output.loss #因为传入了label
loss.backward() #后向传播
optimizer.step() #更新参数
optimizer.zero_grad()
#保存模型
model.save_pretrained("output_dir")
- 使用某种框架训练 eg: trl
""" 这里使用trl库训练 """ from trl import SFTTrainer, SFTConfig, DataCollatorForCompletionOnlyLM sft_config = SFTConfig(output_dir="/tmp", neftune_noise_alpha=10, per_device_train_batch_size=1, max_seq_length=100, num_train_epochs=10, logging_steps=10, logging_strategy="steps") response_template = "<|start_header_id|>assistant<|end_header_id""|>\n\n" collator = DataCollatorForCompletionOnlyLM(response_template, tokenizer=tokenizer) trainer = SFTTrainer( model=model, train_dataset=dataset, args=sft_config, data_collator=collator ) trainer.train()
微调(Fine-Tuning)
大模型微调(Fine-tuning)是针对特定任务优化预训练模型的核心技术。
方法 数据量 计算资源 性能 适用场景 推荐框架 全参数微调 百万级以上 多 GPU(8×A100) 最优 工业级高要求任务 Transformers PEFT(LoRA) 数千 - 数万 单 GPU(16GB+) 接近全量 中小规模任务、快速迭代 PEFT、MS-Swift
全参数微调(Full Fine-Tuning)
更新模型所有参数,让模型完全适配下游任务(如特定领域问答、情感分析)。
优缺点
优点:性能理论上最优,能最大程度挖掘模型潜力,适合数据量充足的场景。
缺点:参数量巨大(如 10B 模型需更新 100 亿 + 参数),显存消耗极高(单卡难以支撑),训练速度慢,容易过拟合(小数据集场景)。
应用场景
有大规模标注数据(如百万级以上)。
有充足计算资源(多 GPU 集群,如 8×A100)。
对任务性能要求极高(如工业级质检、专业领域推理)。
示例:
基于 Transformers+Accelerate
训练参数(全量微调需大batch和低学习率)
from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments, Trainer
from datasets import load_dataset
# 加载模型和分词器(以Llama 3为例)
model_name = "meta-llama/Llama-3-8B-Instruct"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(
model_name,
device_map="auto", # 自动分配到可用GPU
torch_dtype="auto"
)
# 加载微调数据集(示例:情感分析)
dataset = load_dataset("imdb")
def preprocess_function(examples):
texts = [f"情感分析:{text}\n答案:{'正面' if label == 1 else '负面'}"
for text, label in zip(examples["text"], examples["label"])]
return tokenizer(texts, truncation=True, max_length=512, padding="max_length")
tokenized_dataset = dataset.map(preprocess_function, batched=True)
# 训练参数(全量微调需大batch和低学习率)
training_args = TrainingArguments(
output_dir="./full_finetune_llama3",
per_device_train_batch_size=4, # 单卡batch
gradient_accumulation_steps=8, # 梯度累积(模拟大batch)
learning_rate=2e-5, # 全量微调学习率较低
num_train_epochs=3,
logging_dir="./logs",
fp16=True, # 混合精度训练节省显存
report_to="none"
)
# 训练
trainer = Trainer(
model=model,
args=training_args,
train_dataset=tokenized_dataset["train"],
eval_dataset=tokenized_dataset["test"]
)
trainer.train()
参数高效微调(PEFT,Parameter-Efficient Fine-Tuning)
仅更新模型少量参数(如新增适配器层),冻结预训练模型主体参数,在保证性能的同时大幅降低计算成本。
主流方法:LoRA(Low-Rank Adaptation)、Prefix Tuning、IA³、Adapter 等,其中LoRA应用最广泛。
优缺点
优点:显存消耗低(仅需全量微调的 10%-30%),训练速度快,适合小数据集(万级样本),泛化性强(不易过拟合)。
缺点:理论性能略低于全量微调(但实际场景中差距极小),推理时需加载适配器权重(部分框架需合并权重)。
应用场景
- 中小规模数据集(数千至数万样本)。
- 计算资源有限(单 GPU 或少量 GPU)。
- 需快速迭代的场景(如企业内部工具、垂直领域微调)。
| 特征 | Prompt Tuning | Prefix Tuning | Adapter | LoRA |
|---|---|---|---|---|
| 核心思想 | 在输入层加入可学习的软提示向量 | 在Transformer每一层的Key和Value前添加可训练向量 | 在Transformer层内插入小型神经网络模块 | 为原始权重矩阵增加一个低秩的增量矩阵 |
| 调参位置 | 输入嵌入层 | 所有Transformer层的注意力模块 | 通常位于FFN层之后或注意力模块后 | 通常应用于注意力层的Q、V投影矩阵 |
| 参数效率 | 极高 | 高 | 中等 | 高 |
| 训练速度 | 很快 | 较快 | 中等(存在序列化操作) | 快 |
| 性能表现 | 较好(尤其对大模型) | 好,接近全量微调 | 好,但早期结构有瓶颈 | 很好,常与全量微调媲美 |
| 推理延迟 | 无 | 有(因延长了序列) | 有(因增加了深度) | 无(权重可合并) |
LoRA:用“低秩分解”模拟参数更新
原理:LoRA的灵感来源于一个发现:模型在微调过程中的参数增量(ΔW)可能拥有很低的"内在秩"。它并不直接学习完整的增量矩阵,而是用两个更小矩阵的乘积(B·A)来模拟这个增量。训练时,固定原始权重W,只训练A和B。训练结束后,增量部分可以直接合并到原始权重中,因此推理时没有任何额外开销。
数学公式:微调后的权重 W' = W + ΔW = W + B * A (其中 B ∈ ℝ^(d×r), A ∈ ℝ^(r×k), r << min(d,k))
示意图:
上下矩阵AB的初始化
- 上矩阵(A 矩阵)上矩阵 A 通常采用随机初始化的方式。
- 常见的初始化方法有正态分布初始化(如从均值为 0、标准差为较小值的正态分布中采样)。这样的初始化能让模型在微调开始时,LoRA 模块有一定的初始表达能力,后续通过训练逐步学习到适配任务的参数。
- 下矩阵(B 矩阵)下矩阵 B 通常初始化为全零矩阵。
- 这是因为在训练初期,希望 LoRA 模块对原始预训练模型的干扰尽可能小,让模型先基于预训练的知识进行学习,后续再通过训练逐步更新 B 矩阵的参数,使 LoRA 模块逐渐发挥作用,实现对预训练模型的高效适配微调。
LoRA 可以加在哪些层?
LoRA 的适配层选择与模型结构和任务相关,核心是加在模型中对任务敏感的 “关键交互层”,以下是常见选择:
1. Transformer 模型的核心应用层(最常用)
Transformer 是 LoRA 应用的典型场景,主要加在注意力机制的权重矩阵中:
Q/K/V 投影层(Query/Key/Value Projection):注意力机制中,将输入向量映射到 Q、K、V 的线性层是捕捉任务相关性的核心(如翻译任务中需关注源语言与目标语言的对齐),LoRA 加在此处可高效学习任务特异性的注意力模式。
例:在 GPT 中,对每个 Transformer 块的 Q、K、V 矩阵分别添加 LoRA;在 BERT 中,可选择仅对 Q 矩阵或 Q+V 矩阵添加(实践中 Q 矩阵效果更显著)。
输出投影层(可选):部分场景会在注意力输出的线性投影层(如 Multi-Head Attention 的拼接后投影层)添加 LoRA,但通常优先级低于 Q/K/V 层。
2. 前馈网络(FFN)层(较少用)
Transformer 的前馈网络(Feed-Forward Network)负责对每个 Token 的向量进行非线性变换,部分任务(如文本生成)可在 FFN 的线性层添加 LoRA,但效果通常不如注意力层显著,且可能增加冗余参数。
3. 嵌入层(Embedding Layer,极少用)
词嵌入层(Token Embedding)是模型的输入层,直接影响对输入 Token 的语义编码。但嵌入层参数与词汇表强相关,对新任务的适配需求较低,且添加 LoRA 可能破坏预训练的通用语义,因此极少使用。
示例:
(基于 PEFT+LoRA)
训练参数(LoRA可使用更高学习率)
伪代码:
import torch import torch.nn as nn # 假设有一个预训练模型的线性层 pretrained_linear_layer = nn.Linear(768, 768).requires_grad_(False) # 冻结 # ---------- LoRA (简化版) ---------- class LoRALayer(nn.Module): def __init__(self, original_weight, rank, alpha): super().__init__() self.original_weight = original_weight # 冻结的原始权重 d, k = original_weight.shape # 低秩矩阵A和B self.lora_A = nn.Parameter(torch.zeros(d, rank)) self.lora_B = nn.Parameter(torch.zeros(rank, k)) self.scaling = alpha / rank nn.init.kaiming_uniform_(self.lora_A, a=math.sqrt(5)) nn.init.zeros_(self.lora_B) def forward(self, x): # 原始输出 + LoRA适配后的输出 return x @ (self.original_weight + self.lora_B @ self.lora_A).T * self.scaling
from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments, Trainer
from peft import LoraConfig, get_peft_model
from datasets import load_dataset
# 加载模型和分词器
model_name = "meta-llama/Llama-3-8B-Instruct"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(
model_name,
device_map="auto",
torch_dtype="auto",
load_in_4bit=True # 4bit量化进一步节省显存 ------多的操作
)
# 配置LoRA(仅更新注意力层的低秩矩阵) ------Lora才有的操作
lora_config = LoraConfig(
r=16, # 低秩矩阵维度(越大性能越好,显存消耗越高)
lora_alpha=32,
target_modules=["q_proj", "v_proj"], # 目标层(不同模型层名不同)
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM"
)
model = get_peft_model(model, lora_config)
model.print_trainable_parameters() # 打印可训练参数比例(通常<1%)
# 数据集预处理(同全量微调)
dataset = load_dataset("imdb")
def preprocess_function(examples):
texts = [f"情感分析:{text}\n答案:{'正面' if label == 1 else '负面'}"
for text, label in zip(examples["text"], examples["label"])]
return tokenizer(texts, truncation=True, max_length=512, padding="max_length")
tokenized_dataset = dataset.map(preprocess_function, batched=True)
# 训练参数(LoRA可使用更高学习率)
training_args = TrainingArguments(
output_dir="./lora_llama3",
per_device_train_batch_size=8, # 单卡batch可更大
gradient_accumulation_steps=4,
learning_rate=2e-4, # LoRA学习率更高
num_train_epochs=3,
fp16=True,
report_to="none"
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=tokenized_dataset["train"],
eval_dataset=tokenized_dataset["test"]
)
trainer.train()
# 保存LoRA权重(仅几百MB)
model.save_pretrained("lora_weights")
提示微调(Prompt Tuning):给模型一个可学习的“提示”
- 原理:传统的Prompt是人工设计的文本提示(Hard Prompt)。Prompt Tuning则将其转化为可学习的连续向量(Soft Prompt),直接拼接到输入序列的嵌入表示中,模型通过训练来学习这些向量的最佳值。在训练时,只有这些提示向量会被更新,预训练模型的所有参数都被冻结。
- 示意图:(更容易进行多任务学习,一次训练得到)
示例:(伪代码)
# ---------- Prompt Tuning (简化版) ----------
class PromptTuning(nn.Module):
def __init__(self, prompt_length, hidden_size):
super().__init__()
self.prompts = nn.Parameter(torch.randn(prompt_length, hidden_size))
def forward(self, input_embeddings):
# 将提示符拼接到输入序列前
batch_size = input_embeddings.size(0)
prompts = self.prompts.unsqueeze(0).expand(batch_size, -1, -1)
return torch.cat([prompts, input_embeddings], dim=1)
Prefix Tuning:在模型每一层“前置”知识
原理:Prefix Tuning认为,仅仅在输入层加提示不够深入。它在每一个Transformer层的自注意力模块中,在处理序列本身的Key和Value向量之前,拼接上一组可训练的向量(即Prefix)。这使得引导信息能够贯穿模型的整个前向传播过程,影响力更强。
自注意力计算: Attn(Query, Concat(Prefix_Key, Original_Key), Concat(Prefix_Value, Original_Value))
示意图:(只对K,V层+前缀知识)
Adapter:在模块之间插入“转换插头”
原理:Adapter借鉴了计算机科学中的适配器设计模式。它在Transformer架构的特定位置(例如,每个FFN层之后)插入一个小型的前馈神经网络。这个网络通常采用"降维-非线性-升维"的结构(瓶颈结构),并配有一个残差连接。训练时,冻结主模型参数,只训练这些Adapter模块。
示意图:
示例:(伪代码)
# ---------- Adapter (简化版) ----------
class Adapter(nn.Module):
def __init__(self, hidden_size, adapter_size):
super().__init__()
# 降维
self.down_proj = nn.Linear(hidden_size, adapter_size)
# 升维
self.up_proj = nn.Linear(adapter_size, hidden_size)
self.activation = nn.ReLU()
def forward(self, x):
# 残差连接
return x + self.up_proj(self.activation(self.down_proj(x)))
不同框架以及使用方法
1. PEFT(参数高效微调首选)
- 特点:Hugging Face 官方库,支持 LoRA、Prefix Tuning 等多种 PEFT 方法,无缝对接 Transformers 和 Trainer。
- 安装:
pip install peft - 核心优势:简单易用,可与量化(BitsAndBytes)、加速(Accelerate)工具结合。
2. MS-Swift(阿里一站式微调框架)
- 特点:集成数据处理、微调、部署全流程,支持全量微调、LoRA、Prompt Tuning,自动优化训练参数。
- 安装:
pip install ms-swift - 使用示例(LoRA 微调):
# 命令行一键微调(无需写代码) swift sft \ --model_type llama3 \ --model_name_or_path meta-llama/Llama-3-8B-Instruct \ --dataset imdb \ --peft_type lora \ --output_dir ./swift_lora_results
3. FastChat(大模型微调 + 部署一体化)
- 特点:专注于对话模型,支持全量微调、LoRA,内置训练脚本和评估工具,适合聊天机器人场景。
- 安装:
pip install "fschat[model_worker,webui]" - 使用示例:
# 微调命令(LoRA) python -m fastchat.train.train_lora \ --model_name_or_path meta-llama/Llama-3-8B-Instruct \ --dataset path/to/your/data \ --output_dir ./fastchat_lora
更多推荐












所有评论(0)