首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【大模型学习 | SFT & PPO原理&代码实现】

【大模型学习 | SFT & PPO原理&代码实现】

原创
作者头像
九年义务漏网鲨鱼
发布2025-07-22 19:58:37
发布2025-07-22 19:58:37
1.2K0
举报

Training language models to follow instructions with human feedback

🎯 在学习完prompting工程【大模型学习 | Prompt工程基础学习】-腾讯云开发者社区-腾讯云,RAG技术【大模型学习 | RAG & DeepSeek 实战】-腾讯云开发者社区-腾讯云后,虽然模型已经可以输出用户想要的信息,但是依然可能存在着幻觉、有害内容、不遵循指令等情况。它能启发任务能力,但无法系统控制模型行为。这是由于目前答案的生成是通过预测网页文本数据的下一个token,作者认为这是语言建模目标的不一致,为此,作者提出采用reinforcement learning from human feedback (RLHF)来微调GPT3.

一、微调方法

InstructGPT主要分为了三个步骤:

Step1. 标注数据,通过SFT(有监督微调)来训练模型

Step2. 收集相同prompt不同模型的输出数据,并标注不同输出的得分排名,构建奖励模型RM,训练出一个可以选择出更符合人类偏好的模型

Step3. 将奖励模型作为奖励函数,通过PPO最大化奖励机制微调SFT后的模型

1️⃣ Supervised fine-tuning (SFT)

这一阶段的数据标注是 prompt + labeler 写的回答

在这一阶段,作者对GPT-3模型进行微调,通过标注数据集,训练16轮。作者发现:在一轮后的验证损失已经存在了过拟合,但是更多轮次的迭代训练更有助于RM得分以及人类偏好评级。

2️⃣ Reward modeling (RM)

这一阶段的数据标注是 prompt + 多个回答 + labeler 排序. 原本的语言模型只是根据 token 预测下一个词,并不理解‘什么是好回答’,而我们希望它学会更符合人类偏好的回答,就需要一个机制告诉它“这样回答更好”

基于上一阶段训练后的模型,作者将模型输出token的词嵌入层丢弃,并加入一个评分头,用于输出一个标量reward得分。作者只采用了6B大小作为RM模型,因为175B的模型不稳定,不适合用于奖励函数。(在之前的做法中,是通过同一个prompt输出两个结果,让模型选择更优的结果来训练奖励函数。)在本文中,作者在每个prompt中输出4-9个回答,如果采用以前的方式,会产生$C(9,2)$个问答对,容易导致过拟合,这是由于:

🧠 将每一个问答对作为一个独立样本的话,会导致模型在同一个 prompt 上见到太多相关数据,进而过拟合到局部排序模式而不是学到真正的泛化偏好信号。例如同一个 prompt 会在多个 batch 中反复出现,比如:

less复制编辑Prompt A: - A > B - A > C - B > D ...

模型每次都在更新:A 比 B 好,A 比 C 好…,会特别强化 A 的 reward,即使这些比较结果之间有冗余。容易在这个 prompt 上学得太好,导致泛化能力差

为此,作者将这些问答对放在同一个batch中进行训练,所有回答仅需进行一次前向传播,获得所 reward分数,对这些reward分数进行组合、计算 pairwise loss

3️⃣ Reinforcement learning (RL)

这一阶段的数据标注是 prompt + 模型生成回答(无需标注)

在 SFT 阶段,模型只是模仿人类写的回应; 在 PPO (RL)阶段,模型要自己尝试回应,然后通过 Reward Model 打分,优化“怎么写人更喜欢”。

强化学习(RL):智能体(GPT-3)与一个环境(人类偏好环境)交互。环境会根据模型生成的行为(如回答一个问题)给出一个反馈信号(奖励)。如果模型的输出符合预期,就给予正向奖励;如果表现不佳,则给予较低甚至负向奖励。模型通过反复尝试、获得奖励并不断调整策略,逐步学会产生更优的输出。

PPO:是强化学习中常用的策略优化方法。它通过限制模型每次策略更新的幅度,保证训练稳定、避免模型输出发生剧烈漂移。在语言模型训练中,PPO 会让模型在获得更高奖励的同时,尽量保持语言流畅性和原始风格(通常通过引入 KL 散度惩罚项来控制变化幅度)

