初始化项目,由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