170 lines
8.3 KiB
Markdown
170 lines
8.3 KiB
Markdown
# MVP v1.1 计划(Hardening + 多 Workload 可行性验证)
|
||
|
||
本目录是 `specs/mvp/v1/` 的下一步迭代:在 v1 已经跑通(Ray head + 2 worker,PPO on Ray,持久化落盘)的基础上,把它升级为**可长期回归**的最小系统,并扩展至少一个新 workload 的可行性闭环。
|
||
|
||
> v1.1 的目标不是做平台服务化(API/队列/多用户)——那是 v2/v3 的工作;v1.1 聚焦“工程化 + 可行性边界验证 + 可观测/可排障基础”。
|
||
|
||
---
|
||
|
||
## 1. v1 基线回顾(已完成)
|
||
|
||
- 拓扑:1 head(无 GPU,CPU/GPU=0)+ 2 worker(各 4 GPU)
|
||
- 提交方式:必须用 head 上的 `ray job submit`
|
||
- driver 调度:通过 `worker_node` 自定义资源 + `--entrypoint-resources` 强制 driver 在 worker
|
||
- 输出:按 `submission_id` 组织到共享目录(NFS)
|
||
|
||
相关实现参考:
|
||
|
||
- 脚本:`src/mvp/v1/`
|
||
- 验收动作:`specs/mvp/v1/v1_action.md`
|
||
- Roadmap:`specs/mvp/mvp_roadmap.md`
|
||
|
||
---
|
||
|
||
## 2. v1.1 目标(必须达成)
|
||
|
||
### 2.1 工程化(Hardening)
|
||
|
||
1) **JobSpec 标准化(最小)**
|
||
- 把“提交 job 需要的参数”收敛成结构化文件:
|
||
- Ray 基础配置(YAML):cluster 地址、entrypoint 资源约束、runtime_env 等
|
||
- 训练 JobSpec(YAML):workload 语义与训练参数
|
||
- 至少覆盖:`submission_id`、workload 类型、资源需求、共享根路径、模型/数据路径、输出目录、超时、环境变量注入。
|
||
- v1.1 实现落点(已在 repo 里提供,SDK 方式):
|
||
- RayConfig 示例:`src/mvp/v1.1/py/configs/dev.yaml`
|
||
- JobSpec 示例:`src/mvp/v1.1/py/jobspecs/{ppo,grpo,sft}.yaml`
|
||
- 提交入口:`src/mvp/v1.1/py/run.py`(在 head 容器内执行,使用 Ray Python SDK 提交)
|
||
- 设计文档:`specs/mvp/v1.1/sdk_submit_refactor.md`
|
||
|
||
2) **共享根路径抽象(dev/prod 一致)**
|
||
- 引入 `SHARED_ROOT` 作为唯一共享根路径:
|
||
- dev:建议也用 `/private`(docker compose 把宿主机 shared 挂到容器内 `/private`,模拟生产)
|
||
- prod:固定 `/private`(算力平台容器内 NFS)
|
||
- 任何代码/脚本不得写死 `/mnt/shared`(允许兼容旧路径但不得作为主路径)。
|
||
|
||
3) **共享目录分层(新增 `common/` 与 `user/`)**
|
||
- 在 `datasets/hf/jobs/outputs` 之外,新增一个所有用户可读写的共享区:
|
||
- `${SHARED_ROOT}/common/`:共享模型/数据/代码快照(多版本 verl / 公共数据)
|
||
- `${SHARED_ROOT}/user/`:用户自定义代码(例如 `reward_fn_path` 指向这里)
|
||
- v1.1 默认策略:先假设“所有用户可写”(后续 v3 再做权限与隔离)。
|
||
|
||
4) **可排障基础**
|
||
- 每个 job 目录必须有:
|
||
- `config/`:提交命令、JobSpec 快照、关键 env_vars
|
||
- `logs/`:Ray job logs + hydra logs(如有)
|
||
- `checkpoints/`:按 `save_freq` 控制频率(默认每 10 step)
|
||
- 提供“失败快照”能力:收集 `ray status` / `ray job list` / `ray list nodes` / `ray list actors`(最少其中 2 项)写入 job 目录。
|
||
- v1.1 submitter 默认落盘:
|
||
- `${SHARED_ROOT}/jobs/<id>/config/job_spec.json`
|
||
- `${SHARED_ROOT}/jobs/<id>/config/runtime_env.json`
|
||
- `${SHARED_ROOT}/jobs/<id>/config/submit_cmd.txt`
|
||
- `${SHARED_ROOT}/jobs/<id>/logs/ray_job_submit.out`
|
||
- `${SHARED_ROOT}/jobs/<id>/debug/ray_status_{pre,post}.txt`
|
||
- `${SHARED_ROOT}/jobs/<id>/debug/ray_job_list_post.txt`
|
||
|
||
### 2.2 Workload 扩展(至少新增 1 个)
|
||
|
||
v1.1 需要新增并验收通过两个 workload(都要跑通闭环):
|
||
|
||
- **GRPO on Ray**(推荐优先,复用 PPO 入口,通过算法配置切换)
|
||
- 基于 `python -m verl.trainer.main_ppo`
|
||
- 通过配置覆盖:`algorithm.adv_estimator=grpo`(以及必要的 rollout 参数)
|
||
|
||
- **SFT on Ray(Ray-native)**
|
||
- 入口:`python -m verl.trainer.sft_trainer_ray`
|
||
- 参考实现:`verl/verl/trainer/sft_trainer_ray.py`(内部会 `ray.init()`)
|
||
- 需要确保 `ray.init()` 连接已有集群:
|
||
- 优先:`runtime_env.env_vars.RAY_ADDRESS=auto`(配合 `ray job submit`)
|
||
- 兜底:在 v1.1 的 launcher 脚本里显式 `ray.init(address="auto")` 再调用 trainer(避免依赖 Ray 的 env var 行为差异)
|
||
- 重要细节:Ray Job 的 entrypoint(driver)默认不分配 GPU,因此 SFT driver 侧不要强依赖 CUDA:
|
||
- 推荐:`trainer.device=cpu`(driver 只做 orchestration;训练由 Ray workers 占 GPU)
|
||
|
||
---
|
||
|
||
## 3. v1.1 关键设计点
|
||
|
||
### 3.1 多版本代码与自定义逻辑(为 v3.1 铺路,但 v1.1 先做最小验证)
|
||
|
||
已确定优先方案(A):通过 **Ray Job 的 `runtime_env.env_vars`** 注入 `PYTHONPATH`。
|
||
|
||
- `code_path`(例如 `${SHARED_ROOT}/common/code/verl/<commit>`)
|
||
- 提交 job 时设置:
|
||
- `runtime_env.env_vars.PYTHONPATH = "<code_path>:$PYTHONPATH"`
|
||
|
||
并约定:
|
||
|
||
- `reward_fn_path` 可指向 `${SHARED_ROOT}/user/code/...` 下用户自定义代码
|
||
- 与 `code_path` 一样,必须通过 `runtime_env.env_vars` 确保该路径可被 import(例如把 `${SHARED_ROOT}/user/code` 也加入 `PYTHONPATH`)
|
||
|
||
v1.1 中至少做一次“代码覆盖验证”:
|
||
|
||
- 在 code_path 下放一个可识别的 `verl` 版本标识(例如 `verl.__version__` 打印差异)
|
||
- 提交 job 并在日志中确认 import 的是 code_path 的版本(而不是镜像内默认安装)
|
||
|
||
v1.1 的最小落地方式(已实现):
|
||
|
||
- 提供代码快照脚本:`src/mvp/v1.1/scripts/31_snapshot_verl_code.sh`
|
||
- 会把 `/workspace/verl`(挂载的 repo)复制到 `${SHARED_ROOT}/common/code/verl/<code_id>/`
|
||
- 并写入 `${code_path}/mvp_marker.py`,用于在 Ray job logs 中验证“选用的是哪份 code_path”
|
||
- submitter 会在 entrypoint 前运行 preflight:
|
||
- 打印 `verl.__file__` 与 `mvp_marker.MARKER`
|
||
- 由此确认 job 粒度的 PYTHONPATH 生效,且不同 job 可指向不同 `code_path`(多版本共存)
|
||
|
||
### 3.2 Checkpoint 策略(磁盘保护)
|
||
|
||
- 默认:`save_freq=10`(每 10 step 保存一次)
|
||
- 对于 step 数已知的短任务(例如 29 steps),可以通过配置把 `save_freq` 调整为 10/15/29(按需求权衡)
|
||
- 作业目录按 `submission_id` 隔离,方便清理与归档
|
||
|
||
---
|
||
|
||
## 4. v1.1 交付物清单(代码 + 文档)
|
||
|
||
### 4.1 代码(建议落点)
|
||
|
||
在 `src/mvp/` 下新增 v1.1 级别的提交器与模板(或在 `src/mvp/v1` 原地演进但要保持 v1 可回归):
|
||
|
||
- `src/mvp/v1.1/`
|
||
- `docker-compose.yaml`(与 v1 互不干扰的容器名/网络名)
|
||
- `scripts/`(Ray 启动/prepare 保留 bash;submit 通过 SDK 工具执行)
|
||
- `py/`(工程化提交层:YAML + Ray Python SDK)
|
||
- `py/configs/`(Ray 基础配置)
|
||
- `py/jobspecs/`(训练 JobSpec)
|
||
- `py/run.py`(入口)
|
||
|
||
此外,为了对齐 dev 环境约束(远程机固定目录):
|
||
|
||
- 远程机目录必须新增:`argus@h1:/home2/argus/infra/mvp/v1.1/`
|
||
- 该目录内需包含 v1.1 的全部内容(compose + scripts + README),可由本 repo 的 `src/mvp/v1.1/` 同步过去
|
||
|
||
### 4.2 文档
|
||
|
||
- `specs/mvp/v1.1/v1.1_action.md`:开发、部署、测试、验收流程(可复现)
|
||
- 更新 `specs/mvp/mvp_roadmap.md`:保持路线图与落地一致(按需)
|
||
|
||
---
|
||
|
||
## 5. v1.1 验收标准(DoD)
|
||
|
||
### 5.1 Hardening DoD
|
||
|
||
- [ ] 所有提交均由 head 执行 `ray job submit`,且显式 `--submission-id=<id>`
|
||
- [ ] 共享根路径由 `SHARED_ROOT` 控制(dev/prod 可切换),脚本无硬编码
|
||
- [ ] 每个 job 的输出目录为:`${SHARED_ROOT}/jobs/<submission_id>/`
|
||
- [ ] checkpoint 不会“每 step 保存”导致爆盘:默认 `save_freq=10`
|
||
- [ ] job 失败时,`${SHARED_ROOT}/jobs/<id>/config/` 中有足够信息定位(命令、env、ray 状态快照)
|
||
- [ ] v1.1 测试前会清理 v1 的遗留容器/进程(避免端口、容器名、Ray session 干扰)
|
||
|
||
### 5.2 Workload DoD(GRPO + SFT 都必须)
|
||
|
||
GRPO(必须):
|
||
|
||
- [ ] `algorithm.adv_estimator=grpo` 的 job 可提交并进入 RUNNING
|
||
- [ ] job 能跑完最小训练步数(可设 `total_epochs=1` 或 `total_training_steps`)
|
||
- [ ] 输出目录内有日志与至少 1 次 checkpoint(或明确不保存并说明原因)
|
||
|
||
SFT(必须):
|
||
|
||
- [ ] `sft_trainer_ray` 可连接集群并跑到至少 1 个 step(推荐最小训练步数/epoch)
|
||
- [ ] 输出目录与 checkpoint 策略同 v1.1 规范(落盘到 `${SHARED_ROOT}/jobs/<id>/...`)
|