mxguru1 commited on
Commit
59cc609
·
verified ·
1 Parent(s): 3aebaba

Upload scripts/qlora_qwythos_job.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. scripts/qlora_qwythos_job.py +179 -0
scripts/qlora_qwythos_job.py ADDED
@@ -0,0 +1,179 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ QLoRA fine-tune Qwen3.5-9B base on Solidity security data via Unsloth.
4
+ Targets: severity calibration + tool calling (Qwythos-9B base).
5
+ Trains on A100 via HF Jobs.
6
+ """
7
+
8
+ import sys, os, subprocess
9
+
10
+ sys.stdout.reconfigure(encoding="utf-8", errors="replace")
11
+ sys.stderr.reconfigure(encoding="utf-8", errors="replace")
12
+ os.environ.setdefault("PYTHONIOENCODING", "utf-8")
13
+
14
+ WORKDIR = "/workspace"
15
+ os.makedirs(WORKDIR, exist_ok=True)
16
+
17
+
18
+ def log(msg):
19
+ print(msg)
20
+
21
+
22
+ def run_cmd(cmd, timeout=None):
23
+ r = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout)
24
+ return r
25
+
26
+
27
+ def main():
28
+ log("=" * 50)
29
+ log("QLoRA Fine-Tune: Qwen3.5-9B (Unsloth)")
30
+ log("Dataset: qwythos-sec-training-data")
31
+ log("Target: severity calibration + tool calling")
32
+ log("=" * 50)
33
+
34
+ # ================================================================
35
+ # Step 1/4: Install Unsloth
36
+ # ================================================================
37
+ log("\n[1/4] Installing Unsloth ...")
38
+ r1 = run_cmd(["pip", "install", "--quiet", "--no-cache-dir", "unsloth"], timeout=600)
39
+ log(f" pip install unsloth exit={r1.returncode}")
40
+ if r1.returncode != 0:
41
+ log(f" stderr (last 1000): {r1.stderr[-1000:]}")
42
+ sys.exit(1)
43
+ log(" [OK] Unsloth installed")
44
+
45
+ # hf_transfer for faster model upload
46
+ r2 = run_cmd(["pip", "install", "--quiet", "--no-cache-dir", "hf_transfer"], timeout=60)
47
+ log(f" hf_transfer exit={r2.returncode}")
48
+
49
+ # ================================================================
50
+ # Step 2/4: Load dataset
51
+ # ================================================================
52
+ log("\n[2/4] Loading security training dataset ...")
53
+ from datasets import load_dataset, Dataset
54
+
55
+ ds = load_dataset("mxguru1/qwythos-sec-training-data", split="train")
56
+ val_ds = load_dataset("mxguru1/qwythos-sec-training-data", split="validation")
57
+ log(f" train: {len(ds)} rows, val: {len(val_ds)} rows")
58
+
59
+ # Format as chat templates for Unsloth SFT
60
+ def format_prompt(row):
61
+ text = (
62
+ "<|im_start|>user\n" + row["prompt"] + "<|im_end|>\n"
63
+ "<|im_start|>assistant\n" + row["completion"] + "<|im_end|>"
64
+ )
65
+ return {"text": text}
66
+
67
+ train_ds = ds.map(format_prompt, remove_columns=ds.column_names)
68
+ val_ds_out = val_ds.map(format_prompt, remove_columns=val_ds.column_names)
69
+ log(f" formatted {len(train_ds)} train / {len(val_ds_out)} val samples")
70
+
71
+ # ================================================================
72
+ # Step 3/4: Train with Unsloth
73
+ # ================================================================
74
+ log("\n[3/4] Loading Qwen3.5-9B + tokenizer (Unsloth 4-bit) ...")
75
+ from unsloth import FastLanguageModel
76
+
77
+ model, tokenizer = FastLanguageModel.from_pretrained(
78
+ model_name="Qwen/Qwen3.5-9B",
79
+ max_seq_length=2048,
80
+ load_in_4bit=True,
81
+ load_in_8bit=False,
82
+ fast_inference=False,
83
+ token=os.environ.get("HF_TOKEN", ""),
84
+ )
85
+ log(" model loaded (4-bit QLoRA)")
86
+
87
+ # Add LoRA adapters - all linear modules for full coverage
88
+ model = FastLanguageModel.get_peft_model(
89
+ model,
90
+ r=32,
91
+ lora_alpha=64,
92
+ lora_dropout=0.05,
93
+ target_modules=[
94
+ "q_proj", "k_proj", "v_proj", "o_proj",
95
+ "gate_proj", "up_proj", "down_proj",
96
+ "embed_tokens", "lm_head",
97
+ ],
98
+ bias="none",
99
+ use_gradient_checkpointing="unsloth",
100
+ )
101
+ log(" LoRA adapters attached (r=32, all linear modules)")
102
+
103
+ log(" Starting training ...")
104
+ from unsloth import is_bf16_supported
105
+ from trl import SFTTrainer
106
+ from transformers import TrainingArguments, DataCollatorForSeq2Seq
107
+
108
+ trainer = SFTTrainer(
109
+ model=model,
110
+ tokenizer=tokenizer,
111
+ train_dataset=train_ds,
112
+ eval_dataset=val_ds_out,
113
+ dataset_text_field="text",
114
+ max_seq_length=2048,
115
+ data_collator=DataCollatorForSeq2Seq(tokenizer, model=model, padding=True),
116
+ args=TrainingArguments(
117
+ output_dir="/workspace/checkpoints",
118
+ per_device_train_batch_size=2,
119
+ gradient_accumulation_steps=8,
120
+ num_train_epochs=3,
121
+ warmup_steps=10,
122
+ learning_rate=2e-4,
123
+ weight_decay=0.0,
124
+ lr_scheduler_type="cosine",
125
+ optim="adamw_8bit",
126
+ bf16=is_bf16_supported(),
127
+ fp16=not is_bf16_supported(),
128
+ logging_steps=5,
129
+ save_steps=50,
130
+ eval_steps=50,
131
+ save_total_limit=3,
132
+ report_to="none",
133
+ ),
134
+ )
135
+ log(" trainer initialized - calling train() ...")
136
+ trainer.train()
137
+ log(" [OK] training complete")
138
+
139
+ # ================================================================
140
+ # Step 4/4: Push adapter to HF
141
+ # ================================================================
142
+ log("\n[4/4] Saving and pushing adapters to HuggingFace ...")
143
+ os.environ["HF_HUB_ENABLE_HF_TRANSFER"] = "1"
144
+
145
+ adapter_dir = "/workspace/qwythos-9b-security-adapter"
146
+ model.save_pretrained(adapter_dir)
147
+ tokenizer.save_pretrained(adapter_dir)
148
+ log(f" adapters saved to {adapter_dir}")
149
+
150
+ from huggingface_hub import HfApi, create_repo
151
+
152
+ org_repo = "mxguru1/qwythos-9b-security-unsloth"
153
+ try:
154
+ create_repo(org_repo, repo_type="model", private=True, exist_ok=True)
155
+ log(f" repo ready: {org_repo}")
156
+ except Exception as e:
157
+ log(f" [WARN] create_repo: {e}")
158
+
159
+ api = HfApi(token=os.environ.get("HF_TOKEN", ""))
160
+ try:
161
+ api.upload_folder(
162
+ folder_path=adapter_dir,
163
+ repo_id=org_repo,
164
+ repo_type="model",
165
+ )
166
+ log(" [OK] adapter pushed to HF")
167
+ except Exception as e:
168
+ log(f" [FAIL] upload: {e}")
169
+ sys.exit(1)
170
+
171
+ log("")
172
+ log("=" * 50)
173
+ log("COMPLETE")
174
+ log(f"Adapter: https://huggingface.co/{org_repo}")
175
+ log("=" * 50)
176
+
177
+
178
+ if __name__ == "__main__":
179
+ main()