Lomesh2000
project structure
85a749e
Raw
History Blame Contribute Delete
4.3 kB
"""
scripts/train_sft.py
SFT warm-up training script.
Run: python scripts/train_sft.py --config configs/sft.yaml
HALLUCINATION NOTE:
- SFTConfig field 'max_length' (not 'max_seq_length') verified in trl 1.4.0.
- SFTConfig field 'dataset_text_field' verified in trl 1.4.0.
- gradient_checkpointing_kwargs passed via SFTConfig directly.
"""
from __future__ import annotations
import argparse
import logging
import os
import sys
import yaml
import wandb
from datasets import Dataset
from peft import LoraConfig, TaskType
from transformers import AutoTokenizer
from trl import SFTConfig, SFTTrainer
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
from src.data.dataset import build_sft_dataset
from src.model.loader import load_base_model, load_tokenizer, make_lora_config
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
)
logger = logging.getLogger(__name__)
def parse_args():
parser = argparse.ArgumentParser(description="SFT warm-up for Phi-3-Mini")
parser.add_argument("--config", default="configs/sft.yaml")
parser.add_argument("--dry-run", action="store_true",
help="Load data and model but don't train (sanity check)")
return parser.parse_args()
def main():
args = parse_args()
with open(args.config) as f:
cfg = yaml.safe_load(f)
# --- W&B init ---
wandb.init(
project=cfg["wandb"]["project"],
name=cfg["training"]["run_name"],
config=cfg,
)
# --- Data ---
logger.info("Loading datasets...")
train_ds, val_ds = build_sft_dataset(
gsm8k_fraction=cfg["data"]["gsm8k_fraction"],
aqua_fraction=cfg["data"]["aqua_fraction"],
val_size=cfg["data"]["val_size"],
)
logger.info("Train: %d examples, Val: %d examples", len(train_ds), len(val_ds))
if args.dry_run:
logger.info("Dry run: printing 2 training examples then exiting.")
for i in range(min(2, len(train_ds))):
print(f"\n--- Example {i} ---")
print(train_ds[i]["text"][:500])
return
# --- Model + LoRA ---
logger.info("Loading model: %s", cfg["model"]["base_id"])
model = load_base_model(
model_id=cfg["model"]["base_id"],
torch_dtype=cfg["model"]["torch_dtype"],
attn_implementation=cfg["model"]["attn_implementation"],
)
tok = load_tokenizer(cfg["model"]["base_id"])
lora_cfg = make_lora_config(
r=cfg["lora"]["r"],
lora_alpha=cfg["lora"]["lora_alpha"],
lora_dropout=cfg["lora"]["lora_dropout"],
bias=cfg["lora"]["bias"],
target_modules=cfg["lora"]["target_modules"],
)
# --- SFTConfig ---
# Field names verified against trl 1.4.0 SFTConfig
t = cfg["training"]
sft_cfg = SFTConfig(
output_dir=t["output_dir"],
num_train_epochs=t["num_train_epochs"],
per_device_train_batch_size=t["per_device_train_batch_size"],
gradient_accumulation_steps=t["gradient_accumulation_steps"],
learning_rate=t["learning_rate"],
lr_scheduler_type=t["lr_scheduler_type"],
warmup_ratio=t["warmup_ratio"],
bf16=t["bf16"],
gradient_checkpointing=t["gradient_checkpointing"],
logging_steps=t["logging_steps"],
save_strategy=t["save_strategy"],
eval_strategy=t["eval_strategy"],
eval_steps=t["eval_steps"],
save_total_limit=t["save_total_limit"],
report_to=t["report_to"],
run_name=t["run_name"],
# SFT-specific fields (verified trl 1.4.0)
dataset_text_field="text",
max_length=cfg["data"]["max_seq_length"],
packing=False, # disable sample packing for simplicity
)
# --- Trainer ---
trainer = SFTTrainer(
model=model,
args=sft_cfg,
train_dataset=train_ds,
eval_dataset=val_ds,
processing_class=tok,
peft_config=lora_cfg,
)
logger.info("Starting SFT training...")
trainer.train()
logger.info("Saving final SFT checkpoint to %s", t["output_dir"])
trainer.save_model(t["output_dir"])
tok.save_pretrained(t["output_dir"])
wandb.finish()
logger.info("SFT training complete.")
if __name__ == "__main__":
main()