已合并
【R1-Zero-qwen复现 Part1】GRPO+多reward #2216
AtomGit-Bot创建于 2025年2月13日
【R1-Zero-qwen复现 Part1】GRPO+多reward #2216
已合并
AtomGit-Bot创建于 2025年2月13日
refs/pull/2216/head合入到master
28 个文件变更+720-86
@@ -32,6 +32,10 @@ MindSpeed-LLM是基于昇腾生态的大语言模型分布式训练框架,旨
32 32 
33**[DeepSeek-R1-Distill-LLaMA](./examples/mcore/deepseek_r1_distill_llama/)** 😊33**[DeepSeek-R1-Distill-LLaMA](./examples/mcore/deepseek_r1_distill_llama/)** 😊
34 34 
35+🚀🚀🚀**DeepSeek-R1** 系列功能逐步上线!!🚀🚀🚀
36+ 
37+**[DeepSeek-R1-ZERO](./examples/mcore/deepseek_r1_recipes/)** 😊
38+ 
35包含数据处理、权重转换、在线推理、全参微调39包含数据处理、权重转换、在线推理、全参微调
36 40 
37## COMING !!!41## COMING !!!
@@ -300,6 +300,62 @@
300 ],300 ],
301 "replace_eos": true301 "replace_eos": true
302 },302 },
303+ {
304+ "name": "qwen_r1",
305+ "format_user": {
306+ "slots": [
307+ "<|im_start|>user\nA conversation between User and Assistant. The user asks a question, and the Assistant solves it. The assistant first thinks about the reasoning process in the mind and then provides the user with the answer. The reasoning process and answer are enclosed within <think> </think> and <answer> </answer> tags, respectively, i.e., <think> reasoning process here </think><answer> answer here </answer>Put your final answer within \\\\boxed{}. {{content}}<|im_end|>\n<|im_start|>assistant\n"
308+ ]
309+ },
310+ "format_system": {
311+ "slots": [
312+ "<|im_start|>system\n{{content}}<|im_end|>\n"
313+ ]
314+ },
315+ "format_observation": {
316+ "slots": [
317+ "<|im_start|>tool\n{{content}}<|im_end|>\n<|im_start|>assistant\n"
318+ ]
319+ },
320+ "format_separator": {
321+ "slots": [
322+ "\n"
323+ ]
324+ },
325+ "default_system": "You are a helpful assistant.",
326+ "stop_words": [
327+ "<|im_end|>"
328+ ],
329+ "replace_eos": true
330+ },
331+ {
332+ "name": "qwen_math_r1",
333+ "format_user": {
334+ "slots": [
335+ "<|im_start|>user\n{{content}}<|im_end|>\n<|im_start|>assistant\n"
336+ ]
337+ },
338+ "format_system": {
339+ "slots": [
340+ "<|im_start|>system\n{{content}}<|im_end|>\n"
341+ ]
342+ },
343+ "format_observation": {
344+ "slots": [
345+ "<|im_start|>tool\n{{content}}<|im_end|>\n<|im_start|>assistant\n"
346+ ]
347+ },
348+ "format_separator": {
349+ "slots": [
350+ "\n"
351+ ]
352+ },
353+ "default_system": "Please reason step by step, and put your final answer within \\boxed{}.",
354+ "stop_words": [
355+ "<|im_end|>"
356+ ],
357+ "replace_eos": true
358+ },
303 {359 {
304 "name": "llama3",360 "name": "llama3",
305 "format_user": {361 "format_user": {
@@ -0,0 +1,87 @@
1+defaults:
2+ - model:
3+ - qwen25-7b
4+ 
5+training:
6+ global_batch_size: 12
7+ seq_length: 4096
8+ tokenizer_type: PretrainedFromHF
9+ tokenizer_name_or_path: ./models/Qwen2.5-Math-7B
10+ train_iters: 100
11+ distributed_backend: nccl
12+ no_shared_storage: true
13+ save_interval: 10
14+ no_load_optim: true
15+ no_load_rng: true
16+ bf16: true
17+ is_instruction_dataset: true
18+ variable_seq_lengths: true
19+ no_shuffle: false
20+ stage: ray_grpo
21+ sequence_parallel: true
22+ dataset_with_labels: true
23+ 
24+actor_rollout_ref:
25+ actor_rollout:
26+ model: qwen25-7b
27+ do_sample: true
28+ micro_batch_size: 2
29+ ppo_mini_batch_size: 12
30+ num_samples_per_step: 2
31+ temperature: 1.0
32+ max_prompt_length: 1536
33+ max-tokens-to-oom: 1000000
34+ ppo_epochs: 1
35+ clip_ratio: 0.2
36+ entropy_coeff: 0.001
37+ shuffle_minibatch: false
38+ use_kv_cache: true
39+ tensor_model_parallel_size: 2
40+ pipeline_model_parallel_size: 4
41+ lr: 1e-6
42+ lr_decay_style: constant
43+ min_lr: 0.0
44+ weight_decay: 0.0
45+ lr_warmup_fraction: 0.0
46+ clip_grad: 10000.0
47+ initial_loss_scale: 4096
48+ finetune: true
49+ load: ./ckpt
50+ save: ./ckpt
51+ num_gpus_for_train: 8
52+ num_gpus_for_infer: 6
53+ data_path: ./dataset/pe-nlp/data
54+ split: 100,0,0
55+ n_samples_per_prompt: 4
56+ 
57+ ref:
58+ model: qwen25-7b
59+ tensor_model_parallel_size: 2
60+ pipeline_model_parallel_size: 1
61+ micro_batch_size: 4
62+ load: ./ckpt
63+ 
64+reward:
65+ model: qwen25-7b
66+ verifier: true
67+ tensor_model_parallel_size: 2
68+ pipeline_model_parallel_size: 1
P
Ppanchenyixxx2025年2月14日

要和R1的复现参数格式协调

likedislike
69+ micro_batch_size: 4
70+ load: ./ckpt
71+ 
72+algorithm:
73+ gamma: 1.0
74+ lam: 0.95
75+ adv_estimator: group_norm
76+ kl_penalty: kl
77+ kl_ctrl:
78+ type: fixed
79+ kl_coef: 0.05
80+ missing_eos_penalty: 0.0
81+ verifier_function: ["acc", "format"]
82+ verifier_weight: [0.5, 0.5]
83+ 
84+resource_pool:
85+ actor_rollout: [6, 8]
86+ ref: [2]
87+ reward: []
@@ -0,0 +1,33 @@
1+qwen25-7b:
2+ use_mcore_models: true
3+ num_layers: 28
4+ hidden_size: 3584
5+ ffn_hidden_size: 18944
6+ num_attention_heads: 28
7+ seq_length: 4096
8+ rotary_base: 1000000
9+ max_position_embeddings: 32768
10+ make_vocab_size_divisible_by: 1
11+ padded_vocab_size: 152064
12+ untie_embeddings_and_output_weights: true
13+ add_qkv_bias: true
14+ disable_bias_linear: true
15+ group_query_attention: true
16+ num_query_groups: 4
17+ attention_dropout: 0.0
18+ init_method_std: 0.01
19+ hidden_dropout: 0.0
20+ adam_beta1: 0.9
21+ adam_beta2: 0.95
22+ position_embedding_type: rope
23+ normalization: RMSNorm
24+ use_fused_rmsnorm: true
25+ swiglu: true
26+ use_flash_attn: true
27+ use_mc2: true
28+ no_masked_softmax_fusion: true
29+ attention_softmax_in_fp32: true
30+ no_gradient_accumulation_fusion: true
31+ use_fused_swiglu: true
32+ use_fused_rotary_pos_emb: true
33+ bf16: true
@@ -89,7 +89,7 @@ def model_provider(pre_process=True, post_process=True) -> Union[GPTModelInfer,
89 pre_process=pre_process,89 pre_process=pre_process,
90 post_process=post_process,90 post_process=post_process,
91 fp16_lm_cross_entropy=args.fp16_lm_cross_entropy,91 fp16_lm_cross_entropy=args.fp16_lm_cross_entropy,
92- parallel_output=True,92+ parallel_output=True if args.sequence_parallel else False,
93 share_embeddings_and_output_weights=not args.untie_embeddings_and_output_weights,93 share_embeddings_and_output_weights=not args.untie_embeddings_and_output_weights,
94 position_embedding_type=args.position_embedding_type,94 position_embedding_type=args.position_embedding_type,
95 rotary_percent=args.rotary_percent,95 rotary_percent=args.rotary_percent,
@@ -101,7 +101,7 @@ def model_provider(pre_process=True, post_process=True) -> Union[GPTModelInfer,
101 101 
102 model = GPTModel(102 model = GPTModel(
103 config,103 config,
104- parallel_output=True,104+ parallel_output=True if args.sequence_parallel else False,
105 pre_process=pre_process,105 pre_process=pre_process,
106 post_process=post_process106 post_process=post_process
107 )107 )
@@ -0,0 +1,156 @@
1+# DeepSeek-R1-Zero(qwen)
2+该特性是基于GPRO+ORM基础上扩展打分器进行混合打分而来,可用于复现DeepSeek-R1-Zero的工作
3+ 
4+## 整体流程示意图
5+![](../../../sources/images/r1/R1-Zero-qwen.png)
6+ 
7+ 
8+ 
9+## **模型**
10+ 
11+##### 模型选择
12+* Qwen2.5-Math-7B
13+我们先尝试了该模型,发现模型在初始prompt上对数学类问题的回复存在代码文字混用,中英文混杂的情况;当加了回复格式的约束指令后,没法引导出模型按`<think></think><answer></answer>`格式回复,且回复变得容易重复且难以读懂
14+* Qwen2.5-7B-Instruct
15+该模型指令遵从度高,有一定概率能引导模型输出`<think>...</think><answer>...$\boxed{}</answer>`格式回复
16+ 
17+为了模型达到更好的效果,我们以下以Qwen2.5-7B-Instruct为例
18+ 
19+##### 权重转换
20+同MindSpeed-LLM仓一样,模型需要从HuggingFace权重转换为MindSpeed权重,可参考[**这里**](../../../docs/features/checkpoint.md)
21+ 
22+ 
23+## 模板构造
24+R1-Zero是基于一个base模型训练而来,由于其基底模型本身并没有激发长思维的能力,因此我们
25+需要根据选择的模型进行调试,编写prompt模板以激发`<think>...</think><answer>...$\boxed{}</answer>`,以Qwen2.5-7B-Instruct为例:
26+ 
27+```
28+<|im_start|>system\nYou are a helpful assistant.<|im_end|>\n<|im_start|>user\nA conversation between User and Assistant. The user asks a question, and the Assistant solves it. The assistant first thinks about the reasoning process in the mind and then provides the user with the answer. The reasoning process and answer are enclosed within <think> </think> and <answer> </answer> tags, respectively, i.e., <think> reasoning process here </think><answer> answer here </answer>Put your final answer within \\boxed{}.\n{你真正的问题}<|im_end|>\n<|im_start|>assistant\n{模型真正的回答}
29+```
30+ 
31+用户可以在`configs/finetune/templates.json`添加自己的自定义模板,添加的新数据模板需要在`preprocess_data.py``mindspeed_llm/training/arguments.py`中的`prompt-type`参数choices里加上响应的自定义模板名字
32+ 
33+ 
34+## 数据集
35+使用SimpleRL仓默认的8K数据集
36+* [pe-nlp/math_level3to5_data_processed_with_qwen_prompt](https://huggingface.co/datasets/pe-nlp/math_level3to5_data_processed_with_qwen_prompt?row=0)
37+ 
38+处理的时候要使用qwen_r1的模板(或者自行参考上一节进行构造,自定义数据集需要设置--map-keys映射,具体参考[**这里**](../../../docs/features/alpaca_dataset.md))
39+ 
40+```
41+python ./preprocess_data.py \
42+ --input ./dataset/pe-nlp/train-00000-of-00001.parquet \
43+ --tokenizer-name-or-path ./models/Qwen2.5-7B-Instruct \
44+ --output-prefix ./dataset/pe-nlp/data \
45+ --handler-name AlpacaStyleInstructionHandler \
46+ --tokenizer-type PretrainedFromHF \
47+ --workers 4 \
48+ --log-interval 1000 \
49+ --prompt-type qwen_r1 \
50+ --map-keys '{"prompt":"question", "query":"", "response": "ground_truth_answer", "system":""}' \
51+ 
52+```
53+ 
54+## 打分器
55+DeepSeek-R1-Zero训练的过程中仅使用了基于程序的打分器而没有使用ORM,我们在数学领域上参考OpenR1的打分逻辑分为以下几个部分:
56+* [权重: 0.5] 回答风格格式分:完全遵从格式`<think> reasoning process here </think><answer> answer here with final answer within \\boxed{}</answer>`的得1分,否则得0分
57+* [权重: 0.5] 准确性得分:模型回复中boxed中提取的与标准答案一致得1分,否则-1分
58+ 
59+## 训练
60+##### 背景
61+```
62+传统的PPO中需要一个通过广义优势估计(Generalized Advantage Estimation)计算得到的advantage,并依赖于和reward model同结构的需要同步训练的critic model计算得到价值函数(V)
63+```
64+ 
65+```
66+GRPO通过分组采样n个输出,利用组内的平均奖励作为基线计算每个输出在组内的相对奖励,并基于相对奖励计算优势值,从而避免了引入额外的价值网络(critic model)
67+```
68+![](../../../sources/images/r1/GRPO.png)
69+ 
70+DeepSeek-R1-Zero的训练过程使用GRPO算法,将ORM(结果奖励模型)替换为基于规则的打分器。
71+ 
72+##### 配置准备
73+ 
74+模型结构的配置文件位于configs/model下,训练配置文件位于configs/rlxf目录下,我们以qwen2.5-7b为例[grpo_trainer_qwen25_7b.yaml],以下为参数配置:
75+ 
76+ 
77+ 
78+```
79+defaults:
80+ - model:
81+ - qwen25-7b <-- 网络结构需要定义在model目录的yaml文件下
82+ 
83+training:
84+ global_batch_size: 120 <-- 经过多少样本后acotr-train和rollout权重同步
85+ ...
86+ has-labels: true <-- 使用打分器时需要labels,因此需要开启
87+ 
88+actor_rollout_ref:
89+ 
90+ actor_rollout:
91+ model: qwen25-7b
92+ do_sample: true <-- 一定要开启采样
93+ micro_batch_size: 2 <-- 训练的mbs
94+ ppo_mini_batch_size: 60 <-- 一个gbs内经过多少样本后acotr-train更新
95+ num_samples_per_step: 2 <-- 推理的mbs
96+ temperature: 1.0 <-- 推理温度,建议0.8~1.2,越大越鼓励模型探索
97+ max_prompt_length: 2048 <-- 输入prompt的长度限制,输出长度=seq-length-max_prompt_length
98+ max-tokens-to-oom: 1000000 <-- 同一次推理最大可输入的token数
99+ ...
100+ 
101+ num_gpus_for_train: 8 <-- 用多少卡进行训练,注意训练和推理的TP需要保持一致
102+ num_gpus_for_infer: 6 <-- 用多少卡进行推理,注意ppo_mini_batch_size % (推理节点 * num_samples_per_step)= 0
103+ n_samples_per_prompt: 4
104+ 
105+ ref:
106+ model: qwen25-7b
107+ ...
108+ 
109+reward:
110+ model: qwen25-7b
111+ verifier: true <-- 是否开启打分器
112+ 
113+algorithm:
114+ gamma: 1.0
115+ lam: 0.95
116+ adv_estimator: group_norm
117+ kl_penalty: kl
118+ kl_ctrl:
119+ type: fixed
120+ kl_coef: 0.05
121+ missing_eos_penalty: 0.0
122+ verifier_function: ["acc", "format"] <-- 打分器子类组合,准确性得分、格式得分
123+ verifier_weight: [0.5, 0.5] <-- 打分器子类组合权重
124+ 
125+resource_pool:
126+ actor_rollout: [6,8] <-- actor_rollout worker资源分配
127+ ref: [2] <-- ref worker资源分配
128+ reward: [] <-- rm worker资源分配,填空为不需要ORM
129+```
130+##### 启动训练
131+与基于ray的其他强化训练一样,我们多机需要先在主节点初始化ray:
132+ 
133+```
134+# 创建一个集群,端口6344,dashboard端口8260,有8个NPU
135+ray start --head --port 6344 --dashboard-host=0.0.0.0 --dashboard-port=8260 --resources='{"NPU": 8}'
136+```
137+ 
138+随后,在其他节点加入主节点的集群:
139+```
140+# IP_ADDRESS 处填写主节点 IP 地址
141+ray start --address="IP_ADDRESS:6344" --resources='{"NPU": 8}'
142+```
143+ 
144+最后,在主节点上启动训练:
145+```
146+export HCCL_CONNECT_TIMEOUT=1800
147+export CUDA_DEVICE_MAX_CONNECTIONS=1
148+ 
149+python ray_gpt.py --config-name grpo_trainer_qwen25_7b | tee logs/r1_zero_qwen25_7b_full.log
150+```
151+ 
152+***注意:所有节点的代码、权重、数据等路径的层级要保持一致,且启动ray的时候都位于MindSpeed-LLM目录下***
153+ 
154+ 
155+## VLLM接入、支持DeepSeek-V3-671B-R1复现
156+comming soon ...
@@ -0,0 +1,12 @@
1+export HCCL_CONNECT_TIMEOUT=1800
2+export CUDA_DEVICE_MAX_CONNECTIONS=1
3+ 
4+# 主节点初始化ray
5+ray start --head --port 6344 --dashboard-host=0.0.0.0 --dashboard-port=8260 --resources='{"NPU": 8}'
6+ 
7+# 子节点全部注册上ray后,查看是否状态正常
8+ray status
9+ 
10+# 启动训练
11+python ray_gpt.py --config-name grpo_trainer_qwen25_7b | tee logs/r1_zero_qwen25_7b_full.log
12+ 
@@ -0,0 +1,6 @@
1+export HCCL_CONNECT_TIMEOUT=1800
2+export CUDA_DEVICE_MAX_CONNECTIONS=1
3+ 
4+# 子节点往主节点注册ray
5+# IP_ADDRESS 处填写主节点 IP 地址
6+ray start --address="IP_ADDRESS:6344" --resources='{"NPU": 8}'
@@ -45,6 +45,9 @@ def model_provider(pre_process=True, post_process=True) -> Union[GPTModelInfer,
45 args = get_args()45 args = get_args()
46 use_te = args.transformer_impl == "transformer_engine"46 use_te = args.transformer_impl == "transformer_engine"
47 47 
48+ if args.sequence_parallel and args.use_kv_cache:
49+ raise AssertionError('Use_kv_cache can not be true in sequence_parallel mode.')
50+ 
48 print_rank_0('building GPT model ...')51 print_rank_0('building GPT model ...')
49 # Experimental loading arguments from yaml52 # Experimental loading arguments from yaml
50 if args.yaml_cfg is not None:53 if args.yaml_cfg is not None:
@@ -69,7 +72,7 @@ def model_provider(pre_process=True, post_process=True) -> Union[GPTModelInfer,
69 pre_process=pre_process,72 pre_process=pre_process,
70 post_process=post_process,73 post_process=post_process,
71 fp16_lm_cross_entropy=args.fp16_lm_cross_entropy,74 fp16_lm_cross_entropy=args.fp16_lm_cross_entropy,
72- parallel_output=True,75+ parallel_output=True if args.sequence_parallel else False,
73 share_embeddings_and_output_weights=not args.untie_embeddings_and_output_weights,76 share_embeddings_and_output_weights=not args.untie_embeddings_and_output_weights,
74 position_embedding_type=args.position_embedding_type,77 position_embedding_type=args.position_embedding_type,
75 rotary_percent=args.rotary_percent,78 rotary_percent=args.rotary_percent,
@@ -81,7 +84,7 @@ def model_provider(pre_process=True, post_process=True) -> Union[GPTModelInfer,
81 84 
82 model = GPTModel(85 model = GPTModel(
83 config,86 config,
84- parallel_output=True,87+ parallel_output=True if args.sequence_parallel else False,
85 pre_process=pre_process,88 pre_process=pre_process,
86 post_process=post_process89 post_process=post_process
87 )90 )
@@ -87,6 +87,7 @@ def _with_pipelining_forward_step_wrapper(_with_pipelining_forward_step):
87 @wraps(_with_pipelining_forward_step)87 @wraps(_with_pipelining_forward_step)
88 def wrapper(self, tokens, position_ids, attention_mask, micro_batch_size):88 def wrapper(self, tokens, position_ids, attention_mask, micro_batch_size):
89 """No interleaving is supported."""89 """No interleaving is supported."""
90+ args = get_args()
90 sequence_length = tokens.size(1)91 sequence_length = tokens.size(1)
91 batch_size = tokens.size(0)92 batch_size = tokens.size(0)
92 93 
@@ -131,6 +132,7 @@ def _with_pipelining_forward_step_wrapper(_with_pipelining_forward_step):
131 # Here for multi batches generation.132 # Here for multi batches generation.
132 if args.sequence_parallel:133 if args.sequence_parallel:
133 output = gather_from_tensor_model_parallel_region(output)134 output = gather_from_tensor_model_parallel_region(output)
135+ 
134 logits[start:end, ...] = output136 logits[start:end, ...] = output
135 137 
136 if self.inference_params:138 if self.inference_params:
@@ -21,7 +21,6 @@ import torch.nn.functional as F
21 21 
22from megatron.training import get_args, get_tokenizer22from megatron.training import get_args, get_tokenizer
23from megatron.core import mpu23from megatron.core import mpu
24-from megatron.core.tensor_parallel.mappings import gather_from_tensor_model_parallel_region
25from megatron.inference.text_generation.communication import (24from megatron.inference.text_generation.communication import (
26 copy_from_last_to_first_pipeline_stage,25 copy_from_last_to_first_pipeline_stage,
27 broadcast_from_last_pipeline_stage,26 broadcast_from_last_pipeline_stage,
@@ -132,8 +131,6 @@ def generate_tokens_probs_and_return_on_first_stage(
132 logits = forward_step(tokens2use, positions2use, attention_mask2use)131 logits = forward_step(tokens2use, positions2use, attention_mask2use)
133 132 
134 if mpu.is_pipeline_last_stage():133 if mpu.is_pipeline_last_stage():
135- # gather along the last dim.
136- logits = gather_from_tensor_model_parallel_region(logits)
137 # Always the last stage should have an output.134 # Always the last stage should have an output.
138 assert logits is not None135 assert logits is not None
139 136 
@@ -284,8 +281,6 @@ def beam_search_and_return_on_first_stage(
284 logits = forward_step(tokens2use, positions2use, attention_mask2use)281 logits = forward_step(tokens2use, positions2use, attention_mask2use)
285 282 
286 if mpu.is_pipeline_last_stage():283 if mpu.is_pipeline_last_stage():
287- # gather along the last dim.
288- logits = gather_from_tensor_model_parallel_region(logits)
289 vocab_size = logits.size(2)284 vocab_size = logits.size(2)
290 285 
291 if args.use_kv_cache:286 if args.use_kv_cache:
@@ -52,6 +52,7 @@ class MegatronModuleForCausalLMABC(torch.nn.Module, abc.ABC):
52 self.include_input = False52 self.include_input = False
53 self.stream = False53 self.stream = False
54 self.return_output_log_probs = False54 self.return_output_log_probs = False
55+ self.truncate = False
55 56 
56 @classmethod57 @classmethod
57 def from_pretrained(58 def from_pretrained(
@@ -152,6 +153,7 @@ class MegatronModuleForCausalLMABC(torch.nn.Module, abc.ABC):
152 self.include_input = kwargs.pop("include_input", False)153 self.include_input = kwargs.pop("include_input", False)
153 self.stream = kwargs.pop("stream", False)154 self.stream = kwargs.pop("stream", False)
154 self.return_output_log_probs = kwargs.pop("return_output_log_probs", False)155 self.return_output_log_probs = kwargs.pop("return_output_log_probs", False)
156+ self.truncate = kwargs.pop("truncate", False)
155 157 
156 158 
157class MegatronModuleForCausalLM(MegatronModuleForCausalLMABC):159class MegatronModuleForCausalLM(MegatronModuleForCausalLMABC):
@@ -428,7 +430,7 @@ class MegatronModuleForCausalLM(MegatronModuleForCausalLMABC):
428 output = [val[context_lengths[i]:] for i, val in enumerate(output)]430 output = [val[context_lengths[i]:] for i, val in enumerate(output)]
429 431 
430 # When batch size > 1, you need truncate the tokens after eos_token_id432 # When batch size > 1, you need truncate the tokens after eos_token_id
431- self._truncate_in_multi_batch(output)433+ output = self._truncate_in_multi_batch(output)
432 434 
433 if self.detokenize:435 if self.detokenize:
434 try:436 try:
@@ -455,12 +457,23 @@ class MegatronModuleForCausalLM(MegatronModuleForCausalLMABC):
455 457 
456 def _truncate_in_multi_batch(self, output):458 def _truncate_in_multi_batch(self, output):
457 if len(output) > 1:459 if len(output) > 1:
460+ truncated_output = []
458 for idx, batch in enumerate(output):461 for idx, batch in enumerate(output):
459 output[idx] = output[idx][:self.max_new_tokens] if self.max_new_tokens else output[idx]462 output[idx] = output[idx][:self.max_new_tokens] if self.max_new_tokens else output[idx]
460 trunc_index = torch.nonzero(batch == self.tokenizer.eos_token_id)463 trunc_index = torch.nonzero(batch == self.tokenizer.eos_token_id)
461 464 
462 if min(trunc_index.shape):465 if min(trunc_index.shape):
463- output[idx][trunc_index.min():] = self.tokenizer.eos_token_id466+ if self.truncate:
467+ truncated_output.append(output[idx][:trunc_index.min()])
468+ else:
469+ output[idx][trunc_index.min():] = self.tokenizer.eos_token_id
470+ else:
471+ truncated_output.append(output[idx])
472+ 
473+ if self.truncate:
474+ output = [val.tolist() if torch.is_tensor(val) else val for val in truncated_output]
475+ 
476+ return output
464 477 
465 def _yield(self, token_stream):478 def _yield(self, token_stream):
466 output, context_lengths, log_probs = None, None, None479 output, context_lengths, log_probs = None, None, None
@@ -1,20 +1,19 @@
1from typing import Type1from typing import Type
2- 
3from codetiming import Timer2from codetiming import Timer
4 3 
5from mindspeed_llm.tasks.posttrain.rlxf.ray_trainer.ppo_trainer import ResourcePoolManager, Role4from mindspeed_llm.tasks.posttrain.rlxf.ray_trainer.ppo_trainer import ResourcePoolManager, Role
6from mindspeed_llm.tasks.posttrain.rlxf.single_controller.ray.megatron import NVMegatronRayWorkerGroup5from mindspeed_llm.tasks.posttrain.rlxf.single_controller.ray.megatron import NVMegatronRayWorkerGroup
7-from mindspeed_llm.tasks.posttrain.rlxf.training.core_algos import compute_grpo_data_metrics, reduce_metrics, compute_advantage, \6+from mindspeed_llm.tasks.posttrain.rlxf.training.core_algos import compute_grpo_data_metrics, reduce_metrics, \
8- get_last_reward, FixedKLController, AdaptiveKLController7+ compute_advantage, compute_score, FixedKLController, AdaptiveKLController
9from mindspeed_llm.tasks.posttrain.rlxf.single_controller.base import Worker8from mindspeed_llm.tasks.posttrain.rlxf.single_controller.base import Worker
10from mindspeed_llm.tasks.posttrain.rlxf.single_controller.ray.base import create_colocated_worker_cls, \9from mindspeed_llm.tasks.posttrain.rlxf.single_controller.ray.base import create_colocated_worker_cls, \
11- set_actor_infer_world_size, set_actor_train_world_size, RayResourcePool, RayClassWithInitArgs10+ set_actor_infer_world_size, set_actor_train_world_size, RayClassWithInitArgs
12from mindspeed_llm.tasks.posttrain.rlxf.utils.loggers import Loggers11from mindspeed_llm.tasks.posttrain.rlxf.utils.loggers import Loggers
13-from mindspeed_llm.tasks.posttrain.rlxf.workers.critic import CriticWorker
14from mindspeed_llm.tasks.posttrain.rlxf.workers.actor_train_infer import PPOActorWorker12from mindspeed_llm.tasks.posttrain.rlxf.workers.actor_train_infer import PPOActorWorker
15from mindspeed_llm.tasks.posttrain.rlxf.workers.reference import ReferenceWorker13from mindspeed_llm.tasks.posttrain.rlxf.workers.reference import ReferenceWorker
16from mindspeed_llm.tasks.posttrain.rlxf.workers.reward import RewardWorker14from mindspeed_llm.tasks.posttrain.rlxf.workers.reward import RewardWorker
17 15 
16+ 
18WorkerType = Type[Worker]17WorkerType = Type[Worker]
19 18 
20 19 
@@ -35,17 +34,27 @@ class RayGRPOTrainer(object):
35 ref_pool_id = 'ref_pool'34 ref_pool_id = 'ref_pool'
36 reward_pool_id = 'reward_pool'35 reward_pool_id = 'reward_pool'
37 36 
38- resource_pool_spec = {37+ if config.resource_pool.reward:
39- actor_pool_id: config.resource_pool.actor_rollout,38+ resource_pool_spec = {
40- ref_pool_id: config.resource_pool.ref,39+ actor_pool_id: config.resource_pool.actor_rollout,
41- reward_pool_id: config.resource_pool.reward,40+ ref_pool_id: config.resource_pool.ref,
42- }41+ reward_pool_id: config.resource_pool.reward,
42+ }
43+ mapping = {
44+ Role.ActorRollout: actor_pool_id,
45+ Role.RefPolicy: ref_pool_id,
46+ Role.RewardModel: reward_pool_id,
47+ }
48+ else:
49+ resource_pool_spec = {
50+ actor_pool_id: config.resource_pool.actor_rollout,
51+ ref_pool_id: config.resource_pool.ref
52+ }
43 53 
44- mapping = {54+ mapping = {
45- Role.ActorRollout: actor_pool_id,55+ Role.ActorRollout: actor_pool_id,
46- Role.RefPolicy: ref_pool_id,56+ Role.RefPolicy: ref_pool_id
47- Role.RewardModel: reward_pool_id,57+ }
48- }
49 58 
50 self.resource_pool_manager = ResourcePoolManager(resource_pool_spec=resource_pool_spec, mapping=mapping)59 self.resource_pool_manager = ResourcePoolManager(resource_pool_spec=resource_pool_spec, mapping=mapping)
51 self.use_reference_policy = Role.RefPolicy in self.role_worker_mapping60 self.use_reference_policy = Role.RefPolicy in self.role_worker_mapping
@@ -86,11 +95,12 @@ class RayGRPOTrainer(object):
86 role='ref')95 role='ref')
87 self.resource_pool_to_cls[resource_pool]['ref'] = ref_policy_cls96 self.resource_pool_to_cls[resource_pool]['ref'] = ref_policy_cls
88 97 
89- resource_pool = self.resource_pool_manager.get_resource_pool(Role.RewardModel)98+ if self.config.resource_pool.reward:
90- reward_cls = RayClassWithInitArgs(cls=self.role_worker_mapping[Role.RewardModel],99+ resource_pool = self.resource_pool_manager.get_resource_pool(Role.RewardModel)
91- config=self.config,100+ reward_cls = RayClassWithInitArgs(cls=self.role_worker_mapping[Role.RewardModel],
92- role='reward')101+ config=self.config,
93- self.resource_pool_to_cls[resource_pool]['reward'] = reward_cls102+ role='reward')
103+ self.resource_pool_to_cls[resource_pool]['reward'] = reward_cls
94 104 
95 # initialize WorkerGroup105 # initialize WorkerGroup
96 all_wg = {}106 all_wg = {}
@@ -106,8 +116,11 @@ class RayGRPOTrainer(object):
106 self.actor_rollout_wg = all_wg.get('actor_rollout')116 self.actor_rollout_wg = all_wg.get('actor_rollout')
107 self.actor_rollout_wg.initialize()117 self.actor_rollout_wg.initialize()
108 118 
109- self.reward_wg = all_wg.get('reward')119+ if self.config.resource_pool.reward:
110- self.reward_wg.initialize()120+ self.reward_wg = all_wg.get('reward')
121+ self.reward_wg.initialize()
122+ else:
123+ self.reward_wg = None
111 124 
112 def train(self):125 def train(self):
113 """126 """
@@ -136,17 +149,21 @@ class RayGRPOTrainer(object):
136 149 
137 with Timer(name='adv', logger=None) as timer:150 with Timer(name='adv', logger=None) as timer:
138 # compute rm scores.151 # compute rm scores.
139- reward_tensor = self.reward_wg.compute_rm_score(batch)152+ batch = compute_score(
140- batch = batch.union(reward_tensor)153+ self.reward_wg,
141- batch = get_last_reward(batch,154+ batch,
142- n_sample_batch=self.config.actor_rollout_ref.actor_rollout.n_samples_per_prompt)155+ metrics,
156+ self.config
157+ )
143 158 
144 # compute advantages, executed on the driver process159 # compute advantages, executed on the driver process
145- batch = compute_advantage(batch,160+ batch = compute_advantage(
146- self.config.algorithm.gamma,161+ batch,
147- self.config.algorithm.lam,162+ self.config.algorithm.gamma,
148- adv_estimator=self.config.algorithm.adv_estimator,163+ self.config.algorithm.lam,
149- )164+ adv_estimator=self.config.algorithm.adv_estimator
165+ )
166+ 
150 metrics['timing/adv'] = timer.last167 metrics['timing/adv'] = timer.last
151 kl_info = {'kl_ctrl': self.kl_ctrl}168 kl_info = {'kl_ctrl': self.kl_ctrl}
152 batch.meta_info.update(kl_info)169 batch.meta_info.update(kl_info)
@@ -167,4 +184,3 @@ class RayGRPOTrainer(object):
167 184 
168 if iteration % self.config.training.save_interval == 0:185 if iteration % self.config.training.save_interval == 0:
169 self.actor_rollout_wg.save_checkpoint(iteration)186 self.actor_rollout_wg.save_checkpoint(iteration)
170- 
@@ -20,9 +20,14 @@ implement PPO
20import numpy as np20import numpy as np
21import torch21import torch
22from copy import deepcopy22from copy import deepcopy
23+from transformers import AutoTokenizer
23 24 
24import mindspeed_llm.tasks.posttrain.rlxf.utils.torch_functional as F25import mindspeed_llm.tasks.posttrain.rlxf.utils.torch_functional as F
26+from mindspeed_llm.tasks.posttrain.rlxf.utils.loggers import Loggers
25from mindspeed_llm.tasks.posttrain.rlxf.utils.protocol import DataProto27from mindspeed_llm.tasks.posttrain.rlxf.utils.protocol import DataProto
28+from mindspeed_llm.tasks.posttrain.verifier.rule_verifier import preprocess_box_response_for_qwen_prompt, format_reward, reasoning_steps_reward
29+ 
30+logger = Loggers()
26 31 
27 32 
28class AdaptiveKLController:33class AdaptiveKLController:
@@ -94,8 +99,12 @@ def compute_gae_advantage_return(token_level_rewards: torch.Tensor, values: torc
94 return advantages, returns99 return advantages, returns
95 100 
96 101 
97-def compute_group_norm_advantage_return(token_level_rewards: torch.Tensor, eos_mask: torch.Tensor,102+def compute_group_norm_advantage_return(
98- gamma: torch.Tensor, lam: torch.Tensor):103+ token_level_rewards: torch.Tensor,
104+ eos_mask: torch.Tensor,
105+ gamma: torch.Tensor,
106+ lam: torch.Tensor
107+):
99 """108 """
100 Args:109 Args:
101 token_level_rewards: `(torch.Tensor)`110 token_level_rewards: `(torch.Tensor)`
@@ -310,9 +319,9 @@ def compute_advantage(data: DataProto, gamma, lam, adv_estimator):
310 data.batch['returns'] = returns319 data.batch['returns'] = returns
311 elif adv_estimator == 'group_norm':320 elif adv_estimator == 'group_norm':
312 advantages, returns = compute_group_norm_advantage_return(token_level_rewards=token_level_rewards,321 advantages, returns = compute_group_norm_advantage_return(token_level_rewards=token_level_rewards,
313- eos_mask=response_mask,322+ eos_mask=response_mask,
314- gamma=gamma,323+ gamma=gamma,
315- lam=lam)324+ lam=lam)
316 data.batch['advantages'] = advantages325 data.batch['advantages'] = advantages
317 data.batch['returns'] = returns326 data.batch['returns'] = returns
318 else:327 else:
@@ -320,20 +329,117 @@ def compute_advantage(data: DataProto, gamma, lam, adv_estimator):
320 return data329 return data
321 330 
322 331 
323-def get_last_reward(data, n_sample_batch):332+def compute_score(reward_wg, batch, metrics, config):
333+ token_level_rewards = torch.zeros_like(batch.batch["responses"], dtype=torch.float32)
334+ 
335+ if reward_wg:
336+ score_tensor = reward_wg.compute_rm_score(batch).batch['rm_scores']
337+ 
338+ rm_token_level_rewards = get_last_reward(
339+ batch,
340+ rm_scores=score_tensor,
341+ n_sample_batch=config.actor_rollout_ref.actor_rollout.n_samples_per_prompt
342+ )
343+ 
344+ token_level_rewards += rm_token_level_rewards
345+ 
346+ 
347+ if hasattr(config.reward, "verifier") and config.reward.verifier:
348+ verifier_token_level_rewards = compute_verifier_score(batch, metrics, config)
349+ token_level_rewards += verifier_token_level_rewards
350+ 
351+ rewards = DataProto.from_dict(
352+ tensors={
353+ 'token_level_rewards': token_level_rewards,
354+ 'rm_scores': token_level_rewards
355+ }
356+ )
357+ 
358+ return batch.union(rewards)
359+ 
360+ 
361+def compute_verifier_score(batch, metrics, config):
362+ tokenizer = AutoTokenizer.from_pretrained(config.training.tokenizer_name_or_path, trust_remote_code=True)
363+ tokenizer.eos_token = tokenizer.decode(tokenizer.eos_token_id, skip_special_tokens=True)
364+ 
365+ responses = batch.batch["responses"]
366+ reward_index = batch.batch["responses_ori_length"].unsqueeze(1) - 1
367+ 
368+ str_labels = tokenizer.batch_decode(batch.batch["labels"], skip_special_tokens=True)
369+ str_responses = tokenizer.batch_decode(responses, skip_special_tokens=True)
370+ 
371+ scores = verifier(str_responses, str_labels, config, metrics, infos=None)
372+ 
373+ scores = torch.tensor(
374+ scores,
375+ dtype=torch.float32,
376+ device=reward_index.device
377+ ).unsqueeze(1)
378+ 
379+ logger.logger.info("=" * 50)
380+ logger.logger.info(str_responses[0])
381+ logger.logger.info(">" * 50)
382+ logger.logger.info(str_labels[0])
383+ logger.logger.info("=" * 50)
384+ 
385+ token_level_rewards = torch.zeros_like(responses, dtype=torch.float32)
386+ token_level_rewards.scatter_(1, reward_index, scores)
387+ 
388+ return token_level_rewards
389+ 
390+ 
391+def verifier(responses, labels, config, metrics, infos=None):
392+ """
393+ User-defined verifier scoring process.
394+ 
395+ Parameters:
396+ ----------
397+ responses(List[`str`]):
398+ Actor rollout answers.
399+ labels(List[`str`]):
400+ Ground Truth.
401+ infos(List[`str`], *optional*):
402+ Additional usable information loaded from the dataset.
403+ 
404+ Return:
405+ scores(List[`float`]): Final scores.
406+ """
407+ rule_verifier_function = {
408+ "acc": preprocess_box_response_for_qwen_prompt,
409+ "format": format_reward,
410+ "step": reasoning_steps_reward
411+ }
412+ 
413+ scores = [0.0] * len(labels)
414+ 
415+ verifier_function = config.algorithm.verifier_function if hasattr(
416+ config.algorithm, "verifier_function") else ["acc"]
417+ verifier_weight = config.algorithm.verifier_weight if hasattr(
418+ config.algorithm, "verifier_weight") else [1.0]
419+ 
420+ for idx, fun_verifier in enumerate(verifier_function):
421+ if fun_verifier not in rule_verifier_function:
422+ continue
423+ score = rule_verifier_function[fun_verifier](sequences=responses, answers=labels)
424+ metrics[f"grpo/{fun_verifier}_rewards/mean"] = sum(score) / max(len(score), 1)
425+ scores = [all_score + tmp_score * verifier_weight[idx]
426+ for all_score, tmp_score in zip(scores, score)]
427+ 
428+ return scores
429+ 
430+ 
431+def get_last_reward(data, rm_scores, n_sample_batch):
324 responses = data.batch['responses']432 responses = data.batch['responses']
325 response_length = responses.size(1)433 response_length = responses.size(1)
326 attention_mask = data.batch['attention_mask']434 attention_mask = data.batch['attention_mask']
327 response_mask = attention_mask[:, -response_length:]435 response_mask = attention_mask[:, -response_length:]
328- rm_scores = data.batch['rm_scores']
329 eos_indices = response_mask.size(1) - 1 - response_mask.long().fliplr().argmax(dim=1, keepdim=True)436 eos_indices = response_mask.size(1) - 1 - response_mask.long().fliplr().argmax(dim=1, keepdim=True)
330 reward = rm_scores.gather(dim=1, index=eos_indices).squeeze(1)437 reward = rm_scores.gather(dim=1, index=eos_indices).squeeze(1)
331 reward = reward.reshape(-1, n_sample_batch)438 reward = reward.reshape(-1, n_sample_batch)
332 reward = (reward - reward.mean(dim=1, keepdim=True)) / (reward.std(dim=1, keepdim=True) + 1e-8)439 reward = (reward - reward.mean(dim=1, keepdim=True)) / (reward.std(dim=1, keepdim=True) + 1e-8)
333 reward = reward.reshape(-1)440 reward = reward.reshape(-1)
334- last_reward = torch.zeros_like(rm_scores).scatter_(dim=1, index=eos_indices, src=reward.unsqueeze(1).to(rm_scores.dtype))441+ token_level_rewards = torch.zeros_like(rm_scores).scatter_(dim=1, index=eos_indices, src=reward.unsqueeze(1).to(rm_scores.dtype))
335- data.batch['token_level_rewards'] = last_reward442+ return token_level_rewards
336- return data
337 443 
338 444 
339def reduce_metrics(metrics: dict):445def reduce_metrics(metrics: dict):
@@ -14,6 +14,10 @@ from megatron.training import get_args, initialize_megatron, get_timers, get_tok
14from megatron.core.pipeline_parallel.schedules import get_forward_backward_func14from megatron.core.pipeline_parallel.schedules import get_forward_backward_func
15from megatron.core import parallel_state as mpu, tensor_parallel15from megatron.core import parallel_state as mpu, tensor_parallel
16from megatron.training.training import append_to_progress_log, build_train_valid_test_data_iterators, print_datetime16from megatron.training.training import append_to_progress_log, build_train_valid_test_data_iterators, print_datetime
17+from megatron.training import get_model
18+from megatron.training.utils import unwrap_model
19+from megatron.training.checkpointing import save_checkpoint
20+from megatron.training.training import num_floating_point_operations
17from mindspeed_llm.tasks.posttrain.rlxf.training.core_algos import compute_policy_loss, find_first_eos_index, compute_grpo_policy_loss21from mindspeed_llm.tasks.posttrain.rlxf.training.core_algos import compute_policy_loss, find_first_eos_index, compute_grpo_policy_loss
18from mindspeed_llm.tasks.posttrain.rlxf.utils.torch_functional import split_dict_tensor_into_batches22from mindspeed_llm.tasks.posttrain.rlxf.utils.torch_functional import split_dict_tensor_into_batches
19from mindspeed_llm.tasks.posttrain.rlxf.single_controller.base.megatron.worker import MegatronWorker23from mindspeed_llm.tasks.posttrain.rlxf.single_controller.base.megatron.worker import MegatronWorker
@@ -24,14 +28,11 @@ from mindspeed_llm.tasks.posttrain.rlxf.utils.protocol import DataProto, make_ba
24from mindspeed_llm.tasks.posttrain.base import BaseTrainer28from mindspeed_llm.tasks.posttrain.base import BaseTrainer
25import mindspeed_llm.tasks.posttrain.rlxf.training.parallel_state as ps29import mindspeed_llm.tasks.posttrain.rlxf.training.parallel_state as ps
26from mindspeed_llm.tasks.inference.module import MegatronModuleForCausalLM30from mindspeed_llm.tasks.inference.module import MegatronModuleForCausalLM
27-from inference import model_provider
28from mindspeed_llm.tasks.preprocess.decoder_packed_mtf_dataset import \31from mindspeed_llm.tasks.preprocess.decoder_packed_mtf_dataset import \
29 build_train_valid_test_datasets as build_instruction_dataset32 build_train_valid_test_datasets as build_instruction_dataset
30from mindspeed_llm.training.initialize import set_jit_fusion_options33from mindspeed_llm.training.initialize import set_jit_fusion_options
31from mindspeed_llm.training.utils import get_finetune_data_on_this_tp_rank, get_tune_attention_mask34from mindspeed_llm.training.utils import get_finetune_data_on_this_tp_rank, get_tune_attention_mask
32from mindspeed_llm.tasks.posttrain.utils import compute_log_probs, append_to_dict35from mindspeed_llm.tasks.posttrain.utils import compute_log_probs, append_to_dict
33-from megatron.training.checkpointing import save_checkpoint
34-from megatron.training.training import num_floating_point_operations
35 36 
36 37 
37def train_valid_test_datasets_provider(train_val_test_num_samples):38def train_valid_test_datasets_provider(train_val_test_num_samples):
@@ -202,6 +203,66 @@ class PPOActorInferWorker(BaseTrainer):
202 def __init__(self):203 def __init__(self):
203 super().__init__()204 super().__init__()
204 self.count = 0205 self.count = 0
206+ self.keys = None
207+ 
208+ def model_provider(self, pre_process=True, post_process=True):
209+ """Builds the inference model.
210+ 
211+ If you set the use_mcore_models to True, it will return the mcore GPT model.
212+ 
213+ Args:
214+ pre_process (bool, optional): Set to true if you need to compute embedings. Defaults to True.
215+ post_process (bool, optional): Set to true if you need to want to compute output logits/loss. Defaults to True.
216+ 
217+ 
218+ Returns:
219+ Union[GPTModelInfer, GPTModel]: The returned model
220+ """
221+ 
222+ from megatron.core.models.gpt.gpt_layer_specs import get_gpt_layer_with_transformer_engine_spec, \
223+ get_gpt_layer_local_spec
224+ from megatron.core.transformer.spec_utils import import_module
225+ from megatron.training import get_args, print_rank_0
226+ from megatron.training.arguments import core_transformer_config_from_args
227+ from megatron.training.yaml_arguments import core_transformer_config_from_yaml
228+ 
229+ from mindspeed_llm.tasks.inference.module import GPTModelInfer
230+ 
231+ args = get_args()
232+ use_te = args.transformer_impl == "transformer_engine"
233+ 
234+ print_rank_0('building GPT Rollout model ...')
235+ # Experimental loading arguments from yaml
236+ if args.yaml_cfg is not None:
237+ config = core_transformer_config_from_yaml(args, "language_model")
238+ else:
239+ config = core_transformer_config_from_args(args)
240+ 
241+ if args.spec is not None:
242+ transformer_layer_spec = import_module(args.spec)
243+ else:
244+ if use_te:
245+ transformer_layer_spec = get_gpt_layer_with_transformer_engine_spec(args.num_experts,
246+ args.moe_grouped_gemm)
247+ else:
248+ transformer_layer_spec = get_gpt_layer_local_spec(args.num_experts, args.moe_grouped_gemm)
249+ 
250+ model = GPTModelInfer(
251+ config=config,
252+ transformer_layer_spec=transformer_layer_spec,
253+ vocab_size=args.padded_vocab_size,
254+ max_sequence_length=args.max_position_embeddings,
255+ pre_process=pre_process,
256+ post_process=post_process,
257+ fp16_lm_cross_entropy=args.fp16_lm_cross_entropy,
258+ parallel_output=False,
259+ share_embeddings_and_output_weights=not args.untie_embeddings_and_output_weights,
260+ position_embedding_type=args.position_embedding_type,
261+ rotary_percent=args.rotary_percent,
262+ seq_len_interpolation_factor=args.rotary_seq_len_interpolation_factor
263+ )
264+ 
265+ return model
205 266 
206 def initialize(self):267 def initialize(self):
207 train_valid_test_datasets_provider.is_distributed = True268 train_valid_test_datasets_provider.is_distributed = True
@@ -220,9 +281,10 @@ class PPOActorInferWorker(BaseTrainer):
220 self.args.num_layer_list = None281 self.args.num_layer_list = None
221 self.args.micro_batch_size = 1282 self.args.micro_batch_size = 1
222 self.args.sequence_parallel = False283 self.args.sequence_parallel = False
223- self.inf_model = MegatronModuleForCausalLM.from_pretrained(284+ 
224- model_provider=model_provider,285+ self.args.model = unwrap_model(get_model(self.model_provider, wrap_with_ddp=False))
225- )286+ self.inf_model = self.args.model[0]
287+ 
226 sync_param_nums(self.inf_model)288 sync_param_nums(self.inf_model)
227 true_pad_to_multiple_of = self.args.pad_to_multiple_of289 true_pad_to_multiple_of = self.args.pad_to_multiple_of
228 self.args.pad_to_multiple_of = 1 # we don't want to pad data here290 self.args.pad_to_multiple_of = 1 # we don't want to pad data here
@@ -237,11 +299,15 @@ class PPOActorInferWorker(BaseTrainer):
237 print('done with setup ...')299 print('done with setup ...')
238 self.timers.log(['model-setup', 'train/valid/test-data-iterators-setup'], barrier=True)300 self.timers.log(['model-setup', 'train/valid/test-data-iterators-setup'], barrier=True)
239 301 
240- @staticmethod302+ def get_batch(self, data_iterator):
241- def get_batch(data_iterator):
242 """Generate a batch identical to Llama factory"""303 """Generate a batch identical to Llama factory"""
243 args = get_args()304 args = get_args()
244 305 
306+ if self.args.dataset_with_labels:
307+ self.keys = ['input_ids', 'labels']
308+ else:
309+ self.keys = ['input_ids']
310+ 
245 if (not mpu.is_pipeline_first_stage()) and (not mpu.is_pipeline_last_stage()):311 if (not mpu.is_pipeline_first_stage()) and (not mpu.is_pipeline_last_stage()):
246 if args.variable_seq_lengths and args.pipeline_model_parallel_size > 2:312 if args.variable_seq_lengths and args.pipeline_model_parallel_size > 2:
247 tokens, _ = get_finetune_data_on_this_tp_rank(data_iterator)313 tokens, _ = get_finetune_data_on_this_tp_rank(data_iterator)
@@ -250,48 +316,91 @@ class PPOActorInferWorker(BaseTrainer):
250 return tokens316 return tokens
251 317 
252 # Items and their type.318 # Items and their type.
253- keys = ['input_ids']319+ 
254 data_type = torch.int64320 data_type = torch.int64
255 321 
256 # Broadcast data.322 # Broadcast data.
257- data_b = tensor_parallel.broadcast_data(keys, next(data_iterator), data_type)323+ data_b = tensor_parallel.broadcast_data(self.keys, next(data_iterator), data_type)
258 324 
259 # Unpack325 # Unpack
260- tokens = data_b.get('input_ids').long()326+ batch = {}
261- return tokens327+ for key in self.keys:
328+ batch[key] = data_b.get(key).long()
329+ 
330+ return batch
262 331 
263 def run_inference(self):332 def run_inference(self):
264 args = get_args()333 args = get_args()
265 num_infer_steps = args.global_batch_size // (args.data_parallel_size * args.num_samples_per_step)334 num_infer_steps = args.global_batch_size // (args.data_parallel_size * args.num_samples_per_step)
266 responses = []335 responses = []
267 idx_list = []336 idx_list = []
337+ label_list = []
268 idx_list_per_step = []338 idx_list_per_step = []
339+ label_list_per_step = []
340+ 
269 max_new_tokens = args.seq_length - args.max_prompt_length341 max_new_tokens = args.seq_length - args.max_prompt_length
270 assert max_new_tokens % args.pad_to_multiple_of == 0, "please adjust pad_to_multiple_of so that \342 assert max_new_tokens % args.pad_to_multiple_of == 0, "please adjust pad_to_multiple_of so that \
271 max_new_tokens % args.pad_to_multiple_of == 0"343 max_new_tokens % args.pad_to_multiple_of == 0"
272 for i in range(num_infer_steps):344 for i in range(num_infer_steps):
273 for j in range(args.num_samples_per_step):345 for j in range(args.num_samples_per_step):
274- tokens = self.get_batch(self.train_data_iterator)346+ batch = self.get_batch(self.train_data_iterator)
347+ 
348+ tokens = batch["input_ids"]
275 tokens_list = tokens.view(-1).cpu().numpy().tolist()349 tokens_list = tokens.view(-1).cpu().numpy().tolist()
350+ labels = batch.get("labels", None)
351+ 
352+ if labels is not None:
353+ labels = labels.view(-1).cpu().numpy().tolist()[::-1]
354+ if -100 in labels:
355+ answer_begin_indices = len(tokens_list) - 1 - labels.index(-100)
356+ answer_list = tokens_list[answer_begin_indices + 1:]
357+ tokens_list = tokens_list[:answer_begin_indices + 1]
358+ else:
359+ answer_list = tokens_list[-1:]
360+ tokens_list = tokens_list[:-1]
361+ 
362+ for _ in range(args.n_samples_per_prompt):
363+ label_list_per_step.append(copy.deepcopy(answer_list))
364+ 
276 for _ in range(args.n_samples_per_prompt):365 for _ in range(args.n_samples_per_prompt):
277 idx_list_per_step.append(copy.deepcopy(tokens_list))366 idx_list_per_step.append(copy.deepcopy(tokens_list))
367+ 
278 if args.stage == "ray_online_dpo":368 if args.stage == "ray_online_dpo":
279 idx_list_per_step.append(copy.deepcopy(tokens_list))369 idx_list_per_step.append(copy.deepcopy(tokens_list))
280 370 
281- responses_per_step = self.inf_model.generate(copy.deepcopy(idx_list_per_step),371+ responses_per_step = self.inf_model.generate(
282- max_new_tokens=max_new_tokens,372+ copy.deepcopy(idx_list_per_step),
283- detokenize=False, broadcast=False, do_sample=args.do_sample)373+ max_new_tokens=max_new_tokens,
374+ temperature=args.temperature,
375+ do_sample=args.do_sample,
376+ detokenize=False,
377+ broadcast=False,
378+ truncate=True
379+ )
380+
284 if not isinstance(responses_per_step, list):381 if not isinstance(responses_per_step, list):
285 responses_per_step = [responses_per_step]382 responses_per_step = [responses_per_step]
286 383 
287 responses.extend(responses_per_step)384 responses.extend(responses_per_step)
288 idx_list.extend(idx_list_per_step)385 idx_list.extend(idx_list_per_step)
386+ label_list.extend(label_list_per_step)
289 idx_list_per_step = []387 idx_list_per_step = []
388+ label_list_per_step = []
290 389 
291- responses = [response.cpu().numpy().tolist() for response in responses]390+ responses_ori_length, responses_pad_length = pad_to_tensor_dict(
391+ responses,
392+ pad_multi_of=args.pad_to_multiple_of
393+ )
394+ prompts_ori_length, prompts_pad_length = pad_to_tensor_dict(
395+ idx_list, "left",
396+ pad_multi_of=args.pad_to_multiple_of
397+ )
292 398 
293- responses_ori_length, responses_pad_length = pad_to_tensor_dict(responses, pad_multi_of=args.pad_to_multiple_of)399+ if label_list:
294- prompts_ori_length, prompts_pad_length = pad_to_tensor_dict(idx_list, "left", pad_multi_of=args.pad_to_multiple_of)400+ pad_to_tensor_dict(
401+ label_list,
402+ pad_multi_of=args.pad_to_multiple_of
403+ )
295 404 
296 input_ids = [prompt + response for prompt, response in zip(idx_list, responses)]405 input_ids = [prompt + response for prompt, response in zip(idx_list, responses)]
297 406 
@@ -304,15 +413,32 @@ class PPOActorInferWorker(BaseTrainer):
304 else:413 else:
305 batch_size = args.global_batch_size // args.data_parallel_size * args.n_samples_per_prompt414 batch_size = args.global_batch_size // args.data_parallel_size * args.n_samples_per_prompt
306 415 
416+ if label_list:
417+ batch = TensorDict(
418+ {
419+ "prompts": idx_list,
420+ "labels": label_list,
421+ "responses": responses,
422+ "input_ids": input_ids,
423+ "attention_mask": attention_mask,
424+ "position_ids": position_ids,
425+ "responses_ori_length": responses_ori_length
426+ },
427+ batch_size=batch_size
428+ )
429+ else:
430+ batch = TensorDict(
431+ {
432+ "prompts": idx_list,
433+ "responses": responses,
434+ "input_ids": input_ids,
435+ "attention_mask": attention_mask,
436+ "position_ids": position_ids,
437+ "responses_ori_length": responses_ori_length
438+ },
439+ batch_size=batch_size
440+ )
307 441 
308- batch = TensorDict({
309- "prompts": idx_list,
310- "responses": responses,
311- "input_ids": input_ids,
312- "attention_mask": attention_mask,
313- "position_ids": position_ids,
314- },
315- batch_size=batch_size)
316 return DataProto(batch=batch)442 return DataProto(batch=batch)
317 443 
318 def loss_func(self, input_tensor, output_tensor):444 def loss_func(self, input_tensor, output_tensor):
@@ -99,7 +99,7 @@ class MegatronPPORM(ORMTrainer):
99 if self.args.load is not None or self.args.pretrained_checkpoint is not None:99 if self.args.load is not None or self.args.pretrained_checkpoint is not None:
100 self.timers('load-checkpoint', log_level=0).start(barrier=True)100 self.timers('load-checkpoint', log_level=0).start(barrier=True)
101 self.args.iteration, self.args.num_floating_point_operations_so_far = load_checkpoint(101 self.args.iteration, self.args.num_floating_point_operations_so_far = load_checkpoint(
102- model, None, None)102+ model, None, None, strict=False)
103 self.timers('load-checkpoint').stop(barrier=True)103 self.timers('load-checkpoint').stop(barrier=True)
104 self.timers.log(['load-checkpoint'])104 self.timers.log(['load-checkpoint'])
105 else:105 else:
@@ -705,6 +705,10 @@ def _add_rl_args(parser):
705 default=False,705 default=False,
706 help="Path to the reference model used for the PPO training."706 help="Path to the reference model used for the PPO training."
707 )707 )
708+ group.add_argument(
709+ "--verifier", action='store_true',
710+ help="Enable verifier in cal scores."
711+ )
708 group.add_argument(712 group.add_argument(
709 '--kl-coef',713 '--kl-coef',
710 default=0.3,714 default=0.3,
@@ -786,7 +790,7 @@ def _add_training_args(parser):
786 help='Setting jit compile mode to True')790 help='Setting jit compile mode to True')
787 group.add_argument('--prompt-type', type=str, default=None,791 group.add_argument('--prompt-type', type=str, default=None,
788 choices=['default', 'empty', 'trl', 'chatglm2', 'chatglm3', 'chatglm3_system', 'glm4', 'chatml',792 choices=['default', 'empty', 'trl', 'chatglm2', 'chatglm3', 'chatglm3_system', 'glm4', 'chatml',
789- 'chatml_de', 'qwen', 'llama3', 'llama2', 'mistral', 'mixtral', 'gemma', 'alpaca',793+ 'chatml_de', 'qwen', 'qwen_r1', "qwen_math_r1", 'llama3', 'llama2', 'mistral', 'mixtral', 'gemma', 'alpaca',
790 'deepseek2', 'deepseek2-lite', 'minicpm3', 'cpm', 'baichuan2', 'deepseek3', 'intern2'],794 'deepseek2', 'deepseek2-lite', 'minicpm3', 'cpm', 'baichuan2', 'deepseek3', 'intern2'],
791 help='Which template to use for constructing prompts in training/inference.' 'e.g., "qwen"')795 help='Which template to use for constructing prompts in training/inference.' 'e.g., "qwen"')
792 group.add_argument('--prompt-type-path', type=str, default=TEMPLATES_DIR,796 group.add_argument('--prompt-type-path', type=str, default=TEMPLATES_DIR,
@@ -901,6 +905,12 @@ def _add_dataset_args(parser):
901 default=False,905 default=False,
902 help='if no shared storage, set it'906 help='if no shared storage, set it'
903 )907 )
908+ group.add_argument('--dataset-with-labels',
909+ action='store_true',
910+ default=False,
911+ help='Whether the labels included in dataset.'
912+ )
913+
904 return parser914 return parser
905 915 
906 916 
@@ -112,7 +112,7 @@ def add_data_args(parser):
112 # LlamaFactory112 # LlamaFactory
113 group.add_argument('--prompt-type', type=str, default=None,113 group.add_argument('--prompt-type', type=str, default=None,
114 choices=['default', 'empty', 'trl', 'chatglm2', 'chatglm3', 'chatglm3_system', 'glm4', 'chatml',114 choices=['default', 'empty', 'trl', 'chatglm2', 'chatglm3', 'chatglm3_system', 'glm4', 'chatml',
115- 'chatml_de', 'qwen', 'llama3', 'llama2', 'mistral', 'mixtral', 'gemma', 'alpaca',115+ 'chatml_de', 'qwen', 'qwen_r1', "qwen_math_r1", 'llama3', 'llama2', 'mistral', 'mixtral', 'gemma', 'alpaca',
116 'deepseek2', 'deepseek2-lite', 'cpm', 'baichuan2', 'deepseek3', 'intern2'],116 'deepseek2', 'deepseek2-lite', 'cpm', 'baichuan2', 'deepseek3', 'intern2'],
117 help='Which template to use for constructing prompts in training.'117 help='Which template to use for constructing prompts in training.'
118 'e.g., "qwen"')118 'e.g., "qwen"')
P
Ppanchenyixxx2025年2月15日

图片需要按照Qwen2.5-7B-instruct重新更新一下

likedislike
@@ -18,3 +18,5 @@ tensordict==0.1.2
18hydra-core==1.3.218hydra-core==1.3.2
19codetiming19codetiming
20bitsandbytes-npu-beta==0.45.220bitsandbytes-npu-beta==0.45.2
21+word2number
22+latex2sympy2
@@ -16,6 +16,7 @@
16 0.5493276,16 0.5493276,
17 0.580090317 0.5800903
18 ],18 ],
19+ "throughput margin": 0.1,
19 "throughput": [20 "throughput": [
20 4.6,21 4.6,
21 10.9,22 10.9,
@@ -16,6 +16,7 @@
16 0.7187351,16 0.7187351,
17 0.65951717 0.659517
18 ],18 ],
19+ "throughput margin": 0.1,
19 "throughput": [20 "throughput": [
20 3.5,21 3.5,
21 5.5,22 5.5,
@@ -16,6 +16,7 @@
16 5.516537,16 5.516537,
17 5.49463617 5.494636
18 ],18 ],
19+ "throughput margin": 0.1,
19 "throughput": [20 "throughput": [
20 15.9,21 15.9,
21 44.6,22 44.6,
@@ -16,6 +16,7 @@
16 5.696367,16 5.696367,
17 5.60203517 5.602035
18 ],18 ],
19+ "throughput margin": 0.1,
19 "throughput": [20 "throughput": [
20 10.4,21 10.4,
21 101.7,22 101.7,
@@ -1,4 +1,5 @@
1{1{
2+ "lm loss margin": 0.03,
2 "lm loss": [3 "lm loss": [
3 0.6931,4 0.6931,
4 0.6925,5 0.6925,
@@ -1,4 +1,5 @@
1{1{
2+ "lm loss margin": 0.01,
2 "lm loss": [3 "lm loss": [
3 0.0214,4 0.0214,
4 0.0412,5 0.0412,
@@ -7,14 +8,14 @@
7 0.0176,8 0.0176,
8 0.0005,9 0.0005,
9 0.0685,10 0.0685,
10- 0.1176,11+ 0.0608,
11- 0.0985,12+ 0.0895,
12 0.2175,13 0.2175,
13 0.1695,14 0.1695,
14 0.2064,15 0.2064,
15 0.0822,16 0.0822,
16 0.0318,17 0.0318,
17- 0.055718+ 0.0624
18 ],19 ],
19 "throughput": [20 "throughput": [
20 ],21 ],
@@ -16,6 +16,7 @@
16 1.560994,16 1.560994,
17 1.47717517 1.477175
18 ],18 ],
19+ "throughput margin": 0.1,
19 "throughput": [20 "throughput": [
20 4.2,21 4.2,
21 19.3,22 19.3,