116 lines
3.0 KiB
Python
116 lines
3.0 KiB
Python
|
|
# train_fft.py
|
||
|
|
|
||
|
|
import os
|
||
|
|
import torch
|
||
|
|
|
||
|
|
from datasets import load_dataset
|
||
|
|
from transformers import AutoTokenizer, AutoModelForCausalLM
|
||
|
|
from trl import SFTTrainer, SFTConfig
|
||
|
|
|
||
|
|
# ============================================================
|
||
|
|
# PATHS
|
||
|
|
# ============================================================
|
||
|
|
|
||
|
|
MODEL_PATH = "./Qwen3-0.6B"
|
||
|
|
DATASET_PATH = "./dataset/train.jsonl"
|
||
|
|
OUTPUT_DIR = "./outputs/qwen3_0.6b_fft"
|
||
|
|
|
||
|
|
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
||
|
|
|
||
|
|
# ============================================================
|
||
|
|
# DATASET
|
||
|
|
# ============================================================
|
||
|
|
|
||
|
|
print("Loading dataset...")
|
||
|
|
dataset = load_dataset(
|
||
|
|
"json",
|
||
|
|
data_files=DATASET_PATH,
|
||
|
|
split="train"
|
||
|
|
)
|
||
|
|
print(f"Dataset size: {len(dataset)}")
|
||
|
|
|
||
|
|
# ============================================================
|
||
|
|
# TOKENIZER
|
||
|
|
# ============================================================
|
||
|
|
|
||
|
|
print("Loading tokenizer...")
|
||
|
|
tokenizer = AutoTokenizer.from_pretrained(
|
||
|
|
MODEL_PATH,
|
||
|
|
trust_remote_code=True
|
||
|
|
)
|
||
|
|
|
||
|
|
# Fix for models that don't have pad_token
|
||
|
|
if tokenizer.pad_token is None:
|
||
|
|
tokenizer.pad_token = tokenizer.eos_token
|
||
|
|
|
||
|
|
# ============================================================
|
||
|
|
# MODEL
|
||
|
|
# ============================================================
|
||
|
|
|
||
|
|
print("Loading model...")
|
||
|
|
model = AutoModelForCausalLM.from_pretrained(
|
||
|
|
MODEL_PATH,
|
||
|
|
torch_dtype=torch.bfloat16,
|
||
|
|
trust_remote_code=True,
|
||
|
|
device_map="auto" # Optional: helps with memory on single GPU
|
||
|
|
)
|
||
|
|
|
||
|
|
model.config.use_cache = False
|
||
|
|
|
||
|
|
# ============================================================
|
||
|
|
# TRAINING CONFIG
|
||
|
|
# ============================================================
|
||
|
|
|
||
|
|
training_args = SFTConfig(
|
||
|
|
output_dir=OUTPUT_DIR,
|
||
|
|
num_train_epochs=3,
|
||
|
|
learning_rate=5e-6,
|
||
|
|
per_device_train_batch_size=1,
|
||
|
|
gradient_accumulation_steps=16,
|
||
|
|
bf16=True,
|
||
|
|
logging_steps=10,
|
||
|
|
save_strategy="steps",
|
||
|
|
save_steps=200,
|
||
|
|
save_total_limit=2,
|
||
|
|
lr_scheduler_type="cosine",
|
||
|
|
warmup_ratio=0.03,
|
||
|
|
max_length=512,
|
||
|
|
packing=False,
|
||
|
|
gradient_checkpointing=True,
|
||
|
|
report_to="none",
|
||
|
|
# Optional but recommended:
|
||
|
|
dataloader_num_workers=2,
|
||
|
|
remove_unused_columns=False,
|
||
|
|
)
|
||
|
|
|
||
|
|
# ============================================================
|
||
|
|
# TRAINER
|
||
|
|
# ============================================================
|
||
|
|
|
||
|
|
trainer = SFTTrainer(
|
||
|
|
model=model,
|
||
|
|
args=training_args,
|
||
|
|
train_dataset=dataset,
|
||
|
|
processing_class=tokenizer, # Newer TRL uses processing_class
|
||
|
|
# tokenizer=tokenizer, # You can use this if processing_class doesn't work
|
||
|
|
)
|
||
|
|
|
||
|
|
# ============================================================
|
||
|
|
# TRAIN
|
||
|
|
# ============================================================
|
||
|
|
|
||
|
|
print("Starting full fine-tuning...")
|
||
|
|
trainer.train()
|
||
|
|
|
||
|
|
# ============================================================
|
||
|
|
# SAVE MODEL
|
||
|
|
# ============================================================
|
||
|
|
|
||
|
|
print("Saving model...")
|
||
|
|
trainer.save_model(OUTPUT_DIR)
|
||
|
|
tokenizer.save_pretrained(OUTPUT_DIR)
|
||
|
|
|
||
|
|
print("=" * 60)
|
||
|
|
print("✅ FULL FINE TUNING COMPLETED")
|
||
|
|
print(f"Model saved to: {OUTPUT_DIR}")
|
||
|
|
print("=" * 60)
|