努力学习🀄️
RLHF
Critic模型:用于价值函数估计
Reward模型:用于奖励信号计算
RewardBySimilarity模型:基于相似度的奖励模型
代码里Critic模型继承ChatGLM-6B模型,确保与Action模型(生成模型)使用相同的词表;大幅减少层数(从原来的28层减少到1层)来降低模型大小;添加线性层输出价值分数:self.output_linear = nn.Linear(self.model.hidden_size, 1)使用tanh激活函数将分数限制在[-1,1]之间。
Reward = Critic分别计算与good_answers和bad_answers的相似度加权得到奖励。
脑瓜子嗡嗡的 不想学了 之后再补
最近要忙其他的 GRPO学习先stop一下 把搜集到的一些资料存放一下
对话相关的:https://github.com/sunsmarterjie/ChatterBox、https://github.com/ioriiod0/tiny_bot、https://github.com/aburkov/theLMbook/blob/main/GRPO_From_Scratch_Multi_GPU_DataParallel_Qwen_2_5_1_5B_Instruct.ipynb、https://blog.youkuaiyun.com/v_JULY_v/article/details/145683641、https://github.com/policy-gradient/GRPO-Zero、https://github.com/lsdefine/simple_GRPO、
实体命名识别、
https://github.com/yiyepiaoling0715/codellm-data-preprocess-pipeline
https://github.com/anakin87/qwen-scheduler-grpo/blob/main/train_grpo.ipynb
https://github.com/Miraclemarvel55/LLaMA-MOSS-RLHF-LoRA
我理解:首先,模型根据输入的 prompt 在当前策略(Actor Model)下进行推理,生成 n 个 response 作为输出。在第一次生成过程中,只关注生成了哪些 token,并不会保存每一步的 logits 或 log_probs。随后,将 prompt 与刚刚生成的 response 拼接为新的输入,再送入 Actor Model 进行前向计算,得到每个 token 的 logits(即整个词表的概率分布),对 response 部分提取每个生成 token 对应位置的 logprob,作为 old_log_prob。
同样地,将 prompt + response 输入到 Reference Model(Ref Model,通常是未经过优化的初始模型)中,计算得到 ref_log_prob,作为参考概率。将 prompt + response 输入 Reward Model,获得 reward 分数。基于 reward、old_log_prob 和 ref_log_prob 计算 advantage,用于 PPO/GRPO 的 policy loss。最终通过backward用 policy loss 更新 Actor Model 的参数。
logprob计算demo
假设词表包含5个token:<pad>(ID 0)、你好(ID 1)、世界(ID 2)、!(ID 3)、吗(ID 4)。输入prompt为"你好",对应token序列[1]。
模型生成response为"世界!",对应token序列[2,3]。前向传播过程输出的logits张量(形状为[序列长度, 词表大小])如下:
[
[-1.0, 0.5, 2.0, -0.5, -1.5], # 第一步:"你好"后接"世界"的logit最高(2.0)
[-2.0, -1.0, 0.1, 3.0, 0.2] # 第二步:"你好世界"后接"!"的logit最高(3.0)
]
概率计算过程
对logits进行softmax计算,得到每个位置的概率分布(数值为自然对数形式):
[
[-3.65, -2.15, -0.64, -3.15, -4.08], # 第一步:"世界"的log_prob=-0.64
[-4.34, -3.32, -2.20, -0.20, -2.10] # 第二步:"!"的log_prob=-0.20
]
提取实际生成token对应的log_prob值,最终序列[2,3]的log_probs为[-0.64, -0.20]。数值越小(负得越少)表示模型对该token的预测置信度越高。
GRPO
输入一个prompt复制k次从而并行采样得到一组response,计算这一组response的奖励分数并-均值/方差,advantages = (rewards - mean_group_rewards) / (std_group_rewards + 1e-8) 。加载模型,基于规则/模型的奖励评分。计算损失
这个奖励写的还挺清楚
import re
def extract_answer(text):
answer = text.split("<answer>")[-1]
answer = answer.split("</answer>")[0]
return answer.strip()
def mark_num(text):
reward = 0
if text.count("<think>\n") == 1:
reward += 0.125
if text.count("</think>\n") == 1:
reward += 0.125
if text.count("<answer>\n") == 1:
reward += 0.125
if text.count("</answer>\n") == 1:
reward += 0.125
return reward
# 生成答案是否正确的奖励
def correctness_reward(prompts, responses, answers):
extracted_responses = [extract_answer(r) for r in responses]
print(f"问题:\n{prompts[0]}", f"\n答案:\n{answers[0]}", f"\n模型输出:\n{responses[0]}", f"\n提取后的答案:\n{extracted_responses[0]}")
return [2.0 if response == str(ans) else 0.0 for response, ans in zip(extracted_responses, answers)]
# 生成答案是否是数字的奖励(单纯依赖结果是否正确进行奖励,条件很苛刻,会导致奖励比较稀疏,模型难以收敛,所以加上答案是否是数字的奖励,虽然答案错误,但是至少生成的是数字(对于数学问题),也要给予适当奖励)
def digit_reward(prompts, responses, answers):
extracted_responses = [extract_answer(r) for r in responses]
return [0.5 if response.isdigit() else 0.0 for response in extracted_responses]
# 格式奖励
def hard_format_reward(prompts, responses, answers):
pattern = r"^<think>\n.*?\n</think>\n<answer>\n.*?\n</answer>\n$"
matches = [re.match(pattern, response) for response in responses]
return [0.5 if match else 0.0 for match in matches]
# 标记奖励(改善格式奖励稀疏问题)
def mark_reward(prompts, responses, answers):
return [mark_num(response) for response in responses]
1121

被折叠的 条评论
为什么被折叠?



