AI大模型原理剖析和实战(第四部分:后训练与微调)

第四部分:大模型后训练与微调

摘要 :本部分聚焦于如何"定制"你的大模型。我们将学习 SFT(有监督微调) 让模型听懂指令,掌握 LoRA 技术以极低成本适配垂直领域,并深入 RLHF(人类反馈强化学习) 的数学原理与代码实现------这是 DeepSeek-R1 等推理模型能产生强大逻辑思维的关键技术。


第11章 【后训练】有监督微调 (SFT)

11.1 什么是 SFT (Supervised Fine-Tuning)?

预训练模型本质上是个"续写机"。如果你问它:"中国的首都在哪里?",它可能会续写:"这个问题的答案很简单..."而不是直接回答"北京"。 SFT 的目的就是通过 (指令, 回答) 数据对,教会模型遵循对话格式。

  • 数据格式

    json 复制代码
    {
      "instruction": "请解释量子纠缠。",
      "input": "",
      "output": "量子纠缠是指两个或多个粒子处于一种纠缠态..."
    }
  • 训练差异

    • 预训练:对所有 Token 计算 Loss。
    • SFT :通常只对 Output(回答部分) 计算 Loss,忽略 Instruction 部分(Masking)。

11.2 强大的微调框架:LLaMA-Factory

手写训练循环虽然有助于理解,但在工程实践中,我们通常使用成熟框架。LLaMA-Factory 是目前最流行的开源微调框架,支持 DeepSeek、Qwen、Llama 等几乎所有主流模型。

【实战】使用 LLaMA-Factory 进行 LoRA 微调

  1. 安装

    bash 复制代码
    git clone https://github.com/hiyouga/LLaMA-Factory.git
    cd LLaMA-Factory
    pip install -e .[metrics]
  2. 启动 Web UI(小白友好模式)

    bash 复制代码
    llamafactory-cli webui
    • 在网页中选择模型路径(如 deepseek-llm-7b-chat)。
    • 选择微调方法(LoRA)。
    • 选择数据集(可以是自定义的 json 文件)。
    • 点击"开始训练"。
  3. 命令行启动(服务器模式)

    bash 复制代码
    llamafactory-cli train \
        --stage sft \
        --do_train \
        --model_name_or_path deepseek-ai/deepseek-llm-7b-base \
        --dataset my_custom_data \
        --finetuning_type lora \
        --output_dir ./saves/deepseek_lora \
        --per_device_train_batch_size 4 \
        --gradient_accumulation_steps 4 \
        --lora_rank 8 \
        --fp16

11.3 思维链 (CoT) 数据构造

DeepSeek 的强大在于推理。普通 SFT 数据只给结果,CoT 数据给过程。

  • 普通数据问:1+1等于几? 答:2
  • CoT 数据问:1+1等于几? 答:思考过程:这是一个基本的算术加法。1代表一个单位... 结论:2 实战技巧 :利用 GPT-4 或 DeepSeek-V3 生成带有 <thinking> 标签的数据来蒸馏小模型。

第12章 【后训练】参数高效微调 (PEFT)

全参数微调(Full Fine-tuning)需要消耗的显存是推理的 4 倍以上。对于 7B 模型,全参数微调至少需要 80GB A100。而 PEFT 让你可以用 RTX 3090/4090 在家微调大模型。

12.1 LoRA (Low-Rank Adaptation) 原理与实战

核心原理 : 不需要更新巨大的权重矩阵 <math xmlns="http://www.w3.org/1998/Math/MathML"> W W </math>W(例如 <math xmlns="http://www.w3.org/1998/Math/MathML"> 4096 × 4096 4096 \times 4096 </math>4096×4096),而是学习两个极小的矩阵 <math xmlns="http://www.w3.org/1998/Math/MathML"> A A </math>A 和 <math xmlns="http://www.w3.org/1998/Math/MathML"> B B </math>B(例如 <math xmlns="http://www.w3.org/1998/Math/MathML"> 4096 × 8 4096 \times 8 </math>4096×8 和 <math xmlns="http://www.w3.org/1998/Math/MathML"> 8 × 4096 8 \times 4096 </math>8×4096)。 <math xmlns="http://www.w3.org/1998/Math/MathML"> W ′ = W + Δ W = W + A × B W' = W + \Delta W = W + A \times B </math>W′=W+ΔW=W+A×B 其中 <math xmlns="http://www.w3.org/1998/Math/MathML"> r r </math>r (rank) 远小于 <math xmlns="http://www.w3.org/1998/Math/MathML"> d d </math>d。训练时冻结 <math xmlns="http://www.w3.org/1998/Math/MathML"> W W </math>W,只更新 <math xmlns="http://www.w3.org/1998/Math/MathML"> A A </math>A 和 <math xmlns="http://www.w3.org/1998/Math/MathML"> B B </math>B。

