149 lines
5.5 KiB
Markdown
149 lines
5.5 KiB
Markdown
# MVP v1.1 工程化重构方案:Ray Python SDK 提交层(YAML Config + YAML JobSpec)
|
||
|
||
本文档把 v1.1 的“代码工程化”目标落到一个明确的设计:**保留现有 scripts**(Ray 集群构建、数据准备、模型准备、代码快照),将“任务提交机制”重构为 **Ray Python SDK**(`ray.job_submission.JobSubmissionClient`)驱动的 Python 工具层。
|
||
|
||
> 约束(已确认)
|
||
> 1) 基础配置用 YAML,JobSpec 也用 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)
|
||
- 读取训练 JobSpec(YAML)
|
||
- 用 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 训练 JobSpec(JobSpec 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 的 entrypoint(driver)默认不分配 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`)
|
||
|