-
Notifications
You must be signed in to change notification settings - Fork 37
feat(recipe): 新增 Qwen3-8B ReMax FSDP 昇腾训练 Recipe #100
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
yukinotech
wants to merge
6
commits into
verl-project:main
Choose a base branch
from
yukinotech:codex/remax-qwen3-8b-fsdp-npu
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+317
−0
Open
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
cb4fea5
feat(recipe): add Qwen3-8B ReMax FSDP NPU recipe
yukinotech 7ea7749
refactor(recipe): keep ReMax submission script-only
yukinotech 30c531a
docs(recipe): add ReMax validation report
yukinotech d1c8499
docs(recipe): refine ReMax validation conclusion
yukinotech 86c95df
refactor(recipe): move ReMax recipe into Ascend practice
yukinotech dc0c417
docs(recipe): move ReMax report under reports
yukinotech File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,195 @@ | ||
| # Qwen3-8B ReMax FSDP vLLM-Ascend 整体交付报告 | ||
|
|
||
| 对应任务:[verl-ascend-recipe #23](https://github.com/verl-project/verl-ascend-recipe/issues/23) | ||
|
|
||
| ## 1. 交付概览 | ||
|
|
||
| 本交付提供 Qwen3-8B ReMax 在 Ascend NPU 上的可复现训练 recipe。训练侧使用 FSDP | ||
| 管理 actor 和 reference model,rollout 侧使用 vLLM-Ascend,训练入口为 | ||
| `verl.trainer.main_ppo`。 | ||
|
|
||
| | 项目 | 配置 | | ||
| | --- | --- | | ||
| | 模型 | Qwen3-8B | | ||
| | 数据集 | GSM8K 和 MATH | | ||
| | 算法 | ReMax,采样 response 与 greedy baseline 的 reward 差作为 advantage | | ||
| | 训练后端 | FSDP actor/reference | | ||
| | Rollout 后端 | vLLM-Ascend | | ||
| | 验证平台 | Atlas 800T A2,8 x Ascend 910B3 64 GB | | ||
| | 验证规模 | Qwen3-8B 连续 60 steps,另含 smoke、稳定性和长序列压力测试 | | ||
| | 运行脚本 | `verl_ascend_practice/run_qwen3_8b_remax_fsdp_npu.sh` | | ||
|
|
||
| ## 2. 适配方案 | ||
|
|
||
| ReMax 通过以下关键配置启用: | ||
|
|
||
| ```text | ||
| algorithm.adv_estimator=remax | ||
| algorithm.use_kl_in_reward=True | ||
| algorithm.kl_penalty=kl | ||
| algorithm.kl_ctrl.kl_coef=0.001 | ||
| actor_rollout_ref.actor.use_kl_loss=False | ||
| actor_rollout_ref.rollout.name=vllm | ||
| trainer.device=npu | ||
| ``` | ||
|
|
||
| ReMax 对每个 prompt 生成采样 response 和一个 greedy baseline,使用二者的 reward 差降低 | ||
| policy-gradient 方差。verl 已在 agent-loop/vLLM 请求中实现 combined rollout,因此无需修改 | ||
| trainer 或 rollout 核心代码,现有流程可以直接使用 vLLM-Ascend。 | ||
|
|
||
| ```text | ||
| GSM8K / MATH prompts | ||
| | | ||
| v | ||
| vLLM-Ascend sampled rollout + greedy baseline | ||
| | | ||
| v | ||
| sampled reward - baseline reward | ||
| | | ||
| v | ||
| ReMax advantage + KL-in-reward | ||
| | | ||
| v | ||
| FSDP actor update | ||
| | | ||
| v | ||
| rollout weight synchronization | ||
| ``` | ||
|
|
||
| ### 2.1 关键训练配置 | ||
|
|
||
| | 配置项 | 脚本默认值 | 60-step 验证值 | | ||
| | --- | ---: | ---: | | ||
| | train batch size | 256 | 128 | | ||
| | PPO mini batch size | 128 | 32 | | ||
| | rollout responses per prompt | 4 | 4 | | ||
| | prompt / response length | 1024 / 2048 | 1024 / 1024 | | ||
| | actor learning rate | `1e-6` | `1e-6` | | ||
| | rollout tensor parallel size | 2 | 2 | | ||
| | rollout memory utilization | 0.6 | 0.6 | | ||
| | KL coefficient | 0.001 | 0.001 | | ||
| | actor parameter / optimizer offload | 开启 / 开启 | 开启 / 开启 | | ||
| | reference parameter offload | 开启 | 开启 | | ||
| | precision | BF16 | BF16 | | ||
|
|
||
| actor 和 reference model 均关闭 torch compile,避免当前 NPU 软件栈下的不稳定行为。 | ||
| 参数及优化器 offload 为同机部署的 vLLM-Ascend rollout engine 保留 HBM 空间。 | ||
| rollout 使用 full-decode-only ACL Graph,并开启 cache engine 释放。 | ||
|
|
||
| ## 3. 环境与数据准备 | ||
|
|
||
| ### 3.1 已验证软件环境 | ||
|
|
||
| | 组件 | 版本 | | ||
| | --- | --- | | ||
| | 硬件 | Atlas 800T A2,8 x Ascend 910B3 64 GB | | ||
| | CANN | 25.5.1 | | ||
| | torch-npu | 2.9.0.post2 | | ||
| | vLLM | 0.18 | | ||
| | vLLM-Ascend | 0.18.1.dev41 | | ||
| | transformers | 5.3.0.dev0 | | ||
|
|
||
| ### 3.2 数据准备 | ||
|
|
||
| 在 verl 根目录执行: | ||
|
|
||
| ```bash | ||
| python3 examples/data_preprocess/gsm8k.py --local_save_dir "$HOME/data/gsm8k" | ||
| python3 examples/data_preprocess/math_dataset.py --local_save_dir "$HOME/data/math" | ||
| ``` | ||
|
|
||
| 默认数据目录结构如下: | ||
|
|
||
| ```text | ||
| $HOME/data/ | ||
| ├── gsm8k/ | ||
| │ ├── train.parquet | ||
| │ └── test.parquet | ||
| └── math/ | ||
| ├── train.parquet | ||
| └── test.parquet | ||
| ``` | ||
|
|
||
| 可以通过 `GSM8K_DATA_DIR` 和 `MATH_DATA_DIR` 覆盖两个数据目录。训练会过滤超过 | ||
| 1024 tokens 的 prompt,并将最大 response length 设为 2048。 | ||
|
|
||
| ## 4. 运行方式 | ||
|
|
||
| 在 verl 根目录执行: | ||
|
|
||
| ```bash | ||
| MODEL_PATH=/data/models/Qwen3-8B \ | ||
| bash /path/to/verl-ascend-recipe/verl_ascend_practice/run_qwen3_8b_remax_fsdp_npu.sh \ | ||
| 'trainer.logger=["console"]' | ||
| ``` | ||
|
|
||
| 模型、数据、节点数、batch、序列长度、rollout 并行度、显存利用率、保存频率和测试频率 | ||
| 均可通过环境变量修改;额外参数会作为 Hydra overrides 继续传递给 | ||
| `verl.trainer.main_ppo`。 | ||
|
|
||
| 例如,复现 60-step 验证所使用的主要 batch 配置: | ||
|
|
||
| ```bash | ||
| TRAIN_BATCH_SIZE=128 \ | ||
| PPO_MINI_BATCH_SIZE=32 \ | ||
| ROLLOUT_N=4 \ | ||
| ROLLOUT_TP=2 \ | ||
| ROLLOUT_GPU_MEM_UTIL=0.6 \ | ||
| MAX_RESPONSE_LENGTH=1024 \ | ||
| MODEL_PATH=/data/models/Qwen3-8B \ | ||
| bash /path/to/verl-ascend-recipe/verl_ascend_practice/run_qwen3_8b_remax_fsdp_npu.sh | ||
| ``` | ||
|
|
||
| ## 5. 验证结果 | ||
|
|
||
| ### 5.1 功能与稳定性验证 | ||
|
|
||
| | 测试 | 结果 | | ||
| | --- | --- | | ||
| | Smoke | Qwen3-0.6B 在 8 张 NPU 上完成 2 steps | | ||
| | ReMax 链路 | `reward_kl_penalty` 和 `critic/advantages` 确认进入 ReMax advantage 流程 | | ||
| | Greedy baseline | server 日志确认 baseline 请求使用 `temperature=0` | | ||
| | Qwen3-8B 稳定性 | batch size 128、response length 1024 连续完成 5 steps,无 OOM 或 HCCL timeout | | ||
| | 长序列压力测试 | response length 2048 完成 3 steps,无 OOM | | ||
|
|
||
| ### 5.2 60-step 训练结果 | ||
|
|
||
| Qwen3-8B 在 GSM8K 上使用 batch size 128、mini-batch size 32、`n=4`、学习率 | ||
| `1e-6` 和 `kl_coef=1e-3`,在约 2 小时 25 分钟内完成 60 steps。 | ||
|
|
||
| | 指标 | 结果 | | ||
| | --- | ---: | | ||
| | 连续训练步数 | 60 | | ||
| | 训练耗时 | 约 2 小时 25 分钟 | | ||
| | `critic/score/mean` 初始值 | 约 0.26 | | ||
| | `critic/score/mean` 后期区间 | 0.60-0.76 | | ||
| | `critic/score/mean` 峰值 | 0.764 | | ||
| | 平均集群吞吐 | 约 381 tokens/s | | ||
| | 60-step 吞吐范围 | 337-425 tokens/s | | ||
| | response length 2048 压力测试吞吐 | 343-411 tokens/s | | ||
|
|
||
| ### 5.3 Reward 曲线 | ||
|
|
||
| 下图展示训练期间的 `critic/rewards/mean` 变化趋势: | ||
|
|
||
|  | ||
|
|
||
| ### 5.4 性能与稳定性 | ||
|
|
||
| - `critic/score/mean` 从约 0.26 上升至 0.60-0.76 区间,最高达到 0.764。 | ||
| - 60-step 平均集群吞吐约为 381 tokens/s,高于无 GPU 标杆时的 100 TPS 门槛。 | ||
| - Qwen3-8B 稳定性测试和长序列压力测试均未出现 OOM 或 HCCL timeout。 | ||
| - offload 会增加 HBM 与 CPU 之间的数据传输开销,但能为 64 GB 设备上的 colocated | ||
| rollout engine 提供安全显存余量。 | ||
|
|
||
| ## 6. 验收结论 | ||
|
|
||
| | Issue #23 验收项 | 本次结果 | | ||
| | --- | --- | | ||
| | reward 上升 | `critic/score/mean` 从约 0.26 上升至 0.60-0.76 区间 | | ||
| | 无 GPU 标杆时 TPS > 100 | 平均集群吞吐约 381 tokens/s | | ||
| | 提供可复现 recipe | 提供环境、数据、关键参数及启动脚本 | | ||
| | 完成 100 steps 或运行 12 小时 | 当前已记录 60 steps、约 2 小时 25 分钟,仍需补充更长验证日志 | | ||
|
|
||
| 现有结果验证了 Qwen3-8B ReMax 在 FSDP + vLLM-Ascend 组合上的功能、reward 趋势、 | ||
| 性能与短期稳定性。 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,122 @@ | ||
| #!/usr/bin/env bash | ||
| # ReMax | Qwen3-8B | vLLM-Ascend rollout | FSDP training | Atlas 800T A2/A3 | ||
|
|
||
| set -xeuo pipefail | ||
|
|
||
| export RAY_DEDUP_LOGS=0 | ||
| export HYDRA_FULL_ERROR=1 | ||
| export TASK_QUEUE_ENABLE=1 | ||
| export HCCL_EXEC_TIMEOUT=3600 | ||
| export HCCL_CONNECT_TIMEOUT=3600 | ||
| export HCCL_ASYNC_ERROR_HANDLING=0 | ||
| export CPU_AFFINITY_CONF=1 | ||
|
|
||
| # ---- user-adjustable ---- | ||
| MODEL_PATH=${MODEL_PATH:-Qwen/Qwen3-8B} | ||
| NNODES=${NNODES:-1} | ||
| NGPUS_PER_NODE=${NGPUS_PER_NODE:-8} | ||
|
|
||
| train_batch_size=${TRAIN_BATCH_SIZE:-256} | ||
| ppo_mini_batch_size=${PPO_MINI_BATCH_SIZE:-128} | ||
| max_prompt_length=${MAX_PROMPT_LENGTH:-1024} | ||
| max_response_length=${MAX_RESPONSE_LENGTH:-2048} | ||
| ppo_max_token_len_per_gpu=${PPO_MAX_TOKEN_LEN_PER_GPU:-16384} | ||
|
|
||
| actor_lr=${ACTOR_LR:-1e-6} | ||
| entropy_coeff=${ENTROPY_COEFF:-0} | ||
| grad_clip=${GRAD_CLIP:-1.0} | ||
|
|
||
| rollout_tp=${ROLLOUT_TP:-2} | ||
| rollout_gpu_mem_util=${ROLLOUT_GPU_MEM_UTIL:-0.6} | ||
| rollout_n=${ROLLOUT_N:-4} | ||
| enforce_eager=${ENFORCE_EAGER:-False} | ||
|
|
||
| total_epochs=${TOTAL_EPOCHS:-5} | ||
| save_freq=${SAVE_FREQ:-20} | ||
| test_freq=${TEST_FREQ:-10} | ||
|
|
||
| project_name=${PROJECT_NAME:-verl_remax_gsm8k_math_ascend} | ||
| experiment_name=${EXPERIMENT_NAME:-qwen3_8b_vllm_ascend_fsdp} | ||
|
|
||
| gsm8k_data_dir=${GSM8K_DATA_DIR:-$HOME/data/gsm8k} | ||
| math_data_dir=${MATH_DATA_DIR:-$HOME/data/math} | ||
| # ---- end user-adjustable ---- | ||
|
|
||
| train_files="['$gsm8k_data_dir/train.parquet', '$math_data_dir/train.parquet']" | ||
| val_files="['$gsm8k_data_dir/test.parquet', '$math_data_dir/test.parquet']" | ||
|
|
||
| DATA=( | ||
| algorithm.adv_estimator=remax | ||
| algorithm.use_kl_in_reward=True | ||
| algorithm.kl_penalty=kl | ||
| algorithm.kl_ctrl.kl_coef=0.001 | ||
| data.train_files="$train_files" | ||
| data.val_files="$val_files" | ||
| data.train_batch_size=${train_batch_size} | ||
| data.max_prompt_length=${max_prompt_length} | ||
| data.max_response_length=${max_response_length} | ||
| data.filter_overlong_prompts=True | ||
| data.truncation='error' | ||
| ) | ||
|
|
||
| MODEL=( | ||
| actor_rollout_ref.model.path="$MODEL_PATH" | ||
| actor_rollout_ref.model.use_remove_padding=True | ||
| actor_rollout_ref.model.enable_gradient_checkpointing=True | ||
| ) | ||
|
|
||
| ACTOR=( | ||
| actor_rollout_ref.actor.optim.lr=${actor_lr} | ||
| actor_rollout_ref.actor.ppo_mini_batch_size=${ppo_mini_batch_size} | ||
| actor_rollout_ref.actor.grad_clip=${grad_clip} | ||
| actor_rollout_ref.actor.use_dynamic_bsz=True | ||
| actor_rollout_ref.actor.ppo_max_token_len_per_gpu=${ppo_max_token_len_per_gpu} | ||
| actor_rollout_ref.actor.use_kl_loss=False | ||
| actor_rollout_ref.actor.entropy_coeff=${entropy_coeff} | ||
| actor_rollout_ref.actor.use_torch_compile=False | ||
| actor_rollout_ref.actor.fsdp_config.param_offload=True | ||
| actor_rollout_ref.actor.fsdp_config.optimizer_offload=True | ||
| ) | ||
|
|
||
| ROLLOUT=( | ||
| actor_rollout_ref.rollout.name=vllm | ||
| actor_rollout_ref.rollout.tensor_model_parallel_size=${rollout_tp} | ||
| actor_rollout_ref.rollout.gpu_memory_utilization=${rollout_gpu_mem_util} | ||
| actor_rollout_ref.rollout.n=${rollout_n} | ||
| actor_rollout_ref.rollout.log_prob_use_dynamic_bsz=True | ||
| actor_rollout_ref.rollout.log_prob_max_token_len_per_gpu=${ppo_max_token_len_per_gpu} | ||
| actor_rollout_ref.rollout.enforce_eager=${enforce_eager} | ||
| actor_rollout_ref.rollout.free_cache_engine=True | ||
| +actor_rollout_ref.rollout.engine_kwargs.vllm.compilation_config.cudagraph_capture_sizes="[4, 8, 12, 16, 20, 24, 28, 32]" | ||
| +actor_rollout_ref.rollout.engine_kwargs.vllm.compilation_config.cudagraph_mode="FULL_DECODE_ONLY" | ||
| ) | ||
|
|
||
| REF=( | ||
| actor_rollout_ref.ref.use_torch_compile=False | ||
| actor_rollout_ref.ref.log_prob_use_dynamic_bsz=True | ||
| actor_rollout_ref.ref.log_prob_max_token_len_per_gpu=${ppo_max_token_len_per_gpu} | ||
| actor_rollout_ref.ref.fsdp_config.param_offload=True | ||
| ) | ||
|
|
||
| TRAINER=( | ||
| trainer.balance_batch=True | ||
| trainer.critic_warmup=0 | ||
| trainer.logger='["console","wandb"]' | ||
| trainer.project_name=${project_name} | ||
| trainer.experiment_name=${experiment_name} | ||
| trainer.n_gpus_per_node=${NGPUS_PER_NODE} | ||
| trainer.nnodes=${NNODES} | ||
| trainer.device=npu | ||
| trainer.save_freq=${save_freq} | ||
| trainer.test_freq=${test_freq} | ||
| trainer.total_epochs=${total_epochs} | ||
| ) | ||
|
|
||
| python3 -m verl.trainer.main_ppo \ | ||
| "${DATA[@]}" \ | ||
| "${MODEL[@]}" \ | ||
| "${ACTOR[@]}" \ | ||
| "${ROLLOUT[@]}" \ | ||
| "${REF[@]}" \ | ||
| "${TRAINER[@]}" \ | ||
| "$@" |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.