二、重要结论

模型能力

InstructGPT 表现

💬 人类偏好

明显优于 GPT-3,即便是小模型1.3B 的 InstructGPT 比 175B 的 GPT-3 更受人类偏好(标签员选择)

📖 事实准确

在 TruthfulQA 基准上,InstructGPT生成真值回答频率是 GPT-3 的 2 倍,RLHF 明显提升 factual 可靠性,但并非完全消除幻觉。

🚫 毒性

RealToxicityPrompts 上, InstructGPT 生成 toxic 内容减少约 25%; 在 Winogender / CrowSPairs 上偏见无显著改善

⚖️ 偏见

无显著提升

🔄 基准能力

RLHF 导致部分任务性能下降(SQuAD、DROP、HellaSwag、WMT15),存在了“对齐代价”

🌐 泛化

能处理 unseen 任务

三、代码实现

1️⃣ SFT(有监督微调):参考【大模型学习 | BLIP2 跌倒检测项目实战(一)】-腾讯云开发者社区-腾讯云

2️⃣ RM函数:难点在于把原有的输出token头换为评分头,但huggingface已经提供了可直接加载的函数:

代码语言:python
复制
from transformers import AutoModelForSequenceClassification
rm_model = AutoModelForSequenceClassification.from_pretrained("your_model", num_labels=1)

🟢 但也可以手动构造:

代码语言:python
复制
from transformers import AutoModel, AutoConfig
import torch.nn as nn

class RewardModel(nn.Module):
    def __init__(self, base_model_name):
        super().__init__()
        self.backbone = AutoModel.from_pretrained(base_model_name)
        self.reward_head = nn.Sequential(
            nn.Linear(self.backbone.config.hidden_size, 1)
        )
    
    def forward(self, input_ids, attention_mask):
        outputs = self.backbone(input_ids=input_ids, attention_mask=attention_mask)
        last_hidden = outputs.last_hidden_state  # shape: (batch, seq_len, hidden)
        cls_repr = last_hidden[:, 0, :]          # 取第一个token的表征
        reward = self.reward_head(cls_repr)
        return reward.squeeze(-1)                # 输出 shape: (batch,)

3️⃣ PPO

代码语言:python
复制
from trl import PPOTrainer, PPOConfig
def run_ppo():
    tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL, use_fast=False)
    model = AutoModelForCausalLM.from_pretrained("sft_output")
    rm_model = AutoModelForSequenceClassification.from_pretrained("rm_output").to(DEVICE)

    config = PPOConfig(
        model_name="sft_output",
        learning_rate=1e-5,
        batch_size=4,
        mini_batch_size=2,
        gradient_accumulation_steps=1,
        log_with=None
    )
    ppo_trainer = PPOTrainer(
        config=config,
        model=model,
        tokenizer=tokenizer,
        reward_model=rm_model
    )

    prompts = ["Explain the concept of overfitting."]
    for epoch in range(5):
        batch = random.sample(prompts, k=3)
        query_tensors = tokenizer(batch, return_tensors="pt", padding=True, truncation=True).input_ids.to(DEVICE)
        response_tensors = ppo_trainer.model.generate(query_tensors, max_new_tokens=100)

        texts = [tokenizer.decode(r, skip_special_tokens=True) for r in response_tensors]
        rewards = []
        for q, r in zip(batch, texts):
            input_text = f"{q}\n{r}"
            inputs = tokenizer(input_text, return_tensors="pt", truncation=True, padding=True).to(DEVICE)
            reward = rm_model(**inputs)["logits"].squeeze().item()
            rewards.append(reward)

        print(f"[PPO] E{epoch}: Rewards = {rewards}")
        ppo_trainer.step(query_tensors, response_tensors, torch.tensor(rewards))

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Training language models to follow instructions with human feedback
    • 一、微调方法
      • 1️⃣ Supervised fine-tuning (SFT)
      • 2️⃣ Reward modeling (RM)
      • 3️⃣ Reinforcement learning (RL)
    • 二、重要结论
    • 三、代码实现
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档