Skip to content

docs(training): align cookbook docs and skill references#421

Closed
Hecate0821 wants to merge 15 commits into
mainfrom
chengxi/training-doc-skill-alignment
Closed

docs(training): align cookbook docs and skill references#421
Hecate0821 wants to merge 15 commits into
mainfrom
chengxi/training-doc-skill-alignment

Conversation

@Hecate0821

@Hecate0821 Hecate0821 commented May 4, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • align training skill references with the current examples tree and shape auto-selection behavior
  • update README/tool docs for current tools, SDK pin, and control-plane checkpoint promotion
  • fold the standalone IGPO recipe into async_rl_loop extension hooks, remove recipes/igpo_loop.py, and document the async IGPO hook path
  • fix multi-hop QA README/run.sh commands so they work from cookbook/training

Verification

  • Markdown local path scan over training/ and skills/ docs (only pre-existing absolute /skills references remain)
  • targeted stale-term grep for removed example paths, old SDK pins, and igpo_loop references
  • bash -n training/examples/multihop_qa/run.sh
  • python -m compileall -q training/recipes/async_rl_loop.py training/utils/rl/igpo.py training/utils/rl/init.py training/tests/unit/test_recipe_trainer_replicas.py
  • git diff --check
  • added-lines sensitive-data regex scan: no real secrets found

Not run

  • pytest -q training/tests/unit/test_llms_txt.py training/tests/unit/test_async_rl_train.py training/tests/unit/test_recipe_trainer_replicas.py (local environment is missing the fireworks package: ModuleNotFoundError: No module named fireworks)

Hecate0821 and others added 14 commits May 4, 2026 22:34
Rebased onto main: this is a clean reapply of the renderer-backed RL
rollout work (the original plan AC-1..13) on top of latest main.  All
checkpoint / GLM5 / weight_sync drift accumulated during the cancelled
RLCR review loop has been dropped — those concerns are addressed (or
intentionally out of scope) on main.

What's in (the original 13 ACs):

- AC-1 single_turn_renderer_rollout (utils/rl/renderer_rollout.py) —
  renderer-built prompts + sampler-returned tokens end-to-end via
  sample_with_prompt_tokens; multimodal raises
  MultimodalRenderingNotSupported
- AC-2 multi_turn_minimal_renderer/rollout.py (concrete example using
  TrajectoryAssembler.add_call)
- AC-3 inline 3-line extension-property guard inside the shared
  _renderer_turn_loop helper (NOT exported as a typed error)
- AC-4 multi_turn_tool/rollout.py (renderer parses tool_calls;
  user-supplied env's execute runs tools; loss_mask=1 only on
  assistant tokens)
- AC-5 RolloutService-backed remote-rollout helper (utils/rl/
  text_rollout.py + rollout_service.py); RolloutPayload / TurnRecord
  schema unchanged
- AC-6 ep_remote_grader/ refactored to renderer-built tokens (no
  chr(...) synthesis); not training-grade and documented as such
- AC-7 NO parse/truncation policy enums, _apply_parse_policy helper,
  or parse_failure_total metric exported
- AC-8 Renderer injection is explicit constructor arg; RolloutContext
  unchanged at the trainer surface
- AC-9 The SDK side (sample_with_prompt_tokens) is in the SDK repo,
  outside this PR
- AC-10 Parametrized RL-behavior tests for gemma4 + kimi_k25
- AC-11 Populated examples: single_turn_sync_on_policy/,
  single_turn_async/, multi_turn_minimal_renderer/, multi_turn_tool/,
  remote_rollout/, ep_remote_grader/, gsm8k_async/; updated
  multihop_qa migration; frozen_lake migration
- AC-12 Trainer code zero parse/truncation policy enums, zero
  _apply_parse_policy, zero parse_failure_total, zero cookbook-local
  sampler shim
- AC-13 Async RL loop (recipes/async_rl_loop.py) with per-turn
  output_versions plumbing

Recipe-side hooks (minimal):
- rl_loop.main(rollout_fn=..., ctx_extras=...) accepts a pluggable
  rollout function that receives RolloutContext, mirroring
  async_rl_loop.RolloutContext.  The default sample_one_prompt path
  is preserved when rollout_fn=None.
- utils/rl/losses.PromptGroup.prompt_lens (Optional[List[int]]) —
  per-sample prompt-token length for heterogeneous multi-turn
  rollouts (different prefix lengths per sample).  None keeps the
  legacy single-prompt behavior.
- utils/rl/metrics.compute_step_metrics(fwd_bwd_weights=...) —
  sample-weighted mean across PPO inner minibatches when the last
  minibatch is smaller than the rest (matches per-sample prompt_lens
  treatment in entropy).
- utils/data.replicate_rows_for_epochs(rows, epochs) — independent
  deep-copied row dicts per epoch so rollout functions that mutate
  rows in place don't leak state across epochs.

