手把手数学推导GRPO算法(含代码实现)

发布于 2025-7-30 06:56
浏览
0收藏

GRPO 算法全称是Group Relative Policy Optimization ,是一种针对无需奖励的强化学习人类反馈(RLHF)任务的算法。

其核心思想是通过分组相对策略优化来改进模型的表现。

想象一下——你是一位野心勃勃的大厨,参加了一场神秘的烹饪大赛。

这场比赛的规则却让你一头雾水:

❌ 你不能尝自己做的菜

❌ 没有人给你打分

❌ 没有评委点评你是“人间黑暗料理”还是“米其林之光”

你心想:这还怎么玩?瞎做一通全靠运气?

别急,这时候你灵机一动——

虽然你尝不到自己的菜,但你可以偷偷观察其他厨师做了啥、用了啥食材、摆了啥盘子、结果大家更爱看哪一桌。

于是你开始分类总结:

“哎,这几桌用鱼子酱的好像更受欢迎……”

“这一桌全是粉红配色的,好像更吸睛……”

你把这些组合按“风格”归类成一组组策略,比如:

👘“日料组”

“法餐组”

“川菜组”

然后你不再关心菜有多好吃,而是只比较:同一组里,哪种搭配更受欢迎?

恭喜你,刚刚发明了 GRPO 算法!GRPO,全称是 Group Relative Policy Optimization。听着像是博士论文标题,其实它的精髓很简单:

  • 不靠“打分”这种绝对评价
  • 靠“谁比谁强”这种相对排序
  • 把策略分组,在组内选最强

组与组之间还能同时探索多种风格,避免大家全扎堆做水煮肉片。

GRPO 就像一个聪明的、不靠嘴巴靠眼神评菜的大厨。它不需要你给个“你这道菜80分”,它只要知道“你这道比那道更讨喜”,它就能一步步变得更强。

原来这就是GRPO

如果把大型语言模型比作一群正在参加辩论大赛的聪明小伙伴,以前的做法是请一个严厉的裁判(外部评估者)来打分、点评,告诉大家谁表现好谁该回家反思。结果大家说话都小心翼翼,还得时刻看裁判脸色,进步慢得像蜗牛爬。

GRPO 的做法就不一样了,它直接取消了那个碎碎念的裁判!改成让小伙伴们自己组团互评。比如,一群人围坐成圈,一人发表观点,剩下的人开始点评:“你这个想法新颖!”、“这个推理有点绕啊!”、“妙啊,妙不可言!”——大家相互较劲、相互激发灵感,比谁的思路更清晰、更有说服力。

这种“没有裁判,自带竞技场”的模式,让大伙在互相较量中不断成长。因为不再拘泥于讨好裁判,他们能更自由地探索复杂问题,还能锻炼出一口气把长难题说清楚的超强推理能力

所以说,GRPO就像是给大脑开了一场没有终点的思维马拉松,跑着跑着,模型的脑瓜子就越来越灵光啦!你说,这种“内卷式进化”,谁能不爱呢?

下图是 PPO的一个图示:

手把手数学推导GRPO算法(含代码实现)-AI.x社区

而 GRPO 更像是下面这样:

手把手数学推导GRPO算法(含代码实现)-AI.x社区

GRPO 的创新在于它打破了传统强化学习对奖励信号的依赖,通过组内相对策略优化来实现模型的自我提升。这一创新点使得GRPO在无需明确奖励信号的场景下仍能进行有效学习,极大地拓展了强化学习的应用范围。

手把手数学推导GRPO算法(含代码实现)-AI.x社区

在 GRPO 算法中,每个小组内的模型策略都会相互比较,通过相对排序来找出当前组内最优的策略。这种组内竞争机制促使模型不断尝试新的策略组合,以在组内脱颖而出。

手把手数学推导GRPO算法(含代码实现)-AI.x社区

下图是它们两者的区别:

手把手数学推导GRPO算法(含代码实现)-AI.x社区

GRPO 是不同组之间相互比较:

手把手数学推导GRPO算法(含代码实现)-AI.x社区

GRPO算法就像小朋友们分组玩游戏,不看谁得分高,只看谁比谁更厉害。每组小朋友都比着谁更聪明,想出好办法。这样,大家玩着玩着就变得更聪明了,就像大脑开了场思维马拉松!

