跳转至

模型微调教程

概述

模型微调(Fine-tuning)是在预训练模型基础上,使用特定领域数据进行二次训练,让模型适应特定任务的技术。

微调类型

# 微调方式对比

全量微调(Full Fine-tuning)
- 更新所有参数
- 效果最好
- 资源需求大

参数高效微调(PEFT)
- 只更新部分参数
- 资源友好
- 效果接近全量

LoRA(Low-Rank Adaptation)
- 低秩分解
- 参数量少
- 主流方法

LoRA微调

原理

# LoRA原理

在原始权重矩阵旁添加低秩分解矩阵:

W' = W + BA

其中:
- W: 原始权重(冻结)
- B, A: 低秩矩阵(可训练)
- rank: 秩(通常8-64)

使用PEFT库

from peft import LoraConfig, get_peft_model, TaskType
from transformers import AutoModelForCausalLM

# 加载基础模型
model = AutoModelForCausalLM.from_pretrained(
    "meta-llama/Llama-3.1-8B",
    load_in_4bit=True
)

# LoRA配置
lora_config = LoraConfig(
    task_type=TaskType.CAUSAL_LM,
    r=16,                    # 秩
    lora_alpha=32,           # 缩放因子
    lora_dropout=0.1,        # Dropout
    target_modules=["q_proj", "v_proj", "k_proj", "o_proj"]
)

# 创建PEFT模型
peft_model = get_peft_model(model, lora_config)

# 打印可训练参数
peft_model.print_trainable_parameters()
# trainable params: 6,553,600 || all params: 4,197,347,328 || trainable%: 0.16%

使用Hugging Face微调

数据准备

from datasets import load_dataset

# 加载数据集
dataset = load_dataset("your_dataset")

# 数据预处理
def preprocess_function(examples):
    # 对于指令微调
    prompt = f"Instruction: {examples['instruction']}\nInput: {examples['input']}\nOutput: {examples['output']}"
    return tokenizer(prompt, truncation=True, max_length=512)

tokenized_dataset = dataset.map(preprocess_function, batched=True)

训练配置

from transformers import TrainingArguments, Trainer
from peft import LoraConfig, get_peft_model

# 训练参数
training_args = TrainingArguments(
    output_dir="./output",
    num_train_epochs=3,
    per_device_train_batch_size=4,
    gradient_accumulation_steps=4,
    learning_rate=2e-4,
    weight_decay=0.01,
    warmup_ratio=0.03,
    lr_scheduler_type="cosine",
    logging_steps=10,
    save_strategy="epoch",
    fp16=True
)

# 创建Trainer
trainer = Trainer(
    model=peft_model,
    args=training_args,
    train_dataset=tokenized_dataset["train"],
    eval_dataset=tokenized_dataset["test"]
)

# 开始训练
trainer.train()

# 保存LoRA权重
peft_model.save_pretrained("./lora_weights")

4bit量化微调(QLoRA)

import torch
from transformers import (
    AutoModelForCausalLM,
    AutoTokenizer,
    BitsAndBytesConfig
)
from peft import LoraConfig, get_peft_model

# 4bit量化配置
bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.float16,
    bnb_4bit_use_double_quant=True
)

# 加载量化模型
model = AutoModelForCausalLM.from_pretrained(
    "meta-llama/Llama-3.1-8B",
    quantization_config=bnb_config,
    device_map="auto"
)

# LoRA配置
lora_config = LoraConfig(
    r=16,
    lora_alpha=32,
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM"
)

# 创建PEFT模型
model = get_peft_model(model, lora_config)

# 模型显存占用:约6GB(对比全量微调约16GB)

指令微调数据格式

Alpaca格式

[
    {
        "instruction": "请解释什么是机器学习",
        "input": "",
        "output": "机器学习是人工智能的一个分支,它使计算机能够从数据中学习..."
    },
    {
        "instruction": "翻译以下句子",
        "input": "Hello, how are you?",
        "output": "你好,你怎么样?"
    }
]

ShareGPT格式

[
    {
        "conversations": [
            {"from": "human", "value": "什么是深度学习?"},
            {"from": "gpt", "value": "深度学习是机器学习的一个子集..."}
        ]
    }
]

对话格式

[
    {
        "messages": [
            {"role": "system", "value": "你是一个有帮助的助手"},
            {"role": "user", "value": "你好"},
            {"role": "assistant", "value": "你好!有什么可以帮你的吗?"}
        ]
    }
]

数据处理技巧

数据清洗

def clean_dataset(dataset):
    # 去除过长样本
    dataset = dataset.filter(lambda x: len(x['text']) < 2000)

    # 去除重复数据
    dataset = dataset.unique(column='text')

    # 过滤低质量数据
    def is_valid(example):
        # 检查输出长度
        return len(example['output']) > 10

    dataset = dataset.filter(is_valid)

    return dataset

数据增强

# 1. 回译增强
def back_translate(text):
    # 英文 → 中文 → 英文
    pass

# 2. 同义词替换
import random
def synonym_replacement(text):
    # 替换同义词
    pass

# 3. Prompt模板多样化
templates = [
    "请回答:{question}",
    "{question}",
    "问题:{question}\n回答:"
]

微调超参数

# 关键超参数

learning_rate(学习率)
- LoRA: 1e-4 到 3e-4
- 全量: 1e-5 到 5e-5

batch_size(批大小)
- 根据显存调整
- 使用梯度累积

epochs(训练轮数)
- 通常2-5轮
- 过多会过拟合

rank(LoRA秩)
- 通常8-64
- 越大参数越多,效果越好

target_modules(目标模块)
- attention层:q_proj, v_proj
- 全连接层:up_proj, down_proj

评估与测试

自动评估

from datasets import load_metric

# 加载评估指标
bleu = load_metric("bleu")
rouge = load_metric("rouge")

# 评估生成结果
predictions = ["模型生成的文本"]
references = ["参考答案"]

bleu_score = bleu.compute(predictions=predictions, references=references)
print(f"BLEU: {bleu_score}")

人工评估

# 评估维度

1. 相关性:回答是否切题
2. 准确性:信息是否正确
3. 流畅性:语言是否通顺
4. 有用性:是否真正解决问题

常见问题

Q1: 显存不够怎么办?

# 解决方案

1. 使用QLoRA(4bit量化)
2. 减小batch_size
3. 使用梯度累积
4. 选择更小的模型

Q2: 训练不稳定?

# 解决方案

1. 降低学习率
2. 使用warmup
3. 增加gradient_accumulation_steps
4. 检查数据质量

Q3: 过拟合?

# 解决方案

1. 增加训练数据
2. 使用dropout
3. 减少训练轮数
4. 使用早停

工具与平台

# 微调工具

Hugging Face PEFT
- 官方推荐
- 支持多种方法

Unsloth
- 速度快2倍
- 显存减少60%

Axolotl
- 简单配置
- 功能丰富

LLaMA-Factory
- 可视化界面
- 支持多种模型

下一步学习

  1. 模型量化部署教程 - 优化模型部署
  2. 大语言模型原理 - 深入理解原理
  3. Hugging Face教程 - 使用HF平台