What's deliberately NOT in:
- All checkpoint/resume changes (TrainingCheckpoints API, dataloader.json,
  legacy mirroring, _ResumeAnchor, record_cursor_only, durable
  counters, _durable_delta fallback).  Those were either out of scope
  or accumulated drift from the cancelled review loop; correctness on
  main is unchanged by this PR.
- All renderer (glm5.py) changes.  Take main's version.
- All SFT preserve-thinking changes (already on main).
- DPO / IGPO / ORPO recipe changes (drift).
- promote_checkpoint.py changes (drift).
- weight_sync inline-in-train_step (doc-vs-impl semantics, no real
  correctness benefit; reverted in this rebase).

Sanity checks:
- All rollout-side imports resolve
- training/tests/unit/test_rollout.py + test_renderer_rollout.py +
  test_rollout_helpers.py + test_rl_renderer_behavior.py +
  test_data_utils.py + tests/structural/: 77 pass / 18 skipped
- training/tests/unit/test_rl_loop.py + test_checkpoints.py:
  36 pass (no regression on main's existing tests)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ests

Restructure the async RL recipe surface and remove redundant
policy-as-test infrastructure that grew out of the original RLCR loop.

- Move training/recipes/async_rl_loop.py -> training/advanced/async_rl.py;
  recipes/async_rl_loop.py is now a thin re-export shim so existing
  examples (single_turn_async, gsm8k_async, multi_turn_minimal,
  remote_rollout, ep_remote_grader) keep importing the legacy path.
- Add empty training/examples/advanced/ scaffold for examples that
  exercise training.advanced.async_rl.
- Drop renderer-heavy reference docs that were artifacts of the
  original audit: training/utils/rl/RENDERER_AUDIT.md and
  training/utils/rl/SCHEMA_DECISION.md.
- Drop training/tests/structural/test_rl_helper_boundaries.py and
  training/tests/unit/test_rl_renderer_behavior.py as redundant
  policy-as-test (the boundaries are now reviewer-enforced and listed
  in training/utils/rl/README.md).
- Drop TestAsyncMainReturnContract from test_async_rl_train.py
  (source-string inspection of main() rather than behavior).
- Add fixture-only docstring to multi_turn_minimal_renderer/__init__.py
  pointing at runnable siblings (single_turn_async, ep_remote_grader).
- Fix stale assembler.to_payload(...) -> pack_payload_to_sample chain
  in multi_turn_minimal_renderer/rollout.py and multi_turn_tool/rollout.py
  module docstrings (the code calls pack_assembled_to_sample).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reorganize rollout helpers into training/utils/rl/rollout/ as five
focused modules (types, service, remote, renderer, assembler). Drop
silent fallbacks introduced earlier in this branch:

- rl_loop.main(rollout_fn=...) is required; the recipe ships a
  module-level default_rollout_fn instead of an in-main closure.
- default_rollout_fn fails loud on sampler exceptions and on
  logprob/token misalignment (no try/except, no padding/truncation).
- _dump_trajectory reads prompt/completions from row_meta only
  (no PromptGroup-field fallback).
- Restore router_replay end-to-end through Rollout: RolloutSample
  carries routing_matrices; rollout_to_prompt_group aligns them via
  build_r3_routing_matrices and threads them into ModelInput.from_ints.

Naming + merges:
- text_rollout.py -> rollout/remote.py (the file was never about text)
- make_text_rollout_fn -> make_remote_rollout_fn (drop alias)
- rollout_helpers.py merged into rollout/assembler.py (the helpers
  build InferenceCall, which only the assembler consumes)
- Drop unused RolloutHelperInfo / renderer_helper_info / helper_info
  triage scaffolding (only ever read by tests, no production caller)

async_rl recipe stays at training/recipes/async_rl_loop.py (no shim).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Delete three AST-walk-the-sibling-train.py "tests" that only assert
the example imports a specific symbol. They guard prior-review wiring
choices, not behavior — an example that imports the right symbol but
mis-wires it still passes. Smoke tests in training/tests/smoke_test/
already cover real breakage.

Removed:
- training/examples/rl/deepmath/test_deepmath_imports.py
- training/examples/rl/gsm8k_async/test_gsm8k_async_imports.py
- training/examples/rl/single_turn_sync_on_policy/test_train_imports.py

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace the lazy-init dict-of-strings cache with eager construction in
the closure. Tokenizer + renderer depend only on cfg, so build them
once at the top of _build_rollout_fn; sampler depends on ctx and stays
inline in rollout_fn (it's just a thin dataclass).

Drops the per-row "if 'renderer' not in cached:" guard and the unused
typing.Any imports.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous cleanup moved sampler construction into rollout_fn, which
made it run per row. DeploymentSampler.__init__ chains into _RestClient
which allocates an httpx.Client connection pool — the class has close()
+ __enter__/__exit__, so it owns resources. Per-row construction
without close() leaks connection pools until GC.

ctx.inference_base_url / model / api_key are populated once per training
run (rl_loop.py:623) and never change, so per-row reconstruction was
purely waste. Build once on the first rollout via a nonlocal sentinel,
reuse on every subsequent row.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The default zero-variance filter was named should_accept but is passed
to dynamic_filter_fn=...; the call sites read more naturally with
matching names. should_accept also reads as a question (boolean
predicate), which is fine, but the symmetry with dynamic_filter_fn
matters more for consumers who customize the filter.

Renames the function in both rl_loop and igpo_loop recipes, all six
example train.py files that override it, the two manual test scripts
that monkey-patch it, and the unit/smoke tests that reference it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Make the boolean predicate semantics explicit: dynamic_filter_accept
returns True when the group should be accepted (i.e. NOT filtered).
The "_accept" suffix removes ambiguity about polarity for readers
overriding the filter.

Preserves the dynamic_filter_fn parameter name on main() / run_rl_loop;
only the function symbol is renamed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…main

Step back from the in-PR rl_loop refactor: rl_loop.py and igpo_loop.py go
back to the origin/main versions (no RolloutContext, no default_rollout_fn,
rollout_fn optional, should_accept name kept).  Pre-existing examples,
manual tests, and smoke/e2e tests that the PR had migrated to the new
rl_loop API are likewise reset to main so the rl_loop ecosystem is
identical to main.

The PR-new sync example single_turn_sync_on_policy/ was the only
non-test consumer of rl_loop's PR-only RolloutContext; it's removed so
the new async loop stays fully separate from rl_loop.

The renderer-reuse helpers under training/utils/rl/rollout/ and the new
async_rl_loop.py + its async examples are untouched.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The masking helpers live under training.examples.rl.frozen_lake, not
training.examples.frozen_lake — importing the latter raised
ModuleNotFoundError at module load and made train_multihop_qa_igpo.py
unrunnable (and broke the smoke-imports test).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The renderer-reuse refactor at the head of this PR accidentally dropped
render_messages_to_datums from training/utils/__init__.py while
renaming neighboring symbols.  sft_loop.py imports it from
training.utils, so the smoke-imports test broke.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Eight small fixes uncovered by running the renderer-backed async loop and the
sync GRPO loop against a real 397B B300 deployment for the first time:

- async_rl_loop.py: drop obsolete kwargs that no longer exist on setup_infra
  / save_checkpoint surfaces (has_separate_lora_reference, warm_start_from_*,
  step). The post-resolve checks live inside setup_infra now.
- logging.py: slime-aligned wandb step axes — train/step, rollout/step,
  eval/step — so async-side perf/* and rollout/* don't pile on the train/step
  axis when sampling and training are decoupled.
- async_train.py + metrics.py: rename async/step_wall_time -> step_wall_time
  to match the metrics-side lookup key, and make the lookup defensive so the
  async path (which writes the key after train_step) doesn't KeyError.
- common.py + rollout/types.py: switch per-token mask key from "loss_mask"
  to "weights". The trainer SDK rejects any loss_fn_inputs key other than
  {"target_tokens", "weights"} for forward_backward_custom.
- rollout/renderer.py: decode integer stop token IDs to literal strings via
  ctx.tokenizer. The Fireworks completions API rejects int stops; Qwen's
  renderer returns [151645] from get_stop_sequences().
- validation.py: add require_dataset=False so async recipes that pass rows=
  directly (no JSONL path) can still run base_model / output_model_id checks.

Plus dataset.jsonl regenerated to 500 rows from zwhe99/DeepMath-103K (was 200).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- recipes.md: rename IGPO row from "Importance-weighted GRPO" to
  "Information Gain-based Policy Optimization (IGPO)" — matches the
  recipe's actual algorithm (Wang et al., ICLR 2026).
- examples.md: add multi_turn_minimal, gsm8k_async, ep_remote_grader;
  drop the misleading "Generic RL wiring → examples/rl/" parent-dir row;
  relabel Multi-hop QA RL → Multi-hop QA IGPO.
- training/README.md: add Async RL and IGPO recipe rows; expand the
  Directory layout block to cover every rl/ example subdir + multihop_qa.
- checkpoints.md: include async_rl_loop in the warm_start support list
  (the recipe already wires validate_warm_start_config).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Hecate0821
Hecate0821 force-pushed the chengxi/training-doc-skill-alignment branch from 6865e57 to ea5c39c Compare May 4, 2026 22:36
@Hecate0821

Copy link
Copy Markdown
Collaborator Author

Closing in favor of a smaller, doc-only PR. The renderer-backed RL refactor / async-loop work in this branch is superseded by what's already on main (#382 etc.); the audit-fix docs are split out so they can land independently.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant