Submit a recipe
OpenRecipes takes two kinds of contribution: a faster recipe for a model and GPU type, including a pair the catalog does not list yet, and a search procedure that finds recipes, such as a tuner, an agent or a set of rules. Submit a procedure through the recipes it finds; each is one recipe file, and its notes describe or link the procedure.
A recipe is one YAML file at recipes/<model-slug>/<gpu>/<handle>-<layout>.yaml: the layout, the command as run, the measured result, the stack it ran on, the correctness evidence and, where needed, notes. You run the commands below yourself and open a pull request with the file.
Steps
- Pick the pair and the reference recipe. Recipes rank within a model and GPU type, on any number of GPUs. The reference recipe is the one you tune from: a public recipe, the pair's current best or one you wrote. You need not publish it. Apply the objective conventions to both.
- Build the rows with
data/(its README gives the command per tokenizer) and check them withpython3 data/verify_rows.py <rows.parquet> --recipe <a recipe of the same model>. - Measure. Run the recipe once under the protocol: 8,192-token rows, global batch 128, BF16, 20 steps with the profiler off, scored over steps 5–19. Record the score, the step-time CV, the GPU-hours and the framework versions.
- Check correctness. Run a 20-step arm of the reference recipe on the same image and rows, compare its per-step loss with the measured run's using Megatron-Bridge's
validate_convergence, and class every argument that differs between the two. Each same-math swap needs a passed component test at the model's shape. OpenRecipes lists a recipe once all of them pass. - Write the recipe from the template below. Count N with
python3 tools/active_params.py <hf-repo>, take the rate fromgpus.yaml, and add notes only for what is specific to the recipe: the steps every recipe shares are under Running a recipe, and those a model's recipes share go in the model'snotesinmodels.yaml. Add the model tomodels.yamlif it is missing, and put any code beyond the stock stack underpatches/. - Validate and build.
python3 tools/validate.pychecks the file against the schema and recomputes the cost, the MFU, the data-parallel size and the window;python3 tools/build.pyrebuildssite/, andpython3 tools/build.py --checkandpython3 -m pytest -q testsmust pass. Commit the rebuiltsite/with the recipe. - Open a pull request with the recipe, any new patches and the rebuilt site.
Leave out internal paths, image registry addresses, account or cluster names, and datasets you may not cite.
The recipe file
The full schema is schema/recipe.schema.yaml; every recipe in recipes/ is a worked example.
schema_version: 1
model: Qwen3.5-122B-A10B # as in models.yaml; add the model there if it is missing
gpu: {type: H200, memory_gb: 141, count: 32, per_node: 8, instance: AWS p5en.48xlarge}
author: {github: your-handle} # or {name: <tool>, url: https://...}
status: verified
stack: # the versions the measured run used; "not pinned" when unknown
framework: slime <version> (THUDM/slime <commit>)
megatron_lm: <commit> (megatron-core <version>)
transformer_engine: <version>
pytorch: <version>
cuda: <version>
nccl: <version>
workload:
row_tokens: 8192
rows: SFT conversations
global_batch: 128
precision: bf16
dataset:
name: Tulu 3 SFT mixture
source: allenai/tulu-3-sft-mixture
revision: b14afda60f1bbebe55d5d2fa1e4df5042f97f8be
license: ODC-By 1.0
rows_sha256: <printed by data/verify_rows.py>
build: {name: qwen35-tulu3-fixed8192-v1, tokenizer: <name and tokenizer.json sha256>, loss_mask: qwen3_5,
rows: 6400, row_tokens: 8192, seed: 42, builder: data/generate_fixed_sft.py}
layout:
label: TP1 PP4 EP8 DP8
summary: <the full layout in words>
highlights: <the settings that set the recipe apart>
tp: 1
pp: 4
vpp: 1
cp: 1
ep: 8
etp: 1
dp: 8 # gpu.count / (tp x pp x cp)
sequence_parallel: false
layer_split: null # or {first: 11, last: 10}
max_tokens_per_gpu: 8192
rows_per_microbatch: 1
recompute: {granularity: full, method: uniform, num_layers: 1}
offload: null # or {optimizer_fraction: 0.9, overlap_d2h_h2d: true}
dispatcher: alltoall
result:
tokens_per_s_per_gpu: <score over steps 5-19>
usd_per_million_tokens: <rate in gpus.yaml / (tokens/s/GPU x 3600) x 1e6, to the cent>
step_time_cv_percent: <CV of the step time over the window>
mfu: <6 x N x tokens/s/GPU / peak, or null>
mfu_note: null # why, when mfu is null
active_params: {count: <N from tools/active_params.py>, source: https://huggingface.co/<repo>, revision: <commit>}
measured: 2026-10-14
steps_per_run: 20
window: [5, 19]
window_tokens: 15728640 # 15 steps x 128 rows x 8,192 tokens
runs: 1
profiler: false
gpu_hours: <GPUs x (admission to finish)>
gpu_hours_note: GPUs x (scheduler admission to finish), including startup
correctness:
result: pass
summary: <one line>
reference: <the reference recipe, or "Not published.">
configuration: pass
component_tests: [] # one entry per same-math swap: test, shape, gpu, date, result, detail
convergence: {steps: 20, result: pass, correlation: <r>, final_loss_difference: <d>, pointwise_failures: 0}
rules: <the rule lists the check used>
env: {CUDA_DEVICE_MAX_CONNECTIONS: "1"}
patches: [] # files under patches/ the recipe needs
run: |
<the training command as run, with paths replaced by variables>
notes: | # optional; plain text, blank lines separate paragraphs, "- " starts a list item
<what a reader needs to run this recipe that the protocol and the model's notes do not say>
Fields
Generated from the schema. tools/validate.py also checks the cross-field rules listed at the top of the schema file.
| Field | Type | Required | Meaning |
|---|---|---|---|
schema_version | always 1 | yes | |
model | string | yes | The model's name exactly as in models.yaml. |
gpu | object | yes | |
gpu.type | string: H100, H200, B200 | yes | A GPU type listed in gpus.yaml. |
gpu.memory_gb | integer | yes | |
gpu.count | integer | yes | GPUs the measured run used. |
gpu.per_node | integer | yes | |
gpu.instance | string | yes | The machine, for example "AWS p5en.48xlarge". |
author | object | yes | Who submitted the recipe: a GitHub handle for a person or team, or a name and a link for a tool. At least one of github and url. |
author.github | string | ||
author.name | string | ||
author.url | string | ||
author.paper | string | A paper that describes the author's method. | |
status | one of verified | yes | verified = measured under the protocol and passed the correctness check. The site lists verified only. |
stack | object | yes | The versions the measured run used. A version the run's evidence does not show reads "not pinned". |
stack.framework | string | yes | slime or miles, with its commit. |
stack.megatron_lm | string | yes | |
stack.transformer_engine | string | yes | |
stack.pytorch | string | yes | |
stack.cuda | string | yes | |
stack.nccl | string | yes | |
stack.deepep | string | ||
stack.python | string | ||
stack.network | string | GPUs per node and the inter-node network. | |
stack.runtime_fixes | string | Run-time patches the run loaded. | |
stack.source | string | How the versions were read. | |
workload | object | yes | |
workload.row_tokens | integer | yes | Tokens in every row; rows are packed to exactly this length. |
workload.rows | string | yes | |
workload.global_batch | integer | yes | Rows per optimizer step. |
workload.precision | one of bf16 | yes | |
workload.dataset | object | yes | |
workload.dataset.name | string | yes | |
workload.dataset.source | string | yes | The Hugging Face dataset id. |
workload.dataset.revision | string | yes | |
workload.dataset.license | string | yes | |
workload.dataset.rows_sha256 | string | yes | sha256 of the rows' row_hash values in file order, one per line (data/verify_rows.py). |
workload.dataset.build | object | yes | How the rows were built (data/README.md); any further keys describe the build. |
workload.dataset.build.name | string | yes | |
workload.dataset.build.tokenizer | string | yes | |
workload.dataset.build.loss_mask | string | yes | |
workload.dataset.build.rows | integer | yes | |
workload.dataset.build.row_tokens | integer | yes | |
workload.dataset.build.padding_tokens | integer | ||
workload.dataset.build.seed | integer | yes | |
workload.dataset.build.parquet_sha256 | string | ||
workload.dataset.build.builder | string | yes | |
layout | object | yes | |
layout.label | string | yes | Short form for tables, for example "TP1 PP4 EP8 DP8". |
layout.summary | string | yes | The full layout in words. |
layout.highlights | string | yes | The non-parallel settings that set the recipe apart |
layout.tp | integer | yes | |
layout.pp | integer | yes | |
layout.vpp | integer | yes | Virtual pipeline stages per pipeline rank; 1 means none. |
layout.cp | integer | yes | |
layout.ep | integer | yes | |
layout.etp | integer | yes | |
layout.dp | integer | yes | |
layout.sequence_parallel | boolean | yes | True when sequence parallelism is on with TP above 1 (Megatron turns it off at TP 1). |
layout.layer_split | object or null | yes | Layers on the first and last pipeline stages when the split is uneven; null for an even split. |
layout.layer_split.first | integer | yes | |
layout.layer_split.last | integer | yes | |
layout.max_tokens_per_gpu | integer or null | yes | Dynamic batching budget; null without it. |
layout.rows_per_microbatch | integer | yes | under dynamic batching, else the micro-batch size. |
layout.recompute | object or null | yes | |
layout.recompute.granularity | one of full, selective | yes | |
layout.recompute.method | one of uniform, block, null | yes | |
layout.recompute.num_layers | integer or null | yes | |
layout.offload | object or null | yes | CPU optimizer offload; null when the optimizer stays on the GPU. |
layout.offload.optimizer_fraction | number | yes | |
layout.offload.overlap_d2h_h2d | boolean | yes | |
layout.dispatcher | one of alltoall, flex, allgather, null | yes | The MoE token dispatcher; null for a dense model. |
result | object | yes | |
result.tokens_per_s_per_gpu | number | yes | |
result.usd_per_million_tokens | number | yes | |
result.step_time_cv_percent | number | yes | |
result.mfu | number or null | yes | |
result.mfu_note | string or null | yes | |
result.active_params | object | yes | |
result.active_params.count | integer or null | yes | N of the MFU (tools/active_params.py). |
result.active_params.source | string | yes | |
result.active_params.revision | string | yes | |
result.measured | date | yes | |
result.steps_per_run | integer | yes | |
result.window | array | yes | |
result.window_tokens | integer | yes | |
result.runs | integer | yes | |
result.profiler | always false | yes | |
result.gpu_hours | number | yes | |
result.gpu_hours_note | string | yes | |
correctness | object | yes | |
correctness.result | one of pass, fail | yes | |
correctness.summary | string | yes | |
correctness.reference | string | yes | The reference recipe the recipe was checked against |
correctness.configuration | one of pass, fail | yes | The configuration check (layer 1): every argument that differs from the reference recipe is structural or a same-math swap with a passed component test. |
correctness.component_tests | array | yes | |
correctness.component_tests[].test | string | yes | |
correctness.component_tests[].shape | string | yes | |
correctness.component_tests[].gpu | string | yes | |
correctness.component_tests[].date | date | yes | |
correctness.component_tests[].result | one of pass, fail | yes | |
correctness.component_tests[].detail | string | yes | |
correctness.component_tests[].note | string | ||
correctness.convergence | object | yes | The 20-step loss comparison against the reference recipe (Megatron-Bridge validate_convergence). |
correctness.convergence.steps | integer | yes | |
correctness.convergence.result | one of pass, fail | yes | |
correctness.convergence.correlation | number | yes | |
correctness.convergence.final_loss_difference | number | yes | |
correctness.convergence.pointwise_failures | integer | yes | |
correctness.convergence.worst_step_tolerance_ratio | number | ||
correctness.convergence.note | string | ||
correctness.rules | string | yes | The rule lists the check used. |
env | object | yes | Environment variables the run sets, in the command or in the container, as name -> value. |
patches | array | yes | Files under patches/ the recipe needs (patches/README.md). |
run | string | yes | The training command as run, with paths replaced by variables. |
notes | string | What a reader needs that is specific to this recipe, if anything; the site shows it with the recipe. Steps every recipe shares are on the protocol page (Running a recipe), and those a model's recipes share are its notes in models.yaml. |