手把手数学推导GRPO算法(含代码实现)-AI.x社区

哪组表现好,哪组就能拿到最高奖。

手把手数学推导GRPO算法(含代码实现)-AI.x社区

GRPO 通过对各组得分进行排序,就像小朋友们分组玩游戏,不比谁得分高,只比谁想法好。每组都想出好办法,玩着玩着大家就更聪明了。这就是GRPO算法,让模型在玩游戏中变得更厉害!

手把手数学推导GRPO算法(含代码实现)-AI.x社区

怎么样,是不是很简单呢。

纸上推演: GRPO的数学推演

和之前一样,我们可以尝试尝试用Excel来解释GRPO,这年头谁还不会Excel呢。

首先,我们初始化一个输入,和之前一样,6个Token,每个是5维的向量。

手把手数学推导GRPO算法(含代码实现)-AI.x社区

接下来先计算一下新的策略与旧的策略的比值,π / π_old,模拟策略偏移程度。

手把手数学推导GRPO算法(含代码实现)-AI.x社区

优势:每个Token的独特优势,源于其在奖励排名中的位置。

手把手数学推导GRPO算法(含代码实现)-AI.x社区

Clipped π/π_old: 限制在[0.8, 1.2]范围内,以防止策略过度波动

手把手数学推导GRPO算法(含代码实现)-AI.x社区

π*A:策略优势乘数,代表学习的方向

手把手数学推导GRPO算法(含代码实现)-AI.x社区

Clipped π*A: 应用clip函数后的更稳定优化结果,这个乘数确保了策略更新既不会过于激进也不会过于保守,有助于模型在保持稳定性的同时逐步改进。

手把手数学推导GRPO算法(含代码实现)-AI.x社区

Final Loss: 每个Token的最终损失等于 min(πA, Clipped πA)。这个损失函数的设计体现了GRPO算法的核心思想:在保持策略稳定性的同时,追求策略的相对优势。通过限制策略更新的幅度(Clipped π/π_old),算法避免了因策略突变而导致的性能不稳定。同时,利用策略优势乘数(π*A)指导学习方向,使得模型能够逐步向更优的策略靠近。

手把手数学推导GRPO算法(含代码实现)-AI.x社区

KL Proxy: 每个Token的策略偏移度量等于(π/π_old - 1)^2。这个度量反映了新策略与旧策略之间的差异程度,是衡量策略更新幅度的关键指标。在GRPO算法中,KL Proxy不仅用于监控策略的稳定性,还作为调整学习步长的重要依据。当KL Proxy值较大时,意味着策略更新幅度较大,可能会引发性能不稳定,此时算法会倾向于减小学习步长,以平稳过渡;而当KL Proxy值较小时,表明策略更新较为平缓,算法则可以适当增大学习步长,以加速学习进程。

手把手数学推导GRPO算法(含代码实现)-AI.x社区

下面是KL代理计算的公式:

手把手数学推导GRPO算法(含代码实现)-AI.x社区

wpsoffice

其中:

π(oi,t)表示在状态t下采取动作Oi的新策略概率

