bench/lora: RunPod warm-agent LoRA runbook + training script#98
Merged
Conversation
Add the checked-in training kit for the v0.7 warm-agent experiment (refs #83): config-driven QLoRA training script with a GPU-free --smoke preflight, completion-only loss, general-code replay mixing, deterministic eval holdout, adapter + model-card + run-manifest export, and --resume checkpointing; r32/r64/ r128 sweep configs (effective batch held constant, r128 carries an OOM-fallback block); a vLLM --enable-lora serve wrapper for the warm arm; pinned requirements; and an operator RUNBOOK (laptop -> adapter in 8 commands) covering pod choice, in-pod datagen, the mandatory sealed-manifest contamination gate (#53), cost table, OOM playbook, and the pre-registered warm-arm eval gate. Lives under bench/ (not kit/) per repo convention. Docs/tests only; no Rust changed. Smoke passes on the committed pilot; cargo test --workspace stays 322/0. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_018P54D8vTMhDcmX5nExnzoK
Remove unused imports (math, sys, dataclasses.field) and two dead module constants (the ASCII SUCCESS_GATE, superseded by the byte-exact SUCCESS_GATE_VERBATIM actually written to the manifest/model card; and RESPONSE_TEMPLATE, a duplicate of ASSISTANT_HEADER that was never referenced). No behavior change: the --smoke preflight and the training recipe (r/alpha/rsLoRA/targets/LR/epochs/replay/completion-only-loss) are untouched. Smoke still exits 0/SMOKE PASSED; cargo test --workspace still 322/0. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_018P54D8vTMhDcmX5nExnzoK
madmax983
marked this pull request as ready for review
July 16, 2026 16:29
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #83
Before / After (plain language)
Before: the v0.7 design doc specifies a "warm" MTL agent — a LoRA fine-tune that writes MTL with zero quickref preamble in context — but there was no checked-in, runnable way to train it. An operator had nothing to point at a rented GPU.
After: a self-contained kit under
bench/lora/takes an operator from laptop to a trained adapter in 8 commands, with a GPU-free preflight, a mandatory contamination gate, and a pre-registered evaluation plan.How
train_mtl_lora.pyis config-driven (YAML + CLI overrides). It loads the oracle-validated MTL JSONL (instruction→user /response→assistant), renders with the tokenizer's native chat template, and applies completion-only loss (loss only on the assistant/response span; thecheckprovenance field is ignored). It mixes in general-code replay (defaultbigcode/the-stack-smol— permissively-licensed code only, trained as plain code-continuation, sized to ~15% of the MTL token budget) as a catastrophic-forgetting mitigation, carves a deterministic tier-stratified eval holdout, and on completion exports the adapter + tokenizer + aMODEL_CARD.mdandrun_manifest.jsonrecording the full resolved config, seed, dataset sha256, record count, and the verbatim success gate. Checkpointing (save_steps/save_total_limit) +--resumemake it eviction-recoverable when--outis on the RunPod network volume. All heavy/GPU imports (torch, unsloth, trl, datasets, vllm) are lazy — they live only inside the real training path — so--smokeruns torch-free on a laptop or in CI. Three sweep configs (r32/r64/r128) hold the effective batch constant;r128.yamlcarries an OOM-fallback block.serve_adapter.pywrapsvllm serve --enable-lorato expose the adapter as the OpenAI-compatible warm arm for the existingbench/agent-trial/batteries.Lives under
bench/(notkit/) becausekit/holds only replication-driver scripts while every experiment lives underbench/<name>/. Docs/tests only — no Rust changed.Command count: 8 (laptop → adapter)
clone → install Rust toolchain →
pip install -r requirements.txt→ in-podgen --seed 0→cargo test -p mtl-datagen(contamination gate) → train (auto-exports adapter + model card) →huggingface-cli upload→runpodctl stop pod.Smoke-test result
python bench/lora/train_mtl_lora.py --smoke --config bench/lora/config/r64.yamlexits 0 / SMOKE PASSED on the committed pilot (1500 records): config sanity ✓, JSONL schema ✓, chat-template + real tokenizer encode/decode round-trip ✓ (downloaded and verified; a self-contained ChatML structural check is the offline fallback), VRAM estimate ✓ (~7.7 GB peak at r=64 → fits 24 GB / 80 GB). Also verified end-to-end against a freshly generatedgen --count 300 --seed 0slice.cargo test -p mtl-datagen(8 contamination tests) passes;cargo test --workspacestays 322 / 0.Success gate (pre-registered, verbatim from design doc §6)
AND the warm-arm gate:
Cost / wall-clock (RunPod Secure Cloud)
Recommend the A100 for the full sweep / time-sensitive work (cheaper and faster over a long job), the 4090 for cost-optimizing a single run.
Note: #53 vs #87 discrepancy
The task referred to a "#87 gate", but #87 does not exist in this repo. The real, checked-in contamination gate is #53 — the sealed-manifest gate run via
cargo test -p mtl-datagen(saltmtl-sealed-v1:issue-53). The RUNBOOK and model card cite #53.🤖 Generated with Claude Code
https://claude.ai/code/session_018P54D8vTMhDcmX5nExnzoK
Generated by Claude Code