opsguard / scripts /hf_launcher.py
sai1906's picture
SFT only path - skip GRPO tools chaos
491f220 verified
Raw
History Blame Contribute Delete
5.79 kB
"""HF Jobs launcher — boots env locally + runs training in same container.
Optimized 3-round coevolution-light:
Round 0: SFT warmstart (Unsloth, 1 epoch on 611 traces)
Round 1: GRPO defender (train_grpo.py, 100 steps) vs scripted env adversary
Round 2: GRPO defender (train_grpo.py, 100 steps) vs scripted env adversary (E2-E4)
Round 3: Final eval + push LoRA to Hub
Total: ~3 × 30min on a100-large = 90min, ~$3.75.
Usage on HF Jobs:
hf jobs uv run --flavor a100-large \
--with "trl>=0.18,unsloth,peft,bitsandbytes,openenv-core,vllm,matplotlib,networkx,datasets" \
--secrets HF_TOKEN \
https://huggingface.co/spaces/sai1906/opsguard/raw/main/scripts/hf_launcher.py
"""
from __future__ import annotations
import os
import subprocess
import sys
import time
from pathlib import Path
REPO_ZIP = "https://huggingface.co/spaces/sai1906/opsguard/resolve/main"
WORK = Path("/tmp/opsguard")
def sh(cmd, check=True, **kw):
print(f"[sh] {cmd if isinstance(cmd, str) else ' '.join(cmd)}", flush=True)
return subprocess.run(cmd, shell=isinstance(cmd, str), check=check, **kw)
def clone_repo():
if WORK.exists():
sh(["rm", "-rf", str(WORK)])
WORK.mkdir(parents=True, exist_ok=True)
sh(["git", "clone", "https://huggingface.co/spaces/sai1906/opsguard", str(WORK)])
os.chdir(WORK)
sys.path.insert(0, str(WORK))
def install_deps():
sh([sys.executable, "-m", "pip", "install", "-q",
"trl>=0.18", "peft>=0.13", "bitsandbytes>=0.44", "openenv-core[core]>=0.2.2",
"matplotlib", "networkx>=3", "datasets", "huggingface_hub", "accelerate>=1.0",
"transformers>=4.46", "jmespath", "fastapi", "uvicorn", "requests"])
def boot_env_server() -> subprocess.Popen:
print("[env] starting opsguard env server on 0.0.0.0:8001...", flush=True)
proc = subprocess.Popen(
[sys.executable, "-m", "uvicorn", "server.app:app", "--host", "0.0.0.0", "--port", "8001"],
cwd=str(WORK),
env={**os.environ, "PYTHONPATH": str(WORK)},
)
for _ in range(60):
time.sleep(2)
try:
import urllib.request
urllib.request.urlopen("http://0.0.0.0:8001/health", timeout=2).read()
print("[env] healthy", flush=True)
return proc
except Exception:
continue
raise RuntimeError("env server did not become healthy within 120s")
def sft_warmstart():
print("\n=== SFT WARM-START ===", flush=True)
sh([sys.executable, "scripts/sft_warmstart.py",
"--model", "Qwen/Qwen2.5-3B-Instruct",
"--episodes", "32",
"--output-dir", "/tmp/opsguard-sft",
"--epochs", "1",
"--train-only",
])
def grpo_round(round_idx: int, num_steps: int, sft_adapter: str | None, hub_repo: str):
print(f"\n=== ROUND {round_idx} — GRPO DEFENDER ({num_steps} steps) ===", flush=True)
args = [
sys.executable, "scripts/train_grpo.py",
"--model", "unsloth/Qwen2.5-7B-Instruct-bnb-4bit",
"--env-url", "http://0.0.0.0:8001",
"--num-steps", str(num_steps),
"--num-generations", "4",
"--max-steps-per-episode", "30",
"--scenarios", "E2_social_eng_buildup", "E3_compromised_maintainer", "E4_multi_vector",
"--no-vllm",
"--max-completion-length", "512",
"--output-dir", f"/tmp/opsguard-grpo-r{round_idx}",
]
if sft_adapter:
args.extend(["--sft-adapter", sft_adapter])
if hub_repo:
args.extend(["--hub-repo", hub_repo])
sh(args)
def final_eval():
print("\n=== FINAL EVAL: trained LoRA vs baseline policies ===", flush=True)
sh([sys.executable, "scripts/run_baseline_eval.py",
"--policies", "keyword_security_triager", "memory_aware", "debate", "ensemble_voting",
"--scenarios", "E2_social_eng_buildup", "E3_compromised_maintainer",
"E4_multi_vector", "E5_jia_tan_saga",
"--seeds", "0", "1", "2",
"--out", "/tmp/eval_post_train"])
def push_outputs():
from huggingface_hub import HfApi
api = HfApi(token=os.environ.get("HF_TOKEN"))
try:
api.create_repo("sai1906/opsguard-grpo", repo_type="model", exist_ok=True)
except Exception as e:
print(f"[push] create_repo: {e}", flush=True)
for src, dest in [
("/tmp/opsguard-grpo-r2", "checkpoints/r2"),
("/tmp/eval_post_train", "eval_post_train"),
]:
if Path(src).exists():
try:
api.upload_folder(folder_path=src, repo_id="sai1906/opsguard-grpo",
path_in_repo=dest, repo_type="model")
print(f"[push] uploaded {src} -> {dest}", flush=True)
except Exception as e:
print(f"[push] upload failed for {src}: {e}", flush=True)
def main():
if not os.environ.get("HF_TOKEN"):
raise SystemExit("HF_TOKEN required as secret")
clone_repo()
install_deps()
try:
from huggingface_hub import HfApi as _HfApi
_HfApi(token=os.environ["HF_TOKEN"]).create_repo(
"sai1906/opsguard-sft", repo_type="model", exist_ok=True
)
print("[preflight] hub repo ready", flush=True)
except Exception as _e:
print(f"[preflight] create_repo: {_e}", flush=True)
sft_train_and_push()
final_eval()
push_outputs()
def sft_train_and_push():
print("\n=== SFT TRAINING (Qwen 7B 4bit + LoRA) ===", flush=True)
sh([sys.executable, "scripts/sft_warmstart.py",
"--model", "unsloth/Qwen2.5-7B-Instruct-bnb-4bit",
"--episodes", "32",
"--output-dir", "/tmp/opsguard-sft",
"--epochs", "2",
"--train-only",
"--push-to-hub", "sai1906/opsguard-sft",
])
if __name__ == "__main__":
main()