refactor: update training scripts and environment setup for Qwen3 model
Browse filesModified training scripts to transition from Qwen2.5 to Qwen3, including updates to model and adapter paths in `train_rlvr.py` and `train_grpo.py`. Removed legacy environment variables from setup scripts and README.md, introducing new command-line arguments for stub workers and LLM judge control. Enhanced documentation to reflect these changes and improve user guidance for the updated training process.
- env_artifacts/README.md +9 -13
- env_artifacts/setup_lightning_h100.sh +0 -2
- training/train_grpo.py +27 -7
- training/train_rlvr.py +21 -39
env_artifacts/README.md
CHANGED
|
@@ -61,8 +61,6 @@ pip install -e . # picks up project deps without touching the pinned to
|
|
| 61 |
|
| 62 |
# Per-session exports (stick these in ~/.bashrc if you want):
|
| 63 |
export HF_HUB_ENABLE_HF_TRANSFER=1
|
| 64 |
-
export CORP_STUB_WORKERS=1
|
| 65 |
-
export CORP_DISABLE_LLM_JUDGE=1
|
| 66 |
export TOKENIZERS_PARALLELISM=false
|
| 67 |
export TRANSFORMERS_VERBOSITY=warning
|
| 68 |
|
|
@@ -81,17 +79,17 @@ You can pull them locally on a new box with:
|
|
| 81 |
huggingface-cli download Navigam/corp-env-sft-qwen2.5-7b --local-dir outputs/sft_adapter
|
| 82 |
```
|
| 83 |
|
| 84 |
-
Then for
|
| 85 |
|
| 86 |
```bash
|
| 87 |
python training/train_rlvr.py \
|
| 88 |
-
--model Qwen/
|
| 89 |
-
--adapter outputs/
|
| 90 |
--examples data/processed/e1_m1_clean.jsonl,data/processed/h1_seed_clean.jsonl \
|
| 91 |
-
--output outputs/
|
| 92 |
--rounds 3 --n-samples 8 --max-prompts 128 \
|
| 93 |
--stats-file results/runs/rlvr_stats.jsonl \
|
| 94 |
-
--push-to-hub
|
| 95 |
```
|
| 96 |
|
| 97 |
## Notes / gotchas
|
|
@@ -99,12 +97,10 @@ python training/train_rlvr.py \
|
|
| 99 |
- **First time only on any new box**: `unsloth` writes patched-trainer classes
|
| 100 |
into `corp_gym/unsloth_compiled_cache/`. Delete that folder if you ever
|
| 101 |
change TRL/unsloth versions to avoid stale compiled patches.
|
| 102 |
-
- **Flash-attn fp32
|
| 103 |
-
`training/
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
of the symbol bypasses ours and FA2 rejects fp32 tensors during the no-grad
|
| 107 |
-
reference logprob forward.
|
| 108 |
- **max_prompt_length filter**: both legacy GRPO and RLVR scripts tokenise every
|
| 109 |
prompt up-front and drop rows whose chat-template-encoded length exceeds
|
| 110 |
`0.9 * max_prompt_length` (long H1 trajectories otherwise produce a causal
|
|
|
|
| 61 |
|
| 62 |
# Per-session exports (stick these in ~/.bashrc if you want):
|
| 63 |
export HF_HUB_ENABLE_HF_TRANSFER=1
|
|
|
|
|
|
|
| 64 |
export TOKENIZERS_PARALLELISM=false
|
| 65 |
export TRANSFORMERS_VERBOSITY=warning
|
| 66 |
|
|
|
|
| 79 |
huggingface-cli download Navigam/corp-env-sft-qwen2.5-7b --local-dir outputs/sft_adapter
|
| 80 |
```
|
| 81 |
|
| 82 |
+
Then for a direct 14B RLVR run:
|
| 83 |
|
| 84 |
```bash
|
| 85 |
python training/train_rlvr.py \
|
| 86 |
+
--model Qwen/Qwen3-14B-Instruct \
|
| 87 |
+
--adapter outputs/sft_qwen3_14b \
|
| 88 |
--examples data/processed/e1_m1_clean.jsonl,data/processed/h1_seed_clean.jsonl \
|
| 89 |
+
--output outputs/rlvr_qwen3_14b \
|
| 90 |
--rounds 3 --n-samples 8 --max-prompts 128 \
|
| 91 |
--stats-file results/runs/rlvr_stats.jsonl \
|
| 92 |
+
--push-to-hub <your-user-or-org>/corp-env-rlvr-qwen3-14b
|
| 93 |
```
|
| 94 |
|
| 95 |
## Notes / gotchas
|
|
|
|
| 97 |
- **First time only on any new box**: `unsloth` writes patched-trainer classes
|
| 98 |
into `corp_gym/unsloth_compiled_cache/`. Delete that folder if you ever
|
| 99 |
change TRL/unsloth versions to avoid stale compiled patches.
|
| 100 |
+
- **Flash-attn fp32 workaround**: this is now **legacy-only** for
|
| 101 |
+
`training/train_grpo.py`. It is disabled by default and can be enabled only
|
| 102 |
+
when needed via `CORP_ENABLE_FA2_BF16_PATCH=1`.
|
| 103 |
+
- `training/train_rlvr.py` now runs without this monkey patch on modern stacks.
|
|
|
|
|
|
|
| 104 |
- **max_prompt_length filter**: both legacy GRPO and RLVR scripts tokenise every
|
| 105 |
prompt up-front and drop rows whose chat-template-encoded length exceeds
|
| 106 |
`0.9 * max_prompt_length` (long H1 trajectories otherwise produce a causal
|
env_artifacts/setup_lightning_h100.sh
CHANGED
|
@@ -71,8 +71,6 @@ log "done. Export env vars in your shell (rc file or per-session):"
|
|
| 71 |
cat <<'EOF'
|
| 72 |
|
| 73 |
export HF_HUB_ENABLE_HF_TRANSFER=1
|
| 74 |
-
export CORP_STUB_WORKERS=1
|
| 75 |
-
export CORP_DISABLE_LLM_JUDGE=1
|
| 76 |
export TOKENIZERS_PARALLELISM=false
|
| 77 |
export TRANSFORMERS_VERBOSITY=warning
|
| 78 |
|
|
|
|
| 71 |
cat <<'EOF'
|
| 72 |
|
| 73 |
export HF_HUB_ENABLE_HF_TRANSFER=1
|
|
|
|
|
|
|
| 74 |
export TOKENIZERS_PARALLELISM=false
|
| 75 |
export TRANSFORMERS_VERBOSITY=warning
|
| 76 |
|
training/train_grpo.py
CHANGED
|
@@ -48,8 +48,17 @@ from typing import Any, Dict, List
|
|
| 48 |
|
| 49 |
import torch
|
| 50 |
|
| 51 |
-
|
| 52 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 53 |
|
| 54 |
_orig_fa_func = _fa_mod.flash_attn_func
|
| 55 |
_orig_fa_var = getattr(_fa_mod, "flash_attn_varlen_func", None)
|
|
@@ -67,16 +76,14 @@ try:
|
|
| 67 |
_fa_mod.flash_attn_func = _fa_func_bf16
|
| 68 |
if _orig_fa_var is not None:
|
| 69 |
_fa_mod.flash_attn_varlen_func = _fa_varlen_bf16
|
| 70 |
-
|
| 71 |
try:
|
| 72 |
import unsloth.utils.attention_dispatch as _ad_mod
|
|
|
|
| 73 |
_ad_mod.flash_attn_func = _fa_func_bf16
|
| 74 |
if _orig_fa_var is not None and hasattr(_ad_mod, "flash_attn_varlen_func"):
|
| 75 |
_ad_mod.flash_attn_varlen_func = _fa_varlen_bf16
|
| 76 |
except Exception:
|
| 77 |
pass
|
| 78 |
-
except ImportError:
|
| 79 |
-
pass
|
| 80 |
|
| 81 |
ROOT = Path(__file__).resolve().parents[1]
|
| 82 |
if str(ROOT) not in sys.path:
|
|
@@ -343,10 +350,23 @@ def main() -> None:
|
|
| 343 |
default=1,
|
| 344 |
help="Filter training examples to traces with at least this many log_reasoning actions.",
|
| 345 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 346 |
args = parser.parse_args()
|
| 347 |
|
| 348 |
-
|
| 349 |
-
|
|
|
|
|
|
|
|
|
|
| 350 |
|
| 351 |
try:
|
| 352 |
from unsloth import FastLanguageModel, PatchFastRL
|
|
|
|
| 48 |
|
| 49 |
import torch
|
| 50 |
|
| 51 |
+
def _maybe_patch_flash_attn_bf16() -> None:
|
| 52 |
+
"""Legacy workaround for older Unsloth/FA2 stacks.
|
| 53 |
+
|
| 54 |
+
Disabled by default; enable only if your GRPO run hits fp32 FA2 dtype errors.
|
| 55 |
+
"""
|
| 56 |
+
if os.environ.get("CORP_ENABLE_FA2_BF16_PATCH", "").strip() != "1":
|
| 57 |
+
return
|
| 58 |
+
try:
|
| 59 |
+
import flash_attn.flash_attn_interface as _fa_mod
|
| 60 |
+
except ImportError:
|
| 61 |
+
return
|
| 62 |
|
| 63 |
_orig_fa_func = _fa_mod.flash_attn_func
|
| 64 |
_orig_fa_var = getattr(_fa_mod, "flash_attn_varlen_func", None)
|
|
|
|
| 76 |
_fa_mod.flash_attn_func = _fa_func_bf16
|
| 77 |
if _orig_fa_var is not None:
|
| 78 |
_fa_mod.flash_attn_varlen_func = _fa_varlen_bf16
|
|
|
|
| 79 |
try:
|
| 80 |
import unsloth.utils.attention_dispatch as _ad_mod
|
| 81 |
+
|
| 82 |
_ad_mod.flash_attn_func = _fa_func_bf16
|
| 83 |
if _orig_fa_var is not None and hasattr(_ad_mod, "flash_attn_varlen_func"):
|
| 84 |
_ad_mod.flash_attn_varlen_func = _fa_varlen_bf16
|
| 85 |
except Exception:
|
| 86 |
pass
|
|
|
|
|
|
|
| 87 |
|
| 88 |
ROOT = Path(__file__).resolve().parents[1]
|
| 89 |
if str(ROOT) not in sys.path:
|
|
|
|
| 350 |
default=1,
|
| 351 |
help="Filter training examples to traces with at least this many log_reasoning actions.",
|
| 352 |
)
|
| 353 |
+
parser.add_argument(
|
| 354 |
+
"--use-stub-workers",
|
| 355 |
+
action="store_true",
|
| 356 |
+
help="Use deterministic stub workers (default: real workers).",
|
| 357 |
+
)
|
| 358 |
+
parser.add_argument(
|
| 359 |
+
"--disable-llm-judge",
|
| 360 |
+
action="store_true",
|
| 361 |
+
help="Disable LLM judge scoring for deterministic verifier-only runs.",
|
| 362 |
+
)
|
| 363 |
args = parser.parse_args()
|
| 364 |
|
| 365 |
+
if args.use_stub_workers:
|
| 366 |
+
os.environ["CORP_STUB_WORKERS"] = "1"
|
| 367 |
+
if args.disable_llm_judge:
|
| 368 |
+
os.environ["CORP_DISABLE_LLM_JUDGE"] = "1"
|
| 369 |
+
_maybe_patch_flash_attn_bf16()
|
| 370 |
|
| 371 |
try:
|
| 372 |
from unsloth import FastLanguageModel, PatchFastRL
|
training/train_rlvr.py
CHANGED
|
@@ -22,12 +22,12 @@ completions, and the advantage-variance collapse in GRPO no longer applies.
|
|
| 22 |
Run (after SFT)::
|
| 23 |
|
| 24 |
python training/train_rlvr.py \\
|
| 25 |
-
--model Qwen/
|
| 26 |
-
--adapter outputs/
|
| 27 |
--examples data/processed/e1_m1_clean.jsonl,data/processed/h1_seed_clean.jsonl \\
|
| 28 |
-
--output outputs/
|
| 29 |
--rounds 3 --n-samples 8 --max-prompts 64 \\
|
| 30 |
-
--push-to-hub
|
| 31 |
"""
|
| 32 |
|
| 33 |
from __future__ import annotations
|
|
@@ -45,36 +45,6 @@ from typing import Any, Dict, List, Tuple
|
|
| 45 |
|
| 46 |
import torch
|
| 47 |
|
| 48 |
-
try:
|
| 49 |
-
import flash_attn.flash_attn_interface as _fa_mod
|
| 50 |
-
|
| 51 |
-
_orig_fa_func = _fa_mod.flash_attn_func
|
| 52 |
-
_orig_fa_var = getattr(_fa_mod, "flash_attn_varlen_func", None)
|
| 53 |
-
|
| 54 |
-
def _fa_func_bf16(q, k, v, *args, **kwargs):
|
| 55 |
-
if q.dtype not in (torch.bfloat16, torch.float16):
|
| 56 |
-
q, k, v = q.to(torch.bfloat16), k.to(torch.bfloat16), v.to(torch.bfloat16)
|
| 57 |
-
return _orig_fa_func(q, k, v, *args, **kwargs)
|
| 58 |
-
|
| 59 |
-
def _fa_varlen_bf16(q, k, v, *args, **kwargs):
|
| 60 |
-
if q.dtype not in (torch.bfloat16, torch.float16):
|
| 61 |
-
q, k, v = q.to(torch.bfloat16), k.to(torch.bfloat16), v.to(torch.bfloat16)
|
| 62 |
-
return _orig_fa_var(q, k, v, *args, **kwargs)
|
| 63 |
-
|
| 64 |
-
_fa_mod.flash_attn_func = _fa_func_bf16
|
| 65 |
-
if _orig_fa_var is not None:
|
| 66 |
-
_fa_mod.flash_attn_varlen_func = _fa_varlen_bf16
|
| 67 |
-
|
| 68 |
-
try:
|
| 69 |
-
import unsloth.utils.attention_dispatch as _ad_mod
|
| 70 |
-
_ad_mod.flash_attn_func = _fa_func_bf16
|
| 71 |
-
if _orig_fa_var is not None and hasattr(_ad_mod, "flash_attn_varlen_func"):
|
| 72 |
-
_ad_mod.flash_attn_varlen_func = _fa_varlen_bf16
|
| 73 |
-
except Exception:
|
| 74 |
-
pass
|
| 75 |
-
except ImportError:
|
| 76 |
-
pass
|
| 77 |
-
|
| 78 |
ROOT = Path(__file__).resolve().parents[1]
|
| 79 |
if str(ROOT) not in sys.path:
|
| 80 |
sys.path.insert(0, str(ROOT))
|
|
@@ -345,8 +315,8 @@ def maybe_push_to_hub(output_dir: str, repo_id: str) -> None:
|
|
| 345 |
|
| 346 |
def main() -> None:
|
| 347 |
parser = argparse.ArgumentParser(description="RLVR / Rejection-Sampling FT for CORP-ENV.")
|
| 348 |
-
parser.add_argument("--model", default="Qwen/
|
| 349 |
-
parser.add_argument("--adapter", default="outputs/
|
| 350 |
help="Start from this LoRA adapter (usually SFT).")
|
| 351 |
parser.add_argument(
|
| 352 |
"--examples",
|
|
@@ -356,7 +326,7 @@ def main() -> None:
|
|
| 356 |
"--tasks",
|
| 357 |
default="e1_launch_readiness,m1_budget_reallocation,h1_acquisition_defence",
|
| 358 |
)
|
| 359 |
-
parser.add_argument("--output", default="outputs/
|
| 360 |
parser.add_argument("--rounds", type=int, default=3,
|
| 361 |
help="Outer rollout -> filter -> SFT iterations.")
|
| 362 |
parser.add_argument("--n-samples", type=int, default=8,
|
|
@@ -396,10 +366,22 @@ def main() -> None:
|
|
| 396 |
default="",
|
| 397 |
help="Optional JSONL to append per-round rollout stats to.",
|
| 398 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 399 |
args = parser.parse_args()
|
| 400 |
|
| 401 |
-
|
| 402 |
-
|
|
|
|
|
|
|
| 403 |
|
| 404 |
random.seed(args.seed)
|
| 405 |
torch.manual_seed(args.seed)
|
|
|
|
| 22 |
Run (after SFT)::
|
| 23 |
|
| 24 |
python training/train_rlvr.py \\
|
| 25 |
+
--model Qwen/Qwen3-14B-Instruct \\
|
| 26 |
+
--adapter outputs/sft_qwen3_14b \\
|
| 27 |
--examples data/processed/e1_m1_clean.jsonl,data/processed/h1_seed_clean.jsonl \\
|
| 28 |
+
--output outputs/rlvr_qwen3_14b \\
|
| 29 |
--rounds 3 --n-samples 8 --max-prompts 64 \\
|
| 30 |
+
--push-to-hub your-org/corp-env-rlvr-qwen3-14b
|
| 31 |
"""
|
| 32 |
|
| 33 |
from __future__ import annotations
|
|
|
|
| 45 |
|
| 46 |
import torch
|
| 47 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
ROOT = Path(__file__).resolve().parents[1]
|
| 49 |
if str(ROOT) not in sys.path:
|
| 50 |
sys.path.insert(0, str(ROOT))
|
|
|
|
| 315 |
|
| 316 |
def main() -> None:
|
| 317 |
parser = argparse.ArgumentParser(description="RLVR / Rejection-Sampling FT for CORP-ENV.")
|
| 318 |
+
parser.add_argument("--model", default="Qwen/Qwen3-14B-Instruct")
|
| 319 |
+
parser.add_argument("--adapter", default="outputs/sft_qwen3_14b",
|
| 320 |
help="Start from this LoRA adapter (usually SFT).")
|
| 321 |
parser.add_argument(
|
| 322 |
"--examples",
|
|
|
|
| 326 |
"--tasks",
|
| 327 |
default="e1_launch_readiness,m1_budget_reallocation,h1_acquisition_defence",
|
| 328 |
)
|
| 329 |
+
parser.add_argument("--output", default="outputs/rlvr_qwen3_14b")
|
| 330 |
parser.add_argument("--rounds", type=int, default=3,
|
| 331 |
help="Outer rollout -> filter -> SFT iterations.")
|
| 332 |
parser.add_argument("--n-samples", type=int, default=8,
|
|
|
|
| 366 |
default="",
|
| 367 |
help="Optional JSONL to append per-round rollout stats to.",
|
| 368 |
)
|
| 369 |
+
parser.add_argument(
|
| 370 |
+
"--use-stub-workers",
|
| 371 |
+
action="store_true",
|
| 372 |
+
help="Use deterministic stub workers (default: real workers).",
|
| 373 |
+
)
|
| 374 |
+
parser.add_argument(
|
| 375 |
+
"--disable-llm-judge",
|
| 376 |
+
action="store_true",
|
| 377 |
+
help="Disable LLM judge scoring for deterministic verifier-only runs.",
|
| 378 |
+
)
|
| 379 |
args = parser.parse_args()
|
| 380 |
|
| 381 |
+
if args.use_stub_workers:
|
| 382 |
+
os.environ["CORP_STUB_WORKERS"] = "1"
|
| 383 |
+
if args.disable_llm_judge:
|
| 384 |
+
os.environ["CORP_DISABLE_LLM_JUDGE"] = "1"
|
| 385 |
|
| 386 |
random.seed(args.seed)
|
| 387 |
torch.manual_seed(args.seed)
|