zabaanai-v2 / scripts /02b_train_sft_cpu.py
shaikhsalman's picture
ZabaanAI v2 complete project - Pakistan multilingual AI
c1f5657 verified
Raw
History Blame Contribute Delete
3.82 kB
#!/usr/bin/env python3
# ============================================================
# ZabaanAI-v2: CPU-Only Training Script (Gradient Checkpointing + LoRA)
# WARNING: This will be VERY SLOW on CPU (~10-100x slower than GPU)
# For 7B models on CPU: only for small experiments or 1B models
# Recommended: use google/gemma-2b or microsoft/phi-2 for CPU training
# ============================================================
import os, warnings, sys
warnings.filterwarnings('ignore')
from transformers import (
AutoTokenizer, AutoModelForCausalLM,
TrainingArguments, set_seed
)
from peft import LoraConfig, get_peft_model, TaskType, prepare_model_for_kbit_training
from datasets import load_dataset
import torch
MODEL_ID = 'microsoft/phi-2' # 2.7B = smallest model that trains on CPU RAM
HF_REPO = 'shaikhsalman/zabaanai-v2-cpu'
DATA_PATH = '/app/data/processed/zabaanai_v2_sft_pakistan.jsonl'
OUTPUT_DIR = '/app/output/zabaanai-v2-cpu'
LORA_RANK = 16
SEQ_LEN = 512 # reduced for CPU RAM
BS = 1
GRAD_ACCUM = 32 # effective batch = 32
EPOCHS = 2
LR = 1e-3 # LoRA default lr
if not os.path.exists(DATA_PATH):
print(f'Data not found: {DATA_PATH} — run 01_curate_sft_data.py first!')
sys.exit(1)
set_seed(42)
print('Loading tokenizer...')
tokenizer = AutoTokenizer.from_pretrained(MODEL_ID, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token
print('Loading dataset...')
ds = load_dataset('json', data_files=DATA_PATH, split='train')
ds = ds.train_test_split(test_size=0.02, seed=42)
print(f' Train: {len(ds[\"train\"])} | Eval: {len(ds[\"test\"])}')
def preprocess(example):
text = example.get('text', '')
enc = tokenizer(text, max_length=SEQ_LEN, truncation=True,
padding='max_length', return_tensors=None)
enc['labels'] = enc['input_ids'].copy()
return enc
print('Tokenizing...')
tokenized = ds.map(preprocess, remove_columns=ds.column_names, num_proc=2)
print('Loading model with LoRA...')
model = AutoModelForCausalLM.from_pretrained(
MODEL_ID,
device_map='cpu',
torch_dtype=torch.float16,
offload_folder='/tmp/offload',
trust_remote_code=True,
)
model = prepare_model_for_kbit_training(model)
model.config.use_cache = False
lora_config = LoraConfig(
r=LORA_RANK, lora_alpha=LORA_RANK*2,
lora_dropout=0.05,
target_modules=['q_proj','k_proj','v_proj','o_proj','gate_proj','up_proj','down_proj'],
bias='none', task_type=TaskType.CAUSAL_LM,
)
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
from trl import SFTTrainer
trainer = SFTTrainer(
model=model,
args=TrainingArguments(
output_dir=OUTPUT_DIR,
per_device_train_batch_size=BS,
per_device_eval_batch_size=BS,
gradient_accumulation_steps=GRAD_ACCUM,
num_train_epochs=EPOCHS,
learning_rate=LR,
bf16=False, fp16=True,
logging_dir=f'{OUTPUT_DIR}/logs',
logging_strategy='steps', logging_steps=10,
save_strategy='steps', save_steps=200,
eval_steps=200, eval_strategy='steps',
save_total_limit=2,
report_to=['none'],
dataloader_num_workers=1,
seed=42,
max_grad_norm=1.0,
gradient_checkpointing=True,
gradient_checkpointing_kwargs={'use_reentrant': False},
),
train_dataset=tokenized['train'],
eval_dataset=tokenized['test'],
data_collator=None,
max_seq_length=SEQ_LEN,
tokenizer=tokenizer,
dataset_text_field='text',
)
print('Starting CPU training (WARNING: this will take many hours/days)...')
print(f' Effective batch: {BS * GRAD_ACCUM}, steps: ~{len(tokenized[\"train\"]) // GRAD_ACCUM * EPOCHS}')
trainer.train()
trainer.save_model(f'{OUTPUT_DIR}/final')
print('CPU training complete!')