Upload folder using huggingface_hub
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .claude/settings.local.json +21 -0
- .gitattributes +2 -0
- .sii/ide-port +1 -0
- 0519_sft_test/data/convert_to_parquet.py +154 -0
- 0519_sft_test/data/train.parquet +3 -0
- 0519_sft_test/data/val.parquet +3 -0
- 0519_sft_test/run_sft_qwen3vl_8b.sh +75 -0
- 0520_rej_test/README.md +69 -0
- 0520_rej_test/data/build_prompts.py +135 -0
- 0520_rej_test/reward/__pycache__/reward_fn.cpython-312.pyc +0 -0
- 0520_rej_test/reward/reward_fn.py +34 -0
- 0520_rej_test/reward/score.py +80 -0
- 0520_rej_test/run_pipeline.sh +43 -0
- 0520_rej_test/scripts/run_generate.sh +48 -0
- 0520_rej_test/scripts/run_sft.sh +20 -0
- 0520_rej_test/select/topk_to_sft.py +148 -0
- data.tar.gz +3 -0
- pip_list.txt +206 -0
- requirements.txt +132 -0
- verl.tar.gz +3 -0
- verl/.agent/skills/issue/SKILL.md +47 -0
- verl/.agent/skills/pr/SKILL.md +33 -0
- verl/.gemini/config.yaml +10 -0
- verl/.git-blame-ignore-revs +13 -0
- verl/.github/CODEOWNERS +25 -0
- verl/.github/ISSUE_TEMPLATE/bug-report.yml +65 -0
- verl/.github/ISSUE_TEMPLATE/config.yml +2 -0
- verl/.github/ISSUE_TEMPLATE/feature-request.yml +32 -0
- verl/.github/PULL_REQUEST_TEMPLATE.md +41 -0
- verl/.github/dependabot.yml +9 -0
- verl/.github/workflows/README.md +73 -0
- verl/.github/workflows/check-pr-title.yml +58 -0
- verl/.github/workflows/cpu_unit_tests.yml +117 -0
- verl/.github/workflows/doc.yml +101 -0
- verl/.github/workflows/docker-build-ascend-a2-qwen3_5.yml +123 -0
- verl/.github/workflows/docker-build-ascend-a2.yml +281 -0
- verl/.github/workflows/docker-build-ascend-a3-qwen3_5.yml +123 -0
- verl/.github/workflows/docker-build-ascend-a3.yml +281 -0
- verl/.github/workflows/docker-build-ascend-sglang-a2.yml +84 -0
- verl/.github/workflows/docker-build-ascend-sglang-a3.yml +84 -0
- verl/.github/workflows/e2e_ascend.yml +215 -0
- verl/.github/workflows/e2e_fully_async_policy.yml +169 -0
- verl/.github/workflows/e2e_fully_async_policy_ascend.yml +169 -0
- verl/.github/workflows/e2e_fully_async_policy_opd.yml +105 -0
- verl/.github/workflows/e2e_fully_async_policy_trtllm.yml +171 -0
- verl/.github/workflows/e2e_one_step_off_policy.yml +169 -0
- verl/.github/workflows/e2e_one_step_off_policy_ascend.yml +170 -0
- verl/.github/workflows/e2e_ppo_grpo_trainer_trtllm.yml +289 -0
- verl/.github/workflows/e2e_ppo_trainer.yml +78 -0
- verl/.github/workflows/e2e_ppo_trainer_megatron_sglang.yml +202 -0
.claude/settings.local.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"permissions": {
|
| 3 |
+
"allow": [
|
| 4 |
+
"Bash(env)",
|
| 5 |
+
"Bash(curl -s -o /dev/null -w \"HTTP %{http_code} time=%{time_total}s\\\\n\" --max-time 5 http://nexus.sii.shaipower.online/repository/pypi/simple/)",
|
| 6 |
+
"Bash(curl -s -o /dev/null -w \"HTTPS %{http_code} time=%{time_total}s\\\\n\" --max-time 5 https://nexus.sii.shaipower.online/repository/pypi/simple/)",
|
| 7 |
+
"Bash(curl -s -o /dev/null -w \"HTTP %{http_code} time=%{time_total}s\\\\n\" --max-time 15 http://nexus.sii.shaipower.online/repository/pypi/simple/)",
|
| 8 |
+
"Bash(python3 -c \"import sys, json; d=json.loads\\(sys.stdin.read\\(\\)\\); print\\(json.dumps\\(d, indent=2, ensure_ascii=False\\)[:3000]\\)\")",
|
| 9 |
+
"Bash(python3 -c ' *)",
|
| 10 |
+
"Bash(nvidia-smi)",
|
| 11 |
+
"Bash(python3 *)",
|
| 12 |
+
"Read(//root/miniconda3/envs/**)",
|
| 13 |
+
"Bash(conda env *)",
|
| 14 |
+
"Bash(/root/miniconda3/envs/verl/bin/python *)",
|
| 15 |
+
"Bash(/root/miniconda3/envs/verl/bin/pip list *)",
|
| 16 |
+
"Bash(chmod +x *)",
|
| 17 |
+
"Bash(/root/miniconda3/envs/verl/bin/pip show *)",
|
| 18 |
+
"Bash(grep -E \"\\\\.\\(py|sh\\)$\")"
|
| 19 |
+
]
|
| 20 |
+
}
|
| 21 |
+
}
|
.gitattributes
CHANGED
|
@@ -33,3 +33,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
verl/core.778099 filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
verl/verl/trainer/ppo/__pycache__/core_algos.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
.sii/ide-port
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
30003
|
0519_sft_test/data/convert_to_parquet.py
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Convert ind_v4 SFT JSONL into a verl-compatible parquet for MultiTurnSFTDataset.
|
| 2 |
+
#
|
| 3 |
+
# Source format (per line):
|
| 4 |
+
# {
|
| 5 |
+
# "messages": [
|
| 6 |
+
# {"role": "user", "content": "<image>\n..."},
|
| 7 |
+
# {"role": "assistant", "content": "", "tool_calls": [{"id": "...", "type": "function",
|
| 8 |
+
# "function": {"name": "...",
|
| 9 |
+
# "arguments": "{...}"}}]}
|
| 10 |
+
# ],
|
| 11 |
+
# "images": ["/abs/path/to/img.png"],
|
| 12 |
+
# "tools": [{"type": "function", "function": {...}}],
|
| 13 |
+
# "metadata": {...}
|
| 14 |
+
# }
|
| 15 |
+
#
|
| 16 |
+
# Target parquet columns (verl MultiTurnSFTDataset):
|
| 17 |
+
# - messages: list[dict]
|
| 18 |
+
# - images: list[{"bytes": <png bytes>}] (loadable by qwen_vl_utils.fetch_image)
|
| 19 |
+
# - tools: list[dict]
|
| 20 |
+
|
| 21 |
+
import argparse
|
| 22 |
+
import json
|
| 23 |
+
import os
|
| 24 |
+
import random
|
| 25 |
+
from pathlib import Path
|
| 26 |
+
|
| 27 |
+
import pandas as pd
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def load_jsonl(path):
|
| 31 |
+
rows = []
|
| 32 |
+
with open(path, "r", encoding="utf-8") as f:
|
| 33 |
+
for line in f:
|
| 34 |
+
line = line.strip()
|
| 35 |
+
if line:
|
| 36 |
+
rows.append(json.loads(line))
|
| 37 |
+
return rows
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
def read_image_bytes(path: str) -> bytes:
|
| 41 |
+
with open(path, "rb") as f:
|
| 42 |
+
return f.read()
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
def normalize_messages(messages):
|
| 46 |
+
out = []
|
| 47 |
+
for m in messages:
|
| 48 |
+
nm = {"role": m["role"], "content": m.get("content", "") or ""}
|
| 49 |
+
if "tool_calls" in m and m["tool_calls"]:
|
| 50 |
+
tcs = []
|
| 51 |
+
for tc in m["tool_calls"]:
|
| 52 |
+
fn = tc.get("function", {})
|
| 53 |
+
args = fn.get("arguments", "")
|
| 54 |
+
if not isinstance(args, str):
|
| 55 |
+
args = json.dumps(args, ensure_ascii=False)
|
| 56 |
+
tcs.append(
|
| 57 |
+
{
|
| 58 |
+
"id": tc.get("id", ""),
|
| 59 |
+
"type": tc.get("type", "function"),
|
| 60 |
+
"function": {
|
| 61 |
+
"name": fn.get("name", ""),
|
| 62 |
+
"arguments": args,
|
| 63 |
+
},
|
| 64 |
+
}
|
| 65 |
+
)
|
| 66 |
+
nm["tool_calls"] = tcs
|
| 67 |
+
out.append(nm)
|
| 68 |
+
return out
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
def convert(rows, image_root: str | None, max_samples: int = -1):
|
| 72 |
+
if max_samples > 0:
|
| 73 |
+
rows = rows[:max_samples]
|
| 74 |
+
out = []
|
| 75 |
+
for row in rows:
|
| 76 |
+
messages = normalize_messages(row["messages"])
|
| 77 |
+
|
| 78 |
+
images = []
|
| 79 |
+
for img_path in row.get("images", []) or []:
|
| 80 |
+
p = img_path
|
| 81 |
+
if image_root and not os.path.isabs(p):
|
| 82 |
+
p = os.path.join(image_root, p)
|
| 83 |
+
images.append({"bytes": read_image_bytes(p)})
|
| 84 |
+
|
| 85 |
+
tools = row.get("tools", []) or []
|
| 86 |
+
|
| 87 |
+
out.append(
|
| 88 |
+
{
|
| 89 |
+
"messages": messages,
|
| 90 |
+
"images": images,
|
| 91 |
+
"tools": tools,
|
| 92 |
+
}
|
| 93 |
+
)
|
| 94 |
+
return out
|
| 95 |
+
|
| 96 |
+
|
| 97 |
+
def main():
|
| 98 |
+
parser = argparse.ArgumentParser()
|
| 99 |
+
parser.add_argument(
|
| 100 |
+
"--src",
|
| 101 |
+
default="/inspire/qb-ilm2/project/26summer-camp-21/26210880/0518_dataBuilder_liubw"
|
| 102 |
+
"/in_domain/output/ind_v4/sft_rl/sft_train.jsonl",
|
| 103 |
+
help="Path to source SFT JSONL.",
|
| 104 |
+
)
|
| 105 |
+
parser.add_argument(
|
| 106 |
+
"--image_root",
|
| 107 |
+
default=None,
|
| 108 |
+
help="Root for relative image paths. JSONL already has absolute paths, leave None.",
|
| 109 |
+
)
|
| 110 |
+
parser.add_argument(
|
| 111 |
+
"--out_dir",
|
| 112 |
+
default=str(Path(__file__).resolve().parent),
|
| 113 |
+
help="Directory to write {train,val}.parquet.",
|
| 114 |
+
)
|
| 115 |
+
parser.add_argument("--val_ratio", type=float, default=0.02)
|
| 116 |
+
parser.add_argument("--max_samples", type=int, default=-1)
|
| 117 |
+
parser.add_argument("--seed", type=int, default=42)
|
| 118 |
+
args = parser.parse_args()
|
| 119 |
+
|
| 120 |
+
out_dir = Path(args.out_dir)
|
| 121 |
+
out_dir.mkdir(parents=True, exist_ok=True)
|
| 122 |
+
|
| 123 |
+
rows = load_jsonl(args.src)
|
| 124 |
+
print(f"loaded {len(rows)} rows from {args.src}")
|
| 125 |
+
|
| 126 |
+
rng = random.Random(args.seed)
|
| 127 |
+
rng.shuffle(rows)
|
| 128 |
+
|
| 129 |
+
if args.max_samples > 0:
|
| 130 |
+
rows = rows[: args.max_samples]
|
| 131 |
+
print(f"truncated to {len(rows)} samples")
|
| 132 |
+
|
| 133 |
+
n_val = max(1, int(len(rows) * args.val_ratio)) if args.val_ratio > 0 else 0
|
| 134 |
+
val_rows = rows[:n_val]
|
| 135 |
+
train_rows = rows[n_val:]
|
| 136 |
+
print(f"split: train={len(train_rows)}, val={len(val_rows)}")
|
| 137 |
+
|
| 138 |
+
train_records = convert(train_rows, args.image_root)
|
| 139 |
+
val_records = convert(val_rows, args.image_root) if val_rows else []
|
| 140 |
+
|
| 141 |
+
train_df = pd.DataFrame(train_records)
|
| 142 |
+
train_path = out_dir / "train.parquet"
|
| 143 |
+
train_df.to_parquet(train_path, index=False)
|
| 144 |
+
print(f"wrote {train_path} ({len(train_df)} rows)")
|
| 145 |
+
|
| 146 |
+
if val_records:
|
| 147 |
+
val_df = pd.DataFrame(val_records)
|
| 148 |
+
val_path = out_dir / "val.parquet"
|
| 149 |
+
val_df.to_parquet(val_path, index=False)
|
| 150 |
+
print(f"wrote {val_path} ({len(val_df)} rows)")
|
| 151 |
+
|
| 152 |
+
|
| 153 |
+
if __name__ == "__main__":
|
| 154 |
+
main()
|
0519_sft_test/data/train.parquet
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:e61cc170fa7c579bb897cfca7ec2058ead67bfbab7e3c7830b80211958737d4c
|
| 3 |
+
size 131141435
|
0519_sft_test/data/val.parquet
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:7741860c3e5aadef4589d9306a95495c232b91798e4f1cc3ddcde799b03b48e7
|
| 3 |
+
size 2522091
|
0519_sft_test/run_sft_qwen3vl_8b.sh
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
# SFT for Qwen3-VL-8B-Thinking on the ind_v4 dataset (verl FSDP engine).
|
| 3 |
+
#
|
| 4 |
+
# Usage:
|
| 5 |
+
# bash run_sft_qwen3vl_8b.sh # default 8 GPUs
|
| 6 |
+
# NUM_TRAINERS=4 bash run_sft_qwen3vl_8b.sh # override GPU count
|
| 7 |
+
# SP_SIZE=2 NUM_TRAINERS=8 bash run_sft_qwen3vl_8b.sh
|
| 8 |
+
set -xeuo pipefail
|
| 9 |
+
|
| 10 |
+
WORKDIR=$(cd "$(dirname "$0")" && pwd)
|
| 11 |
+
|
| 12 |
+
MODEL_PATH=${MODEL_PATH:-/inspire/qb-ilm2/project/26summer-camp-21/26210880/0518_test_liubw/models/Qwen3-VL-8B-Thinking}
|
| 13 |
+
TRAIN_FILES=${TRAIN_FILES:-${WORKDIR}/data/train.parquet}
|
| 14 |
+
VAL_FILES=${VAL_FILES:-${WORKDIR}/data/val.parquet}
|
| 15 |
+
|
| 16 |
+
NUM_TRAINERS=${NUM_TRAINERS:-8}
|
| 17 |
+
SP_SIZE=${SP_SIZE:-2} # ulysses sequence parallel
|
| 18 |
+
FSDP_SIZE=${FSDP_SIZE:--1}
|
| 19 |
+
FSDP_STRATEGY=${FSDP_STRATEGY:-fsdp2}
|
| 20 |
+
|
| 21 |
+
TRAIN_BATCH_SIZE=${TRAIN_BATCH_SIZE:-32}
|
| 22 |
+
MICRO_BATCH_SIZE_PER_GPU=${MICRO_BATCH_SIZE_PER_GPU:-1}
|
| 23 |
+
MAX_LENGTH=${MAX_LENGTH:-8192}
|
| 24 |
+
MAX_TOKEN_LEN_PER_GPU=${MAX_TOKEN_LEN_PER_GPU:-16384}
|
| 25 |
+
TOTAL_EPOCHS=${TOTAL_EPOCHS:-3}
|
| 26 |
+
LR=${LR:-1e-5}
|
| 27 |
+
|
| 28 |
+
PROJECT_NAME=${PROJECT_NAME:-ind_v4_sft}
|
| 29 |
+
EXPERIMENT_NAME=${EXPERIMENT_NAME:-qwen3vl-8b-thinking-fsdp${FSDP_STRATEGY}-sp${SP_SIZE}}
|
| 30 |
+
SAVE_DIR=${SAVE_DIR:-${WORKDIR}/checkpoints/${PROJECT_NAME}/${EXPERIMENT_NAME}}
|
| 31 |
+
LOGGER=${LOGGER:-"['console']"} # set to "['console','wandb']" once wandb is logged in
|
| 32 |
+
RESUME_MODE=${RESUME_MODE:-auto}
|
| 33 |
+
|
| 34 |
+
mkdir -p "${SAVE_DIR}"
|
| 35 |
+
|
| 36 |
+
cd /inspire/qb-ilm2/project/26summer-camp-21/26210880/0519_verl/verl
|
| 37 |
+
|
| 38 |
+
torchrun --standalone --nnodes=1 --nproc-per-node="${NUM_TRAINERS}" \
|
| 39 |
+
-m verl.trainer.sft_trainer \
|
| 40 |
+
data.train_files="${TRAIN_FILES}" \
|
| 41 |
+
data.val_files="${VAL_FILES}" \
|
| 42 |
+
data.train_batch_size="${TRAIN_BATCH_SIZE}" \
|
| 43 |
+
data.micro_batch_size_per_gpu="${MICRO_BATCH_SIZE_PER_GPU}" \
|
| 44 |
+
data.max_length="${MAX_LENGTH}" \
|
| 45 |
+
data.max_token_len_per_gpu="${MAX_TOKEN_LEN_PER_GPU}" \
|
| 46 |
+
data.use_dynamic_bsz=True \
|
| 47 |
+
data.pad_mode=no_padding \
|
| 48 |
+
data.truncation=right \
|
| 49 |
+
data.messages_key=messages \
|
| 50 |
+
data.tools_key=tools \
|
| 51 |
+
data.ignore_input_ids_mismatch=True \
|
| 52 |
+
model.path="${MODEL_PATH}" \
|
| 53 |
+
model.use_remove_padding=True \
|
| 54 |
+
engine=fsdp \
|
| 55 |
+
optim=fsdp \
|
| 56 |
+
optim.lr="${LR}" \
|
| 57 |
+
optim.lr_warmup_steps_ratio=0.03 \
|
| 58 |
+
optim.weight_decay=0.1 \
|
| 59 |
+
optim.betas="[0.9,0.95]" \
|
| 60 |
+
optim.clip_grad=1.0 \
|
| 61 |
+
optim.min_lr_ratio=0.1 \
|
| 62 |
+
optim.warmup_style=cosine \
|
| 63 |
+
engine.ulysses_sequence_parallel_size="${SP_SIZE}" \
|
| 64 |
+
engine.strategy="${FSDP_STRATEGY}" \
|
| 65 |
+
engine.fsdp_size="${FSDP_SIZE}" \
|
| 66 |
+
trainer.default_local_dir="${SAVE_DIR}" \
|
| 67 |
+
trainer.project_name="${PROJECT_NAME}" \
|
| 68 |
+
trainer.experiment_name="${EXPERIMENT_NAME}" \
|
| 69 |
+
trainer.total_epochs="${TOTAL_EPOCHS}" \
|
| 70 |
+
trainer.logger="${LOGGER}" \
|
| 71 |
+
trainer.save_freq=500 \
|
| 72 |
+
trainer.test_freq=200 \
|
| 73 |
+
trainer.max_ckpt_to_keep=3 \
|
| 74 |
+
trainer.resume_mode="${RESUME_MODE}" \
|
| 75 |
+
checkpoint.save_contents=[model,optimizer,extra]
|
0520_rej_test/README.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 0520_rej_test — Offline RAFT/RFT framework
|
| 2 |
+
|
| 3 |
+
verl 主仓库**没有现成的 reward-based 拒绝采样训练循环**:
|
| 4 |
+
- `algorithm.filter_groups` 只有 dataclass,没有 trainer 消费
|
| 5 |
+
- `algorithm.rollout_correction` 是 IS-based 拒绝,依据是重要性比值,不是 reward
|
| 6 |
+
|
| 7 |
+
这里搭的是经典 **RAFT (Reward-rAnked Fine-Tuning)** —— 完全离线、字面意义上的拒绝采样:
|
| 8 |
+
对当前模型采样 N 条 → reward 打分 → 取 top-K → 喂给 SFT。
|
| 9 |
+
|
| 10 |
+
```
|
| 11 |
+
rl_train.jsonl
|
| 12 |
+
↓ build_prompts.py
|
| 13 |
+
prompts.parquet
|
| 14 |
+
↓ Stage A: verl.trainer.main_generation_server (vLLM, n=N)
|
| 15 |
+
gen.parquet
|
| 16 |
+
↓ Stage B: reward/score.py + reward/reward_fn.py (STUB)
|
| 17 |
+
scored.parquet
|
| 18 |
+
↓ Stage C: select/topk_to_sft.py
|
| 19 |
+
raft_train.parquet
|
| 20 |
+
↓ Stage D: scripts/run_sft.sh -> 0519_sft_test/run_sft_qwen3vl_8b.sh
|
| 21 |
+
checkpoints/
|
| 22 |
+
```
|
| 23 |
+
|
| 24 |
+
## 现状
|
| 25 |
+
- 框架完整可执行;
|
| 26 |
+
- **`reward/reward_fn.py` 是 stub**,固定 `compute_reward(prompt, response, metadata, tools, ...)` 签名,永远返回 `0.0`,等后续实现;
|
| 27 |
+
- 不动 `0519_sft_test/` 任何文件,Stage D 通过环境变量复用其 SFT 脚本。
|
| 28 |
+
|
| 29 |
+
## 使用
|
| 30 |
+
|
| 31 |
+
整体跑:
|
| 32 |
+
```bash
|
| 33 |
+
bash run_pipeline.sh
|
| 34 |
+
```
|
| 35 |
+
|
| 36 |
+
只跑某一段:
|
| 37 |
+
```bash
|
| 38 |
+
STAGE=A_pre bash run_pipeline.sh # 只生成 prompts.parquet
|
| 39 |
+
STAGE=A bash run_pipeline.sh # 跑 vLLM 采样
|
| 40 |
+
STAGE=B bash run_pipeline.sh # 打分
|
| 41 |
+
STAGE=C bash run_pipeline.sh # 选 top-K + 转 SFT 格式
|
| 42 |
+
STAGE=D bash run_pipeline.sh # SFT
|
| 43 |
+
```
|
| 44 |
+
|
| 45 |
+
Smoke 试跑(4 条 prompt × 2 个 sample):
|
| 46 |
+
```bash
|
| 47 |
+
MAX_SAMPLES=4 N_SAMPLES=2 RESPONSE_LENGTH=512 STAGE=A_pre bash run_pipeline.sh
|
| 48 |
+
MAX_SAMPLES=4 N_SAMPLES=2 RESPONSE_LENGTH=512 STAGE=A bash run_pipeline.sh
|
| 49 |
+
STAGE=B bash run_pipeline.sh
|
| 50 |
+
TOP_K=1 STAGE=C bash run_pipeline.sh
|
| 51 |
+
```
|
| 52 |
+
|
| 53 |
+
## 关键依赖
|
| 54 |
+
|
| 55 |
+
| 用途 | 路径 |
|
| 56 |
+
|---|---|
|
| 57 |
+
| Stage A 入口 | `verl/trainer/main_generation_server.py` |
|
| 58 |
+
| 多模态 chat template | `verl/workers/rollout/schemas.py` |
|
| 59 |
+
| SFT 目标 schema | `verl/utils/dataset/multiturn_sft_dataset.py` |
|
| 60 |
+
| SFT 启动脚本(被复用) | `0519_sft_test/run_sft_qwen3vl_8b.sh` |
|
| 61 |
+
| 模型 | `0518_test_liubw/models/Qwen3-VL-8B-Thinking` |
|
| 62 |
+
| RL 原始数据 | `0518_dataBuilder_liubw/.../sft_rl/rl_train.jsonl` |
|
| 63 |
+
|
| 64 |
+
## 设计要点
|
| 65 |
+
|
| 66 |
+
- **图像如何进 vLLM?** verl 的 `main_generation_server` 直接把 `prompt` 列里的 OpenAI 格式 messages 转给 vLLM 的 chat completions 接口 —— 我们把每张图编成 `data:image/png;base64,...` URL 塞进 multimodal content block。Stage C 再从 `image_paths` 重新读字节进 SFT parquet。
|
| 67 |
+
- **tools 怎么走?** `main_generation_server` 不读 `tools` 列;`tools` 的 JSON schema 当作文本前缀拼进 user turn。模型是 Qwen3-VL-Thinking,训练时见过 `<tool_call>{...}</tool_call>` 输出格式,会自然产出。
|
| 68 |
+
- **怎么把模型输出还原成结构化 tool_calls?** Stage C 用正则提 `<tool_call>` 块 → `json.loads` → 构造 OpenAI tool_call dict(`arguments` 强制成字符串,与 `0519_sft_test/data/convert_to_parquet.py` 一致)。解析失败的样本直接丢。
|
| 69 |
+
- **SFT schema 完全和 0519_sft_test 一致**,所以可以直接复用其 dataset 加载 + chat template 验证路径。
|
0520_rej_test/data/build_prompts.py
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Build prompts.parquet for Stage A (verl.trainer.main_generation_server).
|
| 2 |
+
|
| 3 |
+
Source: ind_v4 rl_train.jsonl with shape
|
| 4 |
+
{messages, images, tools, metadata}
|
| 5 |
+
|
| 6 |
+
main_generation_server expects a single `prompt` column whose value is an
|
| 7 |
+
OpenAI-style chat-completions `messages` list. It does NOT read `tools` or
|
| 8 |
+
`images` columns directly — both must be baked into `prompt`.
|
| 9 |
+
|
| 10 |
+
Encoding:
|
| 11 |
+
- `images[i]` is read from disk and embedded as a base64 data-URL inside
|
| 12 |
+
a multimodal content block on the user turn.
|
| 13 |
+
- `tools` (the JSON spec) is rendered as a textual preamble prepended to
|
| 14 |
+
the user turn so that even without server-side tool injection the model
|
| 15 |
+
sees the tool name + schema. The model is Qwen3-VL-Thinking, which is
|
| 16 |
+
trained to emit `<tool_call>{...}</tool_call>` blocks — Stage C will
|
| 17 |
+
parse them back out.
|
| 18 |
+
|
| 19 |
+
Extra columns kept on the parquet so downstream stages can use them:
|
| 20 |
+
- `metadata`: original metadata dict (test_points, expression_numpy, ...)
|
| 21 |
+
- `image_paths`: original image paths (so Stage C can re-read bytes
|
| 22 |
+
without going through the data-URL).
|
| 23 |
+
- `tools_orig`: original tools spec (for Stage C's SFT reconstruction).
|
| 24 |
+
"""
|
| 25 |
+
|
| 26 |
+
import argparse
|
| 27 |
+
import base64
|
| 28 |
+
import json
|
| 29 |
+
import mimetypes
|
| 30 |
+
import os
|
| 31 |
+
import random
|
| 32 |
+
from pathlib import Path
|
| 33 |
+
|
| 34 |
+
import pandas as pd
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def load_jsonl(path):
|
| 38 |
+
rows = []
|
| 39 |
+
with open(path, "r", encoding="utf-8") as f:
|
| 40 |
+
for line in f:
|
| 41 |
+
line = line.strip()
|
| 42 |
+
if line:
|
| 43 |
+
rows.append(json.loads(line))
|
| 44 |
+
return rows
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
def img_to_data_url(path: str) -> str:
|
| 48 |
+
mime, _ = mimetypes.guess_type(path)
|
| 49 |
+
if mime is None:
|
| 50 |
+
mime = "image/png"
|
| 51 |
+
with open(path, "rb") as f:
|
| 52 |
+
b64 = base64.b64encode(f.read()).decode("ascii")
|
| 53 |
+
return f"data:{mime};base64,{b64}"
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
def render_tools_preamble(tools: list[dict]) -> str:
|
| 57 |
+
if not tools:
|
| 58 |
+
return ""
|
| 59 |
+
lines = ["You have access to the following tools. Reply via a single "
|
| 60 |
+
"<tool_call>{...}</tool_call> block whose JSON contains "
|
| 61 |
+
"`name` and `arguments`."]
|
| 62 |
+
for t in tools:
|
| 63 |
+
lines.append(json.dumps(t, ensure_ascii=False))
|
| 64 |
+
return "\n".join(lines) + "\n\n"
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
def build_prompt(row: dict) -> list[dict]:
|
| 68 |
+
"""Construct OpenAI multimodal `messages` from one raw RL sample."""
|
| 69 |
+
user_text = row["messages"][0]["content"]
|
| 70 |
+
if user_text.startswith("<image>\n"):
|
| 71 |
+
user_text = user_text[len("<image>\n") :]
|
| 72 |
+
elif user_text.startswith("<image>"):
|
| 73 |
+
user_text = user_text[len("<image>") :]
|
| 74 |
+
|
| 75 |
+
preamble = render_tools_preamble(row.get("tools") or [])
|
| 76 |
+
text_block = preamble + user_text
|
| 77 |
+
|
| 78 |
+
content = []
|
| 79 |
+
for img_path in row.get("images") or []:
|
| 80 |
+
content.append(
|
| 81 |
+
{"type": "image_url",
|
| 82 |
+
"image_url": {"url": img_to_data_url(img_path)}}
|
| 83 |
+
)
|
| 84 |
+
content.append({"type": "text", "text": text_block})
|
| 85 |
+
|
| 86 |
+
return [{"role": "user", "content": content}]
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
def main():
|
| 90 |
+
parser = argparse.ArgumentParser()
|
| 91 |
+
parser.add_argument(
|
| 92 |
+
"--src",
|
| 93 |
+
default="/inspire/qb-ilm2/project/26summer-camp-21/26210880"
|
| 94 |
+
"/0518_dataBuilder_liubw/in_domain/output/ind_v4/sft_rl/rl_train.jsonl",
|
| 95 |
+
)
|
| 96 |
+
parser.add_argument(
|
| 97 |
+
"--out",
|
| 98 |
+
default=str(Path(__file__).resolve().parent / "prompts.parquet"),
|
| 99 |
+
)
|
| 100 |
+
parser.add_argument("--max_samples", type=int, default=-1)
|
| 101 |
+
parser.add_argument("--shuffle", action="store_true")
|
| 102 |
+
parser.add_argument("--seed", type=int, default=42)
|
| 103 |
+
args = parser.parse_args()
|
| 104 |
+
|
| 105 |
+
rows = load_jsonl(args.src)
|
| 106 |
+
print(f"loaded {len(rows)} rows from {args.src}")
|
| 107 |
+
|
| 108 |
+
if args.shuffle:
|
| 109 |
+
rng = random.Random(args.seed)
|
| 110 |
+
rng.shuffle(rows)
|
| 111 |
+
|
| 112 |
+
if args.max_samples > 0:
|
| 113 |
+
rows = rows[: args.max_samples]
|
| 114 |
+
print(f"truncated to {len(rows)}")
|
| 115 |
+
|
| 116 |
+
records = []
|
| 117 |
+
for row in rows:
|
| 118 |
+
records.append(
|
| 119 |
+
{
|
| 120 |
+
"prompt": build_prompt(row),
|
| 121 |
+
"metadata": row.get("metadata", {}),
|
| 122 |
+
"image_paths": row.get("images") or [],
|
| 123 |
+
"tools_orig": row.get("tools") or [],
|
| 124 |
+
}
|
| 125 |
+
)
|
| 126 |
+
|
| 127 |
+
out_path = Path(args.out)
|
| 128 |
+
out_path.parent.mkdir(parents=True, exist_ok=True)
|
| 129 |
+
df = pd.DataFrame(records)
|
| 130 |
+
df.to_parquet(out_path, index=False)
|
| 131 |
+
print(f"wrote {out_path} ({len(df)} rows)")
|
| 132 |
+
|
| 133 |
+
|
| 134 |
+
if __name__ == "__main__":
|
| 135 |
+
main()
|
0520_rej_test/reward/__pycache__/reward_fn.cpython-312.pyc
ADDED
|
Binary file (1.4 kB). View file
|
|
|
0520_rej_test/reward/reward_fn.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Stage B reward function.
|
| 2 |
+
|
| 3 |
+
This is a STUB. The signature is fixed; downstream `score.py` calls
|
| 4 |
+
`compute_reward(...)` row-wise by keyword. Implement the body later.
|
| 5 |
+
|
| 6 |
+
Inputs (kwargs):
|
| 7 |
+
prompt: list[dict] # OpenAI chat-completions messages used at generation
|
| 8 |
+
response: str # one model completion (raw text)
|
| 9 |
+
metadata: dict # original sample metadata (test_points, expression_numpy, ...)
|
| 10 |
+
tools: list[dict] # original `tools` JSON spec
|
| 11 |
+
index: int # sample index (for logging)
|
| 12 |
+
sample: int # which of the N samples (0..N-1)
|
| 13 |
+
|
| 14 |
+
Returns:
|
| 15 |
+
float in [0, 1] -- higher is better
|
| 16 |
+
"""
|
| 17 |
+
|
| 18 |
+
from __future__ import annotations
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def compute_reward(
|
| 22 |
+
*,
|
| 23 |
+
prompt: list[dict],
|
| 24 |
+
response: str,
|
| 25 |
+
metadata: dict,
|
| 26 |
+
tools: list[dict],
|
| 27 |
+
index: int = 0,
|
| 28 |
+
sample: int = 0,
|
| 29 |
+
) -> float:
|
| 30 |
+
# TODO: parse <tool_call>{"name": "submit_expression", "arguments": "..."}</tool_call>
|
| 31 |
+
# eval expression at metadata["test_points"], compute MSE-based reward.
|
| 32 |
+
# Return 0.0 if parse fails or eval errors out.
|
| 33 |
+
del prompt, response, metadata, tools, index, sample
|
| 34 |
+
return 0.0
|
0520_rej_test/reward/score.py
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Stage B driver: read gen.parquet, score each (prompt, response) pair via
|
| 2 |
+
reward_fn.compute_reward, write scored.parquet with a new `scores` column
|
| 3 |
+
(parallel to `responses`).
|
| 4 |
+
|
| 5 |
+
Reward fn lives in reward/reward_fn.py and can be swapped via --reward_fn.
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
+
import argparse
|
| 9 |
+
import importlib.util
|
| 10 |
+
import sys
|
| 11 |
+
from pathlib import Path
|
| 12 |
+
|
| 13 |
+
import pandas as pd
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def load_reward_fn(path: str, name: str = "compute_reward"):
|
| 17 |
+
spec = importlib.util.spec_from_file_location("reward_fn_module", path)
|
| 18 |
+
mod = importlib.util.module_from_spec(spec)
|
| 19 |
+
sys.modules["reward_fn_module"] = mod
|
| 20 |
+
assert spec.loader is not None
|
| 21 |
+
spec.loader.exec_module(mod)
|
| 22 |
+
fn = getattr(mod, name)
|
| 23 |
+
return fn
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def main():
|
| 27 |
+
parser = argparse.ArgumentParser()
|
| 28 |
+
parser.add_argument(
|
| 29 |
+
"--gen",
|
| 30 |
+
default=str(Path(__file__).resolve().parent.parent / "data" / "gen.parquet"),
|
| 31 |
+
)
|
| 32 |
+
parser.add_argument(
|
| 33 |
+
"--out",
|
| 34 |
+
default=str(Path(__file__).resolve().parent.parent / "data" / "scored.parquet"),
|
| 35 |
+
)
|
| 36 |
+
parser.add_argument(
|
| 37 |
+
"--reward_fn",
|
| 38 |
+
default=str(Path(__file__).resolve().parent / "reward_fn.py"),
|
| 39 |
+
)
|
| 40 |
+
parser.add_argument("--reward_name", default="compute_reward")
|
| 41 |
+
args = parser.parse_args()
|
| 42 |
+
|
| 43 |
+
df = pd.read_parquet(args.gen)
|
| 44 |
+
print(f"loaded {len(df)} rows from {args.gen}; columns: {list(df.columns)}")
|
| 45 |
+
|
| 46 |
+
if "responses" not in df.columns:
|
| 47 |
+
raise SystemExit("expected `responses` column from Stage A; not found.")
|
| 48 |
+
|
| 49 |
+
compute_reward = load_reward_fn(args.reward_fn, args.reward_name)
|
| 50 |
+
|
| 51 |
+
all_scores = []
|
| 52 |
+
for idx, row in df.iterrows():
|
| 53 |
+
prompt = row["prompt"]
|
| 54 |
+
responses = list(row["responses"])
|
| 55 |
+
metadata = row.get("metadata", {}) or {}
|
| 56 |
+
tools = list(row.get("tools_orig", []) or [])
|
| 57 |
+
scores = []
|
| 58 |
+
for s_idx, resp in enumerate(responses):
|
| 59 |
+
score = compute_reward(
|
| 60 |
+
prompt=prompt,
|
| 61 |
+
response=resp,
|
| 62 |
+
metadata=metadata,
|
| 63 |
+
tools=tools,
|
| 64 |
+
index=int(idx),
|
| 65 |
+
sample=s_idx,
|
| 66 |
+
)
|
| 67 |
+
scores.append(float(score))
|
| 68 |
+
all_scores.append(scores)
|
| 69 |
+
|
| 70 |
+
df = df.copy()
|
| 71 |
+
df["scores"] = all_scores
|
| 72 |
+
|
| 73 |
+
out_path = Path(args.out)
|
| 74 |
+
out_path.parent.mkdir(parents=True, exist_ok=True)
|
| 75 |
+
df.to_parquet(out_path, index=False)
|
| 76 |
+
print(f"wrote {out_path} ({len(df)} rows)")
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
if __name__ == "__main__":
|
| 80 |
+
main()
|
0520_rej_test/run_pipeline.sh
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
# End-to-end RAFT pipeline: build prompts -> generate -> score -> top-K -> SFT.
|
| 3 |
+
# Each stage is overrideable via env vars and idempotent.
|
| 4 |
+
set -xeuo pipefail
|
| 5 |
+
|
| 6 |
+
WORKDIR=$(cd "$(dirname "$0")" && pwd)
|
| 7 |
+
PY=${PY:-python}
|
| 8 |
+
|
| 9 |
+
MAX_SAMPLES=${MAX_SAMPLES:--1}
|
| 10 |
+
N_SAMPLES=${N_SAMPLES:-8}
|
| 11 |
+
TOP_K=${TOP_K:-1}
|
| 12 |
+
|
| 13 |
+
STAGE=${STAGE:-all} # all | A | B | C | D
|
| 14 |
+
|
| 15 |
+
if [[ "${STAGE}" == "all" || "${STAGE}" == "A_pre" || "${STAGE}" == "A" ]]; then
|
| 16 |
+
"${PY}" "${WORKDIR}/data/build_prompts.py" \
|
| 17 |
+
--out "${WORKDIR}/data/prompts.parquet" \
|
| 18 |
+
--max_samples "${MAX_SAMPLES}"
|
| 19 |
+
fi
|
| 20 |
+
|
| 21 |
+
if [[ "${STAGE}" == "all" || "${STAGE}" == "A" ]]; then
|
| 22 |
+
N_SAMPLES="${N_SAMPLES}" \
|
| 23 |
+
PROMPTS="${WORKDIR}/data/prompts.parquet" \
|
| 24 |
+
OUT="${WORKDIR}/data/gen.parquet" \
|
| 25 |
+
bash "${WORKDIR}/scripts/run_generate.sh"
|
| 26 |
+
fi
|
| 27 |
+
|
| 28 |
+
if [[ "${STAGE}" == "all" || "${STAGE}" == "B" ]]; then
|
| 29 |
+
"${PY}" "${WORKDIR}/reward/score.py" \
|
| 30 |
+
--gen "${WORKDIR}/data/gen.parquet" \
|
| 31 |
+
--out "${WORKDIR}/data/scored.parquet"
|
| 32 |
+
fi
|
| 33 |
+
|
| 34 |
+
if [[ "${STAGE}" == "all" || "${STAGE}" == "C" ]]; then
|
| 35 |
+
"${PY}" "${WORKDIR}/select/topk_to_sft.py" \
|
| 36 |
+
--scored "${WORKDIR}/data/scored.parquet" \
|
| 37 |
+
--out "${WORKDIR}/data/raft_train.parquet" \
|
| 38 |
+
--k "${TOP_K}"
|
| 39 |
+
fi
|
| 40 |
+
|
| 41 |
+
if [[ "${STAGE}" == "all" || "${STAGE}" == "D" ]]; then
|
| 42 |
+
bash "${WORKDIR}/scripts/run_sft.sh"
|
| 43 |
+
fi
|
0520_rej_test/scripts/run_generate.sh
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
# Stage A: rollout N completions per prompt with vLLM, via verl's
|
| 3 |
+
# main_generation_server.
|
| 4 |
+
#
|
| 5 |
+
# Usage:
|
| 6 |
+
# bash run_generate.sh # full prompts.parquet
|
| 7 |
+
# PROMPTS=/path/to/sub.parquet OUT=/tmp/gen.parquet \
|
| 8 |
+
# N_SAMPLES=2 bash run_generate.sh # smoke
|
| 9 |
+
set -xeuo pipefail
|
| 10 |
+
|
| 11 |
+
WORKDIR=$(cd "$(dirname "$0")/.." && pwd)
|
| 12 |
+
VERL_ROOT=/inspire/qb-ilm2/project/26summer-camp-21/26210880/0519_verl/verl
|
| 13 |
+
|
| 14 |
+
MODEL_PATH=${MODEL_PATH:-/inspire/qb-ilm2/project/26summer-camp-21/26210880/0518_test_liubw/models/Qwen3-VL-8B-Thinking}
|
| 15 |
+
PROMPTS=${PROMPTS:-${WORKDIR}/data/prompts.parquet}
|
| 16 |
+
OUT=${OUT:-${WORKDIR}/data/gen.parquet}
|
| 17 |
+
|
| 18 |
+
NNODES=${NNODES:-1}
|
| 19 |
+
NGPUS_PER_NODE=${NGPUS_PER_NODE:-8}
|
| 20 |
+
ROLLOUT_TP=${ROLLOUT_TP:-2}
|
| 21 |
+
ROLLOUT_GPU_MEM_UTIL=${ROLLOUT_GPU_MEM_UTIL:-0.85}
|
| 22 |
+
|
| 23 |
+
PROMPT_LENGTH=${PROMPT_LENGTH:-4096}
|
| 24 |
+
RESPONSE_LENGTH=${RESPONSE_LENGTH:-4096}
|
| 25 |
+
N_SAMPLES=${N_SAMPLES:-8}
|
| 26 |
+
TEMPERATURE=${TEMPERATURE:-1.0}
|
| 27 |
+
TOP_P=${TOP_P:-0.95}
|
| 28 |
+
|
| 29 |
+
mkdir -p "$(dirname "${OUT}")"
|
| 30 |
+
|
| 31 |
+
cd "${VERL_ROOT}"
|
| 32 |
+
|
| 33 |
+
python3 -m verl.trainer.main_generation_server \
|
| 34 |
+
trainer.nnodes="${NNODES}" \
|
| 35 |
+
trainer.n_gpus_per_node="${NGPUS_PER_NODE}" \
|
| 36 |
+
data.train_files="${PROMPTS}" \
|
| 37 |
+
data.prompt_key=prompt \
|
| 38 |
+
+data.output_path="${OUT}" \
|
| 39 |
+
actor_rollout_ref.model.path="${MODEL_PATH}" \
|
| 40 |
+
actor_rollout_ref.model.trust_remote_code=True \
|
| 41 |
+
actor_rollout_ref.rollout.name=vllm \
|
| 42 |
+
actor_rollout_ref.rollout.temperature="${TEMPERATURE}" \
|
| 43 |
+
actor_rollout_ref.rollout.top_p="${TOP_P}" \
|
| 44 |
+
actor_rollout_ref.rollout.prompt_length="${PROMPT_LENGTH}" \
|
| 45 |
+
actor_rollout_ref.rollout.response_length="${RESPONSE_LENGTH}" \
|
| 46 |
+
actor_rollout_ref.rollout.tensor_model_parallel_size="${ROLLOUT_TP}" \
|
| 47 |
+
actor_rollout_ref.rollout.gpu_memory_utilization="${ROLLOUT_GPU_MEM_UTIL}" \
|
| 48 |
+
actor_rollout_ref.rollout.n="${N_SAMPLES}" "$@"
|
0520_rej_test/scripts/run_sft.sh
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
# Stage D wrapper: re-use 0519_sft_test/run_sft_qwen3vl_8b.sh against the
|
| 3 |
+
# RAFT-mined parquet, without modifying the original script.
|
| 4 |
+
set -xeuo pipefail
|
| 5 |
+
|
| 6 |
+
WORKDIR=$(cd "$(dirname "$0")/.." && pwd)
|
| 7 |
+
|
| 8 |
+
TRAIN_FILES=${TRAIN_FILES:-${WORKDIR}/data/raft_train.parquet}
|
| 9 |
+
VAL_FILES=${VAL_FILES:-${WORKDIR}/data/raft_val.parquet}
|
| 10 |
+
|
| 11 |
+
PROJECT_NAME=${PROJECT_NAME:-ind_v4_raft}
|
| 12 |
+
EXPERIMENT_NAME=${EXPERIMENT_NAME:-qwen3vl-8b-thinking-raft}
|
| 13 |
+
SAVE_DIR=${SAVE_DIR:-${WORKDIR}/checkpoints/${PROJECT_NAME}/${EXPERIMENT_NAME}}
|
| 14 |
+
|
| 15 |
+
TRAIN_FILES="${TRAIN_FILES}" \
|
| 16 |
+
VAL_FILES="${VAL_FILES}" \
|
| 17 |
+
PROJECT_NAME="${PROJECT_NAME}" \
|
| 18 |
+
EXPERIMENT_NAME="${EXPERIMENT_NAME}" \
|
| 19 |
+
SAVE_DIR="${SAVE_DIR}" \
|
| 20 |
+
bash /inspire/qb-ilm2/project/26summer-camp-21/26210880/0519_verl/0519_sft_test/run_sft_qwen3vl_8b.sh "$@"
|
0520_rej_test/select/topk_to_sft.py
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Stage C: scored.parquet -> raft_train.parquet (verl SFT schema).
|
| 2 |
+
|
| 3 |
+
For each row pick the top-K responses by score, parse Qwen3-VL-Thinking
|
| 4 |
+
`<tool_call>{...}</tool_call>` blocks back into structured tool_calls, and
|
| 5 |
+
emit one SFT example per (row, kept response). Output schema matches
|
| 6 |
+
`verl/utils/dataset/multiturn_sft_dataset.py`:
|
| 7 |
+
- messages: [user_turn, assistant_turn_with_tool_calls]
|
| 8 |
+
- images: [{"bytes": <png>}] (re-read from row["image_paths"])
|
| 9 |
+
- tools: original tools spec
|
| 10 |
+
"""
|
| 11 |
+
|
| 12 |
+
import argparse
|
| 13 |
+
import json
|
| 14 |
+
import os
|
| 15 |
+
import re
|
| 16 |
+
from pathlib import Path
|
| 17 |
+
|
| 18 |
+
import pandas as pd
|
| 19 |
+
|
| 20 |
+
TOOL_CALL_RE = re.compile(r"<tool_call>\s*(.*?)\s*</tool_call>", re.DOTALL)
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def read_image_bytes(path: str) -> bytes:
|
| 24 |
+
with open(path, "rb") as f:
|
| 25 |
+
return f.read()
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def parse_tool_calls(text: str) -> tuple[str, list[dict]]:
|
| 29 |
+
"""Strip <tool_call>...</tool_call> blocks out of `text`.
|
| 30 |
+
|
| 31 |
+
Returns:
|
| 32 |
+
(residual_text_with_blocks_removed, list_of_tool_call_dicts)
|
| 33 |
+
|
| 34 |
+
Each tool_call dict is OpenAI-style:
|
| 35 |
+
{"id": "...", "type": "function",
|
| 36 |
+
"function": {"name": "...", "arguments": "<json string>"}}
|
| 37 |
+
Failed JSON parses make the whole sample invalid (caller should drop).
|
| 38 |
+
"""
|
| 39 |
+
tool_calls = []
|
| 40 |
+
for i, m in enumerate(TOOL_CALL_RE.finditer(text)):
|
| 41 |
+
raw = m.group(1).strip()
|
| 42 |
+
try:
|
| 43 |
+
obj = json.loads(raw)
|
| 44 |
+
except json.JSONDecodeError:
|
| 45 |
+
return text, []
|
| 46 |
+
name = obj.get("name", "")
|
| 47 |
+
args = obj.get("arguments", obj.get("parameters", {}))
|
| 48 |
+
if not isinstance(args, str):
|
| 49 |
+
args = json.dumps(args, ensure_ascii=False)
|
| 50 |
+
tool_calls.append(
|
| 51 |
+
{
|
| 52 |
+
"id": f"call_{i}",
|
| 53 |
+
"type": "function",
|
| 54 |
+
"function": {"name": name, "arguments": args},
|
| 55 |
+
}
|
| 56 |
+
)
|
| 57 |
+
residual = TOOL_CALL_RE.sub("", text).strip()
|
| 58 |
+
return residual, tool_calls
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
def reconstruct_user_turn(prompt_messages: list[dict]) -> dict:
|
| 62 |
+
"""The prompt for generation was multimodal (image_url + text). For SFT
|
| 63 |
+
we replace it with the conventional `<image>\\n<text>` Qwen format —
|
| 64 |
+
this matches the existing 0519_sft_test/data parquet exactly. The image
|
| 65 |
+
bytes are attached separately via the `images` column.
|
| 66 |
+
"""
|
| 67 |
+
user_msg = prompt_messages[0]
|
| 68 |
+
text_parts = []
|
| 69 |
+
for blk in user_msg["content"]:
|
| 70 |
+
if isinstance(blk, dict) and blk.get("type") == "text":
|
| 71 |
+
text_parts.append(blk["text"])
|
| 72 |
+
text = "\n".join(text_parts)
|
| 73 |
+
return {"role": "user", "content": "<image>\n" + text}
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
def main():
|
| 77 |
+
parser = argparse.ArgumentParser()
|
| 78 |
+
parser.add_argument(
|
| 79 |
+
"--scored",
|
| 80 |
+
default=str(Path(__file__).resolve().parent.parent / "data" / "scored.parquet"),
|
| 81 |
+
)
|
| 82 |
+
parser.add_argument(
|
| 83 |
+
"--out",
|
| 84 |
+
default=str(Path(__file__).resolve().parent.parent / "data" / "raft_train.parquet"),
|
| 85 |
+
)
|
| 86 |
+
parser.add_argument("--k", type=int, default=1, help="Top-K responses per prompt.")
|
| 87 |
+
parser.add_argument("--min_score", type=float, default=None)
|
| 88 |
+
parser.add_argument("--keep_above_mean", action="store_true",
|
| 89 |
+
help="Keep responses scoring strictly above the per-row mean.")
|
| 90 |
+
args = parser.parse_args()
|
| 91 |
+
|
| 92 |
+
df = pd.read_parquet(args.scored)
|
| 93 |
+
print(f"loaded {len(df)} rows from {args.scored}")
|
| 94 |
+
|
| 95 |
+
out_records = []
|
| 96 |
+
n_dropped_parse = 0
|
| 97 |
+
n_dropped_score = 0
|
| 98 |
+
for _, row in df.iterrows():
|
| 99 |
+
responses = list(row["responses"])
|
| 100 |
+
scores = list(row["scores"])
|
| 101 |
+
assert len(responses) == len(scores)
|
| 102 |
+
|
| 103 |
+
ranked = sorted(zip(scores, responses), key=lambda x: x[0], reverse=True)
|
| 104 |
+
if args.keep_above_mean:
|
| 105 |
+
mean_s = sum(scores) / max(1, len(scores))
|
| 106 |
+
ranked = [(s, r) for s, r in ranked if s > mean_s]
|
| 107 |
+
if args.min_score is not None:
|
| 108 |
+
ranked = [(s, r) for s, r in ranked if s >= args.min_score]
|
| 109 |
+
ranked = ranked[: args.k]
|
| 110 |
+
|
| 111 |
+
if not ranked:
|
| 112 |
+
n_dropped_score += 1
|
| 113 |
+
continue
|
| 114 |
+
|
| 115 |
+
user_turn = reconstruct_user_turn(list(row["prompt"]))
|
| 116 |
+
tools = list(row.get("tools_orig", []) or [])
|
| 117 |
+
image_paths = list(row.get("image_paths", []) or [])
|
| 118 |
+
images = [{"bytes": read_image_bytes(p)} for p in image_paths]
|
| 119 |
+
|
| 120 |
+
for score, resp in ranked:
|
| 121 |
+
content_text, tool_calls = parse_tool_calls(resp)
|
| 122 |
+
if not tool_calls:
|
| 123 |
+
n_dropped_parse += 1
|
| 124 |
+
continue
|
| 125 |
+
assistant_turn = {
|
| 126 |
+
"role": "assistant",
|
| 127 |
+
"content": content_text or "",
|
| 128 |
+
"tool_calls": tool_calls,
|
| 129 |
+
}
|
| 130 |
+
out_records.append(
|
| 131 |
+
{
|
| 132 |
+
"messages": [user_turn, assistant_turn],
|
| 133 |
+
"images": images,
|
| 134 |
+
"tools": tools,
|
| 135 |
+
}
|
| 136 |
+
)
|
| 137 |
+
|
| 138 |
+
print(f"kept {len(out_records)} sft examples; "
|
| 139 |
+
f"dropped {n_dropped_parse} (parse), {n_dropped_score} (score filter)")
|
| 140 |
+
|
| 141 |
+
out_path = Path(args.out)
|
| 142 |
+
out_path.parent.mkdir(parents=True, exist_ok=True)
|
| 143 |
+
pd.DataFrame(out_records).to_parquet(out_path, index=False)
|
| 144 |
+
print(f"wrote {out_path}")
|
| 145 |
+
|
| 146 |
+
|
| 147 |
+
if __name__ == "__main__":
|
| 148 |
+
main()
|
data.tar.gz
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:13d6c907cdce09739e63e32f40977e608f6afe6169b85bb58938b9df2616b3f8
|
| 3 |
+
size 391661196
|
pip_list.txt
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
absl-py 2.4.0
|
| 2 |
+
accelerate 1.12.0
|
| 3 |
+
aiohappyeyeballs 2.6.1
|
| 4 |
+
aiohttp 3.13.3
|
| 5 |
+
aiohttp-cors 0.8.1
|
| 6 |
+
aiosignal 1.4.0
|
| 7 |
+
annotated-doc 0.0.4
|
| 8 |
+
annotated-types 0.7.0
|
| 9 |
+
antlr4-python3-runtime 4.9.3
|
| 10 |
+
anyio 4.12.1
|
| 11 |
+
astor 0.8.1
|
| 12 |
+
async-timeout 5.0.1
|
| 13 |
+
attrs 25.4.0
|
| 14 |
+
av 16.1.0
|
| 15 |
+
blake3 1.0.8
|
| 16 |
+
cachetools 6.2.5
|
| 17 |
+
cbor2 5.8.0
|
| 18 |
+
certifi 2026.1.4
|
| 19 |
+
cffi 2.0.0
|
| 20 |
+
charset-normalizer 3.4.4
|
| 21 |
+
click 8.3.1
|
| 22 |
+
cloudpickle 3.1.2
|
| 23 |
+
codetiming 1.4.0
|
| 24 |
+
colorful 0.5.8
|
| 25 |
+
compressed-tensors 0.11.0
|
| 26 |
+
cupy-cuda12x 13.6.0
|
| 27 |
+
datasets 4.5.0
|
| 28 |
+
depyf 0.19.0
|
| 29 |
+
dill 0.4.0
|
| 30 |
+
diskcache 5.6.3
|
| 31 |
+
distlib 0.4.0
|
| 32 |
+
distro 1.9.0
|
| 33 |
+
dnspython 2.8.0
|
| 34 |
+
einops 0.8.2
|
| 35 |
+
email-validator 2.3.0
|
| 36 |
+
exceptiongroup 1.3.1
|
| 37 |
+
fastapi 0.128.0
|
| 38 |
+
fastapi-cli 0.0.20
|
| 39 |
+
fastapi-cloud-cli 0.11.0
|
| 40 |
+
fastar 0.8.0
|
| 41 |
+
fastrlock 0.8.3
|
| 42 |
+
filelock 3.20.3
|
| 43 |
+
flash_attn 2.8.3+cu12torch28cxx11abitrue
|
| 44 |
+
frozendict 2.4.7
|
| 45 |
+
frozenlist 1.8.0
|
| 46 |
+
fsspec 2025.10.0
|
| 47 |
+
gguf 0.17.1
|
| 48 |
+
gitdb 4.0.12
|
| 49 |
+
GitPython 3.1.46
|
| 50 |
+
google-api-core 2.29.0
|
| 51 |
+
google-auth 2.47.0
|
| 52 |
+
googleapis-common-protos 1.72.0
|
| 53 |
+
grpcio 1.76.0
|
| 54 |
+
h11 0.16.0
|
| 55 |
+
hf-xet 1.2.0
|
| 56 |
+
httpcore 1.0.9
|
| 57 |
+
httptools 0.7.1
|
| 58 |
+
httpx 0.28.1
|
| 59 |
+
huggingface-hub 0.36.0
|
| 60 |
+
idna 3.11
|
| 61 |
+
importlib_metadata 8.7.1
|
| 62 |
+
interegular 0.3.3
|
| 63 |
+
Jinja2 3.1.6
|
| 64 |
+
jiter 0.12.0
|
| 65 |
+
jsonschema 4.26.0
|
| 66 |
+
jsonschema-specifications 2025.9.1
|
| 67 |
+
lark 1.2.2
|
| 68 |
+
liger_kernel 0.6.4
|
| 69 |
+
llguidance 0.7.30
|
| 70 |
+
llvmlite 0.44.0
|
| 71 |
+
lm-format-enforcer 0.11.3
|
| 72 |
+
Markdown 3.10.1
|
| 73 |
+
markdown-it-py 4.0.0
|
| 74 |
+
MarkupSafe 3.0.3
|
| 75 |
+
mathruler 0.1.0
|
| 76 |
+
mdurl 0.1.2
|
| 77 |
+
mistral_common 1.8.8
|
| 78 |
+
mpmath 1.3.0
|
| 79 |
+
msgpack 1.1.2
|
| 80 |
+
msgspec 0.20.0
|
| 81 |
+
multidict 6.7.1
|
| 82 |
+
multiprocess 0.70.18
|
| 83 |
+
networkx 3.4.2
|
| 84 |
+
ninja 1.13.0
|
| 85 |
+
numba 0.61.2
|
| 86 |
+
numpy 2.2.6
|
| 87 |
+
nvidia-cublas-cu12 12.6.4.1
|
| 88 |
+
nvidia-cuda-cupti-cu12 12.6.80
|
| 89 |
+
nvidia-cuda-nvrtc-cu12 12.6.77
|
| 90 |
+
nvidia-cuda-runtime-cu12 12.6.77
|
| 91 |
+
nvidia-cudnn-cu12 9.10.2.21
|
| 92 |
+
nvidia-cufft-cu12 11.3.0.4
|
| 93 |
+
nvidia-cufile-cu12 1.11.1.6
|
| 94 |
+
nvidia-curand-cu12 10.3.7.77
|
| 95 |
+
nvidia-cusolver-cu12 11.7.1.2
|
| 96 |
+
nvidia-cusparse-cu12 12.5.4.2
|
| 97 |
+
nvidia-cusparselt-cu12 0.7.1
|
| 98 |
+
nvidia-nccl-cu12 2.27.3
|
| 99 |
+
nvidia-nvjitlink-cu12 12.6.85
|
| 100 |
+
nvidia-nvtx-cu12 12.6.77
|
| 101 |
+
omegaconf 2.3.0
|
| 102 |
+
openai 2.15.0
|
| 103 |
+
openai-harmony 0.0.8
|
| 104 |
+
opencensus 0.11.4
|
| 105 |
+
opencensus-context 0.1.3
|
| 106 |
+
opencv-python-headless 4.13.0.90
|
| 107 |
+
opentelemetry-api 1.39.1
|
| 108 |
+
opentelemetry-exporter-prometheus 0.60b1
|
| 109 |
+
opentelemetry-proto 1.39.1
|
| 110 |
+
opentelemetry-sdk 1.39.1
|
| 111 |
+
opentelemetry-semantic-conventions 0.60b1
|
| 112 |
+
orjson 3.11.5
|
| 113 |
+
outlines_core 0.2.11
|
| 114 |
+
packaging 25.0
|
| 115 |
+
pandas 2.3.3
|
| 116 |
+
partial-json-parser 0.2.1.1.post7
|
| 117 |
+
peft 0.18.1
|
| 118 |
+
pillow 12.1.0
|
| 119 |
+
pip 25.3
|
| 120 |
+
platformdirs 4.5.1
|
| 121 |
+
prometheus_client 0.24.1
|
| 122 |
+
prometheus-fastapi-instrumentator 7.1.0
|
| 123 |
+
propcache 0.4.1
|
| 124 |
+
proto-plus 1.27.0
|
| 125 |
+
protobuf 6.33.4
|
| 126 |
+
psutil 7.2.1
|
| 127 |
+
py-cpuinfo 9.0.0
|
| 128 |
+
py-spy 0.4.1
|
| 129 |
+
pyarrow 23.0.0
|
| 130 |
+
pyasn1 0.6.2
|
| 131 |
+
pyasn1_modules 0.4.2
|
| 132 |
+
pybase64 1.4.3
|
| 133 |
+
pycountry 24.6.1
|
| 134 |
+
pycparser 3.0
|
| 135 |
+
pydantic 2.12.5
|
| 136 |
+
pydantic_core 2.41.5
|
| 137 |
+
pydantic-extra-types 2.11.0
|
| 138 |
+
pydantic-settings 2.12.0
|
| 139 |
+
Pygments 2.19.2
|
| 140 |
+
pylatexenc 2.10
|
| 141 |
+
python-dateutil 2.9.0.post0
|
| 142 |
+
python-dotenv 1.2.1
|
| 143 |
+
python-json-logger 4.0.0
|
| 144 |
+
python-multipart 0.0.22
|
| 145 |
+
pytz 2025.2
|
| 146 |
+
pyvers 0.1.0
|
| 147 |
+
PyYAML 6.0.3
|
| 148 |
+
pyzmq 27.1.0
|
| 149 |
+
qwen-vl-utils 0.0.14
|
| 150 |
+
ray 2.53.0
|
| 151 |
+
referencing 0.37.0
|
| 152 |
+
regex 2026.1.15
|
| 153 |
+
requests 2.32.5
|
| 154 |
+
rich 14.3.1
|
| 155 |
+
rich-toolkit 0.17.1
|
| 156 |
+
rignore 0.7.6
|
| 157 |
+
rpds-py 0.30.0
|
| 158 |
+
rsa 4.9.1
|
| 159 |
+
safetensors 0.7.0
|
| 160 |
+
scipy 1.15.3
|
| 161 |
+
sentencepiece 0.2.1
|
| 162 |
+
sentry-sdk 2.50.0
|
| 163 |
+
setproctitle 1.3.7
|
| 164 |
+
setuptools 80.9.0
|
| 165 |
+
shellingham 1.5.4
|
| 166 |
+
six 1.17.0
|
| 167 |
+
smart_open 7.5.0
|
| 168 |
+
smmap 5.0.2
|
| 169 |
+
sniffio 1.3.1
|
| 170 |
+
soundfile 0.13.1
|
| 171 |
+
soxr 1.0.0
|
| 172 |
+
starlette 0.50.0
|
| 173 |
+
sympy 1.14.0
|
| 174 |
+
tensorboard 2.20.0
|
| 175 |
+
tensorboard-data-server 0.7.2
|
| 176 |
+
tensordict 0.10.0
|
| 177 |
+
tiktoken 0.12.0
|
| 178 |
+
tokenizers 0.22.2
|
| 179 |
+
tomli 2.4.0
|
| 180 |
+
torch 2.8.0+cu126
|
| 181 |
+
torchaudio 2.8.0+cu126
|
| 182 |
+
torchdata 0.11.0
|
| 183 |
+
torchvision 0.23.0+cu126
|
| 184 |
+
tqdm 4.67.1
|
| 185 |
+
transformers 4.57.0
|
| 186 |
+
triton 3.4.0
|
| 187 |
+
typer 0.21.1
|
| 188 |
+
typing_extensions 4.15.0
|
| 189 |
+
typing-inspection 0.4.2
|
| 190 |
+
tzdata 2025.3
|
| 191 |
+
urllib3 2.6.3
|
| 192 |
+
uvicorn 0.40.0
|
| 193 |
+
uvloop 0.22.1
|
| 194 |
+
virtualenv 20.36.1
|
| 195 |
+
vllm 0.11.0
|
| 196 |
+
wandb 0.24.0
|
| 197 |
+
watchfiles 1.1.1
|
| 198 |
+
websockets 16.0
|
| 199 |
+
Werkzeug 3.1.5
|
| 200 |
+
wheel 0.45.1
|
| 201 |
+
wrapt 2.0.1
|
| 202 |
+
xformers 0.0.32.post1
|
| 203 |
+
xgrammar 0.1.25
|
| 204 |
+
xxhash 3.6.0
|
| 205 |
+
yarl 1.22.0
|
| 206 |
+
zipp 3.23.0
|
requirements.txt
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Generated from pip_list.txt — exact version pinning
|
| 2 |
+
# Note:
|
| 3 |
+
# - torch / torchaudio / torchvision carry the +cu124 local tag;
|
| 4 |
+
# install with: pip install --index-url https://download.pytorch.org/whl/cu124 ...
|
| 5 |
+
# - conda / mamba / libmambapy / menuinst / libarchive-c are normally managed
|
| 6 |
+
# by conda, not pip. Remove them if installing into a non-conda env.
|
| 7 |
+
# - pip / setuptools / wheel are bootstrap packages; pin only if you intend to
|
| 8 |
+
# control their versions explicitly.
|
| 9 |
+
|
| 10 |
+
absl-py==2.4.0
|
| 11 |
+
annotated-doc==0.0.4
|
| 12 |
+
anyio==4.13.0
|
| 13 |
+
archspec==0.2.3
|
| 14 |
+
asttokens==2.4.1
|
| 15 |
+
astunparse==1.6.3
|
| 16 |
+
attrs==24.2.0
|
| 17 |
+
beautifulsoup4==4.12.3
|
| 18 |
+
blessed==1.33.0
|
| 19 |
+
boltons==24.0.0
|
| 20 |
+
Brotli==1.1.0
|
| 21 |
+
certifi==2024.8.30
|
| 22 |
+
cffi==1.17.1
|
| 23 |
+
chardet==5.2.0
|
| 24 |
+
charset-normalizer==3.4.0
|
| 25 |
+
click==8.3.3
|
| 26 |
+
colorama==0.4.6
|
| 27 |
+
cycler==0.12.1
|
| 28 |
+
decorator==5.1.1
|
| 29 |
+
distro==1.9.0
|
| 30 |
+
dnspython==2.7.0
|
| 31 |
+
exceptiongroup==1.2.2
|
| 32 |
+
executing==2.1.0
|
| 33 |
+
expecttest==0.2.1
|
| 34 |
+
filelock==3.16.1
|
| 35 |
+
fonttools==4.62.1
|
| 36 |
+
frozendict==2.4.6
|
| 37 |
+
fsspec==2024.10.0
|
| 38 |
+
gpustat==1.1.1
|
| 39 |
+
grpcio==1.80.0
|
| 40 |
+
h11==0.16.0
|
| 41 |
+
h2==4.1.0
|
| 42 |
+
hf-xet==1.5.0
|
| 43 |
+
hpack==4.0.0
|
| 44 |
+
httpcore==1.0.9
|
| 45 |
+
httpx==0.28.1
|
| 46 |
+
huggingface-hub==1.14.0
|
| 47 |
+
hyperframe==6.0.1
|
| 48 |
+
hypothesis==6.115.5
|
| 49 |
+
idna==3.10
|
| 50 |
+
importlib-resources==6.4.5
|
| 51 |
+
ipython==8.29.0
|
| 52 |
+
jedi==0.19.1
|
| 53 |
+
Jinja2==3.1.4
|
| 54 |
+
jsonpatch==1.33
|
| 55 |
+
jsonpointer==3.0.0
|
| 56 |
+
jsonschema==4.23.0
|
| 57 |
+
jsonschema-specifications==2024.10.1
|
| 58 |
+
kiwisolver==1.5.0
|
| 59 |
+
libarchive-c==5.1
|
| 60 |
+
lief==0.14.1
|
| 61 |
+
lintrunner==0.12.5
|
| 62 |
+
Markdown==3.10.2
|
| 63 |
+
markdown-it-py==4.2.0
|
| 64 |
+
MarkupSafe==3.0.2
|
| 65 |
+
matplotlib==3.10.9
|
| 66 |
+
matplotlib-inline==0.1.7
|
| 67 |
+
mdurl==0.1.2
|
| 68 |
+
modelscope==1.35.2
|
| 69 |
+
more-itertools==10.5.0
|
| 70 |
+
mpmath==1.3.0
|
| 71 |
+
networkx==3.4.2
|
| 72 |
+
ninja==1.11.1.1
|
| 73 |
+
numpy<2
|
| 74 |
+
nvitop==1.6.2
|
| 75 |
+
optree==0.13.0
|
| 76 |
+
packaging==24.1
|
| 77 |
+
parso==0.8.4
|
| 78 |
+
pexpect==4.9.0
|
| 79 |
+
pickleshare==0.7.5
|
| 80 |
+
pillow==10.2.0
|
| 81 |
+
pip==24.2
|
| 82 |
+
pkginfo==1.11.2
|
| 83 |
+
pkgutil-resolve-name==1.3.10
|
| 84 |
+
platformdirs==4.3.6
|
| 85 |
+
pluggy==1.5.0
|
| 86 |
+
prompt-toolkit==3.0.48
|
| 87 |
+
protobuf==7.34.1
|
| 88 |
+
psutil==6.1.0
|
| 89 |
+
ptyprocess==0.7.0
|
| 90 |
+
pure-eval==0.2.3
|
| 91 |
+
pyarrow==24.0.0
|
| 92 |
+
pycosat==0.6.6
|
| 93 |
+
pycparser==2.22
|
| 94 |
+
Pygments==2.18.0
|
| 95 |
+
pyparsing==3.3.2
|
| 96 |
+
PySocks==1.7.1
|
| 97 |
+
python-dateutil==2.9.0.post0
|
| 98 |
+
python-etcd==0.4.5
|
| 99 |
+
pytz==2024.2
|
| 100 |
+
PyYAML==6.0.2
|
| 101 |
+
referencing==0.35.1
|
| 102 |
+
requests==2.32.3
|
| 103 |
+
rich==15.0.0
|
| 104 |
+
rpds-py==0.20.0
|
| 105 |
+
ruamel.yaml==0.18.6
|
| 106 |
+
ruamel.yaml.clib==0.2.8
|
| 107 |
+
setuptools==72.1.0
|
| 108 |
+
shellingham==1.5.4
|
| 109 |
+
six==1.16.0
|
| 110 |
+
sortedcontainers==2.4.0
|
| 111 |
+
soupsieve==2.5
|
| 112 |
+
stack-data==0.6.2
|
| 113 |
+
sympy==1.13.1
|
| 114 |
+
tensorboard==2.20.0
|
| 115 |
+
tensorboard-data-server==0.7.2
|
| 116 |
+
torch==2.5.1+cu124
|
| 117 |
+
torchaudio==2.5.1+cu124
|
| 118 |
+
torchelastic==0.2.2
|
| 119 |
+
torchvision==0.20.1+cu124
|
| 120 |
+
tqdm==4.66.5
|
| 121 |
+
traitlets==5.14.3
|
| 122 |
+
triton==3.1.0
|
| 123 |
+
truststore==0.9.2
|
| 124 |
+
typer==0.25.1
|
| 125 |
+
types-dataclasses==0.6.6
|
| 126 |
+
typing-extensions==4.12.2
|
| 127 |
+
urllib3==2.2.3
|
| 128 |
+
wcwidth==0.6.0
|
| 129 |
+
Werkzeug==3.1.8
|
| 130 |
+
wheel==0.44.0
|
| 131 |
+
zipp==3.20.2
|
| 132 |
+
zstandard==0.23.0
|
verl.tar.gz
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:ee07dc56371e123a4f5afcd399a6b1b4624ce8af1edac0f8512ef1d98f5bced9
|
| 3 |
+
size 5809181481
|
verl/.agent/skills/issue/SKILL.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
name: issue
|
| 3 |
+
description: Create or update a GitHub issue following verl project conventions.
|
| 4 |
+
user_invocable: true
|
| 5 |
+
---
|
| 6 |
+
|
| 7 |
+
When the user asks to create or update an issue, follow these steps:
|
| 8 |
+
|
| 9 |
+
### 1. Gather Context
|
| 10 |
+
|
| 11 |
+
Read the following to understand available issue types and their required fields:
|
| 12 |
+
|
| 13 |
+
- [`bug-report.yml`](.github/ISSUE_TEMPLATE/bug-report.yml)
|
| 14 |
+
- [`feature-request.yml`](.github/ISSUE_TEMPLATE/feature-request.yml)
|
| 15 |
+
|
| 16 |
+
If updating an existing issue, read its current title, body, labels, and comments first.
|
| 17 |
+
|
| 18 |
+
### 2. Determine Issue Type
|
| 19 |
+
|
| 20 |
+
Based on the user's description, select the appropriate template:
|
| 21 |
+
|
| 22 |
+
- **Bug report** ([`bug-report.yml`](.github/ISSUE_TEMPLATE/bug-report.yml)) — something is broken or behaves unexpectedly
|
| 23 |
+
- **Feature request** ([`feature-request.yml`](.github/ISSUE_TEMPLATE/feature-request.yml)) — a new capability or enhancement
|
| 24 |
+
- **Blank issue** — if neither template fits
|
| 25 |
+
|
| 26 |
+
### 3. Compose the Issue
|
| 27 |
+
|
| 28 |
+
Fill in the template fields based on information from the user and the codebase. For bug reports, run `python scripts/diagnose.py` to gather system info if possible.
|
| 29 |
+
|
| 30 |
+
When updating, ensure the title and body still accurately reflect the current state of the issue.
|
| 31 |
+
|
| 32 |
+
### 4. Check for Duplicates
|
| 33 |
+
|
| 34 |
+
Search for existing issues before creating:
|
| 35 |
+
|
| 36 |
+
```
|
| 37 |
+
gh issue list --repo verl-project/verl --state open --search "<keywords>"
|
| 38 |
+
```
|
| 39 |
+
|
| 40 |
+
If a duplicate exists, inform the user instead of creating a new one.
|
| 41 |
+
|
| 42 |
+
### 5. Create or Update the Issue
|
| 43 |
+
|
| 44 |
+
- **Create**: add `good first issue` and/or `call for contribution` labels if the issue is straightforward and suitable for new contributors.
|
| 45 |
+
- **Update**: update title, body, and labels as needed.
|
| 46 |
+
|
| 47 |
+
Return the issue URL when done.
|
verl/.agent/skills/pr/SKILL.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
name: pr
|
| 3 |
+
description: Create or update a pull request following verl project conventions.
|
| 4 |
+
user_invocable: true
|
| 5 |
+
---
|
| 6 |
+
|
| 7 |
+
When the user asks to create or update a PR, follow these steps:
|
| 8 |
+
|
| 9 |
+
### 1. Gather Context
|
| 10 |
+
|
| 11 |
+
Read the following and understand the current branch's changes compared to main:
|
| 12 |
+
|
| 13 |
+
- [`CONTRIBUTING.md`](CONTRIBUTING.md)
|
| 14 |
+
- [`PULL_REQUEST_TEMPLATE.md`](.github/PULL_REQUEST_TEMPLATE.md)
|
| 15 |
+
|
| 16 |
+
If a PR already exists for this branch, also read its current title, body, and review comments.
|
| 17 |
+
|
| 18 |
+
### 2. Compose PR Title and Body
|
| 19 |
+
|
| 20 |
+
Follow the PR template strictly for both title format and body sections. Only check checklist boxes for steps that have actually been completed.
|
| 21 |
+
|
| 22 |
+
When updating, ensure the title and body still accurately reflect **all** changes on the branch, not just the latest commit.
|
| 23 |
+
|
| 24 |
+
### 3. Pre-submit Checks
|
| 25 |
+
|
| 26 |
+
Run pre-commit and fix any issues before creating or pushing.
|
| 27 |
+
|
| 28 |
+
### 4. Create or Update the PR
|
| 29 |
+
|
| 30 |
+
- **Create**: target `main` by default unless the user specifies otherwise.
|
| 31 |
+
- **Update**: push new commits and update the title and body if the scope has changed. **Read the current PR title and body first** and incorporate any edits the user may have made directly on GitHub — never overwrite with a version generated from scratch.
|
| 32 |
+
|
| 33 |
+
Return the PR URL when done.
|
verl/.gemini/config.yaml
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
have_fun: false
|
| 2 |
+
code_review:
|
| 3 |
+
disable: false
|
| 4 |
+
comment_severity_threshold: HIGH
|
| 5 |
+
max_review_comments: -1
|
| 6 |
+
pull_request_opened:
|
| 7 |
+
help: false
|
| 8 |
+
summary: false
|
| 9 |
+
code_review: true
|
| 10 |
+
ignore_patterns: []
|
verl/.git-blame-ignore-revs
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Local uasge: git config blame.ignoreRevsFile .git-blame-ignore-revs
|
| 2 |
+
|
| 3 |
+
# [dev] feat: immigrate from yapf & pylint to ruff based on pre-commit
|
| 4 |
+
# Changed 268 files, +10k/-9k lines. This is the biggest formatter change.
|
| 5 |
+
b00f77d8559b48d57a33c0132a5ba1c81891a536
|
| 6 |
+
|
| 7 |
+
# [ci] refactor: reduce ruff line-length from 300 to 120
|
| 8 |
+
# Changed 238 files, +6k/-1k lines. Global formatting change.
|
| 9 |
+
00a10a8ef389556f957a2f36132b2358fd6a109f
|
| 10 |
+
|
| 11 |
+
# [Lint] fix: linting errors in all files
|
| 12 |
+
# Changed 179 files, +1k/-3k lines. Global lint fix.
|
| 13 |
+
8e5ad4688a13de81727c014a3c2e2fb26324bc20
|
verl/.github/CODEOWNERS
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/docs @eric-haibin-lin @zhaochenyang20 @hongpeng-guo
|
| 2 |
+
/docs/amd_tutorial @yushengsu-thu
|
| 3 |
+
/docs/slang_multiturn @zhaochenyang20 @SwordFaith
|
| 4 |
+
/docs/ascend_tutorial @wucong25
|
| 5 |
+
|
| 6 |
+
/third_party/sglang @zhaochenyang20 @SwordFaith
|
| 7 |
+
/third_party/vllm @PeterSH6 @wuxibin89
|
| 8 |
+
|
| 9 |
+
/examples/grpo_trainer @vermouth1992 @PeterSH6 @tardis-key @wucong25 @ji-huazhong
|
| 10 |
+
|
| 11 |
+
/verl/single_controller @zw0610 @wuxibin89 @hongpeng-guo
|
| 12 |
+
/verl/trainer @eric-haibin-lin @vermouth1992 @tongyx361 @PeterSH6
|
| 13 |
+
/verl/models/mcore @ISEEKYAN @vermouth1992
|
| 14 |
+
/verl/models/transformers @vermouth1992 @PeterSH6 @tardis-key @wucong25 @ji-huazhong
|
| 15 |
+
/verl/workers/engine @eric-haibin-lin @vermouth1992 @ZihengJiang @ArronHZG
|
| 16 |
+
/verl/workers/roles @eric-haibin-lin @vermouth1992 @ZihengJiang
|
| 17 |
+
/verl/workers/engine/fsdp @eric-haibin-lin @vermouth1992 @ZihengJiang
|
| 18 |
+
/verl/workers/rollout/vllm_rollout @wuxibin89 @PeterSH6 @chenhaiq @ArronHZG
|
| 19 |
+
/verl/workers/rollout/sglang_rollout @zhaochenyang20 @SwordFaith @chenhaiq @ArronHZG
|
| 20 |
+
/verl/workers/engine/megatron @ISEEKYAN @vermouth1992
|
| 21 |
+
/verl/experimental @wuxibin89 @ArronHZG
|
| 22 |
+
|
| 23 |
+
/tests/single_controller @zw0610 @wuxibin89
|
| 24 |
+
/tests/trainer @eric-haibin-lin @vermouth1992 @tongyx361 @PeterSH6
|
| 25 |
+
/tests/workers/rollout/vllm_rollout @wuxibin89 @PeterSH6 @chenhaiq
|
verl/.github/ISSUE_TEMPLATE/bug-report.yml
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# modified from https://github.com/huggingface/transformers/blob/main/.github/ISSUE_TEMPLATE/bug-report.yml?plain=1
|
| 2 |
+
name: "\U0001F41B Bug Report"
|
| 3 |
+
description: Submit a bug report to help us improve verl
|
| 4 |
+
labels: [ "bug" ]
|
| 5 |
+
body:
|
| 6 |
+
- type: markdown
|
| 7 |
+
attributes:
|
| 8 |
+
value: |
|
| 9 |
+
Thanks for taking the time to fill out this bug report! 🤗
|
| 10 |
+
|
| 11 |
+
- type: textarea
|
| 12 |
+
id: system-info
|
| 13 |
+
attributes:
|
| 14 |
+
label: System Info
|
| 15 |
+
description: Please share your system info with us. You can run the command `python scripts/diagnose.py` and copy-paste its output below.
|
| 16 |
+
placeholder: verl version, platform, python version, ...
|
| 17 |
+
validations:
|
| 18 |
+
required: true
|
| 19 |
+
|
| 20 |
+
- type: checkboxes
|
| 21 |
+
id: information-scripts-examples
|
| 22 |
+
attributes:
|
| 23 |
+
label: Information
|
| 24 |
+
description: 'The problem arises when using:'
|
| 25 |
+
options:
|
| 26 |
+
- label: "The official example scripts"
|
| 27 |
+
- label: "My own modified scripts"
|
| 28 |
+
|
| 29 |
+
- type: checkboxes
|
| 30 |
+
id: information-tasks
|
| 31 |
+
attributes:
|
| 32 |
+
label: Tasks
|
| 33 |
+
description: "The tasks I am working on are:"
|
| 34 |
+
options:
|
| 35 |
+
- label: "An officially supported task in the `examples` folder (such as GLUE/SQuAD, ...)"
|
| 36 |
+
- label: "My own task or dataset (give details below)"
|
| 37 |
+
|
| 38 |
+
- type: textarea
|
| 39 |
+
id: reproduction
|
| 40 |
+
validations:
|
| 41 |
+
required: true
|
| 42 |
+
attributes:
|
| 43 |
+
label: Reproduction
|
| 44 |
+
description: |
|
| 45 |
+
Please provide a code sample that reproduces the problem you ran into. It can be a Colab link or just a code snippet.
|
| 46 |
+
Please include relevant config information with your code.
|
| 47 |
+
If you have code snippets, error messages, stack traces please provide them here as well.
|
| 48 |
+
Important! Use code tags to correctly format your code. See https://help.github.com/en/github/writing-on-github/creating-and-highlighting-code-blocks#syntax-highlighting
|
| 49 |
+
Do not use screenshots, as they are hard to read and (more importantly) don't allow others to copy-and-paste your code.
|
| 50 |
+
|
| 51 |
+
placeholder: |
|
| 52 |
+
Steps to reproduce the behavior:
|
| 53 |
+
|
| 54 |
+
1.
|
| 55 |
+
2.
|
| 56 |
+
3.
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
- type: textarea
|
| 60 |
+
id: expected-behavior
|
| 61 |
+
validations:
|
| 62 |
+
required: true
|
| 63 |
+
attributes:
|
| 64 |
+
label: Expected behavior
|
| 65 |
+
description: "A clear and concise description of what you would expect to happen."
|
verl/.github/ISSUE_TEMPLATE/config.yml
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
blank_issues_enabled: true
|
| 2 |
+
version: 0.1
|
verl/.github/ISSUE_TEMPLATE/feature-request.yml
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# modified from https://github.com/huggingface/transformers/blob/main/.github/ISSUE_TEMPLATE/feature-request.yml?plain=1
|
| 2 |
+
name: "\U0001F680 Feature request"
|
| 3 |
+
description: Submit a proposal/request for a new verl feature
|
| 4 |
+
labels: [ "Feature request" ]
|
| 5 |
+
body:
|
| 6 |
+
- type: textarea
|
| 7 |
+
id: feature-request
|
| 8 |
+
validations:
|
| 9 |
+
required: true
|
| 10 |
+
attributes:
|
| 11 |
+
label: Feature request
|
| 12 |
+
description: |
|
| 13 |
+
A clear and concise description of the feature proposal. Please provide a link to the paper and code in case they exist.
|
| 14 |
+
|
| 15 |
+
- type: textarea
|
| 16 |
+
id: motivation
|
| 17 |
+
validations:
|
| 18 |
+
required: true
|
| 19 |
+
attributes:
|
| 20 |
+
label: Motivation
|
| 21 |
+
description: |
|
| 22 |
+
Please outline the motivation for the proposal. Is your feature request related to a problem? e.g., I'm always frustrated when [...]. If this is related to another GitHub issue, please link here too.
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
- type: textarea
|
| 26 |
+
id: contribution
|
| 27 |
+
validations:
|
| 28 |
+
required: true
|
| 29 |
+
attributes:
|
| 30 |
+
label: Your contribution
|
| 31 |
+
description: |
|
| 32 |
+
Is there any way that you could help, e.g. by submitting a PR? Make sure to read the CONTRIBUTING.MD [readme](https://github.com/verl-project/verl/blob/main/CONTRIBUTING.md)
|
verl/.github/PULL_REQUEST_TEMPLATE.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
### What does this PR do?
|
| 2 |
+
|
| 3 |
+
> Add **concise** overview of what this PR aims to achieve or accomplish. Reference related GitHub issues and PRs that help with the review.
|
| 4 |
+
|
| 5 |
+
### Checklist Before Starting
|
| 6 |
+
|
| 7 |
+
- [ ] Search for similar PRs. Paste at least one query link here: ...
|
| 8 |
+
- [ ] Format the PR title as `[{modules}] {type}: {description}` (This will be checked by the CI)
|
| 9 |
+
- `{modules}` include `fsdp`, `megatron`, `veomni`, `sglang`, `vllm`, `rollout`, `trainer`, `ci`, `training_utils`, `recipe`, `hardware`, `deployment`, `ray`, `worker`, `single_controller`, `misc`, `perf`, `model`, `algo`, `env`, `tool`, `ckpt`, `doc`, `data`, `cfg`, `reward`, `fully_async`, `one_step_off`
|
| 10 |
+
- If this PR involves multiple modules, separate them with `,` like `[megatron, fsdp, doc]`
|
| 11 |
+
- `{type}` is in `feat`, `fix`, `refactor`, `chore`, `test`
|
| 12 |
+
- If this PR breaks any API (CLI arguments, config, function signature, etc.), add `[BREAKING]` to the beginning of the title.
|
| 13 |
+
- Example: `[BREAKING][fsdp, megatron] feat: dynamic batching`
|
| 14 |
+
|
| 15 |
+
### Test
|
| 16 |
+
|
| 17 |
+
> For changes that can not be tested by CI (e.g., algorithm implementation, new model support), validate by experiment(s) and show results like training curve plots, evaluation results, etc.
|
| 18 |
+
|
| 19 |
+
### API and Usage Example
|
| 20 |
+
|
| 21 |
+
> Demonstrate how the API changes if any, and provide usage example(s) if possible.
|
| 22 |
+
|
| 23 |
+
```python
|
| 24 |
+
# Add code snippet or script demonstrating how to use this
|
| 25 |
+
```
|
| 26 |
+
|
| 27 |
+
### Design & Code Changes
|
| 28 |
+
|
| 29 |
+
> Demonstrate the high-level design if this PR is complex, and list the specific changes.
|
| 30 |
+
|
| 31 |
+
### Checklist Before Submitting
|
| 32 |
+
|
| 33 |
+
> [!IMPORTANT]
|
| 34 |
+
> Please check all the following items before requesting a review, otherwise the reviewer might deprioritize this PR for review.
|
| 35 |
+
|
| 36 |
+
- [ ] Read the [Contribute Guide](https://github.com/verl-project/verl/blob/main/CONTRIBUTING.md).
|
| 37 |
+
- [ ] Apply [pre-commit checks](https://github.com/verl-project/verl/blob/main/CONTRIBUTING.md#code-linting-and-formatting): `pre-commit install && pre-commit run --all-files --show-diff-on-failure --color=always`
|
| 38 |
+
- [ ] Add / Update [the documentation](https://github.com/verl-project/verl/tree/main/docs).
|
| 39 |
+
- [ ] Add unit or end-to-end test(s) to [the CI workflow](https://github.com/verl-project/verl/tree/main/.github/workflows) to cover all the code. If not feasible, explain why: ...
|
| 40 |
+
- [ ] Once your PR is ready for CI, send a message in [the `ci-request` channel](https://verl-project.slack.com/archives/C091TCESWB1) in [the `verl` Slack workspace](https://join.slack.com/t/verl-project/shared_invite/zt-3855yhg8g-CTkqXu~hKojPCmo7k_yXTQ). (If not accessible, please try [the Feishu group (飞书群)](https://applink.larkoffice.com/client/chat/chatter/add_by_link?link_token=772jd4f1-cd91-441e-a820-498c6614126a).)
|
| 41 |
+
- [ ] If your PR is related to the `recipe` submodule, please also update the reference to the submodule commit via `git submodule update --remote` or `cd recipe && git pull origin main`.
|
verl/.github/dependabot.yml
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
## Enabled the dependabot to check the dependencies of the project
|
| 2 |
+
## Dependabot will open pull requests to update dependencies automatically
|
| 3 |
+
|
| 4 |
+
version: 2
|
| 5 |
+
updates:
|
| 6 |
+
- package-ecosystem: pip
|
| 7 |
+
directory: "/"
|
| 8 |
+
schedule:
|
| 9 |
+
interval: weekly
|
verl/.github/workflows/README.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
### Adding a New Workflow
|
| 2 |
+
|
| 3 |
+
When adding a new workflow for continuous integration (CI), you have two runner options: a fixed runner or a machine from the vemlp.
|
| 4 |
+
|
| 5 |
+
- **Fixed Runner**: To use a fixed runner, specify it in your workflow using the `runs-on` keyword, like `runs-on: [L20x8]`.
|
| 6 |
+
- **Vemlp Runner**: Opting for a Vemlp machine allows you to launch tasks elastically.
|
| 7 |
+
|
| 8 |
+
Here is a template to assist you. This template is designed for using Vemlp machines. Currently, for each workflow, you need to create a `setup` and a `cleanup` job. When using this template, the main parts you need to modify are the `IMAGE` environment variable and the specific `job steps`.
|
| 9 |
+
|
| 10 |
+
```yaml
|
| 11 |
+
name: Your Default Workflow
|
| 12 |
+
|
| 13 |
+
on:
|
| 14 |
+
push:
|
| 15 |
+
branches:
|
| 16 |
+
- main
|
| 17 |
+
- v0.*
|
| 18 |
+
pull_request:
|
| 19 |
+
branches:
|
| 20 |
+
- main
|
| 21 |
+
- v0.*
|
| 22 |
+
paths:
|
| 23 |
+
- "**/*.py"
|
| 24 |
+
- ".github/workflows/template.yml"
|
| 25 |
+
|
| 26 |
+
concurrency:
|
| 27 |
+
group: ${{ github.workflow }}-${{ github.ref }}
|
| 28 |
+
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
| 29 |
+
|
| 30 |
+
permissions:
|
| 31 |
+
contents: read
|
| 32 |
+
|
| 33 |
+
env:
|
| 34 |
+
IMAGE: "your vemlp image" # e.g. "verl-ci-cn-beijing.cr.volces.com/verlai/verl:sgl059.dev2"
|
| 35 |
+
DYNAMIC_RUNNER_URL: "https://sd10g3clalm04ug7alq90.apigateway-cn-beijing.volceapi.com/runner" # public veFaas api
|
| 36 |
+
|
| 37 |
+
jobs:
|
| 38 |
+
setup:
|
| 39 |
+
if: github.repository_owner == 'verl-project'
|
| 40 |
+
runs-on: ubuntu-latest
|
| 41 |
+
outputs:
|
| 42 |
+
runner-label: ${{ steps.create-runner.outputs.runner-label }}
|
| 43 |
+
task-id: ${{ steps.create-runner.outputs.task-id }}
|
| 44 |
+
steps:
|
| 45 |
+
- uses: actions/checkout@v4
|
| 46 |
+
- id: create-runner
|
| 47 |
+
uses: volcengine/vemlp-github-runner@v1
|
| 48 |
+
with:
|
| 49 |
+
mode: "create"
|
| 50 |
+
faas-url: "${{ env.DYNAMIC_RUNNER_URL }}"
|
| 51 |
+
image: "${{ env.DEFAULT_IMAGE }}"
|
| 52 |
+
|
| 53 |
+
your_job:
|
| 54 |
+
needs: setup
|
| 55 |
+
runs-on: ["${{ needs.setup.outputs.runner-label || 'default-runner' }}"]
|
| 56 |
+
steps:
|
| 57 |
+
xxxx # your jobs
|
| 58 |
+
|
| 59 |
+
cleanup:
|
| 60 |
+
runs-on: ubuntu-latest
|
| 61 |
+
needs: [setup, your_job]
|
| 62 |
+
if: always()
|
| 63 |
+
steps:
|
| 64 |
+
- id: destroy-runner
|
| 65 |
+
uses: volcengine/vemlp-github-runner@v1
|
| 66 |
+
with:
|
| 67 |
+
mode: "destroy"
|
| 68 |
+
faas-url: "${{ env.DYNAMIC_RUNNER_URL }}"
|
| 69 |
+
task-id: "${{ needs.setup.outputs.task-id }}"
|
| 70 |
+
```
|
| 71 |
+
|
| 72 |
+
### Model and Dataset
|
| 73 |
+
To avoid CI relies on network, we pre-download dataset on a NFS on the CI machine. The path for models are \${HOME}/models and the path for dataset is \${HOME}/models/hf_data.
|
verl/.github/workflows/check-pr-title.yml
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# # Tests layout
|
| 2 |
+
|
| 3 |
+
# Each folder under tests/ corresponds to a test category for a sub-namespace in verl. For instance:
|
| 4 |
+
# - `tests/trainer` for testing functionality related to `verl/trainer`
|
| 5 |
+
# - `tests/models` for testing functionality related to `verl/models`
|
| 6 |
+
# - ...
|
| 7 |
+
|
| 8 |
+
# There are a few folders with `special_` prefix, created for special purposes:
|
| 9 |
+
# - `special_distributed`: unit tests that must run with multiple GPUs
|
| 10 |
+
# - `special_e2e`: end-to-end tests with training/generation scripts
|
| 11 |
+
# - `special_npu`: tests for NPUs
|
| 12 |
+
# - `special_sanity`: a suite of quick sanity tests
|
| 13 |
+
# - `special_standalone`: a set of test that are designed to run in dedicated environments
|
| 14 |
+
|
| 15 |
+
# Accelerators for tests
|
| 16 |
+
# - By default tests are run with GPU available, except for the ones under `special_npu`, and any test script whose name ends with `on_cpu.py`.
|
| 17 |
+
# - For test scripts with `on_cpu.py` name suffix would be tested on CPU resources in linux environment.
|
| 18 |
+
|
| 19 |
+
# # Workflow layout
|
| 20 |
+
|
| 21 |
+
# All CI tests are configured by yaml files in `.github/workflows/`. Here's an overview of all test configs:
|
| 22 |
+
# 1. A list of always triggered CPU sanity tests: `check-pr-title.yml`, `secrets_scan.yml`, `check-pr-title,yml`, `pre-commit.yml`, `doc.yml`
|
| 23 |
+
# 2. Some heavy multi-GPU unit tests, such as `model.yml`, `vllm.yml`, `sgl.yml`
|
| 24 |
+
# 3. End-to-end tests: `e2e_*.yml`
|
| 25 |
+
# 4. Unit tests
|
| 26 |
+
# - `cpu_unit_tests.yml`, run pytest on all scripts with file name pattern `tests/**/test_*_on_cpu.py`
|
| 27 |
+
# - `gpu_unit_tests.yml`, run pytest on all scripts with file without the `on_cpu.py` suffix.
|
| 28 |
+
# - Since cpu/gpu unit tests by default runs all tests under `tests`, please make sure tests are manually excluded in them when
|
| 29 |
+
# - new workflow yaml is added to `.github/workflows`
|
| 30 |
+
# - new tests are added to workflow mentioned in 2.
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
on:
|
| 34 |
+
pull_request:
|
| 35 |
+
types: [opened, edited, synchronize]
|
| 36 |
+
|
| 37 |
+
jobs:
|
| 38 |
+
check-title:
|
| 39 |
+
runs-on: ubuntu-latest
|
| 40 |
+
steps:
|
| 41 |
+
- name: Checkout code
|
| 42 |
+
uses: actions/checkout@v4
|
| 43 |
+
|
| 44 |
+
- name: Set up Python
|
| 45 |
+
uses: actions/setup-python@v5
|
| 46 |
+
with:
|
| 47 |
+
python-version: '3.11'
|
| 48 |
+
|
| 49 |
+
- name: Run PR title checker
|
| 50 |
+
run: python3 tests/special_sanity/check_pr_title.py
|
| 51 |
+
env:
|
| 52 |
+
PR_TITLE: ${{ github.event.pull_request.title }}
|
| 53 |
+
|
| 54 |
+
- name: Run PR description checker
|
| 55 |
+
run: python3 tests/special_sanity/check_pr_description.py
|
| 56 |
+
env:
|
| 57 |
+
PR_TITLE: ${{ github.event.pull_request.title }}
|
| 58 |
+
GITHUB_EVENT_PATH: ${{ github.event_path }}
|
verl/.github/workflows/cpu_unit_tests.yml
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# # Tests layout
|
| 2 |
+
|
| 3 |
+
# Each folder under tests/ corresponds to a test category for a sub-namespace in verl. For instance:
|
| 4 |
+
# - `tests/trainer` for testing functionality related to `verl/trainer`
|
| 5 |
+
# - `tests/models` for testing functionality related to `verl/models`
|
| 6 |
+
# - ...
|
| 7 |
+
|
| 8 |
+
# There are a few folders with `special_` prefix, created for special purposes:
|
| 9 |
+
# - `special_distributed`: unit tests that must run with multiple GPUs
|
| 10 |
+
# - `special_e2e`: end-to-end tests with training/generation scripts
|
| 11 |
+
# - `special_npu`: tests for NPUs
|
| 12 |
+
# - `special_sanity`: a suite of quick sanity tests
|
| 13 |
+
# - `special_standalone`: a set of test that are designed to run in dedicated environments
|
| 14 |
+
|
| 15 |
+
# Accelerators for tests
|
| 16 |
+
# - By default tests are run with GPU available, except for the ones under `special_npu`, and any test script whose name ends with `on_cpu.py`.
|
| 17 |
+
# - For test scripts with `on_cpu.py` name suffix would be tested on CPU resources in linux environment.
|
| 18 |
+
|
| 19 |
+
# # Workflow layout
|
| 20 |
+
|
| 21 |
+
# All CI tests are configured by yaml files in `.github/workflows/`. Here's an overview of all test configs:
|
| 22 |
+
# 1. A list of always triggered CPU sanity tests: `check-pr-title.yml`, `secrets_scan.yml`, `check-pr-title,yml`, `pre-commit.yml`, `doc.yml`
|
| 23 |
+
# 2. Some heavy multi-GPU unit tests, such as `model.yml`, `vllm.yml`, `sgl.yml`
|
| 24 |
+
# 3. End-to-end tests: `e2e_*.yml`
|
| 25 |
+
# 4. Unit tests
|
| 26 |
+
# - `cpu_unit_tests.yml`, run pytest on all scripts with file name pattern `tests/**/test_*_on_cpu.py`
|
| 27 |
+
# - `gpu_unit_tests.yml`, run pytest on all scripts with file without the `on_cpu.py` suffix.
|
| 28 |
+
# - Since cpu/gpu unit tests by default runs all tests under `tests`, please make sure tests are manually excluded in them when
|
| 29 |
+
# - new workflow yaml is added to `.github/workflows`
|
| 30 |
+
# - new tests are added to workflow mentioned in 2.
|
| 31 |
+
|
| 32 |
+
name: cpu_unit_tests
|
| 33 |
+
|
| 34 |
+
on:
|
| 35 |
+
# Trigger the workflow on push or pull request,
|
| 36 |
+
# but only for the main branch
|
| 37 |
+
push:
|
| 38 |
+
branches:
|
| 39 |
+
- main
|
| 40 |
+
- v0.*
|
| 41 |
+
pull_request:
|
| 42 |
+
branches:
|
| 43 |
+
- main
|
| 44 |
+
- v0.*
|
| 45 |
+
paths:
|
| 46 |
+
- "**/*.py"
|
| 47 |
+
- "!tests/special_sanity/**"
|
| 48 |
+
- .github/workflows/cpu_unit_tests.yml
|
| 49 |
+
|
| 50 |
+
# Cancel jobs on the same ref if a new one is triggered
|
| 51 |
+
concurrency:
|
| 52 |
+
group: ${{ github.workflow }}-${{ github.ref }}
|
| 53 |
+
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
| 54 |
+
|
| 55 |
+
# Declare permissions just read content.
|
| 56 |
+
permissions:
|
| 57 |
+
contents: read
|
| 58 |
+
|
| 59 |
+
env:
|
| 60 |
+
IMAGE: "verl-ci-cn-beijing.cr.volces.com/verlai/verl:vllm018.dev1"
|
| 61 |
+
DYNAMIC_RUNNER_ENDPOINT: "https://sd10g3clalm04ug7alq90.apigateway-cn-beijing.volceapi.com/runner"
|
| 62 |
+
|
| 63 |
+
jobs:
|
| 64 |
+
setup:
|
| 65 |
+
if: github.repository_owner == 'verl-project'
|
| 66 |
+
runs-on: ubuntu-latest
|
| 67 |
+
outputs:
|
| 68 |
+
runner-label: ${{ steps.create-runner.outputs.runner-label }}
|
| 69 |
+
mlp-task-id: ${{ steps.create-runner.outputs.mlp-task-id }}
|
| 70 |
+
steps:
|
| 71 |
+
- uses: actions/checkout@v4
|
| 72 |
+
- id: create-runner
|
| 73 |
+
uses: volcengine/vemlp-github-runner@v1
|
| 74 |
+
with:
|
| 75 |
+
mode: "create"
|
| 76 |
+
faas-url: "${{ env.DYNAMIC_RUNNER_ENDPOINT }}"
|
| 77 |
+
mlp-image: "${{ env.IMAGE }}"
|
| 78 |
+
|
| 79 |
+
cpu_unit_tests:
|
| 80 |
+
needs: setup
|
| 81 |
+
runs-on: ["${{ needs.setup.outputs.runner-label || 'L20x8' }}"]
|
| 82 |
+
timeout-minutes: 20 # Increase this timeout value as needed
|
| 83 |
+
env:
|
| 84 |
+
HTTPS_PROXY: ${{ secrets.PROXY_HTTPS }}
|
| 85 |
+
NO_PROXY: "localhost,127.0.0.1,hf-mirror.com"
|
| 86 |
+
HF_ENDPOINT: "https://hf-mirror.com"
|
| 87 |
+
HF_HUB_ENABLE_HF_TRANSFER: "0" # This is more stable
|
| 88 |
+
TORCH_COMPILE_DISABLE: 1
|
| 89 |
+
TORCHINDUCTOR_DISABLE: 1
|
| 90 |
+
steps:
|
| 91 |
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
| 92 |
+
with:
|
| 93 |
+
fetch-depth: 0
|
| 94 |
+
- name: Install the current repository
|
| 95 |
+
run: |
|
| 96 |
+
pip3 install -r requirements-test.txt
|
| 97 |
+
pip3 install --no-deps -e .
|
| 98 |
+
- name: Download datasets
|
| 99 |
+
run: |
|
| 100 |
+
python3 examples/data_preprocess/gsm8k.py --local_dataset_path ${HOME}/models/hf_data/gsm8k
|
| 101 |
+
python3 examples/data_preprocess/geo3k.py --local_dataset_path ${HOME}/models/hf_data/hiyouga/geometry3k
|
| 102 |
+
- name: Running CPU unit tests
|
| 103 |
+
run: |
|
| 104 |
+
echo '[pytest]' > pytest.ini
|
| 105 |
+
echo 'python_files = *_on_cpu.py' >> pytest.ini
|
| 106 |
+
pytest -s -x --asyncio-mode=auto tests/
|
| 107 |
+
cleanup:
|
| 108 |
+
runs-on: ubuntu-latest
|
| 109 |
+
needs: [setup, cpu_unit_tests]
|
| 110 |
+
if: always()
|
| 111 |
+
steps:
|
| 112 |
+
- id: destroy-runner
|
| 113 |
+
uses: volcengine/vemlp-github-runner@v1
|
| 114 |
+
with:
|
| 115 |
+
mode: "destroy"
|
| 116 |
+
faas-url: "${{ env.DYNAMIC_RUNNER_ENDPOINT }}"
|
| 117 |
+
mlp-task-id: "${{ needs.setup.outputs.mlp-task-id }}"
|
verl/.github/workflows/doc.yml
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# # Tests layout
|
| 2 |
+
|
| 3 |
+
# Each folder under tests/ corresponds to a test category for a sub-namespace in verl. For instance:
|
| 4 |
+
# - `tests/trainer` for testing functionality related to `verl/trainer`
|
| 5 |
+
# - `tests/models` for testing functionality related to `verl/models`
|
| 6 |
+
# - ...
|
| 7 |
+
|
| 8 |
+
# There are a few folders with `special_` prefix, created for special purposes:
|
| 9 |
+
# - `special_distributed`: unit tests that must run with multiple GPUs
|
| 10 |
+
# - `special_e2e`: end-to-end tests with training/generation scripts
|
| 11 |
+
# - `special_npu`: tests for NPUs
|
| 12 |
+
# - `special_sanity`: a suite of quick sanity tests
|
| 13 |
+
# - `special_standalone`: a set of test that are designed to run in dedicated environments
|
| 14 |
+
|
| 15 |
+
# Accelerators for tests
|
| 16 |
+
# - By default tests are run with GPU available, except for the ones under `special_npu`, and any test script whose name ends with `on_cpu.py`.
|
| 17 |
+
# - For test scripts with `on_cpu.py` name suffix would be tested on CPU resources in linux environment.
|
| 18 |
+
|
| 19 |
+
# # Workflow layout
|
| 20 |
+
|
| 21 |
+
# All CI tests are configured by yaml files in `.github/workflows/`. Here's an overview of all test configs:
|
| 22 |
+
# 1. A list of always triggered CPU sanity tests: `check-pr-title.yml`, `secrets_scan.yml`, `check-pr-title,yml`, `pre-commit.yml`, `doc.yml`
|
| 23 |
+
# 2. Some heavy multi-GPU unit tests, such as `model.yml`, `vllm.yml`, `sgl.yml`
|
| 24 |
+
# 3. End-to-end tests: `e2e_*.yml`
|
| 25 |
+
# 4. Unit tests
|
| 26 |
+
# - `cpu_unit_tests.yml`, run pytest on all scripts with file name pattern `tests/**/test_*_on_cpu.py`
|
| 27 |
+
# - `gpu_unit_tests.yml`, run pytest on all scripts with file without the `on_cpu.py` suffix.
|
| 28 |
+
# - Since cpu/gpu unit tests by default runs all tests under `tests`, please make sure tests are manually excluded in them when
|
| 29 |
+
# - new workflow yaml is added to `.github/workflows`
|
| 30 |
+
# - new tests are added to workflow mentioned in 2.
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
name: doc_test
|
| 34 |
+
|
| 35 |
+
on:
|
| 36 |
+
# Trigger the workflow on push or pull request,
|
| 37 |
+
# but only for the main branch
|
| 38 |
+
push:
|
| 39 |
+
branches:
|
| 40 |
+
- main
|
| 41 |
+
- v0.*
|
| 42 |
+
pull_request:
|
| 43 |
+
branches:
|
| 44 |
+
- main
|
| 45 |
+
- v0.*
|
| 46 |
+
paths:
|
| 47 |
+
- "**/*.py"
|
| 48 |
+
- "docs/**"
|
| 49 |
+
- .github/workflows/doc.yml
|
| 50 |
+
|
| 51 |
+
# Cancel jobs on the same ref if a new one is triggered
|
| 52 |
+
concurrency:
|
| 53 |
+
group: ${{ github.workflow }}-${{ github.ref }}
|
| 54 |
+
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
| 55 |
+
|
| 56 |
+
# Declare permissions just read content.
|
| 57 |
+
permissions:
|
| 58 |
+
contents: read # for checkout
|
| 59 |
+
pages: write # for deploy-pages
|
| 60 |
+
id-token: write # for deploy-pages
|
| 61 |
+
|
| 62 |
+
jobs:
|
| 63 |
+
doc_test:
|
| 64 |
+
runs-on: ubuntu-latest
|
| 65 |
+
timeout-minutes: 5 # Increase this timeout value as needed
|
| 66 |
+
strategy:
|
| 67 |
+
matrix:
|
| 68 |
+
python-version: ["3.10"]
|
| 69 |
+
steps:
|
| 70 |
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
| 71 |
+
- name: Set up Python ${{ matrix.python-version }}
|
| 72 |
+
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
|
| 73 |
+
with:
|
| 74 |
+
python-version: ${{ matrix.python-version }}
|
| 75 |
+
- name: Install the current repository
|
| 76 |
+
run: |
|
| 77 |
+
pip3 install -r requirements-test.txt
|
| 78 |
+
pip3 install --no-deps -e .
|
| 79 |
+
pip install -r docs/requirements-docs.txt
|
| 80 |
+
|
| 81 |
+
- name: Run doc make html
|
| 82 |
+
run: |
|
| 83 |
+
cd docs
|
| 84 |
+
make clean
|
| 85 |
+
make html SPHINXOPTS="--keep-going -w _build/sphinx.log"
|
| 86 |
+
if grep -q ": ERROR:" _build/sphinx.log; then
|
| 87 |
+
echo "🚨 Sphinx doc build contained ERRORs - see _build/sphinx.log"
|
| 88 |
+
exit 1
|
| 89 |
+
fi
|
| 90 |
+
if grep -q "WARNING: document isn't included in any toctree" _build/sphinx.log; then
|
| 91 |
+
echo "🚨 Sphinx doc build contained WARNING. Please include newly added docs in index.rst. See _build/sphinx.log for details"
|
| 92 |
+
exit 1
|
| 93 |
+
fi
|
| 94 |
+
if grep -q "WARNING: Inline emphasis" _build/sphinx.log; then
|
| 95 |
+
echo "🚨 Sphinx doc build contained WARNING. Please check inline emphasis is correct. See _build/sphinx.log for details"
|
| 96 |
+
exit 1
|
| 97 |
+
fi
|
| 98 |
+
if grep -q "WARNING: Definition list ends without a blank line" _build/sphinx.log; then
|
| 99 |
+
echo "🚨 Sphinx doc build contained WARNING. Please check if the indentation is correct. See _build/sphinx.log for details"
|
| 100 |
+
exit 1
|
| 101 |
+
fi
|
verl/.github/workflows/docker-build-ascend-a2-qwen3_5.yml
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: docker-build-ascend-a2-qwen3_5
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
workflow_dispatch:
|
| 5 |
+
|
| 6 |
+
env:
|
| 7 |
+
QUAY_REPO: quay.io/ascend/verl
|
| 8 |
+
|
| 9 |
+
jobs:
|
| 10 |
+
build-push-digest:
|
| 11 |
+
name: build-${{ matrix.tag }}
|
| 12 |
+
if: ${{ github.repository_owner == 'verl-project' }}
|
| 13 |
+
runs-on: ${{ matrix.runner }}
|
| 14 |
+
permissions:
|
| 15 |
+
packages: write
|
| 16 |
+
contents: read
|
| 17 |
+
strategy:
|
| 18 |
+
fail-fast: false
|
| 19 |
+
matrix:
|
| 20 |
+
include:
|
| 21 |
+
- arch: linux/amd64
|
| 22 |
+
runner: ubuntu-latest
|
| 23 |
+
tag: amd64
|
| 24 |
+
- arch: linux/arm64
|
| 25 |
+
runner: ubuntu-22.04-arm
|
| 26 |
+
tag: arm64
|
| 27 |
+
steps:
|
| 28 |
+
- name: Remove unnecessary parts in github actions runners to free up disk space
|
| 29 |
+
uses: jlumbroso/free-disk-space@v1.3.1
|
| 30 |
+
with:
|
| 31 |
+
tool-cache: true
|
| 32 |
+
|
| 33 |
+
- name: Checkout code
|
| 34 |
+
uses: actions/checkout@v4
|
| 35 |
+
|
| 36 |
+
- name: Set up Python
|
| 37 |
+
uses: actions/setup-python@v5
|
| 38 |
+
with:
|
| 39 |
+
python-version: "3.11"
|
| 40 |
+
|
| 41 |
+
- name: Login to Quay.io
|
| 42 |
+
uses: docker/login-action@v3
|
| 43 |
+
with:
|
| 44 |
+
registry: quay.io
|
| 45 |
+
username: ${{ secrets.QUAY_USERNAME }}
|
| 46 |
+
password: ${{ secrets.QUAY_PASSWORD }}
|
| 47 |
+
|
| 48 |
+
- name: Set up Docker Buildx
|
| 49 |
+
uses: docker/setup-buildx-action@v3
|
| 50 |
+
with:
|
| 51 |
+
install: true
|
| 52 |
+
driver: docker-container
|
| 53 |
+
use: true
|
| 54 |
+
|
| 55 |
+
- name: Clean Docker cache before build
|
| 56 |
+
run: |
|
| 57 |
+
docker system prune -a -f --volumes || true
|
| 58 |
+
|
| 59 |
+
- name: Build and push by digest
|
| 60 |
+
uses: docker/build-push-action@v6
|
| 61 |
+
id: build
|
| 62 |
+
with:
|
| 63 |
+
context: .
|
| 64 |
+
platforms: ${{ matrix.arch }}
|
| 65 |
+
file: ./docker/ascend/Dockerfile.ascend_8.5.2_a2_qwen3-5
|
| 66 |
+
push: true
|
| 67 |
+
# 关键:push-by-digest=true 只推送镜像层,不创建 tag
|
| 68 |
+
outputs: type=image,name=${{ env.QUAY_REPO }},push-by-digest=true,name-canonical=true,push=true
|
| 69 |
+
provenance: false
|
| 70 |
+
cache-from: type=gha
|
| 71 |
+
cache-to: type=gha,mode=max
|
| 72 |
+
build-args: |
|
| 73 |
+
BUILDKIT_INLINE_CACHE=1
|
| 74 |
+
|
| 75 |
+
- name: Export digest
|
| 76 |
+
run: |
|
| 77 |
+
mkdir -p ${{ runner.temp }}/digests
|
| 78 |
+
digest="${{ steps.build.outputs.digest }}"
|
| 79 |
+
touch "${{ runner.temp }}/digests/${digest#sha256:}"
|
| 80 |
+
|
| 81 |
+
- name: Upload digest
|
| 82 |
+
uses: actions/upload-artifact@v4
|
| 83 |
+
with:
|
| 84 |
+
name: digests-${{ matrix.tag }}
|
| 85 |
+
path: ${{ runner.temp }}/digests/*
|
| 86 |
+
if-no-files-found: error
|
| 87 |
+
retention-days: 1
|
| 88 |
+
|
| 89 |
+
merge-image:
|
| 90 |
+
name: merge
|
| 91 |
+
runs-on: ubuntu-latest
|
| 92 |
+
needs: build-push-digest
|
| 93 |
+
steps:
|
| 94 |
+
- name: Download digests
|
| 95 |
+
uses: actions/download-artifact@v4
|
| 96 |
+
with:
|
| 97 |
+
path: ${{ runner.temp }}/digests
|
| 98 |
+
pattern: digests-*
|
| 99 |
+
merge-multiple: true
|
| 100 |
+
|
| 101 |
+
- name: Login to Quay.io
|
| 102 |
+
uses: docker/login-action@v3
|
| 103 |
+
with:
|
| 104 |
+
registry: quay.io
|
| 105 |
+
username: ${{ secrets.QUAY_USERNAME }}
|
| 106 |
+
password: ${{ secrets.QUAY_PASSWORD }}
|
| 107 |
+
|
| 108 |
+
- name: Set up Docker Buildx
|
| 109 |
+
uses: docker/setup-buildx-action@v3
|
| 110 |
+
|
| 111 |
+
- name: Merge and push multi-arch image
|
| 112 |
+
env:
|
| 113 |
+
IMAGE: ${{ env.QUAY_REPO }}
|
| 114 |
+
run: |
|
| 115 |
+
# 读取所有 digest 文件,构建 IMAGE@sha256:DIGEST 格式
|
| 116 |
+
DIGESTS=$(printf "$IMAGE@sha256:%s " $(ls ${{ runner.temp }}/digests))
|
| 117 |
+
|
| 118 |
+
echo "Digests: $DIGESTS"
|
| 119 |
+
|
| 120 |
+
# 创建多架构 manifest
|
| 121 |
+
docker buildx imagetools create \
|
| 122 |
+
-t "$IMAGE:verl-8.5.2-910b-ubuntu22.04-py3.11-qwen3-5" \
|
| 123 |
+
$DIGESTS
|
verl/.github/workflows/docker-build-ascend-a2.yml
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: docker-build-ascend-a2
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
workflow_dispatch:
|
| 5 |
+
push:
|
| 6 |
+
branches: ["main"]
|
| 7 |
+
paths:
|
| 8 |
+
- "docker/ascend/Dockerfile.ascend_8.5.0_a2"
|
| 9 |
+
- "docker/ascend/Dockerfile.ascend_8.5.0_a2_v0.7.1"
|
| 10 |
+
- ".github/workflows/docker-build-ascend-a2.yml"
|
| 11 |
+
|
| 12 |
+
release:
|
| 13 |
+
types: [published]
|
| 14 |
+
schedule:
|
| 15 |
+
- cron: "0 16 * * *"
|
| 16 |
+
|
| 17 |
+
env:
|
| 18 |
+
QUAY_REPO: quay.io/ascend/verl
|
| 19 |
+
|
| 20 |
+
jobs:
|
| 21 |
+
# ============================================================
|
| 22 |
+
# 第一阶段:分架构构建并推送 digest(main 镜像)
|
| 23 |
+
# ============================================================
|
| 24 |
+
build-push-digest:
|
| 25 |
+
name: build-${{ matrix.tag }}
|
| 26 |
+
if: ${{ github.event_name != 'pull_request' && github.repository_owner == 'verl-project' }}
|
| 27 |
+
concurrency:
|
| 28 |
+
group: ${{ github.workflow }}-${{ github.ref }}-${{ matrix.tag }}
|
| 29 |
+
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
| 30 |
+
runs-on: ${{ matrix.runner }}
|
| 31 |
+
permissions:
|
| 32 |
+
packages: write
|
| 33 |
+
contents: read
|
| 34 |
+
strategy:
|
| 35 |
+
fail-fast: false
|
| 36 |
+
matrix:
|
| 37 |
+
include:
|
| 38 |
+
- arch: linux/amd64
|
| 39 |
+
runner: ubuntu-latest
|
| 40 |
+
tag: amd64
|
| 41 |
+
- arch: linux/arm64
|
| 42 |
+
runner: ubuntu-22.04-arm
|
| 43 |
+
tag: arm64
|
| 44 |
+
outputs:
|
| 45 |
+
tag: ${{ steps.version.outputs.tag }}
|
| 46 |
+
steps:
|
| 47 |
+
- name: Remove unnecessary parts in github actions runners to free up disk space
|
| 48 |
+
uses: jlumbroso/free-disk-space@v1.3.1
|
| 49 |
+
with:
|
| 50 |
+
tool-cache: true
|
| 51 |
+
|
| 52 |
+
- name: Checkout code
|
| 53 |
+
uses: actions/checkout@v4
|
| 54 |
+
|
| 55 |
+
- name: Set up Python
|
| 56 |
+
uses: actions/setup-python@v5
|
| 57 |
+
with:
|
| 58 |
+
python-version: "3.11"
|
| 59 |
+
|
| 60 |
+
- name: Get base image name and tag
|
| 61 |
+
id: base_image
|
| 62 |
+
run: |
|
| 63 |
+
BASE_IMAGE_FULL=$(grep '^FROM' ./docker/ascend/Dockerfile.ascend_8.5.0_a2 | head -1 | cut -d' ' -f2)
|
| 64 |
+
echo "Base image full: $BASE_IMAGE_FULL"
|
| 65 |
+
BASE_IMAGE_TAG=$(echo "$BASE_IMAGE_FULL" | cut -d':' -f2)
|
| 66 |
+
echo "Base image tag: $BASE_IMAGE_TAG"
|
| 67 |
+
NEW_IMAGE_NAME="verl-$BASE_IMAGE_TAG"
|
| 68 |
+
echo "New image name: $NEW_IMAGE_NAME"
|
| 69 |
+
echo "base_image_tag=$BASE_IMAGE_TAG" >> "$GITHUB_OUTPUT"
|
| 70 |
+
echo "new_image_name=$NEW_IMAGE_NAME" >> "$GITHUB_OUTPUT"
|
| 71 |
+
|
| 72 |
+
- name: Get image tag
|
| 73 |
+
id: version
|
| 74 |
+
run: |
|
| 75 |
+
BRANCH_NAME=$(echo "${{ github.ref }}" | sed 's/refs\/heads\///g' | sed 's/[^a-zA-Z0-9._-]/_/g')
|
| 76 |
+
if [ "${{ github.event_name }}" = "release" ]; then
|
| 77 |
+
echo "tag=${{ steps.base_image.outputs.new_image_name }}-${{ github.event.release.tag_name }}" >> "$GITHUB_OUTPUT"
|
| 78 |
+
elif [ "$BRANCH_NAME" = "main" ]; then
|
| 79 |
+
echo "tag=${{ steps.base_image.outputs.new_image_name }}-latest" >> "$GITHUB_OUTPUT"
|
| 80 |
+
fi
|
| 81 |
+
|
| 82 |
+
- name: Set up Docker Buildx
|
| 83 |
+
uses: docker/setup-buildx-action@v3
|
| 84 |
+
with:
|
| 85 |
+
install: true
|
| 86 |
+
driver: docker-container
|
| 87 |
+
use: true
|
| 88 |
+
|
| 89 |
+
- name: Login to Quay.io
|
| 90 |
+
uses: docker/login-action@v3
|
| 91 |
+
with:
|
| 92 |
+
registry: quay.io
|
| 93 |
+
username: ${{ secrets.QUAY_USERNAME }}
|
| 94 |
+
password: ${{ secrets.QUAY_PASSWORD }}
|
| 95 |
+
|
| 96 |
+
- name: Clean Docker cache before build
|
| 97 |
+
run: |
|
| 98 |
+
docker system prune -a -f --volumes || true
|
| 99 |
+
|
| 100 |
+
- name: Build and push by digest (main image)
|
| 101 |
+
uses: docker/build-push-action@v6
|
| 102 |
+
id: build_main
|
| 103 |
+
with:
|
| 104 |
+
context: .
|
| 105 |
+
platforms: ${{ matrix.arch }}
|
| 106 |
+
file: ./docker/ascend/Dockerfile.ascend_8.5.0_a2
|
| 107 |
+
push: true
|
| 108 |
+
outputs: type=image,name=${{ env.QUAY_REPO }},push-by-digest=true,name-canonical=true,push=true
|
| 109 |
+
provenance: false
|
| 110 |
+
cache-from: type=gha
|
| 111 |
+
cache-to: type=gha,mode=max
|
| 112 |
+
build-args: |
|
| 113 |
+
BUILDKIT_INLINE_CACHE=1
|
| 114 |
+
|
| 115 |
+
- name: Export digest (main image)
|
| 116 |
+
run: |
|
| 117 |
+
mkdir -p ${{ runner.temp }}/digests
|
| 118 |
+
digest="${{ steps.build_main.outputs.digest }}"
|
| 119 |
+
touch "${{ runner.temp }}/digests/main-${digest#sha256:}"
|
| 120 |
+
|
| 121 |
+
- name: Upload digest (main image)
|
| 122 |
+
uses: actions/upload-artifact@v4
|
| 123 |
+
with:
|
| 124 |
+
name: digests-main-${{ matrix.tag }}
|
| 125 |
+
path: ${{ runner.temp }}/digests/*
|
| 126 |
+
if-no-files-found: error
|
| 127 |
+
retention-days: 1
|
| 128 |
+
|
| 129 |
+
# ============================================================
|
| 130 |
+
# 第一阶段(v0.7.1):分架构构建并推送 digest
|
| 131 |
+
# ============================================================
|
| 132 |
+
build-push-digest-v071:
|
| 133 |
+
name: build-v0.7.1-${{ matrix.tag }}
|
| 134 |
+
if: ${{ github.event_name != 'pull_request' && github.repository_owner == 'verl-project' }}
|
| 135 |
+
concurrency:
|
| 136 |
+
group: ${{ github.workflow }}-${{ github.ref }}-v0.7.1-${{ matrix.tag }}
|
| 137 |
+
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
| 138 |
+
runs-on: ${{ matrix.runner }}
|
| 139 |
+
permissions:
|
| 140 |
+
packages: write
|
| 141 |
+
contents: read
|
| 142 |
+
strategy:
|
| 143 |
+
fail-fast: false
|
| 144 |
+
matrix:
|
| 145 |
+
include:
|
| 146 |
+
- arch: linux/amd64
|
| 147 |
+
runner: ubuntu-latest
|
| 148 |
+
tag: amd64
|
| 149 |
+
- arch: linux/arm64
|
| 150 |
+
runner: ubuntu-22.04-arm
|
| 151 |
+
tag: arm64
|
| 152 |
+
steps:
|
| 153 |
+
- name: Remove unnecessary parts in github actions runners to free up disk space
|
| 154 |
+
uses: jlumbroso/free-disk-space@v1.3.1
|
| 155 |
+
with:
|
| 156 |
+
tool-cache: true
|
| 157 |
+
|
| 158 |
+
- name: Checkout code
|
| 159 |
+
uses: actions/checkout@v4
|
| 160 |
+
|
| 161 |
+
- name: Set up Python
|
| 162 |
+
uses: actions/setup-python@v5
|
| 163 |
+
with:
|
| 164 |
+
python-version: "3.11"
|
| 165 |
+
|
| 166 |
+
- name: Set up Docker Buildx
|
| 167 |
+
uses: docker/setup-buildx-action@v3
|
| 168 |
+
with:
|
| 169 |
+
install: true
|
| 170 |
+
driver: docker-container
|
| 171 |
+
use: true
|
| 172 |
+
|
| 173 |
+
- name: Login to Quay.io
|
| 174 |
+
uses: docker/login-action@v3
|
| 175 |
+
with:
|
| 176 |
+
registry: quay.io
|
| 177 |
+
username: ${{ secrets.QUAY_USERNAME }}
|
| 178 |
+
password: ${{ secrets.QUAY_PASSWORD }}
|
| 179 |
+
|
| 180 |
+
- name: Clean Docker cache before build
|
| 181 |
+
run: |
|
| 182 |
+
docker system prune -a -f --volumes || true
|
| 183 |
+
|
| 184 |
+
- name: Build and push by digest (v0.7.1 image)
|
| 185 |
+
uses: docker/build-push-action@v6
|
| 186 |
+
id: build_v071
|
| 187 |
+
with:
|
| 188 |
+
context: .
|
| 189 |
+
platforms: ${{ matrix.arch }}
|
| 190 |
+
file: ./docker/ascend/Dockerfile.ascend_8.5.0_a2_v0.7.1
|
| 191 |
+
push: true
|
| 192 |
+
outputs: type=image,name=${{ env.QUAY_REPO }},push-by-digest=true,name-canonical=true,push=true
|
| 193 |
+
provenance: false
|
| 194 |
+
cache-from: type=gha
|
| 195 |
+
cache-to: type=gha,mode=max
|
| 196 |
+
build-args: |
|
| 197 |
+
BUILDKIT_INLINE_CACHE=1
|
| 198 |
+
|
| 199 |
+
- name: Export digest (v0.7.1 image)
|
| 200 |
+
run: |
|
| 201 |
+
mkdir -p ${{ runner.temp }}/digests-v071
|
| 202 |
+
digest="${{ steps.build_v071.outputs.digest }}"
|
| 203 |
+
touch "${{ runner.temp }}/digests-v071/v071-${digest#sha256:}"
|
| 204 |
+
|
| 205 |
+
- name: Upload digest (v0.7.1 image)
|
| 206 |
+
uses: actions/upload-artifact@v4
|
| 207 |
+
with:
|
| 208 |
+
name: digests-v071-${{ matrix.tag }}
|
| 209 |
+
path: ${{ runner.temp }}/digests-v071/*
|
| 210 |
+
if-no-files-found: error
|
| 211 |
+
retention-days: 1
|
| 212 |
+
|
| 213 |
+
# ============================================================
|
| 214 |
+
# 第二阶段:合并多架构 manifest(main 镜像)
|
| 215 |
+
# ============================================================
|
| 216 |
+
merge-image:
|
| 217 |
+
name: merge
|
| 218 |
+
runs-on: ubuntu-latest
|
| 219 |
+
needs: build-push-digest
|
| 220 |
+
steps:
|
| 221 |
+
- name: Download digests (main image)
|
| 222 |
+
uses: actions/download-artifact@v4
|
| 223 |
+
with:
|
| 224 |
+
path: ${{ runner.temp }}/digests-main
|
| 225 |
+
pattern: digests-main-*
|
| 226 |
+
merge-multiple: true
|
| 227 |
+
|
| 228 |
+
- name: Login to Quay.io
|
| 229 |
+
uses: docker/login-action@v3
|
| 230 |
+
with:
|
| 231 |
+
registry: quay.io
|
| 232 |
+
username: ${{ secrets.QUAY_USERNAME }}
|
| 233 |
+
password: ${{ secrets.QUAY_PASSWORD }}
|
| 234 |
+
|
| 235 |
+
- name: Set up Docker Buildx
|
| 236 |
+
uses: docker/setup-buildx-action@v3
|
| 237 |
+
|
| 238 |
+
- name: Merge and push multi-arch image (main)
|
| 239 |
+
env:
|
| 240 |
+
IMAGE: ${{ env.QUAY_REPO }}
|
| 241 |
+
run: |
|
| 242 |
+
DIGESTS=$(printf "$IMAGE@sha256:%s " $(ls ${{ runner.temp }}/digests-main | sed 's/^main-//'))
|
| 243 |
+
echo "Main image digests: $DIGESTS"
|
| 244 |
+
docker buildx imagetools create \
|
| 245 |
+
-t "$IMAGE:${{ needs.build-push-digest.outputs.tag }}" \
|
| 246 |
+
$DIGESTS
|
| 247 |
+
|
| 248 |
+
# ============================================================
|
| 249 |
+
# 第二阶段(v0.7.1):合并多架构 manifest
|
| 250 |
+
# ============================================================
|
| 251 |
+
merge-image-v071:
|
| 252 |
+
name: merge-v0.7.1
|
| 253 |
+
runs-on: ubuntu-latest
|
| 254 |
+
needs: build-push-digest-v071
|
| 255 |
+
steps:
|
| 256 |
+
- name: Download digests (v0.7.1 image)
|
| 257 |
+
uses: actions/download-artifact@v4
|
| 258 |
+
with:
|
| 259 |
+
path: ${{ runner.temp }}/digests-v071
|
| 260 |
+
pattern: digests-v071-*
|
| 261 |
+
merge-multiple: true
|
| 262 |
+
|
| 263 |
+
- name: Login to Quay.io
|
| 264 |
+
uses: docker/login-action@v3
|
| 265 |
+
with:
|
| 266 |
+
registry: quay.io
|
| 267 |
+
username: ${{ secrets.QUAY_USERNAME }}
|
| 268 |
+
password: ${{ secrets.QUAY_PASSWORD }}
|
| 269 |
+
|
| 270 |
+
- name: Set up Docker Buildx
|
| 271 |
+
uses: docker/setup-buildx-action@v3
|
| 272 |
+
|
| 273 |
+
- name: Merge and push multi-arch image (v0.7.1)
|
| 274 |
+
env:
|
| 275 |
+
IMAGE: ${{ env.QUAY_REPO }}
|
| 276 |
+
run: |
|
| 277 |
+
DIGESTS=$(printf "$IMAGE@sha256:%s " $(ls ${{ runner.temp }}/digests-v071 | sed 's/^v071-//'))
|
| 278 |
+
echo "v0.7.1 image digests: $DIGESTS"
|
| 279 |
+
docker buildx imagetools create \
|
| 280 |
+
-t "$IMAGE:verl-8.5.0-910b-ubuntu22.04-py3.11-v0.7.1" \
|
| 281 |
+
$DIGESTS
|
verl/.github/workflows/docker-build-ascend-a3-qwen3_5.yml
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: docker-build-ascend-a3-qwen3_5
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
workflow_dispatch:
|
| 5 |
+
|
| 6 |
+
env:
|
| 7 |
+
QUAY_REPO: quay.io/ascend/verl
|
| 8 |
+
|
| 9 |
+
jobs:
|
| 10 |
+
build-push-digest:
|
| 11 |
+
name: build-${{ matrix.tag }}
|
| 12 |
+
if: ${{ github.repository_owner == 'verl-project' }}
|
| 13 |
+
runs-on: ${{ matrix.runner }}
|
| 14 |
+
permissions:
|
| 15 |
+
packages: write
|
| 16 |
+
contents: read
|
| 17 |
+
strategy:
|
| 18 |
+
fail-fast: false
|
| 19 |
+
matrix:
|
| 20 |
+
include:
|
| 21 |
+
- arch: linux/amd64
|
| 22 |
+
runner: ubuntu-latest
|
| 23 |
+
tag: amd64
|
| 24 |
+
- arch: linux/arm64
|
| 25 |
+
runner: ubuntu-22.04-arm
|
| 26 |
+
tag: arm64
|
| 27 |
+
steps:
|
| 28 |
+
- name: Remove unnecessary parts in github actions runners to free up disk space
|
| 29 |
+
uses: jlumbroso/free-disk-space@v1.3.1
|
| 30 |
+
with:
|
| 31 |
+
tool-cache: true
|
| 32 |
+
|
| 33 |
+
- name: Checkout code
|
| 34 |
+
uses: actions/checkout@v4
|
| 35 |
+
|
| 36 |
+
- name: Set up Python
|
| 37 |
+
uses: actions/setup-python@v5
|
| 38 |
+
with:
|
| 39 |
+
python-version: "3.11"
|
| 40 |
+
|
| 41 |
+
- name: Login to Quay.io
|
| 42 |
+
uses: docker/login-action@v3
|
| 43 |
+
with:
|
| 44 |
+
registry: quay.io
|
| 45 |
+
username: ${{ secrets.QUAY_USERNAME }}
|
| 46 |
+
password: ${{ secrets.QUAY_PASSWORD }}
|
| 47 |
+
|
| 48 |
+
- name: Set up Docker Buildx
|
| 49 |
+
uses: docker/setup-buildx-action@v3
|
| 50 |
+
with:
|
| 51 |
+
install: true
|
| 52 |
+
driver: docker-container
|
| 53 |
+
use: true
|
| 54 |
+
|
| 55 |
+
- name: Clean Docker cache before build
|
| 56 |
+
run: |
|
| 57 |
+
docker system prune -a -f --volumes || true
|
| 58 |
+
|
| 59 |
+
- name: Build and push by digest
|
| 60 |
+
uses: docker/build-push-action@v6
|
| 61 |
+
id: build
|
| 62 |
+
with:
|
| 63 |
+
context: .
|
| 64 |
+
platforms: ${{ matrix.arch }}
|
| 65 |
+
file: ./docker/ascend/Dockerfile.ascend_8.5.2_a3_qwen3-5
|
| 66 |
+
push: true
|
| 67 |
+
# 关键:push-by-digest=true 只推送镜像层,不创建 tag
|
| 68 |
+
outputs: type=image,name=${{ env.QUAY_REPO }},push-by-digest=true,name-canonical=true,push=true
|
| 69 |
+
provenance: false
|
| 70 |
+
cache-from: type=gha
|
| 71 |
+
cache-to: type=gha,mode=max
|
| 72 |
+
build-args: |
|
| 73 |
+
BUILDKIT_INLINE_CACHE=1
|
| 74 |
+
|
| 75 |
+
- name: Export digest
|
| 76 |
+
run: |
|
| 77 |
+
mkdir -p ${{ runner.temp }}/digests
|
| 78 |
+
digest="${{ steps.build.outputs.digest }}"
|
| 79 |
+
touch "${{ runner.temp }}/digests/${digest#sha256:}"
|
| 80 |
+
|
| 81 |
+
- name: Upload digest
|
| 82 |
+
uses: actions/upload-artifact@v4
|
| 83 |
+
with:
|
| 84 |
+
name: digests-${{ matrix.tag }}
|
| 85 |
+
path: ${{ runner.temp }}/digests/*
|
| 86 |
+
if-no-files-found: error
|
| 87 |
+
retention-days: 1
|
| 88 |
+
|
| 89 |
+
merge-image:
|
| 90 |
+
name: merge
|
| 91 |
+
runs-on: ubuntu-latest
|
| 92 |
+
needs: build-push-digest
|
| 93 |
+
steps:
|
| 94 |
+
- name: Download digests
|
| 95 |
+
uses: actions/download-artifact@v4
|
| 96 |
+
with:
|
| 97 |
+
path: ${{ runner.temp }}/digests
|
| 98 |
+
pattern: digests-*
|
| 99 |
+
merge-multiple: true
|
| 100 |
+
|
| 101 |
+
- name: Login to Quay.io
|
| 102 |
+
uses: docker/login-action@v3
|
| 103 |
+
with:
|
| 104 |
+
registry: quay.io
|
| 105 |
+
username: ${{ secrets.QUAY_USERNAME }}
|
| 106 |
+
password: ${{ secrets.QUAY_PASSWORD }}
|
| 107 |
+
|
| 108 |
+
- name: Set up Docker Buildx
|
| 109 |
+
uses: docker/setup-buildx-action@v3
|
| 110 |
+
|
| 111 |
+
- name: Merge and push multi-arch image
|
| 112 |
+
env:
|
| 113 |
+
IMAGE: ${{ env.QUAY_REPO }}
|
| 114 |
+
run: |
|
| 115 |
+
# 读取所有 digest 文件,构建 IMAGE@sha256:DIGEST 格式
|
| 116 |
+
DIGESTS=$(printf "$IMAGE@sha256:%s " $(ls ${{ runner.temp }}/digests))
|
| 117 |
+
|
| 118 |
+
echo "Digests: $DIGESTS"
|
| 119 |
+
|
| 120 |
+
# 创建多架构 manifest
|
| 121 |
+
docker buildx imagetools create \
|
| 122 |
+
-t "$IMAGE:verl-8.5.2-a3-ubuntu22.04-py3.11-qwen3-5" \
|
| 123 |
+
$DIGESTS
|
verl/.github/workflows/docker-build-ascend-a3.yml
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: docker-build-ascend-a3
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
workflow_dispatch:
|
| 5 |
+
push:
|
| 6 |
+
branches: ["main"]
|
| 7 |
+
paths:
|
| 8 |
+
- "docker/ascend/Dockerfile.ascend_8.5.0_a3"
|
| 9 |
+
- "docker/ascend/Dockerfile.ascend_8.5.0_a3_v0.7.1"
|
| 10 |
+
- ".github/workflows/docker-build-ascend-a3.yml"
|
| 11 |
+
|
| 12 |
+
release:
|
| 13 |
+
types: [published]
|
| 14 |
+
schedule:
|
| 15 |
+
- cron: "0 19 * * *"
|
| 16 |
+
|
| 17 |
+
env:
|
| 18 |
+
QUAY_REPO: quay.io/ascend/verl
|
| 19 |
+
|
| 20 |
+
jobs:
|
| 21 |
+
# ============================================================
|
| 22 |
+
# 第一阶段:分架构构建并推送 digest(main 镜像)
|
| 23 |
+
# ============================================================
|
| 24 |
+
build-push-digest:
|
| 25 |
+
name: build-${{ matrix.tag }}
|
| 26 |
+
if: ${{ github.event_name != 'pull_request' && github.repository_owner == 'verl-project' }}
|
| 27 |
+
concurrency:
|
| 28 |
+
group: ${{ github.workflow }}-${{ github.ref }}-${{ matrix.tag }}
|
| 29 |
+
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
| 30 |
+
runs-on: ${{ matrix.runner }}
|
| 31 |
+
permissions:
|
| 32 |
+
packages: write
|
| 33 |
+
contents: read
|
| 34 |
+
strategy:
|
| 35 |
+
fail-fast: false
|
| 36 |
+
matrix:
|
| 37 |
+
include:
|
| 38 |
+
- arch: linux/amd64
|
| 39 |
+
runner: ubuntu-latest
|
| 40 |
+
tag: amd64
|
| 41 |
+
- arch: linux/arm64
|
| 42 |
+
runner: ubuntu-22.04-arm
|
| 43 |
+
tag: arm64
|
| 44 |
+
outputs:
|
| 45 |
+
tag: ${{ steps.version.outputs.tag }}
|
| 46 |
+
steps:
|
| 47 |
+
- name: Remove unnecessary parts in github actions runners to free up disk space
|
| 48 |
+
uses: jlumbroso/free-disk-space@v1.3.1
|
| 49 |
+
with:
|
| 50 |
+
tool-cache: true
|
| 51 |
+
|
| 52 |
+
- name: Checkout code
|
| 53 |
+
uses: actions/checkout@v4
|
| 54 |
+
|
| 55 |
+
- name: Set up Python
|
| 56 |
+
uses: actions/setup-python@v5
|
| 57 |
+
with:
|
| 58 |
+
python-version: "3.11"
|
| 59 |
+
|
| 60 |
+
- name: Get base image name and tag
|
| 61 |
+
id: base_image
|
| 62 |
+
run: |
|
| 63 |
+
BASE_IMAGE_FULL=$(grep '^FROM' ./docker/ascend/Dockerfile.ascend_8.5.0_a3 | head -1 | cut -d' ' -f2)
|
| 64 |
+
echo "Base image full: $BASE_IMAGE_FULL"
|
| 65 |
+
BASE_IMAGE_TAG=$(echo "$BASE_IMAGE_FULL" | cut -d':' -f2)
|
| 66 |
+
echo "Base image tag: $BASE_IMAGE_TAG"
|
| 67 |
+
NEW_IMAGE_NAME="verl-$BASE_IMAGE_TAG"
|
| 68 |
+
echo "New image name: $NEW_IMAGE_NAME"
|
| 69 |
+
echo "base_image_tag=$BASE_IMAGE_TAG" >> "$GITHUB_OUTPUT"
|
| 70 |
+
echo "new_image_name=$NEW_IMAGE_NAME" >> "$GITHUB_OUTPUT"
|
| 71 |
+
|
| 72 |
+
- name: Get image tag
|
| 73 |
+
id: version
|
| 74 |
+
run: |
|
| 75 |
+
BRANCH_NAME=$(echo "${{ github.ref }}" | sed 's/refs\/heads\///g' | sed 's/[^a-zA-Z0-9._-]/_/g')
|
| 76 |
+
if [ "${{ github.event_name }}" = "release" ]; then
|
| 77 |
+
echo "tag=${{ steps.base_image.outputs.new_image_name }}-${{ github.event.release.tag_name }}" >> "$GITHUB_OUTPUT"
|
| 78 |
+
elif [ "$BRANCH_NAME" = "main" ]; then
|
| 79 |
+
echo "tag=${{ steps.base_image.outputs.new_image_name }}-latest" >> "$GITHUB_OUTPUT"
|
| 80 |
+
fi
|
| 81 |
+
|
| 82 |
+
- name: Set up Docker Buildx
|
| 83 |
+
uses: docker/setup-buildx-action@v3
|
| 84 |
+
with:
|
| 85 |
+
install: true
|
| 86 |
+
driver: docker-container
|
| 87 |
+
use: true
|
| 88 |
+
|
| 89 |
+
- name: Login to Quay.io
|
| 90 |
+
uses: docker/login-action@v3
|
| 91 |
+
with:
|
| 92 |
+
registry: quay.io
|
| 93 |
+
username: ${{ secrets.QUAY_USERNAME }}
|
| 94 |
+
password: ${{ secrets.QUAY_PASSWORD }}
|
| 95 |
+
|
| 96 |
+
- name: Clean Docker cache before build
|
| 97 |
+
run: |
|
| 98 |
+
docker system prune -a -f --volumes || true
|
| 99 |
+
|
| 100 |
+
- name: Build and push by digest (main image)
|
| 101 |
+
uses: docker/build-push-action@v6
|
| 102 |
+
id: build_main
|
| 103 |
+
with:
|
| 104 |
+
context: .
|
| 105 |
+
platforms: ${{ matrix.arch }}
|
| 106 |
+
file: ./docker/ascend/Dockerfile.ascend_8.5.0_a3
|
| 107 |
+
push: true
|
| 108 |
+
outputs: type=image,name=${{ env.QUAY_REPO }},push-by-digest=true,name-canonical=true,push=true
|
| 109 |
+
provenance: false
|
| 110 |
+
cache-from: type=gha
|
| 111 |
+
cache-to: type=gha,mode=max
|
| 112 |
+
build-args: |
|
| 113 |
+
BUILDKIT_INLINE_CACHE=1
|
| 114 |
+
|
| 115 |
+
- name: Export digest (main image)
|
| 116 |
+
run: |
|
| 117 |
+
mkdir -p ${{ runner.temp }}/digests
|
| 118 |
+
digest="${{ steps.build_main.outputs.digest }}"
|
| 119 |
+
touch "${{ runner.temp }}/digests/main-${digest#sha256:}"
|
| 120 |
+
|
| 121 |
+
- name: Upload digest (main image)
|
| 122 |
+
uses: actions/upload-artifact@v4
|
| 123 |
+
with:
|
| 124 |
+
name: digests-main-${{ matrix.tag }}
|
| 125 |
+
path: ${{ runner.temp }}/digests/*
|
| 126 |
+
if-no-files-found: error
|
| 127 |
+
retention-days: 1
|
| 128 |
+
|
| 129 |
+
# ============================================================
|
| 130 |
+
# 第一阶段(v0.7.1):分架构构建并推送 digest
|
| 131 |
+
# ============================================================
|
| 132 |
+
build-push-digest-v071:
|
| 133 |
+
name: build-v0.7.1-${{ matrix.tag }}
|
| 134 |
+
if: ${{ github.event_name != 'pull_request' && github.repository_owner == 'verl-project' }}
|
| 135 |
+
concurrency:
|
| 136 |
+
group: ${{ github.workflow }}-${{ github.ref }}-v0.7.1-${{ matrix.tag }}
|
| 137 |
+
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
| 138 |
+
runs-on: ${{ matrix.runner }}
|
| 139 |
+
permissions:
|
| 140 |
+
packages: write
|
| 141 |
+
contents: read
|
| 142 |
+
strategy:
|
| 143 |
+
fail-fast: false
|
| 144 |
+
matrix:
|
| 145 |
+
include:
|
| 146 |
+
- arch: linux/amd64
|
| 147 |
+
runner: ubuntu-latest
|
| 148 |
+
tag: amd64
|
| 149 |
+
- arch: linux/arm64
|
| 150 |
+
runner: ubuntu-22.04-arm
|
| 151 |
+
tag: arm64
|
| 152 |
+
steps:
|
| 153 |
+
- name: Remove unnecessary parts in github actions runners to free up disk space
|
| 154 |
+
uses: jlumbroso/free-disk-space@v1.3.1
|
| 155 |
+
with:
|
| 156 |
+
tool-cache: true
|
| 157 |
+
|
| 158 |
+
- name: Checkout code
|
| 159 |
+
uses: actions/checkout@v4
|
| 160 |
+
|
| 161 |
+
- name: Set up Python
|
| 162 |
+
uses: actions/setup-python@v5
|
| 163 |
+
with:
|
| 164 |
+
python-version: "3.11"
|
| 165 |
+
|
| 166 |
+
- name: Set up Docker Buildx
|
| 167 |
+
uses: docker/setup-buildx-action@v3
|
| 168 |
+
with:
|
| 169 |
+
install: true
|
| 170 |
+
driver: docker-container
|
| 171 |
+
use: true
|
| 172 |
+
|
| 173 |
+
- name: Login to Quay.io
|
| 174 |
+
uses: docker/login-action@v3
|
| 175 |
+
with:
|
| 176 |
+
registry: quay.io
|
| 177 |
+
username: ${{ secrets.QUAY_USERNAME }}
|
| 178 |
+
password: ${{ secrets.QUAY_PASSWORD }}
|
| 179 |
+
|
| 180 |
+
- name: Clean Docker cache before build
|
| 181 |
+
run: |
|
| 182 |
+
docker system prune -a -f --volumes || true
|
| 183 |
+
|
| 184 |
+
- name: Build and push by digest (v0.7.1 image)
|
| 185 |
+
uses: docker/build-push-action@v6
|
| 186 |
+
id: build_v071
|
| 187 |
+
with:
|
| 188 |
+
context: .
|
| 189 |
+
platforms: ${{ matrix.arch }}
|
| 190 |
+
file: ./docker/ascend/Dockerfile.ascend_8.5.0_a3_v0.7.1
|
| 191 |
+
push: true
|
| 192 |
+
outputs: type=image,name=${{ env.QUAY_REPO }},push-by-digest=true,name-canonical=true,push=true
|
| 193 |
+
provenance: false
|
| 194 |
+
cache-from: type=gha
|
| 195 |
+
cache-to: type=gha,mode=max
|
| 196 |
+
build-args: |
|
| 197 |
+
BUILDKIT_INLINE_CACHE=1
|
| 198 |
+
|
| 199 |
+
- name: Export digest (v0.7.1 image)
|
| 200 |
+
run: |
|
| 201 |
+
mkdir -p ${{ runner.temp }}/digests-v071
|
| 202 |
+
digest="${{ steps.build_v071.outputs.digest }}"
|
| 203 |
+
touch "${{ runner.temp }}/digests-v071/v071-${digest#sha256:}"
|
| 204 |
+
|
| 205 |
+
- name: Upload digest (v0.7.1 image)
|
| 206 |
+
uses: actions/upload-artifact@v4
|
| 207 |
+
with:
|
| 208 |
+
name: digests-v071-${{ matrix.tag }}
|
| 209 |
+
path: ${{ runner.temp }}/digests-v071/*
|
| 210 |
+
if-no-files-found: error
|
| 211 |
+
retention-days: 1
|
| 212 |
+
|
| 213 |
+
# ============================================================
|
| 214 |
+
# 第二阶段:合并多架构 manifest(main 镜像)
|
| 215 |
+
# ============================================================
|
| 216 |
+
merge-image:
|
| 217 |
+
name: merge
|
| 218 |
+
runs-on: ubuntu-latest
|
| 219 |
+
needs: build-push-digest
|
| 220 |
+
steps:
|
| 221 |
+
- name: Download digests (main image)
|
| 222 |
+
uses: actions/download-artifact@v4
|
| 223 |
+
with:
|
| 224 |
+
path: ${{ runner.temp }}/digests-main
|
| 225 |
+
pattern: digests-main-*
|
| 226 |
+
merge-multiple: true
|
| 227 |
+
|
| 228 |
+
- name: Login to Quay.io
|
| 229 |
+
uses: docker/login-action@v3
|
| 230 |
+
with:
|
| 231 |
+
registry: quay.io
|
| 232 |
+
username: ${{ secrets.QUAY_USERNAME }}
|
| 233 |
+
password: ${{ secrets.QUAY_PASSWORD }}
|
| 234 |
+
|
| 235 |
+
- name: Set up Docker Buildx
|
| 236 |
+
uses: docker/setup-buildx-action@v3
|
| 237 |
+
|
| 238 |
+
- name: Merge and push multi-arch image (main)
|
| 239 |
+
env:
|
| 240 |
+
IMAGE: ${{ env.QUAY_REPO }}
|
| 241 |
+
run: |
|
| 242 |
+
DIGESTS=$(printf "$IMAGE@sha256:%s " $(ls ${{ runner.temp }}/digests-main | sed 's/^main-//'))
|
| 243 |
+
echo "Main image digests: $DIGESTS"
|
| 244 |
+
docker buildx imagetools create \
|
| 245 |
+
-t "$IMAGE:${{ needs.build-push-digest.outputs.tag }}" \
|
| 246 |
+
$DIGESTS
|
| 247 |
+
|
| 248 |
+
# ============================================================
|
| 249 |
+
# 第二阶段(v0.7.1):合并多架构 manifest
|
| 250 |
+
# ============================================================
|
| 251 |
+
merge-image-v071:
|
| 252 |
+
name: merge-v0.7.1
|
| 253 |
+
runs-on: ubuntu-latest
|
| 254 |
+
needs: build-push-digest-v071
|
| 255 |
+
steps:
|
| 256 |
+
- name: Download digests (v0.7.1 image)
|
| 257 |
+
uses: actions/download-artifact@v4
|
| 258 |
+
with:
|
| 259 |
+
path: ${{ runner.temp }}/digests-v071
|
| 260 |
+
pattern: digests-v071-*
|
| 261 |
+
merge-multiple: true
|
| 262 |
+
|
| 263 |
+
- name: Login to Quay.io
|
| 264 |
+
uses: docker/login-action@v3
|
| 265 |
+
with:
|
| 266 |
+
registry: quay.io
|
| 267 |
+
username: ${{ secrets.QUAY_USERNAME }}
|
| 268 |
+
password: ${{ secrets.QUAY_PASSWORD }}
|
| 269 |
+
|
| 270 |
+
- name: Set up Docker Buildx
|
| 271 |
+
uses: docker/setup-buildx-action@v3
|
| 272 |
+
|
| 273 |
+
- name: Merge and push multi-arch image (v0.7.1)
|
| 274 |
+
env:
|
| 275 |
+
IMAGE: ${{ env.QUAY_REPO }}
|
| 276 |
+
run: |
|
| 277 |
+
DIGESTS=$(printf "$IMAGE@sha256:%s " $(ls ${{ runner.temp }}/digests-v071 | sed 's/^v071-//'))
|
| 278 |
+
echo "v0.7.1 image digests: $DIGESTS"
|
| 279 |
+
docker buildx imagetools create \
|
| 280 |
+
-t "$IMAGE:verl-8.5.0-a3-ubuntu22.04-py3.11-v0.7.1" \
|
| 281 |
+
$DIGESTS
|
verl/.github/workflows/docker-build-ascend-sglang-a2.yml
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: docker-build-ascend-sglang-a2
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
workflow_dispatch:
|
| 5 |
+
push:
|
| 6 |
+
branches: ["main"]
|
| 7 |
+
paths:
|
| 8 |
+
- "docker/ascend/Dockerfile.ascend.sglang_8.5.0_a2"
|
| 9 |
+
- ".github/workflows/docker-build-ascend-sglang-a2.yml"
|
| 10 |
+
release:
|
| 11 |
+
types: [published]
|
| 12 |
+
schedule:
|
| 13 |
+
- cron: "0 16 * * *"
|
| 14 |
+
|
| 15 |
+
jobs:
|
| 16 |
+
build-ascend-sglang-image-a2:
|
| 17 |
+
if: ${{ github.event_name != 'pull_request' && github.repository_owner == 'verl-project' }}
|
| 18 |
+
runs-on: ubuntu-latest
|
| 19 |
+
concurrency:
|
| 20 |
+
group: ${{ github.workflow }}-${{ github.ref }}-build-ascend-sglang-image-a2
|
| 21 |
+
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
| 22 |
+
steps:
|
| 23 |
+
- name: Remove unnecessary parts in github actions runners to free up disk space
|
| 24 |
+
uses: jlumbroso/free-disk-space@v1.3.1
|
| 25 |
+
with:
|
| 26 |
+
tool-cache: true
|
| 27 |
+
|
| 28 |
+
- name: Checkout code
|
| 29 |
+
uses: actions/checkout@v4
|
| 30 |
+
|
| 31 |
+
- name: Set up Python
|
| 32 |
+
uses: actions/setup-python@v5
|
| 33 |
+
with:
|
| 34 |
+
python-version: "3.11"
|
| 35 |
+
|
| 36 |
+
- name: Get base image name and tag
|
| 37 |
+
id: base_image
|
| 38 |
+
run: |
|
| 39 |
+
BASE_IMAGE_FULL=$(grep '^FROM' ./docker/ascend/Dockerfile.ascend.sglang_8.5.0_a2 | head -1 | cut -d' ' -f2)
|
| 40 |
+
echo "Base image full: $BASE_IMAGE_FULL"
|
| 41 |
+
BASE_IMAGE_TAG=$(echo "$BASE_IMAGE_FULL" | cut -d':' -f2)
|
| 42 |
+
echo "Base image tag: $BASE_IMAGE_TAG"
|
| 43 |
+
NEW_IMAGE_NAME="verl-sglang-$BASE_IMAGE_TAG"
|
| 44 |
+
echo "New image name: $NEW_IMAGE_NAME"
|
| 45 |
+
echo "base_image_tag=$BASE_IMAGE_TAG" >> "$GITHUB_OUTPUT"
|
| 46 |
+
echo "new_image_name=$NEW_IMAGE_NAME" >> "$GITHUB_OUTPUT"
|
| 47 |
+
|
| 48 |
+
- name: Get image tag
|
| 49 |
+
id: version
|
| 50 |
+
run: |
|
| 51 |
+
BRANCH_NAME=$(echo "${{ github.ref }}" | sed 's/refs\/heads\///g' | sed 's/[^a-zA-Z0-9._-]/_/g')
|
| 52 |
+
if [ "${{ github.event_name }}" = "release" ]; then
|
| 53 |
+
echo "tag=${{ steps.base_image.outputs.new_image_name }}-${{ github.event.release.tag_name }}" >> "$GITHUB_OUTPUT"
|
| 54 |
+
elif [ "$BRANCH_NAME" = "main" ]; then
|
| 55 |
+
echo "tag=${{ steps.base_image.outputs.new_image_name }}-latest" >> "$GITHUB_OUTPUT"
|
| 56 |
+
fi
|
| 57 |
+
|
| 58 |
+
- name: Set up Docker Buildx
|
| 59 |
+
uses: docker/setup-buildx-action@v3
|
| 60 |
+
|
| 61 |
+
- name: Login to Quay.io
|
| 62 |
+
uses: docker/login-action@v3
|
| 63 |
+
with:
|
| 64 |
+
registry: quay.io
|
| 65 |
+
username: ${{ secrets.QUAY_USERNAME }}
|
| 66 |
+
password: ${{ secrets.QUAY_PASSWORD }}
|
| 67 |
+
|
| 68 |
+
- name: Clean Docker cache before build
|
| 69 |
+
run: |
|
| 70 |
+
docker system prune -a -f --volumes || true
|
| 71 |
+
|
| 72 |
+
- name: Build and push images Quay
|
| 73 |
+
uses: docker/build-push-action@v6
|
| 74 |
+
with:
|
| 75 |
+
context: .
|
| 76 |
+
platforms: linux/amd64,linux/arm64
|
| 77 |
+
file: ./docker/ascend/Dockerfile.ascend.sglang_8.5.0_a2
|
| 78 |
+
push: true
|
| 79 |
+
tags: |
|
| 80 |
+
quay.io/ascend/verl:${{ steps.version.outputs.tag }}
|
| 81 |
+
cache-from: type=gha
|
| 82 |
+
cache-to: type=gha,mode=max
|
| 83 |
+
build-args: |
|
| 84 |
+
BUILDKIT_INLINE_CACHE=1
|
verl/.github/workflows/docker-build-ascend-sglang-a3.yml
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: docker-build-ascend-sglang-a3
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
workflow_dispatch:
|
| 5 |
+
push:
|
| 6 |
+
branches: ["main"]
|
| 7 |
+
paths:
|
| 8 |
+
- "docker/ascend/Dockerfile.ascend.sglang_8.5.0_a3"
|
| 9 |
+
- ".github/workflows/docker-build-ascend-sglang-a3.yml"
|
| 10 |
+
release:
|
| 11 |
+
types: [published]
|
| 12 |
+
schedule:
|
| 13 |
+
- cron: "0 16 * * *"
|
| 14 |
+
|
| 15 |
+
jobs:
|
| 16 |
+
build-ascend-sglang-image-a3:
|
| 17 |
+
if: ${{ github.event_name != 'pull_request' && github.repository_owner == 'verl-project' }}
|
| 18 |
+
runs-on: ubuntu-latest
|
| 19 |
+
concurrency:
|
| 20 |
+
group: ${{ github.workflow }}-${{ github.ref }}-build-ascend-sglang-image-a3
|
| 21 |
+
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
| 22 |
+
steps:
|
| 23 |
+
- name: Remove unnecessary parts in github actions runners to free up disk space
|
| 24 |
+
uses: jlumbroso/free-disk-space@v1.3.1
|
| 25 |
+
with:
|
| 26 |
+
tool-cache: true
|
| 27 |
+
|
| 28 |
+
- name: Checkout code
|
| 29 |
+
uses: actions/checkout@v4
|
| 30 |
+
|
| 31 |
+
- name: Set up Python
|
| 32 |
+
uses: actions/setup-python@v5
|
| 33 |
+
with:
|
| 34 |
+
python-version: "3.11"
|
| 35 |
+
|
| 36 |
+
- name: Get base image name and tag
|
| 37 |
+
id: base_image
|
| 38 |
+
run: |
|
| 39 |
+
BASE_IMAGE_FULL=$(grep '^FROM' ./docker/ascend/Dockerfile.ascend.sglang_8.5.0_a3 | head -1 | cut -d' ' -f2)
|
| 40 |
+
echo "Base image full: $BASE_IMAGE_FULL"
|
| 41 |
+
BASE_IMAGE_TAG=$(echo "$BASE_IMAGE_FULL" | cut -d':' -f2)
|
| 42 |
+
echo "Base image tag: $BASE_IMAGE_TAG"
|
| 43 |
+
NEW_IMAGE_NAME="verl-sglang-$BASE_IMAGE_TAG"
|
| 44 |
+
echo "New image name: $NEW_IMAGE_NAME"
|
| 45 |
+
echo "base_image_tag=$BASE_IMAGE_TAG" >> "$GITHUB_OUTPUT"
|
| 46 |
+
echo "new_image_name=$NEW_IMAGE_NAME" >> "$GITHUB_OUTPUT"
|
| 47 |
+
|
| 48 |
+
- name: Get image tag
|
| 49 |
+
id: version
|
| 50 |
+
run: |
|
| 51 |
+
BRANCH_NAME=$(echo "${{ github.ref }}" | sed 's/refs\/heads\///g' | sed 's/[^a-zA-Z0-9._-]/_/g')
|
| 52 |
+
if [ "${{ github.event_name }}" = "release" ]; then
|
| 53 |
+
echo "tag=${{ steps.base_image.outputs.new_image_name }}-${{ github.event.release.tag_name }}" >> "$GITHUB_OUTPUT"
|
| 54 |
+
elif [ "$BRANCH_NAME" = "main" ]; then
|
| 55 |
+
echo "tag=${{ steps.base_image.outputs.new_image_name }}-latest" >> "$GITHUB_OUTPUT"
|
| 56 |
+
fi
|
| 57 |
+
|
| 58 |
+
- name: Set up Docker Buildx
|
| 59 |
+
uses: docker/setup-buildx-action@v3
|
| 60 |
+
|
| 61 |
+
- name: Login to Quay.io
|
| 62 |
+
uses: docker/login-action@v3
|
| 63 |
+
with:
|
| 64 |
+
registry: quay.io
|
| 65 |
+
username: ${{ secrets.QUAY_USERNAME }}
|
| 66 |
+
password: ${{ secrets.QUAY_PASSWORD }}
|
| 67 |
+
|
| 68 |
+
- name: Clean Docker cache before build
|
| 69 |
+
run: |
|
| 70 |
+
docker system prune -a -f --volumes || true
|
| 71 |
+
|
| 72 |
+
- name: Build and push images Quay
|
| 73 |
+
uses: docker/build-push-action@v6
|
| 74 |
+
with:
|
| 75 |
+
context: .
|
| 76 |
+
platforms: linux/amd64,linux/arm64
|
| 77 |
+
file: ./docker/ascend/Dockerfile.ascend.sglang_8.5.0_a3
|
| 78 |
+
push: true
|
| 79 |
+
tags: |
|
| 80 |
+
quay.io/ascend/verl:${{ steps.version.outputs.tag }}
|
| 81 |
+
cache-from: type=gha
|
| 82 |
+
cache-to: type=gha,mode=max
|
| 83 |
+
build-args: |
|
| 84 |
+
BUILDKIT_INLINE_CACHE=1
|
verl/.github/workflows/e2e_ascend.yml
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# # Tests layout
|
| 2 |
+
|
| 3 |
+
# Each folder under tests/ corresponds to a test category for a sub-namespace in verl. For instance:
|
| 4 |
+
# - `tests/trainer` for testing functionality related to `verl/trainer`
|
| 5 |
+
# - `tests/models` for testing functionality related to `verl/models`
|
| 6 |
+
# - ...
|
| 7 |
+
|
| 8 |
+
# There are a few folders with `special_` prefix, created for special purposes:
|
| 9 |
+
# - `special_distributed`: unit tests that must run with multiple GPUs
|
| 10 |
+
# - `special_e2e`: end-to-end tests with training/generation scripts
|
| 11 |
+
# - `special_npu`: tests for NPUs
|
| 12 |
+
# - `special_sanity`: a suite of quick sanity tests
|
| 13 |
+
# - `special_standalone`: a set of test that are designed to run in dedicated environments
|
| 14 |
+
|
| 15 |
+
# Accelerators for tests
|
| 16 |
+
# - By default tests are run with GPU available, except for the ones under `special_npu`, and any test script whose name ends with `on_cpu.py`.
|
| 17 |
+
# - For test scripts with `on_cpu.py` name suffix would be tested on CPU resources in linux environment.
|
| 18 |
+
|
| 19 |
+
# # Workflow layout
|
| 20 |
+
|
| 21 |
+
# All CI tests are configured by yaml files in `.github/workflows/`. Here's an overview of all test configs:
|
| 22 |
+
# 1. A list of always triggered CPU sanity tests: `check-pr-title.yml`, `secrets_scan.yml`, `check-pr-title,yml`, `pre-commit.yml`, `doc.yml`
|
| 23 |
+
# 2. Some heavy multi-GPU unit tests, such as `model.yml`, `vllm.yml`, `sgl.yml`
|
| 24 |
+
# 3. End-to-end tests: `e2e_*.yml`
|
| 25 |
+
# 4. Unit tests
|
| 26 |
+
# - `cpu_unit_tests.yml`, run pytest on all scripts with file name pattern `tests/**/test_*_on_cpu.py`
|
| 27 |
+
# - `gpu_unit_tests.yml`, run pytest on all scripts with file without the `on_cpu.py` suffix.
|
| 28 |
+
# - Since cpu/gpu unit tests by default runs all tests under `tests`, please make sure tests are manually excluded in them when
|
| 29 |
+
# - new workflow yaml is added to `.github/workflows`
|
| 30 |
+
# - new tests are added to workflow mentioned in 2.
|
| 31 |
+
|
| 32 |
+
name: e2e_ascend
|
| 33 |
+
|
| 34 |
+
on:
|
| 35 |
+
# Trigger the workflow on push or pull request,
|
| 36 |
+
# but only for the main branch
|
| 37 |
+
push:
|
| 38 |
+
branches:
|
| 39 |
+
- main
|
| 40 |
+
- v0.*
|
| 41 |
+
pull_request:
|
| 42 |
+
branches:
|
| 43 |
+
- main
|
| 44 |
+
paths:
|
| 45 |
+
- ".github/workflows/e2e_ascend.yml"
|
| 46 |
+
- "examples/data_preprocess/**"
|
| 47 |
+
- "examples/grpo_trainer/**"
|
| 48 |
+
- "examples/ppo_trainer/**"
|
| 49 |
+
- "examples/sft/**"
|
| 50 |
+
- "verl/experimental/one_step_off_policy/**"
|
| 51 |
+
- "tests/special_npu/**"
|
| 52 |
+
- "tests/special_sanity/check_device_api_usage.py"
|
| 53 |
+
- "verl/**"
|
| 54 |
+
- "pyproject.toml"
|
| 55 |
+
- "requirements-npu.txt"
|
| 56 |
+
- "setup.py"
|
| 57 |
+
|
| 58 |
+
# Cancel jobs on the same ref if a new one is triggered
|
| 59 |
+
concurrency:
|
| 60 |
+
group: ${{ github.workflow }}-${{ github.ref }}
|
| 61 |
+
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
| 62 |
+
|
| 63 |
+
permissions:
|
| 64 |
+
contents: read
|
| 65 |
+
|
| 66 |
+
jobs:
|
| 67 |
+
llm_rl_job:
|
| 68 |
+
if: github.repository_owner == 'verl-project'
|
| 69 |
+
name: E2E Ascend testing for RL training scenarios of LLM models
|
| 70 |
+
runs-on: linux-aarch64-a3-8
|
| 71 |
+
timeout-minutes: 120
|
| 72 |
+
container:
|
| 73 |
+
image: swr.cn-southwest-2.myhuaweicloud.com/modelfoundry/ascend-ci/verl/verl:verl-8.5.0-a3-ubuntu22.04-py3.11-latest
|
| 74 |
+
options: >-
|
| 75 |
+
--shm-size 16g
|
| 76 |
+
env:
|
| 77 |
+
HF_ENDPOINT: "https://hf-mirror.com"
|
| 78 |
+
HF_HUB_ENABLE_HF_TRANSFER: "0" # This is more stable
|
| 79 |
+
steps:
|
| 80 |
+
- name: Check npu and CANN info
|
| 81 |
+
run: |
|
| 82 |
+
cat /usr/local/Ascend/ascend-toolkit/latest/"$(uname -i)"-linux/ascend_toolkit_install.info
|
| 83 |
+
npu-smi info
|
| 84 |
+
- name: Check initial pip list from image
|
| 85 |
+
run: |
|
| 86 |
+
pip list
|
| 87 |
+
- name: Checkout verl-project/verl repo
|
| 88 |
+
uses: actions/checkout@v4
|
| 89 |
+
with:
|
| 90 |
+
fetch-depth: 0
|
| 91 |
+
clean: true
|
| 92 |
+
- name: Install the current repository
|
| 93 |
+
run: |
|
| 94 |
+
pip install --no-deps -e .
|
| 95 |
+
- name: Check final pip list
|
| 96 |
+
run: |
|
| 97 |
+
pip list
|
| 98 |
+
- name: Preprocess gsm8k dataset
|
| 99 |
+
run: |
|
| 100 |
+
python examples/data_preprocess/gsm8k.py --local_dataset_path ${HOME}/.cache/datasets/openai/gsm8k
|
| 101 |
+
- name: Running gsm8k e2e training tests with PPO on ASCEND NPU (FSDP backend)
|
| 102 |
+
run: |
|
| 103 |
+
ray stop --force
|
| 104 |
+
bash tests/special_npu/run_qwen3_06b_ppo.sh
|
| 105 |
+
rm -rf $HOME/ckpts
|
| 106 |
+
- name: Running gsm8k e2e training tests with GRPO on ASCEND NPU (FSDP backend)
|
| 107 |
+
run: |
|
| 108 |
+
ray stop --force
|
| 109 |
+
bash tests/special_npu/run_qwen2_5_05b_grpo.sh
|
| 110 |
+
rm -rf $HOME/ckpts
|
| 111 |
+
- name: Running gsm8k e2e training tests with GRPO on ASCEND NPU (MindSpeed backend)
|
| 112 |
+
run: |
|
| 113 |
+
ray stop --force
|
| 114 |
+
USE_DIST_CKPT=True bash tests/special_npu/run_qwen2_5_05b_grpo_mindspeed.sh
|
| 115 |
+
rm -rf $HOME/dist_ckpt/qwen2_5_05b_grpo_mindspeed
|
| 116 |
+
rm -rf $HOME/ckpts
|
| 117 |
+
- name: Running gsm8k e2e training tests with GRPO on ASCEND NPU (MindSpeed backend, MoE Model)
|
| 118 |
+
run: |
|
| 119 |
+
ray stop --force
|
| 120 |
+
USE_DIST_CKPT=True USE_DUMMY_MODEL=True DUMMY_MODEL_CONFIG_PATH=tests/special_e2e/ppo_trainer/expert_parallel/qwen3moe_minimal.json DUMMY_MODEL_PATH=$HOME/dist_ckpt/qwen3_30b_grpo_mindspeed bash tests/special_npu/run_qwen3_30b_grpo_mindspeed.sh
|
| 121 |
+
|
| 122 |
+
engine_mindspeed_llm_rl_job:
|
| 123 |
+
if: github.repository_owner == 'verl-project'
|
| 124 |
+
name: E2E Ascend testing for RL training scenarios of LLM models using MindSpeed_LLM engine
|
| 125 |
+
runs-on: linux-aarch64-a3-8
|
| 126 |
+
timeout-minutes: 120
|
| 127 |
+
container:
|
| 128 |
+
image: swr.cn-southwest-2.myhuaweicloud.com/modelfoundry/ascend-ci/verl/verl:verl-sglang-8.3.rc1-a3-ubuntu22.04-py3.11-latest
|
| 129 |
+
options: >-
|
| 130 |
+
--shm-size 16g
|
| 131 |
+
env:
|
| 132 |
+
HF_ENDPOINT: "https://hf-mirror.com"
|
| 133 |
+
HF_HUB_ENABLE_HF_TRANSFER: "0" # This is more stable
|
| 134 |
+
steps:
|
| 135 |
+
- name: Check npu and CANN info
|
| 136 |
+
run: |
|
| 137 |
+
cat /usr/local/Ascend/ascend-toolkit/latest/"$(uname -i)"-linux/ascend_toolkit_install.info
|
| 138 |
+
npu-smi info
|
| 139 |
+
- name: Check initial pip list from image
|
| 140 |
+
run: |
|
| 141 |
+
pip list
|
| 142 |
+
- name: Checkout verl-project/verl repo
|
| 143 |
+
uses: actions/checkout@v4
|
| 144 |
+
with:
|
| 145 |
+
fetch-depth: 0
|
| 146 |
+
clean: true
|
| 147 |
+
- name: Install the current repository
|
| 148 |
+
run: |
|
| 149 |
+
pip install --no-deps --no-build-isolation -e .
|
| 150 |
+
- name: Check final pip list
|
| 151 |
+
run: |
|
| 152 |
+
pip list
|
| 153 |
+
- name: Configure related dependencies
|
| 154 |
+
run: |
|
| 155 |
+
git clone --depth 1 --branch core_v0.12.1 https://github.com/NVIDIA/Megatron-LM.git /Megatron-LM
|
| 156 |
+
rm -rf /MindSpeed
|
| 157 |
+
git clone https://gitcode.com/ascend/MindSpeed.git /MindSpeed
|
| 158 |
+
git clone https://gitcode.com/ascend/MindSpeed-LLM.git /MindSpeed-LLM
|
| 159 |
+
- name: Preprocess gsm8k dataset
|
| 160 |
+
run: |
|
| 161 |
+
python examples/data_preprocess/gsm8k.py --local_dataset_path ${HOME}/.cache/datasets/openai/gsm8k
|
| 162 |
+
- name: Running gsm8k e2e training tests with GRPO on ASCEND NPU (MindSpeedLLM backend)
|
| 163 |
+
run: |
|
| 164 |
+
ray stop --force
|
| 165 |
+
export PYTHONPATH=$PYTHONPATH:/Megatron-LM
|
| 166 |
+
export PYTHONPATH=$PYTHONPATH:/MindSpeed
|
| 167 |
+
export PYTHONPATH=$PYTHONPATH:/MindSpeed-LLM
|
| 168 |
+
bash tests/special_npu/run_qwen3_8b_grpo_mindspeedllm.sh
|
| 169 |
+
- name: Running gsm8k e2e training tests with GRPO on ASCEND NPU (MindSpeedLLM backend, MoE Model)
|
| 170 |
+
run: |
|
| 171 |
+
ray stop --force
|
| 172 |
+
export PYTHONPATH=$PYTHONPATH:/Megatron-LM
|
| 173 |
+
export PYTHONPATH=$PYTHONPATH:/MindSpeed
|
| 174 |
+
export PYTHONPATH=$PYTHONPATH:/MindSpeed-LLM
|
| 175 |
+
USE_DIST_CKPT=True USE_DUMMY_MODEL=True DUMMY_MODEL_CONFIG_PATH=tests/special_e2e/ppo_trainer/expert_parallel/qwen3moe_minimal.json DUMMY_MODEL_PATH=$HOME/dist_ckpt/qwen3_30b_grpo_mindspeedllm bash tests/special_npu/run_qwen3_30b_grpo_mindspeedllm.sh
|
| 176 |
+
|
| 177 |
+
vlm_rl_job:
|
| 178 |
+
if: github.repository_owner == 'verl-project'
|
| 179 |
+
name: E2E Ascend testing for RL training scenarios of VLM models
|
| 180 |
+
runs-on: linux-aarch64-a3-8
|
| 181 |
+
timeout-minutes: 120
|
| 182 |
+
container:
|
| 183 |
+
image: swr.cn-southwest-2.myhuaweicloud.com/modelfoundry/ascend-ci/verl/verl:verl-8.5.0-a3-ubuntu22.04-py3.11-latest
|
| 184 |
+
options: >-
|
| 185 |
+
--shm-size 16g
|
| 186 |
+
env:
|
| 187 |
+
HF_ENDPOINT: "https://hf-mirror.com"
|
| 188 |
+
HF_HUB_ENABLE_HF_TRANSFER: "0" # This is more stable
|
| 189 |
+
steps:
|
| 190 |
+
- name: Check npu and CANN info
|
| 191 |
+
run: |
|
| 192 |
+
cat /usr/local/Ascend/ascend-toolkit/latest/"$(uname -i)"-linux/ascend_toolkit_install.info
|
| 193 |
+
npu-smi info
|
| 194 |
+
- name: Check initial pip list from image
|
| 195 |
+
run: |
|
| 196 |
+
pip list
|
| 197 |
+
- name: Checkout verl-project/verl repo
|
| 198 |
+
uses: actions/checkout@v4
|
| 199 |
+
with:
|
| 200 |
+
fetch-depth: 0
|
| 201 |
+
clean: true
|
| 202 |
+
- name: Install the current repository
|
| 203 |
+
run: |
|
| 204 |
+
pip install --no-deps -e .
|
| 205 |
+
- name: Check final pip list
|
| 206 |
+
run: |
|
| 207 |
+
pip list
|
| 208 |
+
- name: Preprocess geo3k dataset
|
| 209 |
+
run: |
|
| 210 |
+
python examples/data_preprocess/geo3k.py --local_dataset_path ${HOME}/.cache/datasets/hiyouga/geometry3k
|
| 211 |
+
- name: Running geo3k e2e training tests with GRPO on ASCEND NPU
|
| 212 |
+
run: |
|
| 213 |
+
ray stop --force
|
| 214 |
+
bash tests/special_npu/run_qwen2_5_vl_3b_npu.sh
|
| 215 |
+
rm -rf $HOME/ckpts
|
verl/.github/workflows/e2e_fully_async_policy.yml
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# # Tests layout
|
| 2 |
+
|
| 3 |
+
# Each folder under tests/ corresponds to a test category for a sub-namespace in verl. For instance:
|
| 4 |
+
# - `tests/trainer` for testing functionality related to `verl/trainer`
|
| 5 |
+
# - `tests/models` for testing functionality related to `verl/models`
|
| 6 |
+
# - ...
|
| 7 |
+
|
| 8 |
+
# There are a few folders with `special_` prefix, created for special purposes:
|
| 9 |
+
# - `special_distributed`: unit tests that must run with multiple GPUs
|
| 10 |
+
# - `special_e2e`: end-to-end tests with training/generation scripts
|
| 11 |
+
# - `special_npu`: tests for NPUs
|
| 12 |
+
# - `special_sanity`: a suite of quick sanity tests
|
| 13 |
+
# - `special_standalone`: a set of test that are designed to run in dedicated environments
|
| 14 |
+
|
| 15 |
+
# Accelerators for tests
|
| 16 |
+
# - By default tests are run with GPU available, except for the ones under `special_npu`, and any test script whose name ends with `on_cpu.py`.
|
| 17 |
+
# - For test scripts with `on_cpu.py` name suffix would be tested on CPU resources in linux environment.
|
| 18 |
+
|
| 19 |
+
# # Workflow layout
|
| 20 |
+
|
| 21 |
+
# All CI tests are configured by yaml files in `.github/workflows/`. Here's an overview of all test configs:
|
| 22 |
+
# 1. A list of always triggered CPU sanity tests: `check-pr-title.yml`, `secrets_scan.yml`, `check-pr-title,yml`, `pre-commit.yml`, `doc.yml`
|
| 23 |
+
# 2. Some heavy multi-GPU unit tests, such as `model.yml`, `vllm.yml`, `sgl.yml`
|
| 24 |
+
# 3. End-to-end tests: `e2e_*.yml`
|
| 25 |
+
# 4. Unit tests
|
| 26 |
+
# - `cpu_unit_tests.yml`, run pytest on all scripts with file name pattern `tests/**/test_*_on_cpu.py`
|
| 27 |
+
# - `gpu_unit_tests.yml`, run pytest on all scripts with file without the `on_cpu.py` suffix.
|
| 28 |
+
# - Since cpu/gpu unit tests by default runs all tests under `tests`, please make sure tests are manually excluded in them when
|
| 29 |
+
# - new workflow yaml is added to `.github/workflows`
|
| 30 |
+
# - new tests are added to workflow mentioned in 2.
|
| 31 |
+
|
| 32 |
+
name: e2e_fully_async_policy
|
| 33 |
+
|
| 34 |
+
on:
|
| 35 |
+
# Trigger the workflow on push or pull request,
|
| 36 |
+
# but only for the main branch
|
| 37 |
+
# For push, for now only anti-patterns are specified so it is more conservative
|
| 38 |
+
# and achieves higher coverage.
|
| 39 |
+
push:
|
| 40 |
+
branches:
|
| 41 |
+
- main
|
| 42 |
+
- v0.*
|
| 43 |
+
paths:
|
| 44 |
+
- "**/*.py"
|
| 45 |
+
- "!**/*.md"
|
| 46 |
+
- "!**/*.sh"
|
| 47 |
+
# Other entrypoints
|
| 48 |
+
- "!examples/*trainer*"
|
| 49 |
+
- "!tests/**"
|
| 50 |
+
- "!verl/trainer/main_*.py"
|
| 51 |
+
- "!verl/trainer/fsdp_sft_trainer.py"
|
| 52 |
+
- "verl/experimental/fully_async_policy"
|
| 53 |
+
pull_request:
|
| 54 |
+
branches:
|
| 55 |
+
- main
|
| 56 |
+
- v0.*
|
| 57 |
+
paths:
|
| 58 |
+
- "**/*.py"
|
| 59 |
+
- "!**/*.md"
|
| 60 |
+
- "!**/*.sh"
|
| 61 |
+
# Other entrypoints
|
| 62 |
+
- "!examples/**"
|
| 63 |
+
- "!tests/**"
|
| 64 |
+
- "!verl/trainer/main_*.py"
|
| 65 |
+
- "!verl/trainer/fsdp_sft_trainer.py"
|
| 66 |
+
# Home
|
| 67 |
+
- "verl/experimental/fully_async_policy"
|
| 68 |
+
# Entrypoints
|
| 69 |
+
- ".github/workflows/e2e_fully_async_policy.yml"
|
| 70 |
+
- "examples/data_preprocess/gsm8k.py"
|
| 71 |
+
- "tests/special_e2e/run_fully_async_policy.sh"
|
| 72 |
+
|
| 73 |
+
# Cancel jobs on the same ref if a new one is triggered
|
| 74 |
+
concurrency:
|
| 75 |
+
group: ${{ github.workflow }}-${{ github.ref }}
|
| 76 |
+
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
| 77 |
+
|
| 78 |
+
# Declare permissions just read content.
|
| 79 |
+
permissions:
|
| 80 |
+
contents: read
|
| 81 |
+
|
| 82 |
+
env:
|
| 83 |
+
IMAGE: "verl-ci-cn-beijing.cr.volces.com/verlai/verl:vllm018.dev1"
|
| 84 |
+
DYNAMIC_RUNNER_ENDPOINT: "https://sd10g3clalm04ug7alq90.apigateway-cn-beijing.volceapi.com/runner"
|
| 85 |
+
|
| 86 |
+
jobs:
|
| 87 |
+
setup:
|
| 88 |
+
if: github.repository_owner == 'verl-project'
|
| 89 |
+
runs-on: ubuntu-latest
|
| 90 |
+
outputs:
|
| 91 |
+
runner-label: ${{ steps.create-runner.outputs.runner-label }}
|
| 92 |
+
mlp-task-id: ${{ steps.create-runner.outputs.mlp-task-id }}
|
| 93 |
+
steps:
|
| 94 |
+
- uses: actions/checkout@v4
|
| 95 |
+
- id: create-runner
|
| 96 |
+
uses: volcengine/vemlp-github-runner@v1
|
| 97 |
+
with:
|
| 98 |
+
mode: "create"
|
| 99 |
+
faas-url: "${{ env.DYNAMIC_RUNNER_ENDPOINT }}"
|
| 100 |
+
mlp-image: "${{ env.IMAGE }}"
|
| 101 |
+
|
| 102 |
+
# Test FSDP2 strategy
|
| 103 |
+
e2e_fully_async_policy_fsdp2:
|
| 104 |
+
needs: setup
|
| 105 |
+
runs-on: ["${{ needs.setup.outputs.runner-label || 'L20x8' }}"]
|
| 106 |
+
timeout-minutes: 10 # Increase timeout for async training
|
| 107 |
+
env:
|
| 108 |
+
HTTPS_PROXY: ${{ secrets.PROXY_HTTPS }}
|
| 109 |
+
NO_PROXY: "localhost,127.0.0.1,hf-mirror.com"
|
| 110 |
+
HF_ENDPOINT: "https://hf-mirror.com"
|
| 111 |
+
HF_HUB_ENABLE_HF_TRANSFER: "0" # This is more stable
|
| 112 |
+
ACTOR_STRATEGY: "fsdp2"
|
| 113 |
+
steps:
|
| 114 |
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
| 115 |
+
with:
|
| 116 |
+
fetch-depth: 0
|
| 117 |
+
- name: Install the current repository
|
| 118 |
+
run: |
|
| 119 |
+
pip3 install -r requirements-test.txt
|
| 120 |
+
pip3 install --no-deps -e .
|
| 121 |
+
pip3 install cupy-cuda12x==13.6.0
|
| 122 |
+
- name: Prepare GSM8K dataset
|
| 123 |
+
run: |
|
| 124 |
+
python3 examples/data_preprocess/gsm8k.py --local_dataset_path ${HOME}/models/hf_data/gsm8k
|
| 125 |
+
- name: Running the E2E test with fully_async_policy algorithm (FSDP2)
|
| 126 |
+
run: |
|
| 127 |
+
ray stop --force
|
| 128 |
+
bash tests/special_e2e/run_fully_async_policy.sh
|
| 129 |
+
|
| 130 |
+
# Test Megatron strategy
|
| 131 |
+
e2e_fully_async_policy_megatron:
|
| 132 |
+
needs: setup
|
| 133 |
+
runs-on: ["${{ needs.setup.outputs.runner-label || 'L20x8' }}"]
|
| 134 |
+
timeout-minutes: 10 # Increase timeout for async training
|
| 135 |
+
env:
|
| 136 |
+
HTTPS_PROXY: ${{ secrets.PROXY_HTTPS }}
|
| 137 |
+
NO_PROXY: "localhost,127.0.0.1,hf-mirror.com"
|
| 138 |
+
HF_ENDPOINT: "https://hf-mirror.com"
|
| 139 |
+
HF_HUB_ENABLE_HF_TRANSFER: "0" # This is more stable
|
| 140 |
+
ACTOR_STRATEGY: "megatron"
|
| 141 |
+
steps:
|
| 142 |
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
| 143 |
+
with:
|
| 144 |
+
fetch-depth: 0
|
| 145 |
+
- name: Install the current repository
|
| 146 |
+
run: |
|
| 147 |
+
pip3 install -r requirements-test.txt
|
| 148 |
+
pip3 install --no-deps -e .
|
| 149 |
+
pip3 install cupy-cuda12x==13.6.0
|
| 150 |
+
pip3 install git+https://github.com/ISEEKYAN/mbridge.git@main --no-deps --no-build-isolation
|
| 151 |
+
- name: Prepare GSM8K dataset
|
| 152 |
+
run: |
|
| 153 |
+
python3 examples/data_preprocess/gsm8k.py --local_dataset_path ${HOME}/models/hf_data/gsm8k
|
| 154 |
+
- name: Running the E2E test with fully_async_policy algorithm (Megatron)
|
| 155 |
+
run: |
|
| 156 |
+
ray stop --force
|
| 157 |
+
bash tests/special_e2e/run_fully_async_policy.sh
|
| 158 |
+
|
| 159 |
+
cleanup:
|
| 160 |
+
runs-on: ubuntu-latest
|
| 161 |
+
needs: [setup, e2e_fully_async_policy_fsdp2]
|
| 162 |
+
if: always()
|
| 163 |
+
steps:
|
| 164 |
+
- id: destroy-runner
|
| 165 |
+
uses: volcengine/vemlp-github-runner@v1
|
| 166 |
+
with:
|
| 167 |
+
mode: "destroy"
|
| 168 |
+
faas-url: "${{ env.DYNAMIC_RUNNER_ENDPOINT }}"
|
| 169 |
+
mlp-task-id: "${{ needs.setup.outputs.mlp-task-id }}"
|
verl/.github/workflows/e2e_fully_async_policy_ascend.yml
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# # Tests layout
|
| 2 |
+
|
| 3 |
+
# Each folder under tests/ corresponds to a test category for a sub-namespace in verl. For instance:
|
| 4 |
+
# - `tests/trainer` for testing functionality related to `verl/trainer`
|
| 5 |
+
# - `tests/models` for testing functionality related to `verl/models`
|
| 6 |
+
# - ...
|
| 7 |
+
|
| 8 |
+
# There are a few folders with `special_` prefix, created for special purposes:
|
| 9 |
+
# - `special_distributed`: unit tests that must run with multiple GPUs
|
| 10 |
+
# - `special_e2e`: end-to-end tests with training/generation scripts
|
| 11 |
+
# - `special_npu`: tests for NPUs
|
| 12 |
+
# - `special_sanity`: a suite of quick sanity tests
|
| 13 |
+
# - `special_standalone`: a set of test that are designed to run in dedicated environments
|
| 14 |
+
|
| 15 |
+
# Accelerators for tests
|
| 16 |
+
# - By default tests are run with GPU available, except for the ones under `special_npu`, and any test script whose name ends with `on_cpu.py`.
|
| 17 |
+
# - For test scripts with `on_cpu.py` name suffix would be tested on CPU resources in linux environment.
|
| 18 |
+
|
| 19 |
+
# # Workflow layout
|
| 20 |
+
|
| 21 |
+
# All CI tests are configured by yaml files in `.github/workflows/`. Here's an overview of all test configs:
|
| 22 |
+
# 1. A list of always triggered CPU sanity tests: `check-pr-title.yml`, `secrets_scan.yml`, `check-pr-title,yml`, `pre-commit.yml`, `doc.yml`
|
| 23 |
+
# 2. Some heavy multi-GPU unit tests, such as `model.yml`, `vllm.yml`, `sgl.yml`
|
| 24 |
+
# 3. End-to-end tests: `e2e_*.yml`
|
| 25 |
+
# 4. Unit tests
|
| 26 |
+
# - `cpu_unit_tests.yml`, run pytest on all scripts with file name pattern `tests/**/test_*_on_cpu.py`
|
| 27 |
+
# - `gpu_unit_tests.yml`, run pytest on all scripts with file without the `on_cpu.py` suffix.
|
| 28 |
+
# - Since cpu/gpu unit tests by default runs all tests under `tests`, please make sure tests are manually excluded in them when
|
| 29 |
+
# - new workflow yaml is added to `.github/workflows`
|
| 30 |
+
# - new tests are added to workflow mentioned in 2.
|
| 31 |
+
|
| 32 |
+
name: e2e_fully_async_policy_ascend
|
| 33 |
+
|
| 34 |
+
on:
|
| 35 |
+
# Trigger the workflow on push or pull request,
|
| 36 |
+
# but only for the main branch
|
| 37 |
+
# For push, for now only anti-patterns are specified so it is more conservative
|
| 38 |
+
# and achieves higher coverage.
|
| 39 |
+
push:
|
| 40 |
+
branches:
|
| 41 |
+
- main
|
| 42 |
+
- v0.*
|
| 43 |
+
paths:
|
| 44 |
+
- "**/*.py"
|
| 45 |
+
- "!**/*.md"
|
| 46 |
+
- "!**/*.sh"
|
| 47 |
+
# Other entrypoints
|
| 48 |
+
- "!examples/*trainer*"
|
| 49 |
+
- "!tests/**"
|
| 50 |
+
- "!verl/trainer/main_*.py"
|
| 51 |
+
- "!verl/trainer/fsdp_sft_trainer.py"
|
| 52 |
+
- "verl/experimental/fully_async_policy"
|
| 53 |
+
pull_request:
|
| 54 |
+
branches:
|
| 55 |
+
- main
|
| 56 |
+
- v0.*
|
| 57 |
+
paths:
|
| 58 |
+
- "**/*.py"
|
| 59 |
+
- "!**/*.md"
|
| 60 |
+
- "!**/*.sh"
|
| 61 |
+
# Other entrypoints
|
| 62 |
+
- "!examples/**"
|
| 63 |
+
- "!tests/**"
|
| 64 |
+
- "!verl/trainer/main_*.py"
|
| 65 |
+
- "!verl/trainer/fsdp_sft_trainer.py"
|
| 66 |
+
# Home
|
| 67 |
+
- "verl/experimental/fully_async_policy"
|
| 68 |
+
# Entrypoints
|
| 69 |
+
- ".github/workflows/e2e_fully_async_policy_ascend.yml"
|
| 70 |
+
- "examples/data_preprocess/gsm8k.py"
|
| 71 |
+
- "tests/special_e2e/run_fully_async_policy.sh"
|
| 72 |
+
|
| 73 |
+
# Cancel jobs on the same ref if a new one is triggered
|
| 74 |
+
concurrency:
|
| 75 |
+
group: ${{ github.workflow }}-${{ github.ref }}
|
| 76 |
+
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
| 77 |
+
|
| 78 |
+
# Declare permissions just read content.
|
| 79 |
+
permissions:
|
| 80 |
+
contents: read
|
| 81 |
+
|
| 82 |
+
jobs:
|
| 83 |
+
# Test FSDP2 strategy
|
| 84 |
+
e2e_fully_async_policy_fsdp2_ascend:
|
| 85 |
+
if: github.repository_owner == 'verl-project'
|
| 86 |
+
runs-on: linux-aarch64-a3-8
|
| 87 |
+
timeout-minutes: 60 # Increase this timeout value as needed
|
| 88 |
+
container:
|
| 89 |
+
image: swr.cn-southwest-2.myhuaweicloud.com/modelfoundry/ascend-ci/verl/verl:verl-8.5.0-a3-ubuntu22.04-py3.11-latest
|
| 90 |
+
options: >-
|
| 91 |
+
--shm-size 16g
|
| 92 |
+
env:
|
| 93 |
+
HF_ENDPOINT: "https://hf-mirror.com"
|
| 94 |
+
HF_HUB_ENABLE_HF_TRANSFER: "0" # This is more stable
|
| 95 |
+
ACTOR_STRATEGY: "fsdp2"
|
| 96 |
+
device_name: "npu"
|
| 97 |
+
steps:
|
| 98 |
+
- name: Check npu and CANN info
|
| 99 |
+
run: |
|
| 100 |
+
cat /usr/local/Ascend/ascend-toolkit/latest/"$(uname -i)"-linux/ascend_toolkit_install.info
|
| 101 |
+
npu-smi info
|
| 102 |
+
- name: Check initial pip list from image
|
| 103 |
+
run: |
|
| 104 |
+
pip list
|
| 105 |
+
- name: Checkout verl-project/verl repo
|
| 106 |
+
uses: actions/checkout@v4
|
| 107 |
+
with:
|
| 108 |
+
fetch-depth: 0
|
| 109 |
+
clean: true
|
| 110 |
+
- name: Install the current repository
|
| 111 |
+
run: |
|
| 112 |
+
pip install --no-deps -e .
|
| 113 |
+
- name: Check final pip list
|
| 114 |
+
run: |
|
| 115 |
+
pip list
|
| 116 |
+
- name: Prepare weights
|
| 117 |
+
run: |
|
| 118 |
+
ln -s /root/.cache/models ~/models
|
| 119 |
+
- name: Prepare GSM8K dataset
|
| 120 |
+
run: |
|
| 121 |
+
python examples/data_preprocess/gsm8k.py --local_dataset_path ${HOME}/.cache/datasets/openai/gsm8k
|
| 122 |
+
- name: Running the E2E test with fully_async_policy algorithm (FSDP2)
|
| 123 |
+
run: |
|
| 124 |
+
ray stop --force
|
| 125 |
+
bash tests/special_e2e/run_fully_async_policy.sh
|
| 126 |
+
|
| 127 |
+
# Test Megatron strategy
|
| 128 |
+
e2e_fully_async_policy_megatron_ascend:
|
| 129 |
+
if: github.repository_owner == 'verl-project'
|
| 130 |
+
runs-on: linux-aarch64-a3-8
|
| 131 |
+
timeout-minutes: 60 # Increase this timeout value as needed
|
| 132 |
+
container:
|
| 133 |
+
image: swr.cn-southwest-2.myhuaweicloud.com/modelfoundry/ascend-ci/verl/verl:verl-8.5.0-a3-ubuntu22.04-py3.11-latest
|
| 134 |
+
options: >-
|
| 135 |
+
--shm-size 16g
|
| 136 |
+
env:
|
| 137 |
+
HF_ENDPOINT: "https://hf-mirror.com"
|
| 138 |
+
HF_HUB_ENABLE_HF_TRANSFER: "0" # This is more stable
|
| 139 |
+
ACTOR_STRATEGY: "megatron"
|
| 140 |
+
device_name: "npu"
|
| 141 |
+
steps:
|
| 142 |
+
- name: Check npu and CANN info
|
| 143 |
+
run: |
|
| 144 |
+
cat /usr/local/Ascend/ascend-toolkit/latest/"$(uname -i)"-linux/ascend_toolkit_install.info
|
| 145 |
+
npu-smi info
|
| 146 |
+
- name: Check initial pip list from image
|
| 147 |
+
run: |
|
| 148 |
+
pip list
|
| 149 |
+
- name: Checkout verl-project/verl repo
|
| 150 |
+
uses: actions/checkout@v4
|
| 151 |
+
with:
|
| 152 |
+
fetch-depth: 0
|
| 153 |
+
clean: true
|
| 154 |
+
- name: Install the current repository
|
| 155 |
+
run: |
|
| 156 |
+
pip install --no-deps -e .
|
| 157 |
+
- name: Check final pip list
|
| 158 |
+
run: |
|
| 159 |
+
pip list
|
| 160 |
+
- name: Prepare weights
|
| 161 |
+
run: |
|
| 162 |
+
ln -s /root/.cache/models ~/models
|
| 163 |
+
- name: Prepare GSM8K dataset
|
| 164 |
+
run: |
|
| 165 |
+
python examples/data_preprocess/gsm8k.py --local_dataset_path ${HOME}/.cache/datasets/openai/gsm8k
|
| 166 |
+
- name: Running the E2E test with fully_async_policy algorithm (Megatron)
|
| 167 |
+
run: |
|
| 168 |
+
ray stop --force
|
| 169 |
+
bash tests/special_e2e/run_fully_async_policy.sh
|
verl/.github/workflows/e2e_fully_async_policy_opd.yml
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: e2e_fully_async_policy_opd
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
push:
|
| 5 |
+
branches:
|
| 6 |
+
- main
|
| 7 |
+
- v0.*
|
| 8 |
+
paths:
|
| 9 |
+
- "**/*.py"
|
| 10 |
+
- "!**/*.md"
|
| 11 |
+
- "!**/*.sh"
|
| 12 |
+
- "!examples/*trainer*"
|
| 13 |
+
- "!tests/**"
|
| 14 |
+
- "!verl/trainer/main_*.py"
|
| 15 |
+
- "!verl/trainer/fsdp_sft_trainer.py"
|
| 16 |
+
- "verl/experimental/fully_async_policy"
|
| 17 |
+
- "verl/trainer/distillation"
|
| 18 |
+
pull_request:
|
| 19 |
+
branches:
|
| 20 |
+
- main
|
| 21 |
+
- v0.*
|
| 22 |
+
paths:
|
| 23 |
+
- "**/*.py"
|
| 24 |
+
- "!**/*.md"
|
| 25 |
+
- "!**/*.sh"
|
| 26 |
+
- "!examples/**"
|
| 27 |
+
- "!tests/**"
|
| 28 |
+
- "!verl/trainer/main_*.py"
|
| 29 |
+
- "!verl/trainer/fsdp_sft_trainer.py"
|
| 30 |
+
- "verl/experimental/fully_async_policy"
|
| 31 |
+
- "verl/trainer/distillation"
|
| 32 |
+
- ".github/workflows/e2e_fully_async_policy_opd.yml"
|
| 33 |
+
- "examples/data_preprocess/gsm8k.py"
|
| 34 |
+
- "examples/data_preprocess/geo3k.py"
|
| 35 |
+
- "tests/special_e2e/run_fully_async_policy_opd.sh"
|
| 36 |
+
|
| 37 |
+
# Cancel jobs on the same ref if a new one is triggered
|
| 38 |
+
concurrency:
|
| 39 |
+
group: ${{ github.workflow }}-${{ github.ref }}
|
| 40 |
+
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
| 41 |
+
|
| 42 |
+
# Declare permissions just read content.
|
| 43 |
+
permissions:
|
| 44 |
+
contents: read
|
| 45 |
+
|
| 46 |
+
env:
|
| 47 |
+
IMAGE: "verl-ci-cn-beijing.cr.volces.com/verlai/verl:vllm018.dev1"
|
| 48 |
+
DYNAMIC_RUNNER_ENDPOINT: "https://sd10g3clalm04ug7alq90.apigateway-cn-beijing.volceapi.com/runner"
|
| 49 |
+
|
| 50 |
+
jobs:
|
| 51 |
+
setup:
|
| 52 |
+
if: github.repository_owner == 'verl-project'
|
| 53 |
+
runs-on: ubuntu-latest
|
| 54 |
+
outputs:
|
| 55 |
+
runner-label: ${{ steps.create-runner.outputs.runner-label }}
|
| 56 |
+
mlp-task-id: ${{ steps.create-runner.outputs.mlp-task-id }}
|
| 57 |
+
steps:
|
| 58 |
+
- uses: actions/checkout@v4
|
| 59 |
+
- id: create-runner
|
| 60 |
+
uses: volcengine/vemlp-github-runner@v1
|
| 61 |
+
with:
|
| 62 |
+
mode: "create"
|
| 63 |
+
faas-url: "${{ env.DYNAMIC_RUNNER_ENDPOINT }}"
|
| 64 |
+
mlp-image: "${{ env.IMAGE }}"
|
| 65 |
+
|
| 66 |
+
# Test Multi-Teacher OPD with Megatron strategy
|
| 67 |
+
e2e_fully_async_policy_opd_megatron:
|
| 68 |
+
needs: setup
|
| 69 |
+
runs-on: ["${{ needs.setup.outputs.runner-label || 'L20x8' }}"]
|
| 70 |
+
timeout-minutes: 30
|
| 71 |
+
env:
|
| 72 |
+
HTTPS_PROXY: ${{ secrets.PROXY_HTTPS }}
|
| 73 |
+
NO_PROXY: "localhost,127.0.0.1,hf-mirror.com"
|
| 74 |
+
HF_ENDPOINT: "https://hf-mirror.com"
|
| 75 |
+
HF_HUB_ENABLE_HF_TRANSFER: "0"
|
| 76 |
+
steps:
|
| 77 |
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
| 78 |
+
with:
|
| 79 |
+
fetch-depth: 0
|
| 80 |
+
- name: Install the current repository
|
| 81 |
+
run: |
|
| 82 |
+
pip3 install -r requirements-test.txt
|
| 83 |
+
pip3 install --no-deps -e .
|
| 84 |
+
pip3 install cupy-cuda12x==13.6.0
|
| 85 |
+
pip3 install --force-reinstall --no-deps --no-build-isolation git+https://github.com/ISEEKYAN/mbridge.git@main
|
| 86 |
+
- name: Prepare datasets
|
| 87 |
+
run: |
|
| 88 |
+
python3 examples/data_preprocess/gsm8k.py --local_dataset_path ${HOME}/models/hf_data/gsm8k
|
| 89 |
+
python3 examples/data_preprocess/geo3k.py --local_dataset_path ${HOME}/models/hf_data/hiyouga/geometry3k/ --local_save_dir ${HOME}/data/geo3k
|
| 90 |
+
- name: Running the E2E test with fully_async_policy + Multi-Teacher OPD (Megatron)
|
| 91 |
+
run: |
|
| 92 |
+
ray stop --force
|
| 93 |
+
bash tests/special_e2e/run_fully_async_policy_opd.sh
|
| 94 |
+
|
| 95 |
+
cleanup:
|
| 96 |
+
runs-on: ubuntu-latest
|
| 97 |
+
needs: [setup, e2e_fully_async_policy_opd_megatron]
|
| 98 |
+
if: always()
|
| 99 |
+
steps:
|
| 100 |
+
- id: destroy-runner
|
| 101 |
+
uses: volcengine/vemlp-github-runner@v1
|
| 102 |
+
with:
|
| 103 |
+
mode: "destroy"
|
| 104 |
+
faas-url: "${{ env.DYNAMIC_RUNNER_ENDPOINT }}"
|
| 105 |
+
mlp-task-id: "${{ needs.setup.outputs.mlp-task-id }}"
|
verl/.github/workflows/e2e_fully_async_policy_trtllm.yml
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# # Tests layout
|
| 2 |
+
|
| 3 |
+
# Each folder under tests/ corresponds to a test category for a sub-namespace in verl. For instance:
|
| 4 |
+
# - `tests/trainer` for testing functionality related to `verl/trainer`
|
| 5 |
+
# - `tests/models` for testing functionality related to `verl/models`
|
| 6 |
+
# - ...
|
| 7 |
+
|
| 8 |
+
# There are a few folders with `special_` prefix, created for special purposes:
|
| 9 |
+
# - `special_distributed`: unit tests that must run with multiple GPUs
|
| 10 |
+
# - `special_e2e`: end-to-end tests with training/generation scripts
|
| 11 |
+
# - `special_npu`: tests for NPUs
|
| 12 |
+
# - `special_sanity`: a suite of quick sanity tests
|
| 13 |
+
# - `special_standalone`: a set of test that are designed to run in dedicated environments
|
| 14 |
+
|
| 15 |
+
# Accelerators for tests
|
| 16 |
+
# - By default tests are run with GPU available, except for the ones under `special_npu`, and any test script whose name ends with `on_cpu.py`.
|
| 17 |
+
# - For test scripts with `on_cpu.py` name suffix would be tested on CPU resources in linux environment.
|
| 18 |
+
|
| 19 |
+
# # Workflow layout
|
| 20 |
+
|
| 21 |
+
# All CI tests are configured by yaml files in `.github/workflows/`. Here's an overview of all test configs:
|
| 22 |
+
# 1. A list of always triggered CPU sanity tests: `check-pr-title.yml`, `secrets_scan.yml`, `check-pr-title,yml`, `pre-commit.yml`, `doc.yml`
|
| 23 |
+
# 2. Some heavy multi-GPU unit tests, such as `model.yml`, `vllm.yml`, `sgl.yml`
|
| 24 |
+
# 3. End-to-end tests: `e2e_*.yml`
|
| 25 |
+
# 4. Unit tests
|
| 26 |
+
# - `cpu_unit_tests.yml`, run pytest on all scripts with file name pattern `tests/**/test_*_on_cpu.py`
|
| 27 |
+
# - `gpu_unit_tests.yml`, run pytest on all scripts with file without the `on_cpu.py` suffix.
|
| 28 |
+
# - Since cpu/gpu unit tests by default runs all tests under `tests`, please make sure tests are manually excluded in them when
|
| 29 |
+
# - new workflow yaml is added to `.github/workflows`
|
| 30 |
+
# - new tests are added to workflow mentioned in 2.
|
| 31 |
+
|
| 32 |
+
name: e2e_fully_async_policy_trtllm
|
| 33 |
+
|
| 34 |
+
on:
|
| 35 |
+
# Trigger the workflow on push or pull request,
|
| 36 |
+
# but only for the main branch
|
| 37 |
+
push:
|
| 38 |
+
branches:
|
| 39 |
+
- main
|
| 40 |
+
- v0.*
|
| 41 |
+
paths:
|
| 42 |
+
- "**/*.py"
|
| 43 |
+
- "!**/*.md"
|
| 44 |
+
- "!**/*.sh"
|
| 45 |
+
- "!examples/*trainer*"
|
| 46 |
+
- "!tests/**"
|
| 47 |
+
- "!verl/trainer/main_*.py"
|
| 48 |
+
- "!verl/trainer/fsdp_sft_trainer.py"
|
| 49 |
+
- "verl/workers/rollout/trtllm_rollout/**"
|
| 50 |
+
- "verl/experimental/fully_async_policy/**"
|
| 51 |
+
- "verl/checkpoint_engine/**"
|
| 52 |
+
pull_request:
|
| 53 |
+
branches:
|
| 54 |
+
- main
|
| 55 |
+
- v0.*
|
| 56 |
+
paths:
|
| 57 |
+
- "verl/workers/rollout/trtllm_rollout/**"
|
| 58 |
+
- "verl/experimental/fully_async_policy/**"
|
| 59 |
+
- "verl/checkpoint_engine/**"
|
| 60 |
+
- ".github/workflows/e2e_fully_async_policy_trtllm.yml"
|
| 61 |
+
- "tests/special_e2e/run_fully_async_policy.sh"
|
| 62 |
+
- "examples/data_preprocess/gsm8k.py"
|
| 63 |
+
|
| 64 |
+
# Cancel jobs on the same ref if a new one is triggered
|
| 65 |
+
concurrency:
|
| 66 |
+
group: ${{ github.workflow }}-${{ github.ref }}
|
| 67 |
+
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
| 68 |
+
|
| 69 |
+
# Declare permissions just read content.
|
| 70 |
+
permissions:
|
| 71 |
+
contents: read
|
| 72 |
+
|
| 73 |
+
env:
|
| 74 |
+
IMAGE: "verl-ci-cn-beijing.cr.volces.com/verlai/verl:trtllm1.3.0rc14"
|
| 75 |
+
DYNAMIC_RUNNER_ENDPOINT: "https://sd10g3clalm04ug7alq90.apigateway-cn-beijing.volceapi.com/runner"
|
| 76 |
+
|
| 77 |
+
jobs:
|
| 78 |
+
setup:
|
| 79 |
+
if: github.repository_owner == 'verl-project'
|
| 80 |
+
runs-on: ubuntu-latest
|
| 81 |
+
outputs:
|
| 82 |
+
runner-label: ${{ steps.create-runner.outputs.runner-label }}
|
| 83 |
+
mlp-task-id: ${{ steps.create-runner.outputs.mlp-task-id }}
|
| 84 |
+
steps:
|
| 85 |
+
- uses: actions/checkout@v4
|
| 86 |
+
- id: create-runner
|
| 87 |
+
uses: volcengine/vemlp-github-runner@v1
|
| 88 |
+
with:
|
| 89 |
+
mode: "create"
|
| 90 |
+
faas-url: "${{ env.DYNAMIC_RUNNER_ENDPOINT }}"
|
| 91 |
+
mlp-image: "${{ env.IMAGE }}"
|
| 92 |
+
|
| 93 |
+
trtllm_async_unit_tests:
|
| 94 |
+
needs: setup
|
| 95 |
+
runs-on: ["${{ needs.setup.outputs.runner-label || 'L20x8' }}"]
|
| 96 |
+
timeout-minutes: 30
|
| 97 |
+
env:
|
| 98 |
+
HTTPS_PROXY: ${{ secrets.PROXY_HTTPS }}
|
| 99 |
+
NO_PROXY: "localhost,127.0.0.1,hf-mirror.com"
|
| 100 |
+
HF_ENDPOINT: "https://hf-mirror.com"
|
| 101 |
+
HF_HUB_ENABLE_HF_TRANSFER: "0"
|
| 102 |
+
TORCH_CUDA_ARCH_LIST: "7.5;8.0;8.9;9.0;10.0;12.0+PTX"
|
| 103 |
+
steps:
|
| 104 |
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
| 105 |
+
with:
|
| 106 |
+
fetch-depth: 0
|
| 107 |
+
- name: Reinstall FlashInfer for runtime GPU arch
|
| 108 |
+
run: |
|
| 109 |
+
unset TORCH_CUDA_ARCH_LIST
|
| 110 |
+
pip3 install --force-reinstall --no-deps flashinfer-python
|
| 111 |
+
- name: Install the current repository
|
| 112 |
+
run: |
|
| 113 |
+
pip3 install pytest-asyncio
|
| 114 |
+
pip3 install -r requirements-test.txt
|
| 115 |
+
pip3 install --no-deps -e .
|
| 116 |
+
- name: Run TRT-LLM async unit tests
|
| 117 |
+
run: |
|
| 118 |
+
unset TORCH_CUDA_ARCH_LIST
|
| 119 |
+
export TRTLLM_ENABLE_PDL=0
|
| 120 |
+
export TRTLLM_TEST_MODEL_PATH_ROOT="${HOME}/models"
|
| 121 |
+
ray stop --force
|
| 122 |
+
pytest -v -s --durations=20 \
|
| 123 |
+
tests/workers/rollout/rollout_trtllm/test_trtllm_abort.py
|
| 124 |
+
|
| 125 |
+
# Megatron multi-replica: 4 rollout GPUs split into 2 replicas × TP=2.
|
| 126 |
+
e2e_fully_async_policy_trtllm_megatron_multi_replica:
|
| 127 |
+
needs: setup
|
| 128 |
+
runs-on: ["${{ needs.setup.outputs.runner-label || 'L20x8' }}"]
|
| 129 |
+
timeout-minutes: 20
|
| 130 |
+
env:
|
| 131 |
+
HTTP_PROXY: ${{ secrets.PROXY_HTTP }}
|
| 132 |
+
HTTPS_PROXY: ${{ secrets.PROXY_HTTPS }}
|
| 133 |
+
NO_PROXY: "localhost,127.0.0.1,hf-mirror.com"
|
| 134 |
+
HF_ENDPOINT: "https://hf-mirror.com"
|
| 135 |
+
HF_HUB_ENABLE_HF_TRANSFER: "0"
|
| 136 |
+
ACTOR_STRATEGY: "megatron"
|
| 137 |
+
ROLLOUT_NAME: "trtllm"
|
| 138 |
+
GEN_TP: "2" # 4 rollout GPUs / TP=2 = 2 replicas
|
| 139 |
+
steps:
|
| 140 |
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
| 141 |
+
with:
|
| 142 |
+
fetch-depth: 0
|
| 143 |
+
- name: Install the current repository
|
| 144 |
+
run: |
|
| 145 |
+
pip3 install -r requirements-test.txt
|
| 146 |
+
pip3 install --no-deps -e .
|
| 147 |
+
pip3 install cupy-cuda12x==14.0.1
|
| 148 |
+
- name: Prepare GSM8K dataset
|
| 149 |
+
run: |
|
| 150 |
+
python3 examples/data_preprocess/gsm8k.py --local_dataset_path ${HOME}/models/hf_data/gsm8k
|
| 151 |
+
- name: Running TRT-LLM fully-async E2E test with Megatron (multi-replica, 2×TP=2)
|
| 152 |
+
run: |
|
| 153 |
+
ray stop --force
|
| 154 |
+
bash tests/special_e2e/run_fully_async_policy.sh \
|
| 155 |
+
data.max_response_length=128 \
|
| 156 |
+
actor_rollout_ref.rollout.n=2 \
|
| 157 |
+
actor_rollout_ref.rollout.gpu_memory_utilization=0.1 \
|
| 158 |
+
actor_rollout_ref.actor.ppo_mini_batch_size=4 \
|
| 159 |
+
actor_rollout_ref.actor.ppo_max_token_len_per_gpu=1536
|
| 160 |
+
|
| 161 |
+
cleanup:
|
| 162 |
+
runs-on: ubuntu-latest
|
| 163 |
+
needs: [setup, trtllm_async_unit_tests, e2e_fully_async_policy_trtllm_megatron_multi_replica]
|
| 164 |
+
if: always()
|
| 165 |
+
steps:
|
| 166 |
+
- id: destroy-runner
|
| 167 |
+
uses: volcengine/vemlp-github-runner@v1
|
| 168 |
+
with:
|
| 169 |
+
mode: "destroy"
|
| 170 |
+
faas-url: "${{ env.DYNAMIC_RUNNER_ENDPOINT }}"
|
| 171 |
+
mlp-task-id: "${{ needs.setup.outputs.mlp-task-id }}"
|
verl/.github/workflows/e2e_one_step_off_policy.yml
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# # Tests layout
|
| 2 |
+
|
| 3 |
+
# Each folder under tests/ corresponds to a test category for a sub-namespace in verl. For instance:
|
| 4 |
+
# - `tests/trainer` for testing functionality related to `verl/trainer`
|
| 5 |
+
# - `tests/models` for testing functionality related to `verl/models`
|
| 6 |
+
# - ...
|
| 7 |
+
|
| 8 |
+
# There are a few folders with `special_` prefix, created for special purposes:
|
| 9 |
+
# - `special_distributed`: unit tests that must run with multiple GPUs
|
| 10 |
+
# - `special_e2e`: end-to-end tests with training/generation scripts
|
| 11 |
+
# - `special_npu`: tests for NPUs
|
| 12 |
+
# - `special_sanity`: a suite of quick sanity tests
|
| 13 |
+
# - `special_standalone`: a set of test that are designed to run in dedicated environments
|
| 14 |
+
|
| 15 |
+
# Accelerators for tests
|
| 16 |
+
# - By default tests are run with GPU available, except for the ones under `special_npu`, and any test script whose name ends with `on_cpu.py`.
|
| 17 |
+
# - For test scripts with `on_cpu.py` name suffix would be tested on CPU resources in linux environment.
|
| 18 |
+
|
| 19 |
+
# # Workflow layout
|
| 20 |
+
|
| 21 |
+
# All CI tests are configured by yaml files in `.github/workflows/`. Here's an overview of all test configs:
|
| 22 |
+
# 1. A list of always triggered CPU sanity tests: `check-pr-title.yml`, `secrets_scan.yml`, `check-pr-title,yml`, `pre-commit.yml`, `doc.yml`
|
| 23 |
+
# 2. Some heavy multi-GPU unit tests, such as `model.yml`, `vllm.yml`, `sgl.yml`
|
| 24 |
+
# 3. End-to-end tests: `e2e_*.yml`
|
| 25 |
+
# 4. Unit tests
|
| 26 |
+
# - `cpu_unit_tests.yml`, run pytest on all scripts with file name pattern `tests/**/test_*_on_cpu.py`
|
| 27 |
+
# - `gpu_unit_tests.yml`, run pytest on all scripts with file without the `on_cpu.py` suffix.
|
| 28 |
+
# - Since cpu/gpu unit tests by default runs all tests under `tests`, please make sure tests are manually excluded in them when
|
| 29 |
+
# - new workflow yaml is added to `.github/workflows`
|
| 30 |
+
# - new tests are added to workflow mentioned in 2.
|
| 31 |
+
|
| 32 |
+
name: e2e_one_step_off_policy
|
| 33 |
+
|
| 34 |
+
on:
|
| 35 |
+
# Trigger the workflow on push or pull request,
|
| 36 |
+
# but only for the main branch
|
| 37 |
+
# For push, for now only anti-patterns are specified so it is more conservative
|
| 38 |
+
# and achieves higher coverage.
|
| 39 |
+
push:
|
| 40 |
+
branches:
|
| 41 |
+
- main
|
| 42 |
+
- v0.*
|
| 43 |
+
paths:
|
| 44 |
+
- "**/*.py"
|
| 45 |
+
- "!**/*.md"
|
| 46 |
+
- "!**/*.sh"
|
| 47 |
+
# Other entrypoints
|
| 48 |
+
- "!examples/*trainer*"
|
| 49 |
+
- "!tests/**"
|
| 50 |
+
- "!verl/trainer/main_*.py"
|
| 51 |
+
- "!verl/trainer/fsdp_sft_trainer.py"
|
| 52 |
+
- "verl/experimental/one_step_off_policy"
|
| 53 |
+
pull_request:
|
| 54 |
+
branches:
|
| 55 |
+
- main
|
| 56 |
+
- v0.*
|
| 57 |
+
paths:
|
| 58 |
+
- "**/*.py"
|
| 59 |
+
- "!**/*.md"
|
| 60 |
+
- "!**/*.sh"
|
| 61 |
+
# Other entrypoints
|
| 62 |
+
- "!examples/**"
|
| 63 |
+
- "!tests/**"
|
| 64 |
+
- "!verl/trainer/main_*.py"
|
| 65 |
+
- "!verl/trainer/fsdp_sft_trainer.py"
|
| 66 |
+
# Home
|
| 67 |
+
- "verl/experimental/one_step_off_policy"
|
| 68 |
+
# Entrypoints
|
| 69 |
+
- ".github/workflows/e2e_one_step_off_policy.yml"
|
| 70 |
+
- "examples/data_preprocess/gsm8k.py"
|
| 71 |
+
- "tests/special_e2e/run_one_step_off_policy.sh"
|
| 72 |
+
|
| 73 |
+
# Cancel jobs on the same ref if a new one is triggered
|
| 74 |
+
concurrency:
|
| 75 |
+
group: ${{ github.workflow }}-${{ github.ref }}
|
| 76 |
+
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
| 77 |
+
|
| 78 |
+
# Declare permissions just read content.
|
| 79 |
+
permissions:
|
| 80 |
+
contents: read
|
| 81 |
+
|
| 82 |
+
env:
|
| 83 |
+
IMAGE: "verl-ci-cn-beijing.cr.volces.com/verlai/verl:vllm018.dev1"
|
| 84 |
+
DYNAMIC_RUNNER_ENDPOINT: "https://sd10g3clalm04ug7alq90.apigateway-cn-beijing.volceapi.com/runner"
|
| 85 |
+
|
| 86 |
+
jobs:
|
| 87 |
+
setup:
|
| 88 |
+
if: github.repository_owner == 'verl-project'
|
| 89 |
+
runs-on: ubuntu-latest
|
| 90 |
+
outputs:
|
| 91 |
+
runner-label: ${{ steps.create-runner.outputs.runner-label }}
|
| 92 |
+
mlp-task-id: ${{ steps.create-runner.outputs.mlp-task-id }}
|
| 93 |
+
steps:
|
| 94 |
+
- uses: actions/checkout@v4
|
| 95 |
+
- id: create-runner
|
| 96 |
+
uses: volcengine/vemlp-github-runner@v1
|
| 97 |
+
with:
|
| 98 |
+
mode: "create"
|
| 99 |
+
faas-url: "${{ env.DYNAMIC_RUNNER_ENDPOINT }}"
|
| 100 |
+
mlp-image: "${{ env.IMAGE }}"
|
| 101 |
+
|
| 102 |
+
# Test FSDP2 strategy
|
| 103 |
+
e2e_one_step_off_policy_fsdp2:
|
| 104 |
+
needs: setup
|
| 105 |
+
runs-on: ["${{ needs.setup.outputs.runner-label || 'L20x8' }}"]
|
| 106 |
+
timeout-minutes: 10 # Increase timeout for async training
|
| 107 |
+
env:
|
| 108 |
+
HTTPS_PROXY: ${{ secrets.PROXY_HTTPS }}
|
| 109 |
+
NO_PROXY: "localhost,127.0.0.1,hf-mirror.com"
|
| 110 |
+
HF_ENDPOINT: "https://hf-mirror.com"
|
| 111 |
+
HF_HUB_ENABLE_HF_TRANSFER: "0" # This is more stable
|
| 112 |
+
ACTOR_STRATEGY: "fsdp2"
|
| 113 |
+
steps:
|
| 114 |
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
| 115 |
+
with:
|
| 116 |
+
fetch-depth: 0
|
| 117 |
+
- name: Install the current repository
|
| 118 |
+
run: |
|
| 119 |
+
pip3 install -r requirements-test.txt
|
| 120 |
+
pip3 install --no-deps -e .
|
| 121 |
+
pip3 install cupy-cuda12x==13.6.0
|
| 122 |
+
- name: Prepare GSM8K dataset
|
| 123 |
+
run: |
|
| 124 |
+
python3 examples/data_preprocess/gsm8k.py --local_dataset_path ${HOME}/models/hf_data/gsm8k
|
| 125 |
+
- name: Running the E2E test with one_step_off_policy algorithm (FSDP2)
|
| 126 |
+
run: |
|
| 127 |
+
ray stop --force
|
| 128 |
+
bash tests/special_e2e/run_one_step_off_policy.sh
|
| 129 |
+
|
| 130 |
+
# Test Megatron strategy
|
| 131 |
+
e2e_one_step_off_policy_megatron:
|
| 132 |
+
needs: setup
|
| 133 |
+
runs-on: ["${{ needs.setup.outputs.runner-label || 'L20x8' }}"]
|
| 134 |
+
timeout-minutes: 10 # Increase timeout for async training
|
| 135 |
+
env:
|
| 136 |
+
HTTPS_PROXY: ${{ secrets.PROXY_HTTPS }}
|
| 137 |
+
NO_PROXY: "localhost,127.0.0.1,hf-mirror.com"
|
| 138 |
+
HF_ENDPOINT: "https://hf-mirror.com"
|
| 139 |
+
HF_HUB_ENABLE_HF_TRANSFER: "0" # This is more stable
|
| 140 |
+
ACTOR_STRATEGY: "megatron"
|
| 141 |
+
steps:
|
| 142 |
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
| 143 |
+
with:
|
| 144 |
+
fetch-depth: 0
|
| 145 |
+
- name: Install the current repository
|
| 146 |
+
run: |
|
| 147 |
+
pip3 install -r requirements-test.txt
|
| 148 |
+
pip3 install --no-deps -e .
|
| 149 |
+
pip3 install cupy-cuda12x==13.6.0
|
| 150 |
+
- name: Prepare GSM8K dataset
|
| 151 |
+
run: |
|
| 152 |
+
python3 examples/data_preprocess/gsm8k.py --local_dataset_path ${HOME}/models/hf_data/gsm8k
|
| 153 |
+
- name: Running the E2E test with one_step_off_policy algorithm (Megatron)
|
| 154 |
+
run: |
|
| 155 |
+
ray stop --force
|
| 156 |
+
bash tests/special_e2e/run_one_step_off_policy.sh
|
| 157 |
+
|
| 158 |
+
cleanup:
|
| 159 |
+
runs-on: ubuntu-latest
|
| 160 |
+
needs:
|
| 161 |
+
[setup, e2e_one_step_off_policy_fsdp2, e2e_one_step_off_policy_megatron]
|
| 162 |
+
if: always()
|
| 163 |
+
steps:
|
| 164 |
+
- id: destroy-runner
|
| 165 |
+
uses: volcengine/vemlp-github-runner@v1
|
| 166 |
+
with:
|
| 167 |
+
mode: "destroy"
|
| 168 |
+
faas-url: "${{ env.DYNAMIC_RUNNER_ENDPOINT }}"
|
| 169 |
+
mlp-task-id: "${{ needs.setup.outputs.mlp-task-id }}"
|
verl/.github/workflows/e2e_one_step_off_policy_ascend.yml
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# # Tests layout
|
| 2 |
+
|
| 3 |
+
# Each folder under tests/ corresponds to a test category for a sub-namespace in verl. For instance:
|
| 4 |
+
# - `tests/trainer` for testing functionality related to `verl/trainer`
|
| 5 |
+
# - `tests/models` for testing functionality related to `verl/models`
|
| 6 |
+
# - ...
|
| 7 |
+
|
| 8 |
+
# There are a few folders with `special_` prefix, created for special purposes:
|
| 9 |
+
# - `special_distributed`: unit tests that must run with multiple GPUs
|
| 10 |
+
# - `special_e2e`: end-to-end tests with training/generation scripts
|
| 11 |
+
# - `special_npu`: tests for NPUs
|
| 12 |
+
# - `special_sanity`: a suite of quick sanity tests
|
| 13 |
+
# - `special_standalone`: a set of test that are designed to run in dedicated environments
|
| 14 |
+
|
| 15 |
+
# Accelerators for tests
|
| 16 |
+
# - By default tests are run with GPU available, except for the ones under `special_npu`, and any test script whose name ends with `on_cpu.py`.
|
| 17 |
+
# - For test scripts with `on_cpu.py` name suffix would be tested on CPU resources in linux environment.
|
| 18 |
+
|
| 19 |
+
# # Workflow layout
|
| 20 |
+
|
| 21 |
+
# All CI tests are configured by yaml files in `.github/workflows/`. Here's an overview of all test configs:
|
| 22 |
+
# 1. A list of always triggered CPU sanity tests: `check-pr-title.yml`, `secrets_scan.yml`, `check-pr-title,yml`, `pre-commit.yml`, `doc.yml`
|
| 23 |
+
# 2. Some heavy multi-GPU unit tests, such as `model.yml`, `vllm.yml`, `sgl.yml`
|
| 24 |
+
# 3. End-to-end tests: `e2e_*.yml`
|
| 25 |
+
# 4. Unit tests
|
| 26 |
+
# - `cpu_unit_tests.yml`, run pytest on all scripts with file name pattern `tests/**/test_*_on_cpu.py`
|
| 27 |
+
# - `gpu_unit_tests.yml`, run pytest on all scripts with file without the `on_cpu.py` suffix.
|
| 28 |
+
# - Since cpu/gpu unit tests by default runs all tests under `tests`, please make sure tests are manually excluded in them when
|
| 29 |
+
# - new workflow yaml is added to `.github/workflows`
|
| 30 |
+
# - new tests are added to workflow mentioned in 2.
|
| 31 |
+
|
| 32 |
+
name: e2e_one_step_off_policy_ascend
|
| 33 |
+
|
| 34 |
+
on:
|
| 35 |
+
# Trigger the workflow on push or pull request,
|
| 36 |
+
# but only for the main branch
|
| 37 |
+
# For push, for now only anti-patterns are specified so it is more conservative
|
| 38 |
+
# and achieves higher coverage.
|
| 39 |
+
push:
|
| 40 |
+
branches:
|
| 41 |
+
- main
|
| 42 |
+
- v0.*
|
| 43 |
+
paths:
|
| 44 |
+
- "**/*.py"
|
| 45 |
+
- "!**/*.md"
|
| 46 |
+
- "!**/*.sh"
|
| 47 |
+
# Other entrypoints
|
| 48 |
+
- "!examples/*trainer*"
|
| 49 |
+
- "!tests/**"
|
| 50 |
+
- "!verl/trainer/main_*.py"
|
| 51 |
+
- "!verl/trainer/fsdp_sft_trainer.py"
|
| 52 |
+
- "verl/experimental/one_step_off_policy"
|
| 53 |
+
pull_request:
|
| 54 |
+
branches:
|
| 55 |
+
- main
|
| 56 |
+
- v0.*
|
| 57 |
+
paths:
|
| 58 |
+
- "**/*.py"
|
| 59 |
+
- "!**/*.md"
|
| 60 |
+
- "!**/*.sh"
|
| 61 |
+
# Other entrypoints
|
| 62 |
+
- "!examples/**"
|
| 63 |
+
- "!tests/**"
|
| 64 |
+
- "!verl/trainer/main_*.py"
|
| 65 |
+
- "!verl/trainer/fsdp_sft_trainer.py"
|
| 66 |
+
# Home
|
| 67 |
+
- "verl/experimental/one_step_off_policy"
|
| 68 |
+
# Entrypoints
|
| 69 |
+
- ".github/workflows/e2e_one_step_off_policy_ascend.yml"
|
| 70 |
+
- "examples/data_preprocess/gsm8k.py"
|
| 71 |
+
- "tests/special_e2e/run_one_step_off_policy.sh"
|
| 72 |
+
|
| 73 |
+
# Cancel jobs on the same ref if a new one is triggered
|
| 74 |
+
concurrency:
|
| 75 |
+
group: ${{ github.workflow }}-${{ github.ref }}
|
| 76 |
+
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
| 77 |
+
|
| 78 |
+
# Declare permissions just read content.
|
| 79 |
+
permissions:
|
| 80 |
+
contents: read
|
| 81 |
+
|
| 82 |
+
jobs:
|
| 83 |
+
# Test FSDP2 strategy
|
| 84 |
+
e2e_one_step_off_policy_fsdp2_ascend:
|
| 85 |
+
if: github.repository_owner == 'verl-project'
|
| 86 |
+
runs-on: linux-aarch64-a3-8
|
| 87 |
+
timeout-minutes: 60 # Increase this timeout value as needed
|
| 88 |
+
container:
|
| 89 |
+
image: swr.cn-southwest-2.myhuaweicloud.com/modelfoundry/ascend-ci/verl/verl:verl-8.5.0-a3-ubuntu22.04-py3.11-latest
|
| 90 |
+
options: >-
|
| 91 |
+
--shm-size 16g
|
| 92 |
+
env:
|
| 93 |
+
HF_ENDPOINT: "https://hf-mirror.com"
|
| 94 |
+
HF_HUB_ENABLE_HF_TRANSFER: "0" # This is more stable
|
| 95 |
+
ACTOR_STRATEGY: "fsdp2"
|
| 96 |
+
device_name: "npu"
|
| 97 |
+
steps:
|
| 98 |
+
- name: Check npu and CANN info
|
| 99 |
+
run: |
|
| 100 |
+
cat /usr/local/Ascend/ascend-toolkit/latest/"$(uname -i)"-linux/ascend_toolkit_install.info
|
| 101 |
+
npu-smi info
|
| 102 |
+
- name: Check initial pip list from image
|
| 103 |
+
run: |
|
| 104 |
+
pip list
|
| 105 |
+
- name: Checkout verl-project/verl repo
|
| 106 |
+
uses: actions/checkout@v4
|
| 107 |
+
with:
|
| 108 |
+
fetch-depth: 0
|
| 109 |
+
clean: true
|
| 110 |
+
- name: Install the current repository
|
| 111 |
+
run: |
|
| 112 |
+
pip install --no-deps -e .
|
| 113 |
+
- name: Check final pip list
|
| 114 |
+
run: |
|
| 115 |
+
pip list
|
| 116 |
+
- name: Prepare weights
|
| 117 |
+
run: |
|
| 118 |
+
ln -s /root/.cache/models ~/models
|
| 119 |
+
- name: Prepare GSM8K dataset
|
| 120 |
+
run: |
|
| 121 |
+
python examples/data_preprocess/gsm8k.py --local_dataset_path ${HOME}/.cache/datasets/openai/gsm8k
|
| 122 |
+
- name: Running the E2E test with one_step_off_policy algorithm (FSDP2)
|
| 123 |
+
run: |
|
| 124 |
+
ray stop --force
|
| 125 |
+
bash tests/special_e2e/run_one_step_off_policy.sh
|
| 126 |
+
|
| 127 |
+
# Test Megatron strategy
|
| 128 |
+
e2e_one_step_off_policy_megatron_ascend:
|
| 129 |
+
if: github.repository_owner == 'verl-project'
|
| 130 |
+
runs-on: linux-aarch64-a3-8
|
| 131 |
+
timeout-minutes: 60 # Increase this timeout value as needed
|
| 132 |
+
container:
|
| 133 |
+
image: swr.cn-southwest-2.myhuaweicloud.com/modelfoundry/ascend-ci/verl/verl:verl-8.5.0-a3-ubuntu22.04-py3.11-latest
|
| 134 |
+
options: >-
|
| 135 |
+
--shm-size 16g
|
| 136 |
+
env:
|
| 137 |
+
HF_ENDPOINT: "https://hf-mirror.com"
|
| 138 |
+
HF_HUB_ENABLE_HF_TRANSFER: "0" # This is more stable
|
| 139 |
+
ACTOR_STRATEGY: "megatron"
|
| 140 |
+
device_name: "npu"
|
| 141 |
+
steps:
|
| 142 |
+
- name: Check npu and CANN info
|
| 143 |
+
run: |
|
| 144 |
+
cat /usr/local/Ascend/ascend-toolkit/latest/"$(uname -i)"-linux/ascend_toolkit_install.info
|
| 145 |
+
npu-smi info
|
| 146 |
+
- name: Check initial pip list from image
|
| 147 |
+
run: |
|
| 148 |
+
pip list
|
| 149 |
+
- name: Checkout verl-project/verl repo
|
| 150 |
+
uses: actions/checkout@v4
|
| 151 |
+
with:
|
| 152 |
+
fetch-depth: 0
|
| 153 |
+
clean: true
|
| 154 |
+
- name: Install the current repository
|
| 155 |
+
run: |
|
| 156 |
+
pip install --no-deps -e .
|
| 157 |
+
- name: Check final pip list
|
| 158 |
+
run: |
|
| 159 |
+
pip list
|
| 160 |
+
- name: Prepare weights
|
| 161 |
+
run: |
|
| 162 |
+
ln -s /root/.cache/models ~/models
|
| 163 |
+
- name: Prepare GSM8K dataset
|
| 164 |
+
run: |
|
| 165 |
+
python examples/data_preprocess/gsm8k.py --local_dataset_path ${HOME}/.cache/datasets/openai/gsm8k
|
| 166 |
+
- name: Running the E2E test with one_step_off_policy algorithm (Megatron)
|
| 167 |
+
run: |
|
| 168 |
+
ray stop --force
|
| 169 |
+
export PYTHONPATH=$PYTHONPATH:/Megatron-LM
|
| 170 |
+
bash tests/special_e2e/run_one_step_off_policy.sh
|
verl/.github/workflows/e2e_ppo_grpo_trainer_trtllm.yml
ADDED
|
@@ -0,0 +1,289 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# # Tests layout
|
| 2 |
+
|
| 3 |
+
# Each folder under tests/ corresponds to a test category for a sub-namespace in verl. For instance:
|
| 4 |
+
# - `tests/trainer` for testing functionality related to `verl/trainer`
|
| 5 |
+
# - `tests/models` for testing functionality related to `verl/models`
|
| 6 |
+
# - ...
|
| 7 |
+
|
| 8 |
+
# There are a few folders with `special_` prefix, created for special purposes:
|
| 9 |
+
# - `special_distributed`: unit tests that must run with multiple GPUs
|
| 10 |
+
# - `special_e2e`: end-to-end tests with training/generation scripts
|
| 11 |
+
# - `special_npu`: tests for NPUs
|
| 12 |
+
# - `special_sanity`: a suite of quick sanity tests
|
| 13 |
+
# - `special_standalone`: a set of test that are designed to run in dedicated environments
|
| 14 |
+
|
| 15 |
+
# Accelerators for tests
|
| 16 |
+
# - By default tests are run with GPU available, except for the ones under `special_npu`, and any test script whose name ends with `on_cpu.py`.
|
| 17 |
+
# - For test scripts with `on_cpu.py` name suffix would be tested on CPU resources in linux environment.
|
| 18 |
+
|
| 19 |
+
# # Workflow layout
|
| 20 |
+
|
| 21 |
+
# All CI tests are configured by yaml files in `.github/workflows/`. Here's an overview of all test configs:
|
| 22 |
+
# 1. A list of always triggered CPU sanity tests: `check-pr-title.yml`, `secrets_scan.yml`, `check-pr-title,yml`, `pre-commit.yml`, `doc.yml`
|
| 23 |
+
# 2. Some heavy multi-GPU unit tests, such as `model.yml`, `vllm.yml`, `sgl.yml`
|
| 24 |
+
# 3. End-to-end tests: `e2e_*.yml`
|
| 25 |
+
# 4. Unit tests
|
| 26 |
+
# - `cpu_unit_tests.yml`, run pytest on all scripts with file name pattern `tests/**/test_*_on_cpu.py`
|
| 27 |
+
# - `gpu_unit_tests.yml`, run pytest on all scripts with file without the `on_cpu.py` suffix.
|
| 28 |
+
# - Since cpu/gpu unit tests by default runs all tests under `tests`, please make sure tests are manually excluded in them when
|
| 29 |
+
# - new workflow yaml is added to `.github/workflows`
|
| 30 |
+
# - new tests are added to workflow mentioned in 2.
|
| 31 |
+
|
| 32 |
+
name: e2e_ppo_trainer_megatron_trtllm
|
| 33 |
+
|
| 34 |
+
on:
|
| 35 |
+
# Trigger the workflow on push or pull request,
|
| 36 |
+
# but only for the main branch.
|
| 37 |
+
# For push, for now only anti-patterns are specified so it is more conservative
|
| 38 |
+
# and achieves higher coverage.
|
| 39 |
+
push:
|
| 40 |
+
branches:
|
| 41 |
+
- main
|
| 42 |
+
- v0.*
|
| 43 |
+
paths:
|
| 44 |
+
- "**/*.py"
|
| 45 |
+
# Other entrypoints
|
| 46 |
+
- "!verl/trainer/fsdp_sft_trainer.py"
|
| 47 |
+
# Recipes
|
| 48 |
+
- "!recipe/**"
|
| 49 |
+
# FSDP
|
| 50 |
+
- "!verl/workers/**/*dp_*.py"
|
| 51 |
+
pull_request:
|
| 52 |
+
branches:
|
| 53 |
+
- main
|
| 54 |
+
- v0.*
|
| 55 |
+
paths:
|
| 56 |
+
- "**/*.py"
|
| 57 |
+
# Other entrypoints
|
| 58 |
+
- "!docker/**"
|
| 59 |
+
# Docs
|
| 60 |
+
- "!**/*.md"
|
| 61 |
+
- "!docs/**"
|
| 62 |
+
- "!examples/**"
|
| 63 |
+
- "!tests/**"
|
| 64 |
+
- "!verl/trainer/main_*.py"
|
| 65 |
+
- "!verl/trainer/fsdp_sft_trainer.py"
|
| 66 |
+
# Recipes
|
| 67 |
+
- "!recipe/**"
|
| 68 |
+
# FSDP
|
| 69 |
+
- "!verl/workers/**/*dp_*.py"
|
| 70 |
+
# Entrypoints
|
| 71 |
+
- "verl/workers/rollout/trtllm_rollout/**"
|
| 72 |
+
- "tests/workers/rollout/rollout_trtllm/**"
|
| 73 |
+
- ".github/workflows/e2e_ppo_grpo_trainer_trtllm.yml"
|
| 74 |
+
- "examples/data_preprocess/gsm8k.py"
|
| 75 |
+
- "examples/data_preprocess/geo3k.py"
|
| 76 |
+
- "examples/data_preprocess/dapo_multiturn_w_tool.py"
|
| 77 |
+
- "examples/data_preprocess/aime2024_multiturn_w_tool.py"
|
| 78 |
+
- "examples/grpo_trainer/run_qwen3_8b_megatron.sh"
|
| 79 |
+
- "examples/grpo_trainer/run_qwen3_30b_a3b_megatron.sh"
|
| 80 |
+
# add back when ppo flow is ready
|
| 81 |
+
# - "tests/special_e2e/run_ppo_trainer_megatron.sh"
|
| 82 |
+
# - "verl/trainer/main_ppo.py"
|
| 83 |
+
# - "verl/trainer/config/ppo_megatron_trainer.yaml"
|
| 84 |
+
|
| 85 |
+
# Cancel jobs on the same ref if a new one is triggered
|
| 86 |
+
concurrency:
|
| 87 |
+
group: ${{ github.workflow }}-${{ github.ref }}
|
| 88 |
+
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
| 89 |
+
|
| 90 |
+
# Declare permissions just read content.
|
| 91 |
+
permissions:
|
| 92 |
+
contents: read
|
| 93 |
+
|
| 94 |
+
env:
|
| 95 |
+
IMAGE: "verl-ci-cn-beijing.cr.volces.com/verlai/verl:trtllm1.3.0rc14"
|
| 96 |
+
DYNAMIC_RUNNER_ENDPOINT: "https://sd10g3clalm04ug7alq90.apigateway-cn-beijing.volceapi.com/runner"
|
| 97 |
+
|
| 98 |
+
jobs:
|
| 99 |
+
setup:
|
| 100 |
+
if: github.repository_owner == 'verl-project'
|
| 101 |
+
runs-on: ubuntu-latest
|
| 102 |
+
outputs:
|
| 103 |
+
runner-label: ${{ steps.create-runner.outputs.runner-label }}
|
| 104 |
+
mlp-task-id: ${{ steps.create-runner.outputs.mlp-task-id }}
|
| 105 |
+
steps:
|
| 106 |
+
- uses: actions/checkout@v4
|
| 107 |
+
- id: create-runner
|
| 108 |
+
uses: volcengine/vemlp-github-runner@v1
|
| 109 |
+
with:
|
| 110 |
+
mode: "create"
|
| 111 |
+
faas-url: "${{ env.DYNAMIC_RUNNER_ENDPOINT }}"
|
| 112 |
+
mlp-image: "${{ env.IMAGE }}"
|
| 113 |
+
|
| 114 |
+
trtllm_unit_tests:
|
| 115 |
+
needs: setup
|
| 116 |
+
runs-on: ["${{ needs.setup.outputs.runner-label || 'L20x8' }}"]
|
| 117 |
+
timeout-minutes: 30 # Increase this timeout value as needed
|
| 118 |
+
env:
|
| 119 |
+
HTTPS_PROXY: ${{ secrets.PROXY_HTTPS }}
|
| 120 |
+
NO_PROXY: "localhost,127.0.0.1,hf-mirror.com"
|
| 121 |
+
HF_ENDPOINT: "https://hf-mirror.com"
|
| 122 |
+
HF_HUB_ENABLE_HF_TRANSFER: "0" # This is more stable
|
| 123 |
+
TORCH_CUDA_ARCH_LIST: "7.5;8.0;8.9;9.0;10.0;12.0+PTX"
|
| 124 |
+
steps:
|
| 125 |
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
| 126 |
+
with:
|
| 127 |
+
fetch-depth: 0
|
| 128 |
+
- name: Reinstall FlashInfer for runtime GPU arch
|
| 129 |
+
run: |
|
| 130 |
+
unset TORCH_CUDA_ARCH_LIST
|
| 131 |
+
pip3 install --force-reinstall --no-deps flashinfer-python
|
| 132 |
+
- name: Install the current repository
|
| 133 |
+
run: |
|
| 134 |
+
pip3 install pytest-asyncio
|
| 135 |
+
pip3 install -r requirements-test.txt
|
| 136 |
+
pip3 install --no-deps -e .
|
| 137 |
+
- name: Run TRTLLM unit tests
|
| 138 |
+
run: |
|
| 139 |
+
unset TORCH_CUDA_ARCH_LIST # Let TRT-LLM CUTLASS DSL auto-detect runtime GPU arch
|
| 140 |
+
export TRTLLM_ENABLE_PDL=0 # Disable Programmatic Dependent Launch (uses SM 9.0 griddepcontrol)
|
| 141 |
+
export TRTLLM_TEST_MODEL_PATH_ROOT="${HOME}/models"
|
| 142 |
+
ray stop --force
|
| 143 |
+
pytest -v -s --durations=20 \
|
| 144 |
+
tests/workers/rollout/rollout_trtllm/test_adapter.py \
|
| 145 |
+
tests/workers/rollout/rollout_trtllm/test_async_server.py \
|
| 146 |
+
tests/workers/rollout/rollout_trtllm/test_inter_node_rollout.py \
|
| 147 |
+
tests/workers/rollout/rollout_trtllm/test_trtllm_rollout_utils.py
|
| 148 |
+
|
| 149 |
+
e2e_grpo_trainer_megatron-qwen2:
|
| 150 |
+
needs: setup
|
| 151 |
+
runs-on: ["${{ needs.setup.outputs.runner-label || 'L20x8' }}"]
|
| 152 |
+
timeout-minutes: 30 # Increase this timeout value as needed
|
| 153 |
+
env:
|
| 154 |
+
HTTPS_PROXY: ${{ secrets.PROXY_HTTPS }}
|
| 155 |
+
NO_PROXY: "localhost,127.0.0.1,hf-mirror.com"
|
| 156 |
+
HF_ENDPOINT: "https://hf-mirror.com"
|
| 157 |
+
HF_HUB_ENABLE_HF_TRANSFER: "0" # This is more stable
|
| 158 |
+
TORCH_CUDA_ARCH_LIST: "7.5;8.0;8.9;9.0;10.0;12.0+PTX"
|
| 159 |
+
steps:
|
| 160 |
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
| 161 |
+
with:
|
| 162 |
+
fetch-depth: 0
|
| 163 |
+
- name: Reinstall FlashInfer for runtime GPU arch
|
| 164 |
+
run: |
|
| 165 |
+
unset TORCH_CUDA_ARCH_LIST
|
| 166 |
+
pip3 install --force-reinstall --no-deps flashinfer-python
|
| 167 |
+
- name: Install the current repository
|
| 168 |
+
run: |
|
| 169 |
+
pip3 install -r requirements-test.txt
|
| 170 |
+
pip3 install --no-deps -e .
|
| 171 |
+
- name: Prepare GSM8K dataset
|
| 172 |
+
run: |
|
| 173 |
+
python3 examples/data_preprocess/gsm8k.py --local_dataset_path ${HOME}/models/hf_data/gsm8k --local_save_dir ${PWD}/data/gsm8k
|
| 174 |
+
- name: Running GSM8K E2E training tests with 3D parallelism on 8 L20 GPUs with Megatron (Qwen)
|
| 175 |
+
run: |
|
| 176 |
+
unset TORCH_CUDA_ARCH_LIST # Let TRT-LLM CUTLASS DSL auto-detect runtime GPU arch
|
| 177 |
+
export TRTLLM_ENABLE_PDL=0 # Disable Programmatic Dependent Launch (uses SM 9.0 griddepcontrol)
|
| 178 |
+
ray stop --force
|
| 179 |
+
ACTOR_TP=2 \
|
| 180 |
+
ACTOR_PP=1 \
|
| 181 |
+
ROLLOUT_TP=2 \
|
| 182 |
+
INFER_BACKEND=trtllm \
|
| 183 |
+
MODEL_PATH="${HOME}/models/Qwen/Qwen2.5-0.5B-Instruct" \
|
| 184 |
+
bash examples/grpo_trainer/run_qwen3_8b_megatron.sh \
|
| 185 |
+
trainer.total_training_steps=1 \
|
| 186 |
+
data.train_batch_size=32 \
|
| 187 |
+
data.max_prompt_length=128 \
|
| 188 |
+
data.max_response_length=64 \
|
| 189 |
+
actor_rollout_ref.rollout.n=1 \
|
| 190 |
+
actor_rollout_ref.actor.ppo_mini_batch_size=32 \
|
| 191 |
+
actor_rollout_ref.rollout.max_num_seqs=32 \
|
| 192 |
+
actor_rollout_ref.rollout.max_num_batched_tokens=1024 \
|
| 193 |
+
actor_rollout_ref.rollout.max_model_len=256 \
|
| 194 |
+
data.train_files="['${PWD}/data/gsm8k/train.parquet']" \
|
| 195 |
+
data.val_files="['${PWD}/data/gsm8k/test.parquet']" \
|
| 196 |
+
trainer.logger='["console"]'
|
| 197 |
+
- name: clean up
|
| 198 |
+
run: |
|
| 199 |
+
rm -rf checkpoints
|
| 200 |
+
e2e_grpo_trainer_megatron-vlm:
|
| 201 |
+
needs: setup
|
| 202 |
+
runs-on: ["${{ needs.setup.outputs.runner-label || 'L20x8' }}"]
|
| 203 |
+
timeout-minutes: 30 # Increase this timeout value as needed
|
| 204 |
+
env:
|
| 205 |
+
HTTPS_PROXY: ${{ secrets.PROXY_HTTPS }}
|
| 206 |
+
NO_PROXY: "localhost,127.0.0.1,hf-mirror.com"
|
| 207 |
+
HF_ENDPOINT: "https://hf-mirror.com"
|
| 208 |
+
HF_HUB_ENABLE_HF_TRANSFER: "0" # This is more stable
|
| 209 |
+
TORCH_CUDA_ARCH_LIST: "7.5;8.0;8.9;9.0;10.0;12.0+PTX"
|
| 210 |
+
steps:
|
| 211 |
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
| 212 |
+
with:
|
| 213 |
+
fetch-depth: 0
|
| 214 |
+
- name: Reinstall FlashInfer for runtime GPU arch
|
| 215 |
+
run: |
|
| 216 |
+
unset TORCH_CUDA_ARCH_LIST
|
| 217 |
+
pip3 install --force-reinstall --no-deps flashinfer-python
|
| 218 |
+
- name: Install the current repository
|
| 219 |
+
run: |
|
| 220 |
+
pip3 install -r requirements-test.txt
|
| 221 |
+
pip3 install --no-deps -e .
|
| 222 |
+
pip3 install qwen_vl_utils
|
| 223 |
+
pip3 install mathruler
|
| 224 |
+
- name: Prepare GEO3K dataset
|
| 225 |
+
run: |
|
| 226 |
+
python3 examples/data_preprocess/geo3k.py --local_dataset_path ${HOME}/models/hf_data/hiyouga/geometry3k --local_save_dir ${PWD}/data/geo3k
|
| 227 |
+
- name: Running GEO3K E2E training tests with FSDP on 8 L20 GPUs (VLM)
|
| 228 |
+
run: |
|
| 229 |
+
ray stop --force
|
| 230 |
+
ROLLOUT_TP=2 \
|
| 231 |
+
INFER_BACKEND=trtllm \
|
| 232 |
+
MODEL_PATH="${HOME}/models/Qwen/Qwen3-VL-2B-Instruct" \
|
| 233 |
+
bash examples/grpo_trainer/run_qwen2_5_vl_7b_fsdp.sh \
|
| 234 |
+
trainer.total_training_steps=1 \
|
| 235 |
+
data.train_batch_size=8 \
|
| 236 |
+
data.max_response_length=64 \
|
| 237 |
+
actor_rollout_ref.actor.ppo_mini_batch_size=8 \
|
| 238 |
+
actor_rollout_ref.actor.ppo_max_token_len_per_gpu=2048 \
|
| 239 |
+
actor_rollout_ref.rollout.n=2 \
|
| 240 |
+
actor_rollout_ref.rollout.gpu_memory_utilization=0.35 \
|
| 241 |
+
actor_rollout_ref.rollout.max_model_len=2048 \
|
| 242 |
+
actor_rollout_ref.rollout.max_num_seqs=16 \
|
| 243 |
+
actor_rollout_ref.rollout.log_prob_max_token_len_per_gpu=2048 \
|
| 244 |
+
data.train_files="['${PWD}/data/geo3k/train.parquet']" \
|
| 245 |
+
data.val_files="['${PWD}/data/geo3k/test.parquet']" \
|
| 246 |
+
trainer.logger='["console"]'
|
| 247 |
+
- name: clean up
|
| 248 |
+
run: |
|
| 249 |
+
rm -rf checkpoints
|
| 250 |
+
- name: Prepare GSM8K dataset (data_preprocess)
|
| 251 |
+
run: |
|
| 252 |
+
python3 examples/data_preprocess/gsm8k.py --local_dataset_path ${HOME}/models/hf_data/gsm8k --local_save_dir ${PWD}/data/gsm8k
|
| 253 |
+
- name: Running GRPO E2E with FP8 TRT-LLM rollout (Qwen3-0.6B, gsm8k)
|
| 254 |
+
run: |
|
| 255 |
+
unset TORCH_CUDA_ARCH_LIST # Let TRT-LLM CUTLASS DSL auto-detect runtime GPU arch
|
| 256 |
+
export TRTLLM_ENABLE_PDL=0 # Disable Programmatic Dependent Launch (uses SM 9.0 griddepcontrol)
|
| 257 |
+
ray stop --force
|
| 258 |
+
export INFER_TP=2 ACTOR_TP=2 ACTOR_PP=2 ACTOR_VPP=2 ACTOR_EP=1 ACTOR_CP=2 REF_TP=2 REF_PP=2 REF_VPP=2 REF_EP=1 REF_CP=2 GEN_MOE_TP=null GEN_MOE_EP=null
|
| 259 |
+
export NNODES=1 GPUS_PER_NODE=8 TRTLLM_MOE_BACKEND=TRITON
|
| 260 |
+
export DATA_DIR=${PWD} DAPO_MATH_TRAIN=${PWD}/data/gsm8k/train.parquet AIME_VAL=${PWD}/data/gsm8k/test.parquet MODEL_PATH=${HOME}/models/Qwen/Qwen3-0.6B
|
| 261 |
+
INFER_BACKEND=trtllm ROLLOUT_QUANTIZATION=fp8 bash examples/grpo_trainer/run_qwen3_30b_a3b_megatron.sh \
|
| 262 |
+
reward_model.reward_kwargs.overlong_buffer_cfg.len=258 \
|
| 263 |
+
reward_model.reward_kwargs.max_resp_len=512 \
|
| 264 |
+
data.max_prompt_length=128 \
|
| 265 |
+
data.max_response_length=64 \
|
| 266 |
+
data.train_batch_size=32 \
|
| 267 |
+
actor_rollout_ref.rollout.n=1 \
|
| 268 |
+
actor_rollout_ref.rollout.max_num_seqs=16 \
|
| 269 |
+
actor_rollout_ref.rollout.max_num_batched_tokens=1024 \
|
| 270 |
+
actor_rollout_ref.rollout.max_model_len=1024 \
|
| 271 |
+
actor_rollout_ref.actor.megatron.override_transformer_config.moe_grouped_gemm=False \
|
| 272 |
+
actor_rollout_ref.actor.megatron.override_transformer_config.moe_permute_fusion=False \
|
| 273 |
+
trainer.total_training_steps=1 \
|
| 274 |
+
trainer.logger='["console"]'
|
| 275 |
+
- name: clean up
|
| 276 |
+
run: |
|
| 277 |
+
rm -rf checkpoints
|
| 278 |
+
|
| 279 |
+
cleanup:
|
| 280 |
+
runs-on: ubuntu-latest
|
| 281 |
+
needs: [setup, trtllm_unit_tests, e2e_grpo_trainer_megatron-qwen2, e2e_grpo_trainer_megatron-vlm]
|
| 282 |
+
if: always()
|
| 283 |
+
steps:
|
| 284 |
+
- id: destroy-runner
|
| 285 |
+
uses: volcengine/vemlp-github-runner@v1
|
| 286 |
+
with:
|
| 287 |
+
mode: "destroy"
|
| 288 |
+
faas-url: "${{ env.DYNAMIC_RUNNER_ENDPOINT }}"
|
| 289 |
+
mlp-task-id: "${{ needs.setup.outputs.mlp-task-id }}"
|
verl/.github/workflows/e2e_ppo_trainer.yml
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: e2e_ppo_trainer
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
# Trigger the workflow on push or pull request,
|
| 5 |
+
# but only for the main branch
|
| 6 |
+
# For push, for now only anti-patterns are specified so it is more conservative
|
| 7 |
+
# and achieves higher coverage.
|
| 8 |
+
push:
|
| 9 |
+
branches:
|
| 10 |
+
- main
|
| 11 |
+
- v0.*
|
| 12 |
+
paths:
|
| 13 |
+
- "**/*.py"
|
| 14 |
+
# Other entrypoints
|
| 15 |
+
- "!verl/trainer/fsdp_sft_trainer.py"
|
| 16 |
+
|
| 17 |
+
# Megatron
|
| 18 |
+
- "!verl/workers/**/megatron_*.py"
|
| 19 |
+
|
| 20 |
+
pull_request:
|
| 21 |
+
branches:
|
| 22 |
+
- main
|
| 23 |
+
- v0.*
|
| 24 |
+
paths:
|
| 25 |
+
- "**/*.py"
|
| 26 |
+
# Other entrypoints
|
| 27 |
+
- "!**/*.md"
|
| 28 |
+
- "!docker/**"
|
| 29 |
+
- "!examples/**"
|
| 30 |
+
- "!tests/**"
|
| 31 |
+
- "!verl/trainer/main_*.py"
|
| 32 |
+
- "!verl/trainer/fsdp_sft_trainer.py"
|
| 33 |
+
# Docs
|
| 34 |
+
- "!docs/**"
|
| 35 |
+
|
| 36 |
+
# Megatron
|
| 37 |
+
- "!verl/workers/**/megatron_*.py"
|
| 38 |
+
# Entrypoints
|
| 39 |
+
- ".github/workflows/e2e_ppo_trainer.yml"
|
| 40 |
+
- "examples/data_preprocess/gsm8k.py"
|
| 41 |
+
- "examples/data_preprocess/geo3k.py"
|
| 42 |
+
- "tests/special_e2e/ppo_trainer"
|
| 43 |
+
- "verl/trainer/main_ppo.py"
|
| 44 |
+
- "verl/trainer/config/ppo_trainer.yaml"
|
| 45 |
+
|
| 46 |
+
# Cancel jobs on the same ref if a new one is triggered
|
| 47 |
+
concurrency:
|
| 48 |
+
group: ${{ github.workflow }}-${{ github.ref }}
|
| 49 |
+
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
| 50 |
+
|
| 51 |
+
# Declare permissions just read content.
|
| 52 |
+
permissions:
|
| 53 |
+
contents: read
|
| 54 |
+
|
| 55 |
+
jobs:
|
| 56 |
+
pre_commit_for_ppo:
|
| 57 |
+
runs-on: ubuntu-latest
|
| 58 |
+
strategy:
|
| 59 |
+
matrix:
|
| 60 |
+
python-version: ["3.12"]
|
| 61 |
+
steps:
|
| 62 |
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
| 63 |
+
- name: Set up Python ${{ matrix.python-version }}
|
| 64 |
+
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
|
| 65 |
+
with:
|
| 66 |
+
python-version: ${{ matrix.python-version }}
|
| 67 |
+
- name: Install the current repository
|
| 68 |
+
run: |
|
| 69 |
+
pip install pre-commit hydra-core
|
| 70 |
+
pip3 install --no-deps -e .
|
| 71 |
+
- name: Set ruff --output-format=github
|
| 72 |
+
run: |
|
| 73 |
+
sed -i 's/--output-format=full/--output-format=github/' .pre-commit-config.yaml
|
| 74 |
+
git add .pre-commit-config.yaml
|
| 75 |
+
- uses: pre-commit/action@v3.0.1
|
| 76 |
+
with:
|
| 77 |
+
extra_args: "" # Overriding default "--all-files"
|
| 78 |
+
|
verl/.github/workflows/e2e_ppo_trainer_megatron_sglang.yml
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# # Tests layout
|
| 2 |
+
|
| 3 |
+
# Each folder under tests/ corresponds to a test category for a sub-namespace in verl. For instance:
|
| 4 |
+
# - `tests/trainer` for testing functionality related to `verl/trainer`
|
| 5 |
+
# - `tests/models` for testing functionality related to `verl/models`
|
| 6 |
+
# - ...
|
| 7 |
+
|
| 8 |
+
# There are a few folders with `special_` prefix, created for special purposes:
|
| 9 |
+
# - `special_distributed`: unit tests that must run with multiple GPUs
|
| 10 |
+
# - `special_e2e`: end-to-end tests with training/generation scripts
|
| 11 |
+
# - `special_npu`: tests for NPUs
|
| 12 |
+
# - `special_sanity`: a suite of quick sanity tests
|
| 13 |
+
# - `special_standalone`: a set of test that are designed to run in dedicated environments
|
| 14 |
+
|
| 15 |
+
# Accelerators for tests
|
| 16 |
+
# - By default tests are run with GPU available, except for the ones under `special_npu`, and any test script whose name ends with `on_cpu.py`.
|
| 17 |
+
# - For test scripts with `on_cpu.py` name suffix would be tested on CPU resources in linux environment.
|
| 18 |
+
|
| 19 |
+
# # Workflow layout
|
| 20 |
+
|
| 21 |
+
# All CI tests are configured by yaml files in `.github/workflows/`. Here's an overview of all test configs:
|
| 22 |
+
# 1. A list of always triggered CPU sanity tests: `check-pr-title.yml`, `secrets_scan.yml`, `check-pr-title,yml`, `pre-commit.yml`, `doc.yml`
|
| 23 |
+
# 2. Some heavy multi-GPU unit tests, such as `model.yml`, `vllm.yml`, `sgl.yml`
|
| 24 |
+
# 3. End-to-end tests: `e2e_*.yml`
|
| 25 |
+
# 4. Unit tests
|
| 26 |
+
# - `cpu_unit_tests.yml`, run pytest on all scripts with file name pattern `tests/**/test_*_on_cpu.py`
|
| 27 |
+
# - `gpu_unit_tests.yml`, run pytest on all scripts with file without the `on_cpu.py` suffix.
|
| 28 |
+
# - Since cpu/gpu unit tests by default runs all tests under `tests`, please make sure tests are manually excluded in them when
|
| 29 |
+
# - new workflow yaml is added to `.github/workflows`
|
| 30 |
+
# - new tests are added to workflow mentioned in 2.
|
| 31 |
+
|
| 32 |
+
name: e2e_ppo_trainer_megatron_sglang
|
| 33 |
+
|
| 34 |
+
on:
|
| 35 |
+
# Trigger the workflow on push or pull request,
|
| 36 |
+
# but only for the main branch.
|
| 37 |
+
# For push, for now only anti-patterns are specified so it is more conservative
|
| 38 |
+
# and achieves higher coverage.
|
| 39 |
+
push:
|
| 40 |
+
branches:
|
| 41 |
+
- main
|
| 42 |
+
- v0.*
|
| 43 |
+
paths:
|
| 44 |
+
- "**/*.py"
|
| 45 |
+
# Other entrypoints
|
| 46 |
+
- "!verl/trainer/fsdp_sft_trainer.py" # FSDP
|
| 47 |
+
- "!verl/workers/**/*dp_*.py"
|
| 48 |
+
- "!verl/utils/fsdp_utils.py"
|
| 49 |
+
- "!verl/utils/checkpoint/fsdp_checkpoint_manager.py"
|
| 50 |
+
- "!verl/model_merger/fsdp_model_merger.py"
|
| 51 |
+
pull_request:
|
| 52 |
+
branches:
|
| 53 |
+
- main
|
| 54 |
+
- v0.*
|
| 55 |
+
paths:
|
| 56 |
+
- "**/*.py"
|
| 57 |
+
# Other entrypoints
|
| 58 |
+
- "!docker/**"
|
| 59 |
+
# Docs
|
| 60 |
+
- "!**/*.md"
|
| 61 |
+
- "!docs/**"
|
| 62 |
+
- "!examples/**"
|
| 63 |
+
- "!tests/**"
|
| 64 |
+
- "!verl/trainer/main_*.py"
|
| 65 |
+
- "!verl/trainer/fsdp_sft_trainer.py" # FSDP
|
| 66 |
+
- "!verl/workers/**/*dp_*.py"
|
| 67 |
+
- "!verl/utils/fsdp_utils.py"
|
| 68 |
+
- "!verl/utils/checkpoint/fsdp_checkpoint_manager.py"
|
| 69 |
+
- "!verl/model_merger/fsdp_model_merger.py"
|
| 70 |
+
# Entrypoints
|
| 71 |
+
- "verl/worksers/rollout/sglang_rollout/*"
|
| 72 |
+
- ".github/workflows/e2e_ppo_trainer_megatron_sglang.yml"
|
| 73 |
+
- "examples/data_preprocess/gsm8k.py"
|
| 74 |
+
- "examples/data_preprocess/geo3k.py"
|
| 75 |
+
- "tests/special_e2e/run_ppo_trainer_megatron.sh"
|
| 76 |
+
- "verl/trainer/main_ppo.py"
|
| 77 |
+
- "verl/trainer/config/ppo_megatron_trainer.yaml"
|
| 78 |
+
|
| 79 |
+
# Cancel jobs on the same ref if a new one is triggered
|
| 80 |
+
concurrency:
|
| 81 |
+
group: ${{ github.workflow }}-${{ github.ref }}
|
| 82 |
+
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
| 83 |
+
|
| 84 |
+
# Declare permissions just read content.
|
| 85 |
+
permissions:
|
| 86 |
+
contents: read
|
| 87 |
+
|
| 88 |
+
env:
|
| 89 |
+
IMAGE: "verl-ci-cn-beijing.cr.volces.com/verlai/verl:sgl059.dev2"
|
| 90 |
+
DYNAMIC_RUNNER_ENDPOINT: "https://sd10g3clalm04ug7alq90.apigateway-cn-beijing.volceapi.com/runner"
|
| 91 |
+
|
| 92 |
+
jobs:
|
| 93 |
+
setup:
|
| 94 |
+
if: github.repository_owner == 'verl-project'
|
| 95 |
+
runs-on: ubuntu-latest
|
| 96 |
+
outputs:
|
| 97 |
+
runner-label: ${{ steps.create-runner.outputs.runner-label }}
|
| 98 |
+
mlp-task-id: ${{ steps.create-runner.outputs.mlp-task-id }}
|
| 99 |
+
steps:
|
| 100 |
+
- uses: actions/checkout@v4
|
| 101 |
+
- id: create-runner
|
| 102 |
+
uses: volcengine/vemlp-github-runner@v1
|
| 103 |
+
with:
|
| 104 |
+
mode: "create"
|
| 105 |
+
faas-url: "${{ env.DYNAMIC_RUNNER_ENDPOINT }}"
|
| 106 |
+
mlp-image: "${{ env.IMAGE }}"
|
| 107 |
+
|
| 108 |
+
e2e_ppo_trainer_megatron-deepseek:
|
| 109 |
+
needs: setup
|
| 110 |
+
runs-on: ["${{ needs.setup.outputs.runner-label || 'L20x8' }}"]
|
| 111 |
+
timeout-minutes: 60 # Increase this timeout value as needed
|
| 112 |
+
env:
|
| 113 |
+
HTTPS_PROXY: ${{ secrets.PROXY_HTTPS }}
|
| 114 |
+
NO_PROXY: "localhost,127.0.0.1,hf-mirror.com"
|
| 115 |
+
HF_ENDPOINT: "https://hf-mirror.com"
|
| 116 |
+
HF_HUB_ENABLE_HF_TRANSFER: "0" # This is more stable
|
| 117 |
+
ENGINE: sglang
|
| 118 |
+
steps:
|
| 119 |
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
| 120 |
+
with:
|
| 121 |
+
fetch-depth: 0
|
| 122 |
+
- name: Install the current repository
|
| 123 |
+
run: |
|
| 124 |
+
pip3 install -r requirements-test.txt
|
| 125 |
+
pip3 install megatron-bridge --no-deps
|
| 126 |
+
pip3 install git+https://github.com/ISEEKYAN/mbridge.git@main --no-deps --no-build-isolation
|
| 127 |
+
pip3 install --no-deps -e .
|
| 128 |
+
- name: Prepare GSM8K dataset
|
| 129 |
+
run: |
|
| 130 |
+
python3 examples/data_preprocess/gsm8k.py --local_dataset_path ${HOME}/models/hf_data/gsm8k
|
| 131 |
+
- name: Running GSM8K E2E training tests with 3D parallelism on 8 L20 GPUs with Megatron (DeepSeek)
|
| 132 |
+
run: |
|
| 133 |
+
ray stop --force
|
| 134 |
+
OPTIM_MEMORY_EFFICIENT=True ENGINE=sglang SAVE_FREQ=1 MODEL_ID=deepseek-ai/deepseek-coder-1.3b-instruct bash tests/special_e2e/run_ppo_trainer_megatron.sh
|
| 135 |
+
- name: Running GSM8K E2E training tests with 3D parallelism on 8 L20 GPUs with Megatron (DeepSeek)
|
| 136 |
+
run: |
|
| 137 |
+
ray stop --force
|
| 138 |
+
export VLLM_USE_V1=1
|
| 139 |
+
ray start --head
|
| 140 |
+
ENGINE=sglang MODE=async RESUME_MODE=auto MODEL_ID=deepseek-ai/deepseek-coder-1.3b-instruct TOTAL_TRAIN_STEPS=2 bash tests/special_e2e/run_ppo_trainer_megatron.sh
|
| 141 |
+
- name: Profiling GRPO GSM8K E2E training tests with 3D parallelism on 8 L20 GPUs with Megatron (Deepseek)
|
| 142 |
+
run: |
|
| 143 |
+
ray stop --force
|
| 144 |
+
PROFILE_ENABLE=True ENGINE=sglang ADV_ESTIMATOR=grpo USE_DYNAMIC_BSZ=False MODEL_ID=deepseek-ai/deepseek-coder-1.3b-instruct bash tests/special_e2e/run_ppo_trainer_megatron.sh
|
| 145 |
+
if [ -z "$( ls -A '/tmp/ray/session_latest/logs/nsight/' )" ]; then
|
| 146 |
+
echo "[ERROR] not found any profiling files"
|
| 147 |
+
exit 1
|
| 148 |
+
else
|
| 149 |
+
echo "[SUCCESS] profile success"
|
| 150 |
+
fi
|
| 151 |
+
- name: clean up
|
| 152 |
+
run: |
|
| 153 |
+
rm -rf checkpoints
|
| 154 |
+
|
| 155 |
+
# Qwen3-0.6B: dense, tie_word_embeddings=True
|
| 156 |
+
e2e_ppo_trainer_megatron-qwen3:
|
| 157 |
+
needs: setup
|
| 158 |
+
runs-on: ["${{ needs.setup.outputs.runner-label || 'L20x8' }}"]
|
| 159 |
+
timeout-minutes: 60 # Increase this timeout value as needed
|
| 160 |
+
env:
|
| 161 |
+
HTTPS_PROXY: ${{ secrets.PROXY_HTTPS }}
|
| 162 |
+
NO_PROXY: "localhost,127.0.0.1,hf-mirror.com"
|
| 163 |
+
HF_ENDPOINT: "https://hf-mirror.com"
|
| 164 |
+
HF_HUB_ENABLE_HF_TRANSFER: "0" # This is more stable
|
| 165 |
+
ENGINE: sglang
|
| 166 |
+
steps:
|
| 167 |
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
| 168 |
+
with:
|
| 169 |
+
fetch-depth: 0
|
| 170 |
+
- name: Install the current repository
|
| 171 |
+
run: |
|
| 172 |
+
pip3 install -r requirements-test.txt
|
| 173 |
+
pip3 install --no-deps -e .
|
| 174 |
+
pip3 install megatron-bridge --no-deps
|
| 175 |
+
- name: Prepare GSM8K dataset
|
| 176 |
+
run: |
|
| 177 |
+
python3 examples/data_preprocess/gsm8k.py --local_dataset_path ${HOME}/models/hf_data/gsm8k
|
| 178 |
+
- name: Running GSM8K E2E training tests with 3D parallelism on 8 L20 GPUs with Megatron (Qwen3) testing learning rate scheduler
|
| 179 |
+
run: |
|
| 180 |
+
ray stop --force
|
| 181 |
+
ALL_OFFLOAD=True VAL_BEFORE_TRAIN=True TEST_FREQ=1 SAVE_FREQ=1 LR_WARMUP_STEPS=1 TOTAL_TRAIN_STEPS=2 MODEL_ID=Qwen/Qwen3-0.6B bash tests/special_e2e/run_ppo_trainer_megatron.sh
|
| 182 |
+
- name: Running GSM8K E2E training tests with 3D parallelism on 8 L20 GPUs with FP8 rollout
|
| 183 |
+
run: |
|
| 184 |
+
ray stop --force
|
| 185 |
+
export VLLM_USE_V1=1
|
| 186 |
+
ROLLOUT_QUANTIZATION=fp8 TOTAL_TRAIN_STEPS=2 MODEL_ID=Qwen/Qwen3-0.6B bash tests/special_e2e/run_ppo_trainer_megatron.sh
|
| 187 |
+
- name: clean up
|
| 188 |
+
run: |
|
| 189 |
+
rm -rf checkpoints
|
| 190 |
+
|
| 191 |
+
cleanup:
|
| 192 |
+
runs-on: ubuntu-latest
|
| 193 |
+
needs:
|
| 194 |
+
[setup, e2e_ppo_trainer_megatron-deepseek, e2e_ppo_trainer_megatron-qwen3]
|
| 195 |
+
if: always()
|
| 196 |
+
steps:
|
| 197 |
+
- id: destroy-runner
|
| 198 |
+
uses: volcengine/vemlp-github-runner@v1
|
| 199 |
+
with:
|
| 200 |
+
mode: "destroy"
|
| 201 |
+
faas-url: "${{ env.DYNAMIC_RUNNER_ENDPOINT }}"
|
| 202 |
+
mlp-task-id: "${{ needs.setup.outputs.mlp-task-id }}"
|