【实战】手撸 LoRA 层逻辑 (PyTorch)

python 复制代码
import torch
import torch.nn as nn

class LoRALayer(nn.Module):
    def __init__(self, in_dim, out_dim, rank=8, alpha=16):
        super().__init__()
        # 1. 原始的预训练权重 (冻结)
        self.linear = nn.Linear(in_dim, out_dim, bias=False)
        self.linear.weight.requires_grad = False 
        
        # 2. LoRA 旁路矩阵 (A和B)
        # B通常初始化为0,A高斯初始化 -> 初始状态下 LoRA 不影响原模型
        self.lora_a = nn.Parameter(torch.randn(in_dim, rank) / rank)
        self.lora_b = nn.Parameter(torch.zeros(rank, out_dim))
        
        self.scaling = alpha / rank

    def forward(self, x):
        # 原始路径
        original_out = self.linear(x)
        
        # LoRA 路径: x @ A @ B * scaling
        # 注意维度匹配: (Batch, in) @ (in, r) @ (r, out) -> (Batch, out)
        lora_out = (x @ self.lora_a @ self.lora_b) * self.scaling
        
        return original_out + lora_out

# 测试
layer = LoRALayer(in_dim=1024, out_dim=512, rank=8)
x = torch.randn(1, 1024)
print(f"LoRA输出: {layer(x).shape}") # torch.Size([1, 512])

12.2 QLoRA

LoRA 解决了参数量问题,但原模型 <math xmlns="http://www.w3.org/1998/Math/MathML"> W W </math>W 还要占显存。 QLoRA :将 <math xmlns="http://www.w3.org/1998/Math/MathML"> W W </math>W 量化为 4-bit 加载,进一步将 7B 模型的微调门槛降低到 6GB 显存。


第13章 【后训练】强化学习基础

为什么 SFT 不够?因为有些东西很难写出标准答案(比如"写一个好笑的笑话")。强化学习(RL)允许我们定义"什么是好的",让模型自己去探索如何达到。

13.1 RL 核心概念映射

  • Agent (智能体):大模型本身。
  • Environment (环境):用户(Prompt)和 奖励模型。
  • Action (动作):模型生成的每一个 Token。
  • State (状态):当前的上下文(Prompt + 已经生成的 Token)。
  • Reward (奖励):生成的文本有多好(由 Reward Model 打分)。

13.2 策略梯度 (Policy Gradient)

我们要优化的是策略 <math xmlns="http://www.w3.org/1998/Math/MathML"> π \pi </math>π(即模型参数),使得期望奖励最大化。 <math xmlns="http://www.w3.org/1998/Math/MathML"> ∇ J ( θ ) ≈ E [ ∇ log ⁡ π θ ( a ∣ s ) ⋅ R ] \nabla J(\theta) \approx \mathbb{E} [\nabla \log \pi_\theta(a|s) \cdot R] </math>∇J(θ)≈E[∇logπθ(a∣s)⋅R] 通俗理解:如果动作 <math xmlns="http://www.w3.org/1998/Math/MathML"> a a </math>a 获得了高分 <math xmlns="http://www.w3.org/1998/Math/MathML"> R R </math>R,就增加产生 <math xmlns="http://www.w3.org/1998/Math/MathML"> a a </math>a 的概率;如果分低,就降低概率。


第14章 【后训练】人类反馈式强化学习 (RLHF)

这是 ChatGPT 和 DeepSeek-R1 能够实现逻辑飞跃的关键。

14.1 RLHF 三阶段流水线

  1. SFT:先训练一个稍微懂事的模型(如果不懂事,RL 很难探索出来)。
  2. Reward Model (RM) 训练
    • 人工标注:给模型的两个回答排序(A 比 B 好)。
    • 训练 RM:让 RM 给 A 的打分比 B 高。
    • 损失函数:Pairwise Ranking Loss。
  3. PPO (Proximal Policy Optimization) 训练
    • 用 RM 给模型生成的回答打分。
    • 用 PPO 算法更新模型参数。

14.2 深入 PPO 算法与 KL 散度

在强化学习中,为了防止模型为了拿高分而"胡言乱语"(Hacking the reward),我们需要约束它不能偏离原始 SFT 模型太远。 这就是 KL 散度 (KL Divergence) 的作用。

