#!/usr/bin/env bash # GRPO | Qwen2.5-VL-7B | FSDP training | NVIDIA GPUs or Ascend NPUs # # INFER_BACKEND controls rollout backend: vllm | sglang | trtllm. set -xeuo pipefail ########################### user-adjustable ########################### INFER_BACKEND=${INFER_BACKEND:-vllm} # DEVICE is auto-detected by probing torch_npu; override only for special cases. DEVICE=${DEVICE:-$(python3 -c 'import torch_npu' 2>/dev/null && echo npu || echo gpu)} MODEL_PATH=${MODEL_PATH:-Qwen/Qwen2.5-VL-7B-Instruct} NNODES=${NNODES:-1} NGPUS_PER_NODE=${NGPUS_PER_NODE:-8} train_batch_size=${TRAIN_BATCH_SIZE:-512} 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:-24576} actor_lr=${ACTOR_LR:-1e-6} kl_loss_coef=${KL_LOSS_COEF:-0.01} entropy_coeff=${ENTROPY_COEFF:-0} rollout_tp=${ROLLOUT_TP:-} rollout_gpu_mem_util=${ROLLOUT_GPU_MEM_UTIL:-} rollout_n=${ROLLOUT_N:-5} total_epochs=${TOTAL_EPOCHS:-15} save_freq=${SAVE_FREQ:-20} test_freq=${TEST_FREQ:-5} project_name=${PROJECT_NAME:-verl_grpo_geo3k} experiment_name=${EXPERIMENT_NAME:-qwen2_5_vl_7b_${INFER_BACKEND}_fsdp} ########################### end user-adjustable ########################### ########################### derived defaults ########################### rollout_tp=${rollout_tp:-2} rollout_gpu_mem_util=${rollout_gpu_mem_util:-0.6} ########################### parameter arrays ########################### DATA=( algorithm.adv_estimator=grpo algorithm.use_kl_in_reward=False data.train_files=$HOME/data/geo3k/train.parquet data.val_files=$HOME/data/geo3k/test.parquet data.image_key=images 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.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=True actor_rollout_ref.actor.kl_loss_coef=${kl_loss_coef} actor_rollout_ref.actor.kl_loss_type=low_var_kl actor_rollout_ref.actor.entropy_coeff=${entropy_coeff} actor_rollout_ref.actor.fsdp_config.param_offload=False actor_rollout_ref.actor.fsdp_config.optimizer_offload=False ) ROLLOUT=( actor_rollout_ref.rollout.name=${INFER_BACKEND} 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} ) REF=( 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.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.save_freq=${save_freq} trainer.test_freq=${test_freq} trainer.total_epochs=${total_epochs} ) # Conservative rollout extras shared by all inference backends. EXTRA=( actor_rollout_ref.actor.strategy=fsdp2 actor_rollout_ref.model.use_fused_kernels=True actor_rollout_ref.rollout.multi_stage_wake_up=True actor_rollout_ref.rollout.enforce_eager=False actor_rollout_ref.rollout.free_cache_engine=True ) case "${DEVICE}" in gpu) ;; npu) TRAINER+=(trainer.n_gpus_per_node=16 ) ROLLOUT+=( actor_rollout_ref.rollout.gpu_memory_utilization=0.5 +actor_rollout_ref.rollout.engine_kwargs.vllm.mm_processor_cache_gb=0 actor_rollout_ref.rollout.log_prob_micro_batch_size_per_gpu=4 ) REF+=( actor_rollout_ref.ref.fsdp_config.param_offload=True ) EXTRA+=( actor_rollout_ref.model.use_fused_kernels=False actor_rollout_ref.rollout.multi_stage_wake_up=False actor_rollout_ref.rollout.free_cache_engine=False ) ;; *) echo "Unsupported DEVICE=${DEVICE}. Expected 'gpu' or 'npu'." >&2 exit 1 ;; esac ########################### launch ########################### # uv (set VERL_USE_UV=0 for system python): GPU vllm/sglang × fsdp run the driver and every Ray worker # (runtime_env.py_executable) through `uv run` on the matching extras of the committed uv.lock; # other backends / NPU fall back to ambient python. Run from the verl repo root. LAUNCH=(python3) RAY=(ray_kwargs.ray_init.runtime_env.py_executable=null) if [ "${VERL_USE_UV:-1}" != 0 ] && [ "${DEVICE:-gpu}" = gpu ] && { [ "${INFER_BACKEND}" = vllm ] || [ "${INFER_BACKEND}" = sglang ]; }; then LAUNCH=(uv run --frozen --all-packages --extra "${INFER_BACKEND}" --extra fsdp python3) RAY=(ray_kwargs.ray_init.runtime_env.py_executable="uv -v run --frozen --all-packages --extra ${INFER_BACKEND} --extra fsdp") fi "${LAUNCH[@]}" -m verl.trainer.main_ppo \ "${DATA[@]}" \ "${MODEL[@]}" \ "${ACTOR[@]}" \ "${ROLLOUT[@]}" \ "${REF[@]}" \ "${TRAINER[@]}" \ "${EXTRA[@]}" \ "${RAY[@]}" \ "$@"