|
Download code/extras/vllm_rollout/README.md from viai957/align: direct link, hf CLI and curl.
- Browser
- Download file 9.2 kB
-
https://huggingface.co/viai957/align/resolve/main/code/extras/vllm_rollout/README.md
- Command line
-
hf download hf://viai957/align/code/extras/vllm_rollout/README.md
-
curl -L -o README.md https://huggingface.co/viai957/align/resolve/main/code/extras/vllm_rollout/README.md
9.2 kB
| # vLLM rollout (optional extra) | |
| This directory is **not** part of the `align` package and nothing under `align/` | |
| imports it (`tests/test_dependency_firewall.py::test_extras_are_not_reachable_from_core`). | |
| The default GRPO rollout is the dependency-free native sampler, | |
| `align/rollout/native.py`. Use this only when generation throughput is the | |
| bottleneck and a dedicated engine GPU is available. | |
| ## Runs in its own venv | |
| `rollout_worker.py` and `rollout_pilot.py` run under `.venv-rollout` | |
| (vllm 0.26.0, ray, pyarrow, torch cu130), **never** the `align` venv, whose | |
| only dependencies are torch, triton, numpy and safetensors. Build it with | |
| `uv venv .venv-rollout` plus `torch==2.11.0 triton==3.6.0 vllm==0.26.0 ray pyarrow`. | |
| ## How it talks to the trainer | |
| Only through `align/rollout/protocol.py` (stdlib-only by contract): one JSON | |
| file per message in a spool directory, atomically written, with a heartbeat | |
| file for liveness. The worker puts `rollout_worker.py`'s repo root on | |
| `sys.path` and imports that single module; `import align` and | |
| `import align.rollout` are lazy / stdlib-only so no `align` dependency reaches | |
| this venv. | |
| Trainer side: | |
| ```python | |
| from align.rollout.client import make_rollout_client, spawn_worker | |
| proc = spawn_worker(spool, gpu=3, log_path=".../rollout_worker.log") | |
| client = make_rollout_client("spool", spool=spool, timeout_s=3600) | |
| ``` | |
| `spawn_worker` launches `extras/vllm_rollout/rollout_worker.py` with the | |
| required environment (flashinfer sampler off, caches under `/apps`, torchrun | |
| variables scrubbed, own process group so teardown reaps the engine core). | |
| ## Logprob basis caveat | |
| The worker requests `SamplingParams(logprobs=0)`, which in vLLM are the | |
| engine's **raw** logprobs (before temperature). The native backend returns | |
| `log_softmax(logits / T)` untruncated, which is what the GRPO module recomputes | |
| teacher-forced. The two coincide at `temperature == 1.0` (the stage-b setting). | |
| For `T != 1` the spool backend's logprobs differ from the training-side basis | |
| by the temperature rescaling, so rho will not be ~1 on-policy there; use | |
| `T = 1.0` with this worker, or set vLLM's `logprobs_mode` to a processed mode | |
| and accept that top-p/top-k then enter the logprob too. | |
| Weight sync is filesystem-based: a changed `weights_dir` tears the engine down | |
| and rebuilds it (~60 s), so sync every `sync_every` optimizer steps and let | |
| `use_rho_correction=True` absorb the off-policyness. | |
| ## Lean proving generation driver (experiment P2): `lean_gen.py` + `lean_prompts.py` | |
| Generates Goedel-Prover-V2 proof attempts with vLLM and writes the shared Generation | |
| record JSONL (one line per sample). Runs in `.venv-rollout`; `lean_prompts.py` and the | |
| pure half of `lean_gen.py` are stdlib-only at import and are unit-tested from the align | |
| venv (`tests/test_lean_gen_contract.py`, 36 tests, 15/15 hand mutants killed). | |
| ```bash | |
| cd /apps/development/rlhf/align && export TMPDIR=$PWD/.tmp/p2/<you> | |
| # round 0 | |
| .venv-rollout/bin/python extras/vllm_rollout/lean_gen.py --problems problems.jsonl \ | |
| --out gen_r0.jsonl --n 4 --cap-tokens 16384 --tp 4 --seed 0 --wait-lock | |
| # correction round 1 (parents = failed round-0 samples; needs a verification JSONL, see below) | |
| .venv-rollout/bin/python extras/vllm_rollout/lean_gen.py --problems problems.jsonl \ | |
| --out gen_r1.jsonl --n 1 --cap-tokens 16384 --round 1 \ | |
| --corrections-from verif_r0.jsonl gen_r0.jsonl --wait-lock | |
| # plan + prompts only, no GPU / lock | |
| ... --dry-run | |
| ``` | |
| Rerunning the same command resumes. `<out>.manifest.json` has one `sessions[]` entry per | |
| launch (model rev, vllm/torch versions, args, load/generate wall, tokens, finish counts, KV | |
| blocks, peak GPU memory); `<out>.skipped.jsonl` lists correction prompts that did not fit. | |
| **Fidelity.** `python extras/vllm_rollout/lean_prompts.py fidelity --model <snapshot> --out r.json` | |
| (rollout venv) imports the reference `src/utils.py` and asserts identical prompt strings and | |
| token ids on all 244 minif2f problems, identical `extrac_code` + `problem_check` on 63 synthetic | |
| outputs, `get_error_str` / `generate_correction_prompt` on 60 random error sets, and | |
| `compile.py:handle` vs `compile_view`. | |
| **What a record means.** | |
| * `cap_tokens` is the label every reported number carries. `sampling.max_tokens` is what vLLM | |
| got: `min(cap, max_model_len - len(prompt))`. They differ only when the context window ends the | |
| sample (`context_clipped: true`); at `--cap-tokens 40960 --max-model-len 40960` every sample is | |
| clipped by its prompt length (~250-600 tokens). `--max-model-len` above the model's 40960 | |
| position limit raises. | |
| * `completion_ids` are vLLM's `token_ids`: they end with the stop token (`<|im_end|>`) when | |
| `finish_reason == "stop"`. Train on them as they are; do not re-tokenize `completion_text`. | |
| * `messages` are the PROMPT messages (what the chat template rendered; no completion), so a | |
| correction round's history is `parent.messages + [assistant: parent.completion_text, user: errors]` | |
| exactly as Goedel builds it. `lean_code` is Goedel's `full_code` or null, with the reason in | |
| `lean_code_error` (extra field). | |
| * Sampling: temperature 1.0, top_p 0.95, no top_k (Goedel's `SamplingParams`; the model's | |
| `generation_config.json` says top_k=20 / T=0.6 but explicit params override it). One seed per | |
| sample, derived from (seed, problem, sample_idx, round); not the cap. | |
| **Correction rounds need two extra fields in the VERIFICATION record** (the shared contract does | |
| not carry them): `repl_errors` (list of Lean REPL messages with `severity == "error"`, each | |
| `{pos:{line,column}, endPos:{line,column}|null, data}`) and `repl_code` (the exact text those | |
| positions index into; for the Goedel flow that is `lean_prompts.compile_view(lean_code)`, i.e. the | |
| code with `import` / `set_option` / `open` lines removed). Without them `<error>` markers land on | |
| the wrong lines, so a parent lacking them is skipped and counted (`no_repl_errors`), never guessed. | |
| **Throughput/memory choices.** `gpu_memory_utilization=0.90` (20.7 GB of the A10G's 22.5 GiB; | |
| measured peak `nvidia-smi` use 21.7-22.5 GB, i.e. 0.5-1.3 GB of slack for NCCL/allocator; 0.92 was | |
| not tried), `max_num_seqs=128`, prefix caching on, CUDA graphs on, FLASH_ATTN backend (works on | |
| sm_86), `VLLM_USE_FLASHINFER_SAMPLER=0`. KV pool: 28,533 blocks x 16 = 456,528 tokens (TP=4: each | |
| GPU holds 2 of 8 KV heads, 36 KB/token). The driver steps the engine itself (`add_request`/`step`) | |
| with a refill window instead of `LLM.generate` chunks, so a 16k-token straggler does not idle the | |
| GPUs. Measured on Goedel-Prover-V2-8B, TP=4, seeded sampling (minif2f in file order, T=1.0, top_p=0.95): | |
| | run | cap | samples | mean / median / p90 completion tokens | finish=length | end-to-end tok/s | tok/s while >=64 running | | |
| |---|---|---|---|---|---|---| | |
| | 32 problems x n=4, max_num_seqs 128 | 16384 | 128 | 5066 / 3242 / 13993 | 10/128 (7.8%) | 918 | 1602 | | |
| | 64 problems x n=4, max_num_seqs 256 | 16384 | 256 | 4996 / 3033 / 13641 | 21/256 (8.2%) | 1043 | 1363 (KV pool 100% full at peak) | | |
| | 8 problems x n=2, max_num_seqs 128 | 40960 (context-clipped, max_tokens ~40.6-40.8k) | 16 | 4450 / 2662 / 7339 | 0/16 | 256 (tail of 1 sequence) | n/a (max 16 running) | | |
| Per-sequence decode speed is ~25 tok/s at 85-128 concurrent sequences and ~74 tok/s alone: TP=4 | |
| over PCIe (no NVLink) is allreduce-bound, so aggregate throughput saturates near 1.4-2.2k tok/s | |
| beyond ~100 concurrent sequences, and 256 sequences only fill the KV pool. Keep `--max-num-seqs 128`. | |
| ### Class-B trajectories, exit status, un-merged adapter (lane V2) | |
| * `--trajectory-cap-tokens 40000` enforces the class-B cumulative cap; every record carries a | |
| `trajectory` ledger (root id, round, cumulative completion tokens, truncation, budget clipping); | |
| failed parents with no compiler error are `skipped_no_feedback` in `<out>.skipped.jsonl` | |
| (or re-sampled with `--no-feedback-policy resample`). Goedel's rule (repair only problems | |
| without an accepted sample) is the default; `--repair-solved` lifts it. Pass every earlier | |
| round's `VERIF GEN` pair in `--corrections-from` so round-2+ lineage is complete (otherwise the | |
| entry is `partial` and a cap refuses). `build_trajectory_ledger()` aggregates a final state per root. | |
| * Exit status: 0 only for a complete sample set, 143 on SIGTERM/SIGINT. `pipeline_gen_verify.py` | |
| also checks the manifest (exit 4 if not `complete`) and reaps the generator's process group, | |
| sweeps `/dev/shm` and waits for the GPUs to drain after every generator exit. | |
| * Un-merged adapter: `--lora-adapter <peft dir> [--lora-name adapter]` serves it via vLLM | |
| `enable_lora`/`LoRARequest` (no bf16 merge). Adapter sha256 goes in the manifest, each record and | |
| `model_rev` (`<base>+lora-<sha12>`). GPU smoke (run after the chains exit, takes the heavy lock): | |
| ```bash | |
| .venv-rollout/bin/python extras/vllm_rollout/lean_gen.py --problems <5 problems>.jsonl \ | |
| --out .tmp/v2_smoke/gen_lora.jsonl --n 2 --cap-tokens 2048 --tp 1 --max-model-len 8192 \ | |
| --lora-adapter <adapter_dir> --wait-lock | |
| # expect: manifest sessions[-1].adapter.sha256 set, vllm engine log shows LoRA enabled, every | |
| # record has "adapter", exit 0; then rerun the same command (must resume, 0 new samples). | |
| ``` | |