custom/custom:私有 fork、研究循环、Axolotl、一次性脚本。
平台只跑一个文件:experiments/<name>/train.sh。它不读 FRAMEWORK 变量,
不去找 run.py,也绝不会因为别的 adapter 失败就回退到 custom。那个文件里做什么,完全归你。
1. 脚手架
experiments/my-custom/:config.yaml(脚本不读就可以当废纸)、recipe.lock.json、README.md、train.sh。catalog 入口是 kind: experiment,value: train.sh。改名之后提交会报「custom 入口不存在或越界」。
train.sh 必须在实验目录里。adapter 实际执行:
FORGE_WORK_DIR),不是实验目录。Python 脚本写成 "${FORGE_EXP_DIR}/train.py"。
custom adapter 只编译 operation=train。对自定义实验跑 sf export / sf eval,这条 adapter 不支持。
2. 环境变量契约
模板里已经用:? 卡住缺变量的情况。不要改名。
每个作业还会注入(见环境变量参考):有配置时的
HF_TOKEN、CLUSTER_PROFILE、NRL_RUN_ID、recipe digest,以及可选的 STARFORGE_JUDGE_*、STARFORGE_SANDBOX_*。
配额和 watchdog 按 FORGE_CLUSTER_* 记账。实际占卡超出这个数会被告警甚至停作业。把同样的数字传给 accelerate launch --num_processes / torchrun --nproc_per_node。
3. 脚本必须做的三件事
- checkpoint、日志文件、导出写到
$FORGE_OUT_DIR。写在临时工作树里的东西,容器一退就没了。 - 要看控制台曲线就用
starforge.report。stdout 只进日志页。平台不会去解析loss=这种行。 - 遵守
FORGE_CLUSTER_*。
路径会做 realpath,必须落在
FORGE_OUT_DIR 里面。
4. 能真正跑起来的 train.sh
把脚手架里的 exit 1 换成启动命令。set -euo pipefail 已经有了。
单进程:
cd 到随便一个目录再写 ./checkpoints。用变量。
5. 指标:starforge.report
PyPI 包名 starforge-core,代码里 import starforge。这个模块不 import transformers 或 Ray。上报失败不会把异常抛进训练循环。没有 STARFORGE_TOKEN 就不打网(本机直跑、单测)。设 STARFORGE_ENABLED=0 可以强制关掉。
手写循环
init() 可重复调用。嵌套 dict 会摊平。折不成均值的非标量直接丢掉。prefix= 会加命名空间(键上已经有同样前缀则不加)。
init(monitor_hardware=True) 会起硬件采样,除非已经有组件设过 hardware-bridge 环境变量。间隔:STARFORGE_MONITOR_INTERVAL(秒,默认 10)。
HuggingFace / TRL 回调
StarForgeCallback 是鸭子类型(不继承 TrainerCallback)。train begin 调 init,on_log 调 log,evaluate 时 log(..., prefix="validation"),train end 调 finish。
奖励或环境里
init()。有凭据时 log() 会自己建会话,但不起硬件线程。
不要自己 POST /api/ingest/logs。stdout 已经在转。再走一条会打成双份。
不要在脚本里写死控制台 URL。容器里已经有 STARFORGE_ENDPOINT。
6. 观测:external 和 platform
catalog 里 custom/custom 的 adapter_options.observability 是 external。两件事:
- 提交必须带
--observability-url(你们 wandb/swanlab 一类地址)。缺了会在编译期失败:custom external observability 要求 spec.framework.observability_url。 - adapter 不会改
PYTHONPATH。import starforge只有镜像里装了 wheel(或你自己改PYTHONPATH)才行。
--observability-url 会变成进程环境里的 FORGE_EXTERNAL_OBSERVABILITY_URL。平台不会替你启动 wandb。
如果 recipe 是 observability: platform(要改 catalog,由发 starforge-core 的人做):
- 禁止
--observability-url。 - runner 把 capsule / 内核根加到
PYTHONPATH前面,镜像里不装 wheel 也能from starforge.report import log。
starforge-core,同时仍要带 --observability-url,因为已发布的 recipe 是 external。
STARFORGE_ENABLED=1 是另一件事:服务端绑了 ingest token 就会设。目录 custom 仍然要额外的 URL 字段。
7. 提交
--image 是必填。FORGE_ALLOWED_IMAGE_REGISTRIES 为空时拒绝自定义用户镜像(一等框架仍可用部署默认镜像)。让管理员把仓库主机名加进去。
一等框架的解析顺序是 --image → 控制台默认 → runtime 注册表 → catalog。custom 的 runtime.default_version 是 user-managed,没有 catalog 里的 OCI 钉死,所以 --image 就是镜像。
tag 能用。生产用 @sha256:…,避免准入之后 tag 还在飘。
8. 图表空、秒退、import 失败
进容器里可以:
9. 可选的 config.yaml
custom adapter 不读 Hydra。想让 sf validate 有用,也只覆盖 custom recipe 的 params: 里声明的键(目前是空的)。把 config.yaml 当你自己的文件,在 train.py 里解析。
提交时的 --set 会进 spec.hyperparams。custom 不会把它映射成 argv,除非你自己写。
--model / --train-data 是 verl/TRL 的绑定。custom 不用,除非你去读 JobSpec(不要;用环境和你打进包里的文件)。
10. 如果你在维护平台
要发一等方法(新框架,或observability: platform 的 custom 变体)是 catalog 变更:core/starforge/recipes/catalog/<framework>/<recipe>/、一个 FrameworkAdapter、测试、钉 digest 的镜像,然后 CLI/服务端握手。步骤在仓库 docs/framework-adapters.md。已经部署好的控制台用户,不能靠 sf new 完成这件事。