sai1906 commited on
Commit
8fa9ffa
·
verified ·
1 Parent(s): 7f822f2

SFT-only launcher mirroring working Colab

Browse files
Files changed (1) hide show
  1. scripts/hf_sft_launcher.py +105 -0
scripts/hf_sft_launcher.py ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """HF Jobs SFT launcher — exact mirror of working Colab cells.
2
+
3
+ No TRL OpenEnv, no env server, no GRPO. Pure SFT on 611 traces.
4
+ Same code that works on Colab T4. H200 just runs it ~10× faster.
5
+ """
6
+ from __future__ import annotations
7
+
8
+ import os
9
+ import subprocess
10
+ import sys
11
+
12
+ WORK = "/tmp/opsguard"
13
+ HUB_REPO = "sai1906/opsguard-sft"
14
+
15
+
16
+ def sh(cmd):
17
+ print(f"[sh] {cmd if isinstance(cmd, str) else ' '.join(cmd)}", flush=True)
18
+ return subprocess.run(cmd, shell=isinstance(cmd, str), check=True)
19
+
20
+
21
+ def main():
22
+ if not os.environ.get("HF_TOKEN"):
23
+ raise SystemExit("HF_TOKEN required")
24
+
25
+ sh([sys.executable, "-m", "pip", "install", "-q", "-U",
26
+ "transformers>=4.46", "trl>=0.18", "peft>=0.13", "bitsandbytes>=0.44",
27
+ "datasets", "accelerate>=1.0", "huggingface_hub", "matplotlib", "networkx>=3"])
28
+
29
+ sh(f"rm -rf {WORK}")
30
+ sh(["git", "clone", "https://huggingface.co/spaces/sai1906/opsguard", WORK])
31
+ os.chdir(WORK)
32
+ sys.path.insert(0, WORK)
33
+
34
+ from huggingface_hub import login, HfApi
35
+ login(token=os.environ["HF_TOKEN"])
36
+ HfApi(token=os.environ["HF_TOKEN"]).create_repo(HUB_REPO, repo_type="model", exist_ok=True)
37
+ print(f"[preflight] repo {HUB_REPO} ready", flush=True)
38
+
39
+ import torch
40
+ from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
41
+ from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
42
+
43
+ MODEL = "Qwen/Qwen2.5-7B-Instruct"
44
+ print(f"[model] loading {MODEL} 4bit...", flush=True)
45
+ bnb = BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_compute_dtype=torch.bfloat16,
46
+ bnb_4bit_use_double_quant=True, bnb_4bit_quant_type="nf4")
47
+ tok = AutoTokenizer.from_pretrained(MODEL)
48
+ if tok.pad_token_id is None:
49
+ tok.pad_token_id = tok.eos_token_id
50
+ model = AutoModelForCausalLM.from_pretrained(
51
+ MODEL, quantization_config=bnb, torch_dtype=torch.bfloat16, device_map="auto",
52
+ )
53
+ model = prepare_model_for_kbit_training(model, use_gradient_checkpointing=True)
54
+ lc = LoraConfig(r=32, lora_alpha=64, lora_dropout=0.0, bias="none",
55
+ target_modules=["q_proj","k_proj","v_proj","o_proj",
56
+ "gate_proj","up_proj","down_proj"],
57
+ task_type="CAUSAL_LM")
58
+ model = get_peft_model(model, lc)
59
+ model.print_trainable_parameters()
60
+
61
+ import json
62
+ from datasets import Dataset
63
+ rows = [json.loads(l) for l in open("data/sft_traces.jsonl")]
64
+ print(f"[data] {len(rows)} SFT traces loaded", flush=True)
65
+ texts = [r["prompt"] + "\n\nACTION:\n" + r["completion"] + tok.eos_token for r in rows]
66
+ ds = Dataset.from_list([{"text": t} for t in texts])
67
+
68
+ from trl import SFTConfig, SFTTrainer
69
+ import inspect
70
+
71
+ def safe_kwargs(cls, kw):
72
+ sig = inspect.signature(cls).parameters
73
+ return {k: v for k, v in kw.items() if k in sig}
74
+
75
+ raw = dict(
76
+ output_dir="/tmp/opsguard-sft",
77
+ per_device_train_batch_size=4,
78
+ gradient_accumulation_steps=4,
79
+ num_train_epochs=2,
80
+ learning_rate=1e-4,
81
+ warmup_ratio=0.03,
82
+ logging_steps=5,
83
+ save_strategy="epoch",
84
+ save_total_limit=1,
85
+ bf16=True,
86
+ max_seq_length=2048,
87
+ dataset_text_field="text",
88
+ report_to="none",
89
+ push_to_hub=False,
90
+ )
91
+ cfg = SFTConfig(**safe_kwargs(SFTConfig, raw))
92
+ trainer = SFTTrainer(model=model, train_dataset=ds, args=cfg, processing_class=tok)
93
+ trainer.train()
94
+
95
+ print("[push] saving + pushing to Hub...", flush=True)
96
+ model.save_pretrained("/tmp/opsguard-sft-lora")
97
+ tok.save_pretrained("/tmp/opsguard-sft-lora")
98
+ HfApi(token=os.environ["HF_TOKEN"]).upload_folder(
99
+ folder_path="/tmp/opsguard-sft-lora", repo_id=HUB_REPO, repo_type="model",
100
+ )
101
+ print(f"DONE: pushed to https://huggingface.co/{HUB_REPO}", flush=True)
102
+
103
+
104
+ if __name__ == "__main__":
105
+ main()