总奖励计算公式 : <math xmlns="http://www.w3.org/1998/Math/MathML"> R t o t a l = R m o d e l ( x , y ) − β ⋅ log ⁡ π R L ( y ∣ x ) π S F T ( y ∣ x ) R_{total} = R_{model}(x, y) - \beta \cdot \log \frac{\pi_{RL}(y|x)}{\pi_{SFT}(y|x)} </math>Rtotal=Rmodel(x,y)−β⋅logπSFT(y∣x)πRL(y∣x)

  • <math xmlns="http://www.w3.org/1998/Math/MathML"> R m o d e l R_{model} </math>Rmodel:奖励模型给的分。
  • <math xmlns="http://www.w3.org/1998/Math/MathML"> β ⋅ log ⁡ . . . \beta \cdot \log ... </math>β⋅log...:KL 惩罚项。如果 RL 模型生成的概率分布和 SFT 差太多,就扣分。

【实战】手撸 Reward Model 评分代码片段

python 复制代码
from transformers import AutoModelForSequenceClassification, AutoTokenizer
import torch

# 加载奖励模型 (通常基于 BERT 或 Llama 修改了最后一层)
rm_model_name = "deepseek-ai/deepseek-reward-model-dummy" # 伪代码示例
# model = AutoModelForSequenceClassification.from_pretrained(rm_model_name, num_labels=1)

def get_reward_score(prompt, response):
    # 构造输入: [CLS] Prompt [SEP] Response [SEP]
    text = f"{prompt} {response}"
    inputs = tokenizer(text, return_tensors="pt")
    
    with torch.no_grad():
        # 输出是一个标量分数
        score = model(**inputs).logits[0].item()
    return score

# 示例
prompt = "如何学好Python?"
res_A = "多写代码,多看源码。" # 好回答
res_B = "去睡觉吧。" # 坏回答

# print(f"A得分: {get_reward_score(prompt, res_A)}")
# print(f"B得分: {get_reward_score(prompt, res_B)}")

14.3 DeepSeek 的 GRPO (Group Relative Policy Optimization)

DeepSeek-R1 的创新 : 传统的 PPO 需要一个巨大的 Critic 模型(和 Actor 一样大),显存占用翻倍。 DeepSeek 提出了 GRPO

  • 不需要 Critic 模型。
  • 对同一个 Prompt 生成一组(Group)回答。
  • 计算这组回答的平均奖励,以相对优劣作为优势函数(Advantage)。
  • 效果:极大降低了 RLHF 的计算资源消耗,使得大规模强化学习成为可能。我们将在第16章详细实战 GRPO。

第四部分总结: 如果说预训练是"九年义务教育",后训练就是"大学专业课"。通过本部分,你掌握了 SFT 来规范模型输出,利用 LoRA/QLoRA 降低微调成本,并初步触达了让模型产生高级智能的 RLHF/PPO 技术。

下期预告 : 下一部分我们将深入解密 DeepSeek 的核心黑科技 ------第五部分:DeepSeek核心技术解密与逻辑推理 。我们将详细剖析 MLA (多头潜在注意力) 如何压缩 KV Cache,以及 DeepSeek-R1 是如何通过纯强化学习涌现出思维链(Chain-of-Thought)能力的,并手把手带你复现 GRPO 算法。敬请期待!

相关推荐
前端阿森纳10 小时前
从五个关键维度重新审视 RAG 架构设计
llm·aigc·ai编程
Mintopia10 小时前
🌍 技术向善:WebAIGC如何通过技术设计规避负面影响?
人工智能·aigc
Robot侠11 小时前
视觉语言导航从入门到精通(三)
llm·transformer·vln·multi-modal llm
坐吃山猪11 小时前
AutoGLMPhone03-adb模块
adb·llm·glm
LV技术派11 小时前
适合很多公司和团队的 AI Coding 落地范式(一)
前端·aigc·ai编程
EdisonZhou12 小时前
MAF快速入门(7)工作流的状态共享
llm·aigc·agent·.net core
鼎道开发者联盟12 小时前
鼎道AIGUI元件体系如何让DingOS实现“积木”式交互
人工智能·ui·ai·aigc·交互·gui
洛阳泰山12 小时前
快速上手 MaxKB4J:开源企业级智能知识库系统在 Sealos 上的完整部署指南
java·开源·llm·agent·rag
墨风如雪20 小时前
告别抽卡玄学:OpenAI GPT Image 1.5 到底强在哪?
aigc