Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions tests/test_rl_verl_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -447,3 +447,12 @@ def test_verl_data_cursor_refuses_what_it_cannot_honour():
cur.seek({"sample_offset": 2})
with pytest.raises(RuntimeError, match="twice"):
VerlDataCursor(trainer)


def test_verl_refuses_expert_parallel_with_e7_reason():
# S26 E7: verl+EP is refused with the reason and the backend to use instead.
from yeto.rl.adapters.verl import run_config_rules as rules

rules.check_expert_parallel(8, 1)
with pytest.raises(ValueError, match="E7.*Miles"):
rules.check_expert_parallel(8, 8)
10 changes: 10 additions & 0 deletions tests/test_stage1_plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,3 +250,13 @@ def edit(doc):
doc["trainer"]["miles"]["memory_estimate"]["host_optimizer_gib_per_node"] = 600
out = _variant(tmp_path, edit)
assert any("host_optimizer_gib_per_node = 600" in e for e in out.errors)


def test_verl_backend_refuses_megatron_strategy(tmp_path):
# S26 E7: verl Megatron (the verl path with EP) is not wired; EP runs use Miles.
out = _variant(tmp_path, lambda d: d["trainer"].update(backend="verl")
or d["trainer"]["verl"].update(strategy="megatron"))
assert any("verl.strategy 'megatron'" in e and "backend miles" in e for e in out.errors)
# The same strategy value is not checked for the Miles backend (its section is unused).
miles = _variant(tmp_path, lambda d: d["trainer"]["verl"].update(strategy="megatron"))
assert not any("verl.strategy" in e for e in miles.errors)
8 changes: 7 additions & 1 deletion yeto/rl/adapters/verl/run_config_rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,15 @@ def check_trainer_parallel(actor_gpus: int, tensor_parallel: int, pipeline_paral
raise ValueError("verl backend first step: one GPU per island")


# S26 E7 decision: the verl Megatron engine (the only verl path with expert
# parallelism) is not wired into this adapter; MoE runs with EP go to Miles.
EP_REFUSAL = ("verl 后端不支持专家并行(EP>1):yeto 的 verl 适配层只接 FSDP2,"
"未接 verl Megatron 引擎(S26 E7 结论:不做)。EP 训练请用 Miles 后端")


def check_expert_parallel(actor_gpus: int, expert_parallel: int) -> None:
if expert_parallel != 1:
raise ValueError("verl backend first step: no expert parallelism")
raise ValueError(f"{EP_REFUSAL};收到 expert_parallel={expert_parallel}")


def check_global_batch(global_batch: int, data_parallel: int) -> None:
Expand Down
5 changes: 5 additions & 0 deletions yeto/rl/stage1.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@

PLAN_SCHEMA = "yeto.stage1/v1"
BACKENDS = ("miles", "verl")
VERL_STRATEGY = "fsdp2" # the only verl actor strategy the adapter runs (S26 E7)
NEUTRAL_PENALTIES = {"repetition_penalty": 1.0, "frequency_penalty": 0.0, "presence_penalty": 0.0}
RAY_PORT = 6379
MEMORY_TOLERANCE = 0.02 # plan memory figures vs the estimator (both 推算)
Expand Down Expand Up @@ -819,6 +820,10 @@ def check(plan: Stage1Plan, out: Expanded) -> list[str]:
if "fp8" in flat or "fp4" in flat:
errors.append("trainer arguments enable FP8/FP4; training is bf16 only (user 10-19, report #1)")
verl = _section(trainer_cfg, "verl")
if out.trainer["backend"] == "verl" and str(verl["strategy"]) != VERL_STRATEGY:
# S26 E7: the verl Megatron engine (EP) is not wired; EP runs use Miles.
errors.append(f"verl.strategy {verl['strategy']!r}: the yeto verl adapter runs {VERL_STRATEGY} "
"only (verl Megatron/EP not supported, S26 E7); use trainer.backend miles for EP")
if int(verl["fsdp_size"]) not in (0, out.trainer["cards"]) and out.trainer["cards"] % int(verl["fsdp_size"]):
errors.append(f"verl.fsdp_size {verl['fsdp_size']} does not divide {out.trainer['cards']} cards")

Expand Down
Loading