argus-cluster/specs/mvp/v1.1/sdk_submit_refactor.md
2025-12-23 14:22:15 +08:00

149 lines
5.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# MVP v1.1 工程化重构方案Ray Python SDK 提交层YAML Config + YAML JobSpec
本文档把 v1.1 的“代码工程化”目标落到一个明确的设计:**保留现有 scripts**Ray 集群构建、数据准备、模型准备、代码快照),将“任务提交机制”重构为 **Ray Python SDK**`ray.job_submission.JobSubmissionClient`)驱动的 Python 工具层。
> 约束(已确认)
> 1) 基础配置用 YAMLJobSpec 也用 YAML。
> 2) 工具必须在 **head 容器**执行(从 head 发起提交,满足“在 head 提交”的要求)。
> 3) 训练参数组织保持与现在一致:仍然使用 **Hydra overrides** 方式构造 entrypoint。
> 4) 不使用 `requests` 直连 HTTP API只用 Ray SDK
---
## 1. 当前 Ray SDK 能力验证(关键前提)
在 head 容器(`mvp11-ray-head`)中验证:
- Ray 版本:`2.51.1`
- `JobSubmissionClient.submit_job` 支持以下关键字段:
- `submission_id`
- `runtime_env`
- `entrypoint_num_cpus`
- `entrypoint_num_gpus`
- `entrypoint_resources`(用于强制 driver 落 worker
因此 v1.1 可以“纯 SDK”完成提交不需要 `requests` fallback。
---
## 2. 系统分层(不动 scripts只重构提交层
### 2.1 scripts保留
`src/mvp/v1.1/scripts/` 继续负责:
- 容器生命周期:`01_up.sh` / `02_down.sh`
- Ray 启动:`20_start_head.sh` / `21_start_workers.sh`
- 数据/模型准备:`30_prepare_data_and_model.sh`
- 代码快照:`31_snapshot_verl_code.sh`(生成 `${SHARED_ROOT}/common/code/verl/<code_id>/`
scripts 可以新增一个“薄封装”脚本,负责 `docker exec` 进 head 容器并运行 Python 提交器,但 scripts 不再拼 `ray job submit ...` CLI 字符串。
### 2.2 Python 工具层(新增)
`src/mvp/v1.1/py/` 新增提交工具层:
- 读取 Ray 基础配置YAML
- 读取训练 JobSpecYAML
- 用 Ray Python SDK 提交/查询/停止/拉日志
- 将 job 级别产物落盘到:`${SHARED_ROOT}/jobs/<submission_id>/...`
---
## 3. 输入定义:两份 YAML
### 3.1 Ray 基础配置RayConfig YAML
这份配置是“稳定可复用”的,描述 cluster 与 driver placement 等通用信息。
字段建议:
- `address`: `http://127.0.0.1:8265`(从 head 容器内部视角)
- `shared_root`: `/private`
- `entrypoint_num_cpus`: `1`
- `entrypoint_resources`: `{"worker_node": 1}`(强制 driver 使用 worker 才有的资源)
- `runtime_env.env_vars`: HF cache / endpoint 等通用环境变量
- `user_code_path`: `${shared_root}/user/code`(可选,默认值也可)
### 3.2 训练 JobSpecJobSpec YAML
这份配置是“一次训练”语义,描述 workload + 训练参数 + code_path 多版本等。
字段建议:
- `workload`: `ppo|grpo|sft`
- `submission_id`: 可选(不填则生成;但最终必须显式传给 SDK
- `code_path`: `${shared_root}/common/code/verl/<code_id>`(多版本关键字段)
- `model_id`
- 数据路径:`train_file` / `val_file`(按 workload
- 训练参数:`nnodes` / `n_gpus_per_node` / `total_training_steps` / `save_freq` / `test_freq`
注意SFT 的 driver 设备选择):
- Ray job 的 entrypointdriver默认不分配 GPU我们通常不设置 `entrypoint_num_gpus`)。
- `sft_trainer_ray.py` 的 driver 会用 `trainer.device` 做张量统计;若设置为 `cuda` 且 driver 无 GPU会报
- `RuntimeError: No CUDA GPUs are available`
- 因此 v1.1 的 SFT JobSpec 默认应设置:`trainer.device=cpu`(训练 workers 仍会占用 GPU
---
## 4. Python 提交器的职责tool class
建议实现 `RayJobTool`(或类似命名),能力:
### 4.1 submit核心
输入:`RayConfig + JobSpec`
输出:`submission_id`
实现要点:
- `client = JobSubmissionClient(address)`
- 生成/确定 `submission_id`
- `runtime_env` 合并逻辑:
- 合并 config 与 jobspec 的 `env_vars`
- 强制注入多版本:
- `PYTHONPATH = "<code_path>:<user_code_path>:$PYTHONPATH"`
- 构造 entrypoint保持 hydra overrides 风格):
- PPO/GRPO`python3 -m verl.trainer.main_ppo ...`
- SFT`python3 -m verl.trainer.sft_trainer_ray ...`
- 强制 driver 落 worker
- `entrypoint_resources=config.entrypoint_resources`
- `entrypoint_num_cpus=config.entrypoint_num_cpus`
- 落盘产物:
- `${shared_root}/jobs/<id>/config/{ray_config.yaml,jobspec.yaml,submit_payload.json}`
- `${shared_root}/jobs/<id>/logs/submit.out`
- `${shared_root}/jobs/<id>/debug/{ray_status_pre,ray_job_list_post}.txt`(可用 SDK 或 `ray status` 采集)
### 4.2 status / stop / logs / list
- `status(submission_id)`
- `stop(submission_id)`
- `logs(submission_id)`(可支持 tail
- `list()`
---
## 5. `run.py` 入口(必须在 head 容器执行)
建议入口:
- `python3 /workspace/mvp/v1.1/py/run.py --config <ray_config.yaml> --jobspec <jobspec.yaml> --action submit`
- `--action` 支持:`submit|status|stop|logs|list`
host 侧执行方式(由 scripts 薄封装):
- `docker exec mvp11-ray-head python3 /workspace/mvp/v1.1/py/run.py ...`
---
## 6. 验收口径(工程化部分)
1) **SDK 提交**:不使用 `ray job submit` CLI改用 `JobSubmissionClient.submit_job`
2) **driver 仍强制在 worker**SDK 提交时 `entrypoint_resources={"worker_node":1}` 生效。
3) **多版本共存验证**
- 通过 `31_snapshot_verl_code.sh` 生成 `codeA/codeB` 两份 code_path
- 通过两份 JobSpec 分别指向不同 `code_path`
- 在 job logs 中看到不同的 marker例如 `mvp_marker.MARKER`