-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
126 lines (108 loc) · 3.67 KB
/
Copy pathmain.py
File metadata and controls
126 lines (108 loc) · 3.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import os
# prevent transformers from importing torchvision (not needed here)
os.environ["TRANSFORMERS_NO_TORCHVISION"] = "1"
os.environ["PYTORCH_MPS_HIGH_WATERMARK_RATIO"] = "0.0"
import torch
from datasets import load_dataset
from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments
from peft import LoraConfig, get_peft_model, PeftModel
from trl import SFTTrainer
device = "mps" if torch.backends.mps.is_available() else "cpu"
print("device:", device)
# -----------------------------
# Model + tokenizer (LLaMA-arch)
# -----------------------------
MAXLEN = 1024
# BASE = "Qwen/Qwen2.5-1.5B-Instruct" # small enough for M1 Pro
BASE = "TinyLlama/TinyLlama-1.1B-Chat-v1.0" # llama-arch, gguf-friendly
tokenizer = AutoTokenizer.from_pretrained(BASE, use_fast=True)
# ensure pad token exists
if tokenizer.pad_token is None:
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"
model = AutoModelForCausalLM.from_pretrained(
BASE,
torch_dtype=torch.float16,
device_map={"": device},
)
# make sure model knows pad id & disable KV cache during training
if getattr(model.config, "pad_token_id", None) is None:
model.config.pad_token_id = tokenizer.pad_token_id
model.config.use_cache = False
# -----------------------------
# LoRA (LLaMA-style targets)
# -----------------------------
lora_cfg = LoraConfig(
r=16,
lora_alpha=16,
lora_dropout=0.0,
bias="none",
target_modules=[
"q_proj","k_proj","v_proj","o_proj",
"gate_proj","up_proj","down_proj",
],
)
model = get_peft_model(model, lora_cfg)
# -----------------------------
# Dataset (Gretel text-to-sql)
# -----------------------------
ds = load_dataset("gretelai/synthetic_text_to_sql", split="train")
def to_pair(ex):
instr = (
"You are an SQL generator. Using the database context below, "
"write a valid SQL query that answers the user's question.\n\n"
f"### Context:\n{ex['sql_context']}\n\n"
f"### Question:\n{ex['sql_prompt']}"
)
out = (
"<sql_query>\n" + ex["sql"] + "\n</sql_query>\n\n"
"<explanation>\n" + str(ex.get("sql_explanation", "")) + "\n</explanation>"
)
return {"text": f"### Instruction:\n{instr}\n\n### Response:\n{out}"}
train = (
ds.shuffle(seed=42)
.select(range(5000)) # faster run
.map(to_pair, remove_columns=ds.column_names)
)
# -----------------------------
# Trainer config (no mixed precision on MPS)
# -----------------------------
OUTPUT_DIR = "tinyllama-sql-lora"
args = TrainingArguments(
output_dir=OUTPUT_DIR,
per_device_train_batch_size=1,
gradient_accumulation_steps=8,
learning_rate=2e-4,
max_steps=500, # quick PoC
warmup_steps=20,
logging_steps=10,
save_steps=250,
fp16=False, bf16=False, # IMPORTANT: off for accelerate on MPS
dataloader_pin_memory=False,
optim="adamw_torch", # <- avoid Accelerate optimizer shims
)
trainer = SFTTrainer(
model=model,
tokenizer=tokenizer,
train_dataset=train,
args=args,
dataset_text_field="text",
max_seq_length=MAXLEN,
packing=False,
)
# -----------------------------
# Train
# -----------------------------
trainer.train()
# -----------------------------
# Merge LoRA and save full HF model
# -----------------------------
outdir = "merged-model-tinyllama"
if isinstance(model, PeftModel):
merged = model.merge_and_unload()
merged.save_pretrained(outdir, safe_serialization=True)
tokenizer.save_pretrained(outdir)
else:
model.save_pretrained(outdir, safe_serialization=True)
tokenizer.save_pretrained(outdir)
print(f"Saved merged model to ./{outdir}")