π_old((oi,t)表示在状态t下采取动作Oi的旧策略概率

Σ表示对所有可能的状态和动作进行求和。

这个公式计算了每个状态下每个动作的新旧策略概率比值的平方差之和,从而量化了策略更新的幅度。

通过监控KL Proxy值的变化,算法能够动态调整学习步长,确保策略更新的稳定性和有效性。

下面是针对输入的Token的计算结果:

手把手数学推导GRPO算法(含代码实现)-AI.x社区

平均 Loss: 所有为 0.00045977

平均 KL : ≈ (0.0008011 + 0.0002615 + 0.001144 + 0.000688 + 0.000998 + 0.000705) / 6

≈ 0.0007662

最终计算得出:

GRPO = 0.00045977 - 0.1 * 0.0007662 ≈ 0.00038315

嘿,各位,看到这里有何感想?在本节中,我们运用了名为GRPO的算法对模型进行了一次小规模的“优化”,结果如何呢?确实,平均损失又悄然下降了一些!这可是在缺乏奖励信号的情况下实现的,必须承认,GRPO算法在强化学习领域确实显示出了它的独特优势。

木牛流马:GRPO的代码实现

组相对策略优化的核心理念在于评价你的表现,并非基于绝对的优秀程度,而是基于你相较于同组成员的相对优势。

为何这种方法更聪明?

在传统的 AI 训练模式中,模型是独立工作的,它只专注于提升自身的性能。然而,在 GRPO 中,模型被划分为若干个“专家组”,每个小组都有其独特的评价标准。

这样做有什么益处?

✅ 促进多样性,认识到并非只有完全一致的表现才是优秀;

✅ 实现更稳定的学习过程,避免被少数表现突出的“尖子生”所左右。

下让我们用 Python 来模拟一下!接下来将编写一段简洁的代码,通过类比的方式展示 GRPO 的工作原理。

# 导入 PyTorch 库

import torch
from torch.distributions import Categorical
import torch.nn as nn
import torch.optim as optim

# 定义一个“学生模型”,用于根据输入状态选择一个动作(例如选择题选项)
class StudentModel(nn.Module):
    def __init__(self):
        super(StudentModel, self).__init__()
        self.fc = nn.Linear(4, 3)  # 输入4个知识点熟练度,输出3个动作的logits

    def forward(self, state):
        return torch.softmax(self.fc(state), dim=-1)


# 模拟一次考试:让模型对100道题目做出选择
def take_exam(model):
    records = []
    for _ in range(100):
        state = torch.rand(4)  # 模拟一个4维状态(知识点掌握度)
        probs = model(state)
        dist = Categorical(probs)
        action = dist.sample()
        score = torch.rand(1).item()  # 模拟得分(0~1)
        
        # 记录状态、动作、对数概率、得分
        records.append((state, action, dist.log_prob(action), score))
    
    return records


# 计算相对得分(优势值):每个得分减去平均分
def compute_relative_score(records):
    scores = torch.tensor([r[3] for r in records])
    baseline = scores.mean()
    return scores - baseline


# 使用相对优势优化模型参数(策略梯度 + PPO 风格 clip)
def optimize_model(model, records, relative_scores):
    optimizer = optim.Adam(model.parameters(), lr=0.01)
    
    for (state, action, old_log_prob, _), adv in zip(records, relative_scores):
        probs = model(state)
        dist = Categorical(probs)
        new_log_prob = dist.log_prob(action)

        ratio = torch.exp(new_log_prob - old_log_prob.detach())

        # PPO 中的 clipped surrogate objective
        surr1 = ratio * adv
        surr2 = torch.clamp(ratio, 0.8, 1.2) * adv
        loss = -torch.min(surr1, surr2)

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()


# 模型训练流程(模拟5轮考试)
def main():
    model = StudentModel()
    for round_num in range(5):
        exam_results = take_exam(model)
        rel_scores = compute_relative_score(exam_results)
        optimize_model(model, exam_results, rel_scores)

        print(f"Round {round_num + 1}: 平均相对进步 = {rel_scores.mean():.3f}")

if __name__ == "__main__":
    main()

让我们来解释一下上面的代码:

模型与基础库导入:

import torch

from torch.distributions import Categorical
  • torch:深度学习的核心库,用于张量计算和自动求导。
  • Categorical:离散概率分布,用于从一组概率中抽样 —— 类比“学生在多个选项中选择答案”。

定义“学生模型”——策略网络:

class StudentModel(torch.nn.Module):
    def __init__(self):
        super().__init__()
        self.fc = torch.nn.Linear(4, 3) # 输入4个知识点,输出3个动作(选项)

    def forward(self, state):
        return torch.softmax(self.fc(state), dim=-1)

这是一个简单的策略网络(Policy Network),用来决定“在某个状态下选择哪个动作”。

  • ​self.fc = torch.nn.Linear(4, 3)​​:输入4个维度(知识点特征),输出3个维度(选项概率)。
  • ​softmax​​:将输出转成合法的概率分布,符合策略概率π(a|s) 的定义。

“考试过程”——生成交互数据:

def take_exam(model):
    records = []

    for _ in range(100):
        state = torch.rand(4) # 随机生成一个状态(知识点掌握情况)
        probs = model(state) # 得到选择每个选项的概率分布
        dist = Categorical(probs) # 定义分类分布
        action = dist.sample() # 根据概率随机选择一个选项
        score = torch.rand(1).item() # 随机生成得分(模拟环境反馈)
        records.append((state, action, dist.log_prob(action), score))
    
    return records

这就是策略梯度算法的采样过程,采集状态-动作-回报 的三元组,构成经验数据。

这里的 score 相当于奖励(Reward),模拟现实世界的反馈。

dist.sample() 模拟了现实决策中的“试探性尝试”(探索)。

dist.log_prob(action) 是策略的对数概率,后面用来计算策略改进比例。

GRPO 核心 —— 计算相对优势(Advantage):

def compute_relative_score(records):
    rewards = torch.tensor([r[3] for r in records]) # 提取所有得分
    baseline = rewards.mean() # 小组平均水平(基线)
    
    return rewards - baseline # 相对优势 Advantage = Reward - Baseline

这里就是GRPO的“组内对比”机制,用的是优势函数 A(s, a)。

高于平均水平的表现会得到正的优势奖励,低于平均水平的表现产生负反馈。

直观理解:

“考得比班级平均分高” → 奖励大;

“考得比平均分低” → 下次要改进。

用 Advantage 更新模型 —— 策略优化:

# 使用相对优势优化模型参数(策略梯度 + PPO 风格 clip)
def optimize_model(model, records, relative_scores):
    optimizer = optim.Adam(model.parameters(), lr=0.01)
    
    for (state, action, old_log_prob, _), adv in zip(records, relative_scores):
        probs = model(state)
        dist = Categorical(probs)
        new_log_prob = dist.log_prob(action)

        ratio = torch.exp(new_log_prob - old_log_prob.detach())

        # PPO 中的 clipped surrogate objective
        surr1 = ratio * adv
        surr2 = torch.clamp(ratio, 0.8, 1.2) * adv
        loss = -torch.min(surr1, surr2)

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

采用了 PPO(Proximal Policy Optimization) 的核心思想 —— 剪切目标函数,防止剧烈更新。

  • ratio = π_new / π_old:策略改进幅度比值。
  • torch.clamp(ratio, 0.8, 1.2):限制每次更新在 ±20% 以内,保证学习稳定。

为什么要乘以 adv?

  • 正的 Advantage → 鼓励这个动作(增大概率);
  • 负的 Advantage → 惩罚这个动作(减少概率)。

完整的训练过程如下:

model = StudentModel()

for round in range(5):

exam_results = take_exam(model)

rel_scores = compute_relative_score(exam_results)

optimize_model(model, exam_results, rel_scores)

print(f"Round {round+1}: 平均相对进步 = {rel_scores.mean():.3f}")

这是标准的策略优化循环:采样 → 计算优势 → 策略更新,每一轮都打印平均相对进步,观察模型是否在逐渐改进。

直观类比:

5轮模拟了5次大考,每次考完互相切磋复盘,不断提高水平。

GRPO 相当于为 AI 构建了一个“同侪比较”的学习框架——目标不在于超越他人,而在于超越团队平均水平!这一机制有助于 AI 更加贴近人类的思维模式,例如:

  • 多角度分析问题(组内差异性)
  • 动态调整策略(避免死记硬背)
  • 培养更智慧、更通用的学习能力

GRPO是DeepSeek的又一创新,通过组内对比,不仅让 AI 学会了“择优而从”,还学会了“反思与调整”。在每一次的模拟考试中,AI 都能从同伴的表现中汲取经验,不断优化自身的决策策略。这种学习方式,不仅提高了 AI 的学习效率,更使其具备了更强的适应能力和创新能力。

在未来的发展中,我们可以期待 GRPO 框架在更多领域得到应用。无论是自动驾驶、医疗诊断,还是金融投资、教育辅导,GRPO 都能为 AI 提供一个更加高效、智能的学习路径。通过不断地组内对比和策略优化,AI 将能够更快速地适应复杂多变的环境,为人类社会的发展贡献更多的智慧和力量。

本文转载自 ​AI大模型世界​​,作者:roclv

收藏
回复
举报
回复
相关推荐