Skip to main content
训练器不在 catalog 里时用 custom/custom:私有 fork、研究循环、Axolotl、一次性脚本。 平台只跑一个文件:experiments/<name>/train.sh。它不读 FRAMEWORK 变量, 不去找 run.py,也绝不会因为别的 adapter 失败就回退到 custom。那个文件里做什么,完全归你。
不要为了改一个学习率就上 custom。catalog 里的方法已经接好了指标、checkpoint 和镜像; 改用 custom 等于把这三样又还给你自己。

1. 脚手架

得到 experiments/my-custom/config.yaml(脚本不读就可以当废纸)、recipe.lock.jsonREADME.mdtrain.sh。catalog 入口是 kind: experimentvalue: 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_TOKENCLUSTER_PROFILENRL_RUN_ID、recipe digest,以及可选的 STARFORGE_JUDGE_*STARFORGE_SANDBOX_* 配额和 watchdog 按 FORGE_CLUSTER_* 记账。实际占卡超出这个数会被告警甚至停作业。把同样的数字传给 accelerate launch --num_processes / torchrun --nproc_per_node

3. 脚本必须做的三件事

  1. checkpoint、日志文件、导出写到 $FORGE_OUT_DIR。写在临时工作树里的东西,容器一退就没了。
  2. 要看控制台曲线就用 starforge.report。stdout 只进日志页。平台不会去解析 loss= 这种行。
  3. 遵守 FORGE_CLUSTER_*
recipe 声明的产物 glob(平台会在产物目录下找): 路径会做 realpath,必须落在 FORGE_OUT_DIR 里面。

4. 能真正跑起来的 train.sh

把脚手架里的 exit 1 换成启动命令。set -euo pipefail 已经有了。 单进程:
HuggingFace Accelerate,单节点,每卡一个进程:
不要 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 调 initon_loglog,evaluate 时 log(..., prefix="validation"),train end 调 finish

奖励或环境里

不必先 init()。有凭据时 log() 会自己建会话,但不起硬件线程。 不要自己 POST /api/ingest/logs。stdout 已经在转。再走一条会打成双份。 不要在脚本里写死控制台 URL。容器里已经有 STARFORGE_ENDPOINT

6. 观测:externalplatform

catalog 里 custom/customadapter_options.observabilityexternal。两件事:
  • 提交必须--observability-url(你们 wandb/swanlab 一类地址)。缺了会在编译期失败:custom external observability 要求 spec.framework.observability_url
  • adapter 不会PYTHONPATHimport 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
实验目录改不了这个开关。要换就得在 catalog 里发新 recipe。普通用户今天想看控制台曲线:镜像里装 starforge-core,同时仍要带 --observability-url,因为已发布的 recipe 是 external STARFORGE_ENABLED=1 是另一件事:服务端绑了 ingest token 就会设。目录 custom 仍然要额外的 URL 字段。

7. 提交

custom 的 --image 是必填。FORGE_ALLOWED_IMAGE_REGISTRIES 为空时拒绝自定义用户镜像(一等框架仍可用部署默认镜像)。让管理员把仓库主机名加进去。 一等框架的解析顺序是 --image → 控制台默认 → runtime 注册表 → catalog。custom 的 runtime.default_versionuser-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 完成这件事。