初始化项目,由ModelHub XC社区提供模型
Model: Chamaka8/Serendip-LLM-CPT-SFT-v2 Source: Original Platform
This commit is contained in:
36
.gitattributes
vendored
Normal file
36
.gitattributes
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
*.7z filter=lfs diff=lfs merge=lfs -text
|
||||
*.arrow filter=lfs diff=lfs merge=lfs -text
|
||||
*.bin filter=lfs diff=lfs merge=lfs -text
|
||||
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
||||
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
||||
*.ftz filter=lfs diff=lfs merge=lfs -text
|
||||
*.gz filter=lfs diff=lfs merge=lfs -text
|
||||
*.h5 filter=lfs diff=lfs merge=lfs -text
|
||||
*.joblib filter=lfs diff=lfs merge=lfs -text
|
||||
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
||||
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
||||
*.model filter=lfs diff=lfs merge=lfs -text
|
||||
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
||||
*.npy filter=lfs diff=lfs merge=lfs -text
|
||||
*.npz filter=lfs diff=lfs merge=lfs -text
|
||||
*.onnx filter=lfs diff=lfs merge=lfs -text
|
||||
*.ot filter=lfs diff=lfs merge=lfs -text
|
||||
*.parquet filter=lfs diff=lfs merge=lfs -text
|
||||
*.pb filter=lfs diff=lfs merge=lfs -text
|
||||
*.pickle filter=lfs diff=lfs merge=lfs -text
|
||||
*.pkl filter=lfs diff=lfs merge=lfs -text
|
||||
*.pt filter=lfs diff=lfs merge=lfs -text
|
||||
*.pth filter=lfs diff=lfs merge=lfs -text
|
||||
*.rar filter=lfs diff=lfs merge=lfs -text
|
||||
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
||||
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
||||
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
||||
*.tar filter=lfs diff=lfs merge=lfs -text
|
||||
*.tflite filter=lfs diff=lfs merge=lfs -text
|
||||
*.tgz filter=lfs diff=lfs merge=lfs -text
|
||||
*.wasm filter=lfs diff=lfs merge=lfs -text
|
||||
*.xz filter=lfs diff=lfs merge=lfs -text
|
||||
*.zip filter=lfs diff=lfs merge=lfs -text
|
||||
*.zst filter=lfs diff=lfs merge=lfs -text
|
||||
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
||||
tokenizer.json filter=lfs diff=lfs merge=lfs -text
|
||||
166
README.md
Normal file
166
README.md
Normal file
@@ -0,0 +1,166 @@
|
||||
---
|
||||
language:
|
||||
- si
|
||||
license: apache-2.0
|
||||
tags:
|
||||
- sinhala
|
||||
- llama-3
|
||||
- instruction-following
|
||||
- news-classification
|
||||
- text-generation
|
||||
datasets:
|
||||
- Chamaka8/Serendip-sft-sinhala
|
||||
base_model: Chamaka8/serendib-llm-cpt-llama3-8b
|
||||
pipeline_tag: text-generation
|
||||
---
|
||||
|
||||
# SerendipLLM V2 🇱🇰
|
||||
|
||||
**The largest Sinhala instruction-following language model trained on 309,328 examples**
|
||||
|
||||
SerendipLLM V2 is a specialized Sinhala language model with exceptional capabilities in news classification, question answering, and general Sinhala text generation. Built on Llama-3-8B with continued pre-training and instruction fine-tuning, it represents a significant advancement in Sinhala NLP.
|
||||
|
||||
## 🏆 Key Achievements
|
||||
|
||||
- ✅ **6.2x larger dataset** than existing Sinhala models (309K vs ~50K examples)
|
||||
- ✅ **45,080 news classification examples** for specialized Sinhala news categorization
|
||||
- ✅ **50% training loss reduction** (0.54 → 0.27) over 3 epochs
|
||||
- ✅ **Comprehensive training** on diverse Sinhala tasks
|
||||
- ✅ **Open-source** - Complete pipeline and dataset available
|
||||
|
||||
## 📊 Model Details
|
||||
|
||||
| Attribute | Value |
|
||||
|-----------|-------|
|
||||
| **Base Model** | Meta Llama-3-8B |
|
||||
| **CPT Foundation** | [serendib-llm-cpt-llama3-8b](https://huggingface.co/Chamaka8/serendib-llm-cpt-llama3-8b) |
|
||||
| **Parameters** | 8.16B total, 130M trainable (1.59%) |
|
||||
| **Training Examples** | 309,328 |
|
||||
| **Training Method** | LoRA fine-tuning |
|
||||
| **Training Duration** | 26.5 hours on A100 80GB |
|
||||
| **Final Loss** | 0.27 |
|
||||
| **License** | Apache 2.0 |
|
||||
|
||||
## 🎯 Specialized Capabilities
|
||||
|
||||
### News Classification (Our Strength!)
|
||||
Trained on **45,080 Sinhala news examples** - the largest news classification dataset for Sinhala.
|
||||
|
||||
**Example:**
|
||||
```python
|
||||
Input: "ශ්රී ලංකා ක්රිකට් කණ්ඩායම අද ඉන්දියාවට එරෙහිව තරගයක් ආරම්භ කළේය"
|
||||
Output: "මෙය ක්රීඩා පුවතකි" ✅
|
||||
```
|
||||
|
||||
### Question Answering
|
||||
**29,390 QA pairs** covering geography, history, culture, and general knowledge.
|
||||
|
||||
**Example:**
|
||||
```python
|
||||
Input: "ශ්රී ලංකාවේ අගනුවර කුමක්ද?"
|
||||
Output: "ශ්රී ලංකාවේ අගනුවර කොළඹයි" ✅
|
||||
```
|
||||
|
||||
## 📈 Dataset Composition
|
||||
|
||||
| Category | Examples | Percentage |
|
||||
|----------|----------|------------|
|
||||
| **General Sinhala** | 205,403 | 66.4% |
|
||||
| **News Classification** | 45,080 | 14.6% |
|
||||
| **QA Pairs** | 29,390 | 9.5% |
|
||||
| **Summarization** | 19,593 | 6.3% |
|
||||
| **Rewrite/Formatting** | 9,862 | 3.2% |
|
||||
| **TOTAL** | **309,328** | **100%** |
|
||||
|
||||
## 🚀 Usage
|
||||
```python
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
import torch
|
||||
|
||||
# Load model
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"Chamaka8/Serendip-LLM-CPT-SFT-v2",
|
||||
torch_dtype=torch.float16,
|
||||
device_map="auto"
|
||||
)
|
||||
tokenizer = AutoTokenizer.from_pretrained("Chamaka8/Serendip-LLM-CPT-SFT-v2")
|
||||
|
||||
# Format prompt
|
||||
prompt = """### Instruction:
|
||||
පහත පුවත් ලිපිය වර්ගීකරණය කරන්න
|
||||
|
||||
### Input:
|
||||
ශ්රී ලංකා ක්රිකට් කණ්ඩායම අද ඉන්දියාවට එරෙහිව තරගයක් ආරම්භ කළේය.
|
||||
|
||||
### Response:
|
||||
"""
|
||||
|
||||
# Generate
|
||||
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
|
||||
outputs = model.generate(
|
||||
**inputs,
|
||||
max_new_tokens=150,
|
||||
temperature=0.7,
|
||||
top_p=0.9
|
||||
)
|
||||
|
||||
response = tokenizer.decode(outputs[0], skip_special_tokens=True)
|
||||
print(response.split("### Response:")[-1].strip())
|
||||
```
|
||||
|
||||
## ⚙️ Training Configuration
|
||||
|
||||
### Hardware
|
||||
- **GPU:** NVIDIA A100 SXM 80GB
|
||||
- **Training Time:** 26.5 hours
|
||||
- **Cost:** ~$37 USD
|
||||
|
||||
### Hyperparameters
|
||||
```python
|
||||
num_train_epochs = 3
|
||||
per_device_train_batch_size = 8
|
||||
gradient_accumulation_steps = 4
|
||||
learning_rate = 2e-5
|
||||
max_seq_length = 384
|
||||
lora_r = 64
|
||||
lora_alpha = 128
|
||||
```
|
||||
|
||||
### Training Loss
|
||||
|
||||
| Epoch | Loss |
|
||||
|-------|------|
|
||||
| 1.0 | 0.28 |
|
||||
| 2.0 | 0.24 |
|
||||
| 3.0 | 0.27 |
|
||||
|
||||
## 📊 Comparison
|
||||
|
||||
| Model | Training Data | News Examples |
|
||||
|-------|--------------|---------------|
|
||||
| SinLlama | ~50,000 | Limited |
|
||||
| **SerendipLLM V2** | **309,328** | **45,080** ✅ |
|
||||
|
||||
## 🔗 Resources
|
||||
|
||||
- **Dataset:** [Serendip-sft-sinhala](https://huggingface.co/datasets/Chamaka8/Serendip-sft-sinhala)
|
||||
- **Base CPT:** [serendib-llm-cpt-llama3-8b](https://huggingface.co/Chamaka8/serendib-llm-cpt-llama3-8b)
|
||||
- **Training Script:** See `training_scripts/` folder
|
||||
|
||||
## 📚 Citation
|
||||
```bibtex
|
||||
@model{serendipllm2026,
|
||||
title={SerendipLLM V2: Large-Scale Instruction-Tuning for Sinhala},
|
||||
author={Chamaka Alwis},
|
||||
year={2026},
|
||||
url={https://huggingface.co/Chamaka8/Serendip-LLM-CPT-SFT-v2}
|
||||
}
|
||||
```
|
||||
|
||||
## 📄 License
|
||||
|
||||
Apache 2.0
|
||||
|
||||
---
|
||||
|
||||
**Built with ❤️ for the Sinhala NLP community**
|
||||
32
config.json
Normal file
32
config.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"architectures": [
|
||||
"LlamaForCausalLM"
|
||||
],
|
||||
"attention_bias": false,
|
||||
"attention_dropout": 0.0,
|
||||
"bos_token_id": 128000,
|
||||
"dtype": "float16",
|
||||
"eos_token_id": 128001,
|
||||
"head_dim": 128,
|
||||
"hidden_act": "silu",
|
||||
"hidden_size": 4096,
|
||||
"initializer_range": 0.02,
|
||||
"intermediate_size": 14336,
|
||||
"max_position_embeddings": 8192,
|
||||
"mlp_bias": false,
|
||||
"model_type": "llama",
|
||||
"num_attention_heads": 32,
|
||||
"num_hidden_layers": 32,
|
||||
"num_key_value_heads": 8,
|
||||
"pad_token_id": 128001,
|
||||
"pretraining_tp": 1,
|
||||
"rms_norm_eps": 1e-05,
|
||||
"rope_parameters": {
|
||||
"rope_theta": 500000.0,
|
||||
"rope_type": "default"
|
||||
},
|
||||
"tie_word_embeddings": false,
|
||||
"transformers_version": "5.2.0",
|
||||
"use_cache": false,
|
||||
"vocab_size": 128256
|
||||
}
|
||||
12
generation_config.json
Normal file
12
generation_config.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"bos_token_id": 128000,
|
||||
"do_sample": true,
|
||||
"eos_token_id": [
|
||||
128001
|
||||
],
|
||||
"max_length": 4096,
|
||||
"pad_token_id": 128001,
|
||||
"temperature": 0.6,
|
||||
"top_p": 0.9,
|
||||
"transformers_version": "5.2.0"
|
||||
}
|
||||
3
model.safetensors
Normal file
3
model.safetensors
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c434f6524f1bbc536108744f5cd148f2ee3d844a41faf32beac4702d23639ea7
|
||||
size 16060556328
|
||||
3
tokenizer.json
Normal file
3
tokenizer.json
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3c5cf44023714fb39b05e71e425f8d7b92805ff73f7988b083b8c87f0bf87393
|
||||
size 17209961
|
||||
14
tokenizer_config.json
Normal file
14
tokenizer_config.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"backend": "tokenizers",
|
||||
"bos_token": "<|begin_of_text|>",
|
||||
"clean_up_tokenization_spaces": true,
|
||||
"eos_token": "<|end_of_text|>",
|
||||
"is_local": false,
|
||||
"model_input_names": [
|
||||
"input_ids",
|
||||
"attention_mask"
|
||||
],
|
||||
"model_max_length": 1000000000000000019884624838656,
|
||||
"pad_token": "<|end_of_text|>",
|
||||
"tokenizer_class": "TokenizersBackend"
|
||||
}
|
||||
41
training_scripts/README.md
Normal file
41
training_scripts/README.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# Training Scripts
|
||||
|
||||
This folder contains all training scripts used in the SerendipLLM V2 project.
|
||||
|
||||
## ✅ Final Script Used (ACTUAL TRAINING)
|
||||
|
||||
**`train_v2_fast.py`** ← This is the exact script that trained the final model!
|
||||
|
||||
- Training time: 26.5 hours
|
||||
- Loss: 0.54 → 0.27 (50% improvement)
|
||||
- Epochs: 3
|
||||
- Batch size: 8 (effective 32)
|
||||
- LoRA rank: 64
|
||||
- Dataset: 309,328 examples
|
||||
|
||||
## 📝 Other Scripts (Development/Testing)
|
||||
|
||||
- `train_phase1_fixed.py` - Initial attempt (slower, 512 tokens)
|
||||
- `continue_training.py` - Script for resuming training (not used)
|
||||
|
||||
## 🎯 To Reproduce
|
||||
|
||||
Use `train_v2_fast.py` with these settings:
|
||||
- GPU: A100 80GB
|
||||
- Dataset: Chamaka8/Serendip-sft-sinhala (serendipllm_sft_final_train_v2.json)
|
||||
- Time: ~27 hours
|
||||
- Cost: ~$37
|
||||
|
||||
## 📊 Training Results
|
||||
```
|
||||
Epoch 1: Loss 0.28
|
||||
Epoch 2: Loss 0.24
|
||||
Epoch 3: Loss 0.27
|
||||
Final average loss: 0.27
|
||||
```
|
||||
|
||||
## 🔗 Related Resources
|
||||
|
||||
- Model: https://huggingface.co/Chamaka8/Serendip-LLM-CPT-SFT-v2
|
||||
- Dataset: https://huggingface.co/datasets/Chamaka8/Serendip-sft-sinhala
|
||||
- Base CPT: https://huggingface.co/Chamaka8/serendib-llm-cpt-llama3-8b
|
||||
52
training_scripts/TRAINING_LOG.md
Normal file
52
training_scripts/TRAINING_LOG.md
Normal file
@@ -0,0 +1,52 @@
|
||||
# Training Log Summary
|
||||
|
||||
## Final Training Run (train_v2_fast.py)
|
||||
|
||||
**Start:** February 18, 2026, ~17:30
|
||||
**End:** February 19, 2026, ~20:00
|
||||
**Duration:** 26.5 hours
|
||||
|
||||
### Loss Progression
|
||||
|
||||
| Epoch | Loss |
|
||||
|-------|------|
|
||||
| 0.95 | 0.28 |
|
||||
| 1.90 | 0.24 |
|
||||
| 3.00 | 0.27 |
|
||||
|
||||
**Final training loss:** 0.27
|
||||
|
||||
### Configuration Used
|
||||
```python
|
||||
num_train_epochs = 3
|
||||
per_device_train_batch_size = 8
|
||||
gradient_accumulation_steps = 4 # Effective batch = 32
|
||||
learning_rate = 2e-5
|
||||
max_length = 384 # tokens
|
||||
warmup_steps = 200
|
||||
weight_decay = 0.01
|
||||
|
||||
# LoRA Config
|
||||
lora_r = 64
|
||||
lora_alpha = 128
|
||||
lora_target_modules = [
|
||||
"q_proj", "k_proj", "v_proj",
|
||||
"o_proj", "gate_proj", "up_proj"
|
||||
]
|
||||
lora_dropout = 0.05
|
||||
```
|
||||
|
||||
### Hardware
|
||||
|
||||
- GPU: NVIDIA A100 SXM 80GB
|
||||
- Training framework: Transformers + PEFT
|
||||
- Mixed precision: FP16
|
||||
|
||||
### Dataset
|
||||
|
||||
- Source: Chamaka8/Serendip-sft-sinhala
|
||||
- File: serendipllm_sft_final_train_v2.json
|
||||
- Examples: 309,328
|
||||
- News classification: 45,080 examples
|
||||
- General Sinhala: 205,403 examples
|
||||
- QA pairs: 29,390 examples
|
||||
129
training_scripts/archive/train_phase1_fixed.py
Normal file
129
training_scripts/archive/train_phase1_fixed.py
Normal file
@@ -0,0 +1,129 @@
|
||||
import torch, os, gc
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments, Trainer, DataCollatorForLanguageModeling
|
||||
from datasets import load_dataset
|
||||
from peft import LoraConfig, get_peft_model
|
||||
|
||||
os.environ["TOKENIZERS_PARALLELISM"] = "false"
|
||||
|
||||
print("="*70)
|
||||
print("SERENDIPLLM V2 - FRESH TRAINING WITH FIXED DATASET")
|
||||
print("="*70)
|
||||
print("News data: 45,080 examples (was 3!)")
|
||||
print("Total: 309,328 examples")
|
||||
print("Epochs: 3")
|
||||
print("="*70)
|
||||
|
||||
BASE_MODEL = "Chamaka8/serendib-llm-cpt-llama3-8b"
|
||||
OUTPUT_DIR = "./SerendipLLM-V2"
|
||||
FINAL_MODEL = "Chamaka8/Serendip-LLM-CPT-SFT-v2"
|
||||
|
||||
gc.collect()
|
||||
torch.cuda.empty_cache()
|
||||
|
||||
print("\nLoading tokenizer...")
|
||||
tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL, use_fast=True)
|
||||
tokenizer.pad_token = tokenizer.eos_token
|
||||
|
||||
print("Loading model...")
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
BASE_MODEL,
|
||||
torch_dtype=torch.float16,
|
||||
device_map="auto",
|
||||
use_cache=False,
|
||||
)
|
||||
|
||||
print("Adding LoRA...")
|
||||
lora_config = LoraConfig(
|
||||
r=64,
|
||||
lora_alpha=128,
|
||||
target_modules=["q_proj","k_proj","v_proj","o_proj","gate_proj","up_proj"],
|
||||
lora_dropout=0.05,
|
||||
task_type="CAUSAL_LM",
|
||||
)
|
||||
model = get_peft_model(model, lora_config)
|
||||
trainable, total = model.get_nb_trainable_parameters()
|
||||
print(f"Trainable: {trainable:,} / {total:,} ({100*trainable/total:.2f}%)")
|
||||
|
||||
print("Loading dataset...")
|
||||
dataset = load_dataset(
|
||||
"Chamaka8/Serendip-sft-sinhala",
|
||||
data_files={"train": "serendipllm_sft_final_train_v2.json"}
|
||||
)
|
||||
print(f"Examples: {len(dataset['train']):,}")
|
||||
|
||||
def tokenize(examples):
|
||||
texts = []
|
||||
for i in range(len(examples['instruction'])):
|
||||
inp = examples['input'][i] if examples['input'][i] else ""
|
||||
if inp.strip():
|
||||
text = f"### Instruction:\n{examples['instruction'][i]}\n\n### Input:\n{inp}\n\n### Response:\n{examples['output'][i]}"
|
||||
else:
|
||||
text = f"### Instruction:\n{examples['instruction'][i]}\n\n### Response:\n{examples['output'][i]}"
|
||||
texts.append(text)
|
||||
return tokenizer(texts, truncation=True, max_length=512, padding=False)
|
||||
|
||||
print("Tokenizing...")
|
||||
train = dataset["train"].map(
|
||||
tokenize, batched=True, batch_size=5000,
|
||||
num_proc=8, remove_columns=dataset["train"].column_names
|
||||
)
|
||||
|
||||
collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False)
|
||||
|
||||
args = TrainingArguments(
|
||||
output_dir=OUTPUT_DIR,
|
||||
num_train_epochs=3,
|
||||
per_device_train_batch_size=8,
|
||||
gradient_accumulation_steps=4,
|
||||
learning_rate=2e-5,
|
||||
warmup_steps=200,
|
||||
weight_decay=0.01,
|
||||
fp16=True,
|
||||
optim="adamw_torch_fused",
|
||||
logging_steps=50,
|
||||
save_steps=2000,
|
||||
save_total_limit=1,
|
||||
eval_strategy="no",
|
||||
dataloader_num_workers=4,
|
||||
gradient_checkpointing=False,
|
||||
report_to="none",
|
||||
)
|
||||
|
||||
trainer = Trainer(
|
||||
model=model,
|
||||
args=args,
|
||||
train_dataset=train,
|
||||
data_collator=collator,
|
||||
)
|
||||
|
||||
print("\n" + "="*70)
|
||||
print("STARTING TRAINING!")
|
||||
print("3 epochs x 309K examples")
|
||||
print("Estimated time: 21 hours")
|
||||
print("="*70 + "\n")
|
||||
|
||||
trainer.train()
|
||||
|
||||
print("\nSaving checkpoint...")
|
||||
trainer.save_model(OUTPUT_DIR + "/checkpoint")
|
||||
tokenizer.save_pretrained(OUTPUT_DIR + "/checkpoint")
|
||||
|
||||
print("Merging LoRA...")
|
||||
model = model.merge_and_unload()
|
||||
|
||||
print("Saving merged model...")
|
||||
model.save_pretrained(OUTPUT_DIR + "/merged")
|
||||
tokenizer.save_pretrained(OUTPUT_DIR + "/merged")
|
||||
|
||||
print("Uploading to HuggingFace...")
|
||||
try:
|
||||
model.push_to_hub(FINAL_MODEL, commit_message="SerendipLLM v2 - Fixed dataset + 3 epochs")
|
||||
tokenizer.push_to_hub(FINAL_MODEL)
|
||||
print(f"Done! https://huggingface.co/{FINAL_MODEL}")
|
||||
except Exception as e:
|
||||
print(f"Upload failed: {e}")
|
||||
print(f"Model saved locally: {OUTPUT_DIR}/merged")
|
||||
|
||||
print("\n" + "="*70)
|
||||
print("TRAINING COMPLETE!")
|
||||
print("="*70)
|
||||
127
training_scripts/train_v2_fast.py
Normal file
127
training_scripts/train_v2_fast.py
Normal file
@@ -0,0 +1,127 @@
|
||||
import torch, os, gc
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments, Trainer, DataCollatorForLanguageModeling
|
||||
from datasets import load_dataset
|
||||
from peft import LoraConfig, get_peft_model
|
||||
|
||||
os.environ["TOKENIZERS_PARALLELISM"] = "false"
|
||||
|
||||
print("="*70)
|
||||
print("SERENDIPLLM V2 - OPTIMIZED (21 HOURS)")
|
||||
print("="*70)
|
||||
|
||||
BASE_MODEL = "Chamaka8/serendib-llm-cpt-llama3-8b"
|
||||
OUTPUT_DIR = "./SerendipLLM-V2"
|
||||
FINAL_MODEL = "Chamaka8/Serendip-LLM-CPT-SFT-v2"
|
||||
|
||||
gc.collect()
|
||||
torch.cuda.empty_cache()
|
||||
|
||||
print("Loading tokenizer...")
|
||||
tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL, use_fast=True)
|
||||
tokenizer.pad_token = tokenizer.eos_token
|
||||
|
||||
print("Loading model...")
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
BASE_MODEL,
|
||||
torch_dtype=torch.float16,
|
||||
device_map="auto",
|
||||
use_cache=False,
|
||||
)
|
||||
|
||||
print("Adding LoRA...")
|
||||
lora_config = LoraConfig(
|
||||
r=64,
|
||||
lora_alpha=128,
|
||||
target_modules=["q_proj","k_proj","v_proj","o_proj","gate_proj","up_proj"],
|
||||
lora_dropout=0.05,
|
||||
task_type="CAUSAL_LM",
|
||||
)
|
||||
model = get_peft_model(model, lora_config)
|
||||
trainable, total = model.get_nb_trainable_parameters()
|
||||
print(f"Trainable: {trainable:,} / {total:,} ({100*trainable/total:.2f}%)")
|
||||
|
||||
print("Loading dataset...")
|
||||
dataset = load_dataset(
|
||||
"Chamaka8/Serendip-sft-sinhala",
|
||||
data_files={"train": "serendipllm_sft_final_train_v2.json"}
|
||||
)
|
||||
print(f"Examples: {len(dataset['train']):,}")
|
||||
|
||||
def tokenize(examples):
|
||||
texts = []
|
||||
for i in range(len(examples['instruction'])):
|
||||
inp = examples['input'][i] if examples['input'][i] else ""
|
||||
if inp.strip():
|
||||
text = f"### Instruction:\n{examples['instruction'][i]}\n\n### Input:\n{inp}\n\n### Response:\n{examples['output'][i]}"
|
||||
else:
|
||||
text = f"### Instruction:\n{examples['instruction'][i]}\n\n### Response:\n{examples['output'][i]}"
|
||||
texts.append(text)
|
||||
return tokenizer(texts, truncation=True, max_length=384, padding=False)
|
||||
|
||||
print("Tokenizing...")
|
||||
train = dataset["train"].map(
|
||||
tokenize, batched=True, batch_size=5000,
|
||||
num_proc=8, remove_columns=dataset["train"].column_names
|
||||
)
|
||||
|
||||
collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False)
|
||||
|
||||
args = TrainingArguments(
|
||||
output_dir=OUTPUT_DIR,
|
||||
num_train_epochs=3,
|
||||
per_device_train_batch_size=8,
|
||||
gradient_accumulation_steps=4,
|
||||
learning_rate=2e-5,
|
||||
warmup_steps=200,
|
||||
weight_decay=0.01,
|
||||
fp16=True,
|
||||
optim="adamw_torch_fused",
|
||||
logging_steps=50,
|
||||
save_steps=2000,
|
||||
save_total_limit=1,
|
||||
eval_strategy="no",
|
||||
dataloader_num_workers=4,
|
||||
gradient_checkpointing=False,
|
||||
report_to="none",
|
||||
)
|
||||
|
||||
trainer = Trainer(
|
||||
model=model,
|
||||
args=args,
|
||||
train_dataset=train,
|
||||
data_collator=collator,
|
||||
)
|
||||
|
||||
print("\n" + "="*70)
|
||||
print("STARTING OPTIMIZED TRAINING!")
|
||||
print("max_length: 384 (was 512)")
|
||||
print("Expected speed: ~2.9s/step")
|
||||
print("Expected time: ~21 hours")
|
||||
print("Expected cost: ~$19")
|
||||
print("="*70 + "\n")
|
||||
|
||||
trainer.train()
|
||||
|
||||
print("\nSaving checkpoint...")
|
||||
trainer.save_model(OUTPUT_DIR + "/checkpoint")
|
||||
tokenizer.save_pretrained(OUTPUT_DIR + "/checkpoint")
|
||||
|
||||
print("Merging LoRA...")
|
||||
model = model.merge_and_unload()
|
||||
|
||||
print("Saving merged model...")
|
||||
model.save_pretrained(OUTPUT_DIR + "/merged")
|
||||
tokenizer.save_pretrained(OUTPUT_DIR + "/merged")
|
||||
|
||||
print("Uploading to HuggingFace...")
|
||||
try:
|
||||
model.push_to_hub(FINAL_MODEL, commit_message="SerendipLLM v2 - Fixed dataset + 3 epochs")
|
||||
tokenizer.push_to_hub(FINAL_MODEL)
|
||||
print(f"Done! https://huggingface.co/{FINAL_MODEL}")
|
||||
except Exception as e:
|
||||
print(f"Upload failed: {e}")
|
||||
print(f"Model saved locally: {OUTPUT_DIR}/merged")
|
||||
|
||||
print("\n" + "="*70)
|
||||
print("COMPLETE! SerendipLLM V2 ready!")
|
||||
print("="*70)
|
||||
Reference in New Issue
Block a user