模型微调全流程总结
一、Transformer 模型基础
1. 什么是 NLP(自然语言处理)?
定义: NLP 是语言学和机器学习的交叉领域,专注于理解与人类语言相关的一切。
目标: 不仅理解单个单词,而是理解单词的上下文和语义关系。
2. Transformer 是什么?
定义: Transformer 是一种神经网络架构,2017年由Google提出,是现代大语言模型(BERT、GPT等)的基础。
核心创新: 自注意力机制(Self-Attention)
传统模型(RNN):
逐个处理单词,像读书一样从头读到尾
问题:后面的内容看不到前面的,处理长文本困难
Transformer:
同时看到所有单词,像一眼看整篇文章
优势:能捕捉长距离的语义关系,并行计算速度快3. Transformer 核心组件
┌─────────────────────────────────────────────────────────────┐
│ Transformer 架构 │
└─────────────────────────────────────────────────────────────┘
输入文本: "我喜欢学习机器学习"
│
▼
┌──────────────┐
│ Embedding │ 文字 → 数字向量
│ (词嵌入) │ 每个 token → 768维向量
└──────────────┘
│
▼
┌──────────────┐
│ Position │ 加上位置信息
│ Encoding │ 让模型知道词的顺序
└──────────────┘
│
▼
┌──────────────────────────────────────┐
│ Self-Attention (自注意力) │
│ ┌────────────────────────────────┐ │
│ │ "我" 关注谁? → "喜欢"、"学习" │ │
│ │ "机器学习" 关注谁? → "学习" │ │
│ │ 每个词都能看其他所有词 │ │
│ └────────────────────────────────┘ │
│ 作用:理解词与词之间的关系 │
└──────────────────────────────────────┘
│
▼
┌──────────────┐
│ Feed Forward│ 进一步处理
│ Network │ 提取语义信息
└──────────────┘
│
▼ (重复多层)
│
▼
┌──────────────┐
│ Output │ 输出结果
└──────────────┘自注意力通俗理解:
例子:"猫坐在垫子上,它很舒服"
自注意力作用:
"它" 这个词应该关注谁?
- 关注"猫" → 知道"它"指的是猫
- 关注"垫子" → 也有可能指垫子
模型通过注意力权重判断:更可能指"猫"4. Transformer 家族
┌─────────────────────────────────────────────────────────────┐
│ Transformer 模型家族 │
└─────────────────────────────────────────────────────────────┘
┌─────────────┐
│ Transformer │ (2017 Google,原始架构)
└─────────────┘
│
┌────┴────┐
│ │
▼ ▼
┌─────┐ ┌─────┐
│ BERT│ │ GPT │
│编码器│ │解码器│
└─────┘ └─────┘
│ │
▼ ▼
理解类任务 生成类任务
- 分类 - 写文章
- 问答 - 翻译
- 搜索 - 对话BERT vs GPT 对比:
| 对比项 | BERT(编码器) | GPT(解码器) |
|---|---|---|
| 方向 | 双向(看前后文) | 单向(只看前文) |
| 训练方式 | 填空(预测遮盖词) | 预测下一个词 |
| 适用任务 | 理解类:分类、问答 | 生成类:写作、对话 |
| 代表模型 | BERT, RoBERTa | GPT-3, GPT-4, ChatGPT |
二、NLP 任务类型与应用
1. 四大类 NLP 任务
┌─────────────────────────────────────────────────────────────┐
│ NLP 任务分类 │
└─────────────────────────────────────────────────────────────┘
【类型一:文本分类】
输入:一段文本
输出:类别标签
┌────────────────────┐
│ "这部电影很精彩!" │ → 情感分析 → "正面"
└────────────────────┘
应用:情感分析、新闻分类、垃圾邮件检测
【类型二:序列标注】
输入:一段文本
输出:每个词的标签
┌────────────────────────────────────┐
│ "张三在北京创办了公司" │
│ ↓ ↓ ↓ │
│ 人名 地名 O │ → 命名实体识别
└────────────────────────────────────┘
应用:命名实体识别(NER)、词性标注
【类型三:文本生成】
输入:提示文本/条件
输出:新生成的文本
┌────────────────────┐
│ "请写一首关于春天的诗"│ → 文本生成 → "春风拂面..."
└────────────────────┘
应用:机器翻译、摘要生成、对话系统、写作助手
【类型四:问答/抽取】
输入:问题 + 文本
输出:答案
┌────────────────────────────────────┐
│ 文本:"BERT是Google在2018年提出的" │
│ 问题:"BERT是谁提出的?" │ → "Google"
└────────────────────────────────────┘
应用:问答系统、信息抽取2. 常见 NLP 任务详解
| 任务名称 | 输入 | 输出 | 应用场景 | 代表模型 |
|---|---|---|---|---|
| 情感分析 | 评论文本 | 正/负情感 | 产品评论分析 | BERT微调 |
| 命名实体识别(NER) | 文本 | 实体类型 | 信息提取、知识图谱 | BERT+CRF |
| 机器翻译 | 源语言文本 | 目标语言文本 | 跨语言翻译 | T5, mBART |
| 文本摘要 | 长文章 | 简短摘要 | 新闻摘要 | BART, PEGASUS |
| 问答系统 | 问题+文档 | 答案 | 智能客服 | BERT, DPR |
| 文本生成 | 提示词 | 生成的文本 | 写作助手 | GPT系列 |
| 句子相似度 | 两个句子 | 相似度分数 | 搜索匹配 | sentence-transformers |
| 填空预测(MLM) | 遮盖文本 | 预测遮盖词 | 预训练 | BERT |
3. 任务对应的模型架构
┌─────────────────────────────────────────────────────────────┐
│ 任务类型 → 推荐模型架构 │
└─────────────────────────────────────────────────────────────┘
理解类任务(分类、标注、问答)
│
▼
┌─────────────────┐
│ Encoder-only │
│ (BERT系列) │
│ │
│ - BERT │
│ - RoBERTa │
│ - ALBERT │
│ - DistilBERT │
└─────────────────┘
生成类任务(翻译、摘要、写作)
│
▼
┌─────────────────┐
│ Decoder-only │ 或 Encoder-Decoder
│ (GPT系列) │ (T5, BART)
│ │
│ - GPT-2/3/4 │ - T5 (翻译、问答)
│ - LLaMA │ - BART (摘要)
│ - Claude │ - mBART (多语言翻译)
└─────────────────┘
序列标注类任务
│
▼
┌─────────────────┐
│ BERT + CRF │
│ 或 BERT + 分类头│
│ │
│ - NER (命名实体)│
│ - POS (词性标注)│
└─────────────────┘4. 从预训练到任务适配
┌─────────────────────────────────────────────────────────────┐
│ 预训练模型 → 下游任务适配 │
└─────────────────────────────────────────────────────────────┘
预训练模型(通用语言能力)
│
│ 加任务特定的"头"(Head)
│
▼
┌─────────────────────────────────┐
│ 分类任务:Classification Head │
│ 输入 → BERT → 分类头 → 类别 │
│ (如:正面/负面情感) │
└─────────────────────────────────┘
┌─────────────────────────────────┐
│ 标注任务:Token Classification │
│ 输入 → BERT → 每个token分类 │
│ (如:人名/地名/其他) │
└─────────────────────────────────┘
┌─────────────────────────────────┐
│ 问答任务:Span Prediction │
│ 问题+文档 → BERT → 答案位置 │
│ (如:答案从第5词到第8词) │
└─────────────────────────────────┘
┌─────────────────────────────────┐
│ 生成任务:Language Model Head │
│ 输入 → GPT → 逐词生成 │
│ (如:根据前文生成后文) │
└─────────────────────────────────┘三、为什么要微调模型
预训练模型的局限性:
- 预训练模型的分类头是随机初始化的,在下游任务上表现接近随机猜测
- 例如二分类任务,未微调的模型准确率约50-70%,远低于实际需求
微调的价值:
- 让预训练模型适应特定任务(如文本分类、问答、翻译等)
- 充分利用预训练模型已学习的大量通用知识
- 只需少量任务数据即可获得优异效果
- 相比从头训练,大幅降低计算成本和数据需求
四、微调的原理
核心思想: 预训练 → 微调(Pre-training → Fine-tuning)
预训练 vs 微调:两种学习方式的对比
| 对比项 | 预训练(无监督学习) | 微调(监督学习) |
|---|---|---|
| 学习方式 | 无监督学习 | 监督学习 |
| 数据要求 | 海量无标注文本(TB级) | 少量标注数据(几千条) |
| 数据特点 | 只有文本,没有答案 | 文本 + 标注好的答案 |
| 学习目标 | 学习通用语言知识(词义、语法) | 学习特定任务的模式 |
| 训练方式 | 自监督:预测下一个词、填空等 | 有监督:根据答案调整模型 |
| 例子 | BERT:预测被遮盖的词 | MRPC:判断两个句子是否同义 |
通俗理解:
- 预训练 = 读书学习:模型读了海量书籍,学会了语言的基本规律,但不知道如何回答具体问题
- 微调 = 考前刷题:给模型做有答案的练习题,让它学会如何回答特定类型的考题
举例说明:
预训练阶段(无监督):
输入:海量文本,如维基百科、新闻、小说等
任务:预测下一个词、填空
例子:"今天天气很_____" → 模型学习预测"好/坏/晴..."
答案来源:文本本身(自监督)
微调阶段(监督):
输入:标注好的数据
任务:判断两个句子是否同义
例子:
句子1:"苹果发布新手机"
句子2:"Apple推出新款iPhone"
答案(人工标注):同义(label=1)
答案来源:人工标注(有监督)为什么需要两种阶段?
预训练的作用:
- 让模型掌握语言基础能力
- 一次训练,所有任务受益(通用性)
微调的作用:
- 让模型适应具体任务
- 用少量数据快速获得专业能力
关键技术:
| 组件 | 作用 |
|---|---|
| AdamW优化器 | 带权重衰减的Adam,正则化效果更好,是BERT训练的标准选择 |
| 学习率调度器 | 学习率随训练逐渐降低,初期快速学习,后期精细调整 |
| Batch训练 | 多样本并行计算,梯度更稳定,训练更平滑 |
五、微调流程
完整流程图:
┌─────────────────────────────────────────────────────────────────────────────┐
│ 模型微调完整流程 │
└─────────────────────────────────────────────────────────────────────────────┘
┌──────────────────┐
│ 1. 数据准备 │
│ load_dataset() │
│ 获取训练/验证集 │
└───┬──────────────┘
│
▼
┌──────────────────┐
│ 2. 数据预处理 │
│ Tokenizer分词 │
│ → input_ids │
│ 动态填充 │
└───┬──────────────┘
│
▼
┌──────────────────┐
│ 3. 模型加载 │
│ from_pretrained │
│ ('bert-base') │
│ num_labels=2 │
└───┬──────────────┘
│
▼
┌──────────────────┐
│ 4. 训练配置 │
│ epochs=3 │
│ lr=5e-5 │
│ batch_size=8 │
│ AdamW优化器 │
└───┬──────────────┘
│
▼
┌──────────────────┐
│ 5. 训练循环 │─────────────────────────────┐
│ │ │
│ ┌─────────────┐ │ 每个batch: │
│ │ 前向传播 │ │ 1. outputs = model(**batch)│
│ │ 计算loss │ │ 2. loss.backward() │
│ └─────────────┘ │ 3. optimizer.step() │
│ │ │ 4. optimizer.zero_grad() │
│ ▼ │ │
│ ┌─────────────┐ │ 重复num_epochs轮 │
│ │ 反向传播 │ │◄────────────────────────────┘
│ │ 计算梯度 │ │
│ └─────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ 更新参数 │ │
│ │ 清零梯度 │ │
│ └─────────────┘ │
└───┬──────────────┘
│
▼
┌──────────────────┐
│ 6. 评估 │
│ predict验证集 │
│ argmax(logits) │
│ → 预测类别 │
│ 计算accuracy/F1 │
└───┬──────────────┘
│
▼
┌──────────────────┐
│ 7. 保存模型 │
│ save_pretrained │
│ (模型+tokenizer)│
└──────────────────┘1. 数据准备
python
from datasets import load_dataset
raw_datasets = load_dataset("glue", "mrpc") # 加载MRPC句子对分类数据集2. 数据预处理
python
from transformers import AutoTokenizer, DataCollatorWithPadding
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
# 分词处理
def tokenize_function(example):
return tokenizer(example["sentence1"], example["sentence2"], truncation=True)
tokenized_datasets = raw_datasets.map(tokenize_function, batched=True)
# 动态填充(保证batch内长度统一)
data_collator = DataCollatorWithPadding(tokenizer=tokenizer)3. 模型加载
python
from transformers import AutoModelForSequenceClassification
model = AutoModelForSequenceClassification.from_pretrained("bert-base-uncased", num_labels=2)4. 训练配置
python
from transformers import TrainingArguments, Trainer
training_args = TrainingArguments(
"test-trainer",
eval_strategy="epoch", # 每个epoch结束后评估
num_train_epochs=3,
learning_rate=5e-5,
per_device_train_batch_size=8
)5. 训练循环
python
trainer = Trainer(
model,
training_args,
train_dataset=tokenized_datasets["train"],
eval_dataset=tokenized_datasets["validation"],
data_collator=data_collator,
processing_class=tokenizer,
compute_metrics=compute_metrics
)
trainer.train()手动训练循环(无Trainer API):
python
# 优化器和学习率调度器
optimizer = AdamW(model.parameters(), lr=5e-5)
lr_scheduler = get_scheduler("linear", optimizer, num_training_steps=num_training_steps)
# 训练
model.train()
for epoch in range(num_epochs):
for batch in train_dataloader:
outputs = model(**batch) # 前向传播
loss = outputs.loss
loss.backward() # 反向传播
optimizer.step() # 更新参数
lr_scheduler.step() # 更新学习率
optimizer.zero_grad() # 清零梯度6. 评估
python
import evaluate
metric = evaluate.load("glue", "mrpc")
predictions = trainer.predict(tokenized_datasets["validation"])
preds = np.argmax(predictions.predictions, axis=-1)
metric.compute(predictions=preds, references=predictions.label_ids)7. 保存模型
python
model.save_pretrained("./my-model")
tokenizer.save_pretrained("./my-model")六、微调后的效果
MRPC任务效果对比:
| 数据集 | 指标 | Baseline(微调前) | 微调后 | 提升 |
|---|---|---|---|---|
| Validation | Accuracy | 0.6838 | 0.8578 | +17.4% |
| Validation | F1 | 0.8122 | 0.8990 | +8.7% |
| Test | Accuracy | 0.6649 | 0.8458 | +18.1% |
| Test | F1 | 0.7987 | 0.8871 | +8.8% |
效果分析:
- Accuracy相对提升约26%,属于显著提升
- 微调结果接近BERT-base的典型水平(84-85% accuracy)
- 说明微调有效,模型成功学习了任务特定的模式
与基准对比:
| 模型 | Accuracy | F1 |
|---|---|---|
| 原始BERT(未微调) | ~60-70% | ~75-80% |
| 微调后BERT-base | 84-85% | 88-89% |
| 更强模型(RoBERTa等) | ~90% | ~92% |
| 人类水平 | ~90% | ~92% |
七、Embedding 语义向量
1. 什么是 Embedding?
定义: Embedding 是将文本转换为高维向量(数值数组)的过程,使得语义相似的文本在向量空间中距离更近。
"How to load dataset" → [0.12, -0.34, 0.56, ..., 0.78] (768维向量)
"I want to download data" → [0.15, -0.30, 0.52, ..., 0.75] (语义相似,向量相近)
"The weather is nice" → [0.89, 0.12, -0.45, ..., -0.23] (语义不同,向量距离远)通俗理解:
- Embedding = 把文字翻译成数字坐标
- 语义相似的两个句子,坐标位置相近
- 通过向量距离就能判断语义相似度
八、RAG 检索增强生成
1. 什么是 RAG?
定义: RAG(Retrieval-Augmented Generation) = 检索 + 生成
核心流程:
用户问题 → Embedding → 向量检索 → 获取相关文档 → 拼接到Prompt → LLM生成回答为什么需要 RAG?
| 问题 | RAG 解决方案 |
|---|---|
| LLM知识过时 | 实时检索最新文档 |
| LLM会编造答案 | 基于真实文档回答 |
| 私有数据无法训练 | 检索私有知识库 |
2. RAG 完整流程
┌─────────────────────────────────────────────────────────────┐
│ RAG 架构 │
└─────────────────────────────────────────────────────────────┘
【阶段一:知识库构建】
文档 → 分块 → Embedding → 存入向量数据库(FAISS)
┌────────────┐
│ 原始文档 │
│ (10000字) │
└───┬────────┘
│ 分块
▼
┌────────────┐
│ Chunk 1 │ → Embedding → 存入FAISS
│ Chunk 2 │ → Embedding → 存入FAISS
│ Chunk 3 │ → Embedding → 存入FAISS
└────────────┘
【阶段二:查询】
问题 → Embedding → FAISS相似度搜索 → Top-K相关文档
┌────────────┐
│ 用户问题 │
│ "如何..." │
└───┬────────┘
│ Embedding
▼
┌────────────┐
│ 查询向量 │
│ [0.12,...] │
└───┬────────┘
│ FAISS搜索
▼
┌────────────┐
│ 相关文档 │
│ Top-K=5 │
└────────────┘
【阶段三:生成】
问题 + 相关文档 → Prompt → LLM → 回答
┌─────────────────────────────────┐
│ Prompt: │
│ 问题:如何加载离线数据集? │
│ 参考资料: │
│ - 文档1: 使用load_dataset()... │
│ - 文档2: 支持CSV/JSON格式... │
│ 请基于参考资料回答: │
└────────────┴────────────────────┘
↓
┌──────────┐
│ LLM │
└──────────┘
↓
┌──────────┐
│ 回答 │
└──────────┘3. Embedding 搜索 vs 关键词搜索
| 对比项 | 关键词搜索 | Embedding 语义搜索 |
|---|---|---|
| "如何下载模型" | 匹配不到"离线加载" | 能匹配(语义相似) |
| "报错了怎么办" | 匹配不到具体错误 | 能找到解决方案 |
| 精确度 | 精确匹配 | 语义理解 |
| 适用场景 | 明确关键词 | 自然语言问答 |
九、Agentic RAG(智能检索)
传统 RAG vs Agentic RAG
【传统 RAG - 被动检索】
用户问题 → 固定流程检索 → 拼接文档 → LLM生成
特点:检索是前置的、固定的、模型被动接收
【Agentic RAG - 主动检索】
用户问题 → LLM分析 → LLM决定是否检索 →
LLM调用检索工具 → LLM分析结果 → 可能再检索 → LLM总结
特点:检索由模型主动决策、可迭代、可多轮Agentic RAG 的优势
| 优势 | 说明 |
|---|---|
| 智能判断 | 模型自己判断是否需要检索("你好"不需要检索) |
| 动态查询 | 模型可以优化查询词 |
| 迭代检索 | 第一次不满意,可以调整策略再检索 |
| 多源检索 | 可以调用多个不同的知识库 |
| 上下文理解 | 根据对话历史决定检索什么 |
流程示例
用户:"HuggingFace datasets 如何处理大数据?"
↓
LLM分析:"需要检索知识库"
↓
LLM调用:search("datasets large data memory mapping", k=5)
↓
工具返回:5条相关文档
↓
LLM分析:"提到了memory mapping,但不够详细,再检索"
↓
LLM调用:search("Apache Arrow lazy loading", k=3)
↓
工具返回:3条补充文档
↓
LLM总结:综合所有文档生成回答全文关键要点总结
Transformer 与 NLP 基础
- Transformer核心:自注意力机制,让每个词都能看到其他所有词
- BERT vs GPT:BERT双向理解(分类、问答),GPT单向生成(写作、对话)
- 四大NLP任务:文本分类、序列标注、文本生成、问答抽取
微调核心流程
- 微调必要性:预训练模型需要任务适配才能发挥作用
- 核心流程:数据准备 → 预处理 → 训练 → 评估 → 保存
- 关键技术:动态填充、AdamW优化器、学习率调度
- 效果显著:3个epoch即可达到BERT-base典型水平
Embedding 与 RAG
- Embedding本质:把文本翻译成数字坐标,语义相似的坐标相近
- 维度由模型决定:BERT-base是768维,越大模型维度越高
- RAG流程:知识库构建 → 查询检索 → Prompt拼接 → LLM生成
- 语义搜索优势:能理解用户意图,比关键词搜索更智能
- Agentic RAG:让模型主动决定是否检索、如何检索
- 文档过长方案:分块是最常用的解决方案