| name | helsinki-nlp-model-training |
| description | Fine-tune Helsinki-NLP OPUS-MT models for Chuukese translation with custom training data, evaluation, and deployment. Use when training, evaluating, fine-tuning, or deploying translation models for Chuukese-English translation. Use when this capability is needed. |
| metadata | {"author":"findinfinitelabs"} |
Helsinki-NLP Model Training
Overview
Train and fine-tune Helsinki-NLP OPUS-MT models for Chuukese-English translation. These models are specifically designed for translation tasks and perform better than general LLMs for low-resource languages like Chuukese.
Base Models:
Helsinki-NLP/opus-mt-mul-en (Multilingual → English)
Helsinki-NLP/opus-mt-en-mul (English → Multilingual)
Capabilities
- Fine-tuning: Adapt base models to Chuukese-specific data
- Bidirectional Training: Support for both Chuukese→English and English→Chuukese
- Training Data Preparation: Format dictionary and parallel corpus data
- Model Evaluation: BLEU, chrF scoring on test sets
- Local Deployment: Run models locally without API calls
- GPU/CPU Support: Automatic device detection and optimization
Model Architecture
Helsinki-NLP OPUS-MT Architecture:
┌─────────────────────────────────────────────────┐
│ MarianMT (Marian Neural Machine Translation) │
├─────────────────────────────────────────────────┤
│ Encoder: 6 Transformer layers │
│ Decoder: 6 Transformer layers │
│ Attention heads: 8 │
│ Hidden size: 512 │
│ Vocabulary: SentencePiece tokenizer │
└─────────────────────────────────────────────────┘
Directory Structure
models/
├── helsinki-chuukese_chuukese_to_english/
│ ├── finetuned/
│ │ ├── config.json
│ │ ├── pytorch_model.bin
│ │ ├── tokenizer_config.json
│ │ ├── source.spm
│ │ └── target.spm
│ └── training_logs/
├── helsinki-chuukese_english_to_chuukese/
│ ├── finetuned/
│ └── training_logs/
└── test-helsinki_chuukese_to_english/
Training Data Preparation
1. Data Format
training_pairs = [
{"source": "chomong", "target": "to help, assist"},
{"source": "Kopwe pwan chomong", "target": "We will help"},
{"source": "ngang", "target": "fish"},
]
def export_training_data(pairs, output_path, direction="chk_to_en"):
"""Export training pairs to TSV format for transformers."""
with open(output_path, 'w', encoding='utf-8') as f:
for pair in pairs:
if direction == "chk_to_en":
f.write(f"{pair['source']}\t{pair['target']}\n")
else:
f.write(f"{pair['target']}\t{pair['source']}\n")
2. Data Sources
from src.database.dictionary_db import DictionaryDB
def prepare_training_data():
"""Prepare comprehensive training dataset."""
db = DictionaryDB()
training_pairs = []
entries = db.dictionary.find({'is_base_word': True})
for entry in entries:
training_pairs.append({
'source': entry['chuukese_word'],
'target': entry['english_definition'],
'confidence': 0.9
})
phrases = db.phrases.find({'confidence_score': {'$gte': 0.7}})
for phrase in phrases:
training_pairs.append({
'source': phrase['chuukese_phrase'],
'target': phrase['english_translation'],
'confidence': phrase.get('confidence_score', 0.8)
})
from src.utils.nwt_epub_parser import NWTEpubParser
return training_pairs
3. Data Splitting
from sklearn.model_selection import train_test_split
def split_training_data(pairs, test_size=0.1, val_size=0.1):
"""Split data into train/val/test sets."""
train, test = train_test_split(pairs, test_size=test_size, random_state=42)
train, val = train_test_split(train, test_size=val_size/(1-test_size), random_state=42)
return {
'train': train,
'val': val,
'test': test
}
Training Implementation
HelsinkiChuukeseTranslator Class
import torch
from transformers import (
AutoTokenizer,
AutoModelForSeq2SeqLM,
Trainer,
TrainingArguments,
DataCollatorForSeq2Seq
)
from datasets import Dataset
class HelsinkiChuukeseTranslator:
"""Helsinki-NLP based Chuukese translator with fine-tuning support."""
def __init__(self,
base_model: str = "Helsinki-NLP/opus-mt-mul-en",
reverse_model: str = "Helsinki-NLP/opus-mt-en-mul"):
self.base_model = base_model
self.reverse_model = reverse_model
self.device = "cuda" if torch.cuda.is_available() else "cpu"
self.local_chk_to_en = "models/helsinki-chuukese_chuukese_to_english/finetuned"
self.local_en_to_chk = "models/helsinki-chuukese_english_to_chuukese/finetuned"
self.tokenizer = None
self.model = None
def setup_models(self, direction: str = "chk_to_en") -> bool:
"""Load models, preferring fine-tuned versions."""
try:
if direction == "chk_to_en":
model_path = .local_chk_to_en os.path.exists(.local_chk_to_en) .base_model
:
model_path = .local_en_to_chk os.path.exists(.local_en_to_chk) .reverse_model
.tokenizer = AutoTokenizer.from_pretrained(model_path)
.model = AutoModelForSeq2SeqLM.from_pretrained(model_path).to(.device)
Exception e:
()
() -> :
.model :
.setup_models(direction)
inputs = .tokenizer(text, return_tensors=, padding=).to(.device)
outputs = .model.generate(
**inputs,
max_length=,
num_beams=,
early_stopping=
)
.tokenizer.decode(outputs[], skip_special_tokens=)
Fine-Tuning Script
def fine_tune_model(
training_data: list,
direction: str = "chk_to_en",
epochs: int = 10,
batch_size: int = 16,
learning_rate: float = 2e-5,
output_dir: str = None
):
"""
Fine-tune Helsinki-NLP model on Chuukese data.
Args:
training_data: List of {'source': str, 'target': str} pairs
direction: 'chk_to_en' or 'en_to_chk'
epochs: Number of training epochs
batch_size: Training batch size
learning_rate: Learning rate
output_dir: Directory to save fine-tuned model
"""
if direction == "chk_to_en":
base_model = "Helsinki-NLP/opus-mt-mul-en"
output_dir = output_dir or "models/helsinki-chuukese_chuukese_to_english/finetuned"
else:
base_model = "Helsinki-NLP/opus-mt-en-mul"
output_dir = output_dir or "models/helsinki-chuukese_english_to_chuukese/finetuned"
tokenizer = AutoTokenizer.from_pretrained(base_model)
model = AutoModelForSeq2SeqLM.from_pretrained(base_model)
def preprocess_function(examples):
inputs = examples['source']
targets = examples['target']
model_inputs = tokenizer(inputs, max_length=128, truncation=True, padding='max_length')
with tokenizer.as_target_tokenizer():
labels = tokenizer(targets, max_length=128, truncation=, padding=)
model_inputs[] = labels[]
model_inputs
dataset = Dataset.from_dict({
: [p[] p training_data],
: [p[] p training_data]
})
tokenized_dataset = dataset.(preprocess_function, batched=)
split = tokenized_dataset.train_test_split(test_size=)
training_args = TrainingArguments(
output_dir=output_dir,
num_train_epochs=epochs,
per_device_train_batch_size=batch_size,
per_device_eval_batch_size=batch_size,
learning_rate=learning_rate,
weight_decay=,
evaluation_strategy=,
save_strategy=,
load_best_model_at_end=,
logging_dir=,
logging_steps=,
fp16=torch.cuda.is_available(),
gradient_accumulation_steps=,
warmup_ratio=,
)
data_collator = DataCollatorForSeq2Seq(tokenizer, model=model)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=split[],
eval_dataset=split[],
data_collator=data_collator,
)
trainer.train()
trainer.save_model(output_dir)
tokenizer.save_pretrained(output_dir)
()
trainer
Model Evaluation
import sacrebleu
def evaluate_model(translator, test_pairs: list, direction: str = "chk_to_en"):
"""Evaluate translation model on test set."""
predictions = []
references = []
for pair in test_pairs:
source = pair['source']
target = pair['target']
prediction = translator.translate(source, direction)
predictions.append(prediction)
references.append([target])
bleu = sacrebleu.corpus_bleu(predictions, references)
chrf = sacrebleu.corpus_chrf(predictions, references)
return {
'bleu': bleu.score,
'chrf': chrf.score,
'num_samples': len(test_pairs),
'sample_predictions': list(zip(
[p['source'] for p in test_pairs[:5]],
[p['target'] for p in test_pairs[:5]],
predictions[:5]
))
}
GPU vs CPU Training
def get_device_config():
"""Get optimal device configuration for training."""
if torch.cuda.is_available():
device = "cuda"
gpu_name = torch.cuda.get_device_name(0)
gpu_memory = torch.cuda.get_device_properties(0).total_memory / 1e9
if gpu_memory >= 16:
batch_size = 32
elif gpu_memory >= 8:
batch_size = 16
else:
batch_size = 8
return {
'device': device,
'gpu_name': gpu_name,
'gpu_memory_gb': gpu_memory,
'batch_size': batch_size,
'fp16': True,
'gradient_accumulation': 2
}
else:
return {
'device': 'cpu',
'batch_size': 4,
'fp16': False,
'gradient_accumulation': 8
}
Usage Examples
Basic Training
training_data = prepare_training_data()
splits = split_training_data(training_data)
fine_tune_model(
training_data=splits['train'],
direction="chk_to_en",
epochs=10
)
fine_tune_model(
training_data=splits['train'],
direction="en_to_chk",
epochs=10
)
Model Comparison
translator = HelsinkiChuukeseTranslator()
translator.setup_models(use_finetuned=False)
base_results = evaluate_model(translator, splits['test'])
translator.setup_models(use_finetuned=True)
finetuned_results = evaluate_model(translator, splits['test'])
print(f"Base BLEU: {base_results['bleu']:.2f}")
print(f"Fine-tuned BLEU: {finetuned_results['bleu']:.2f}")
print(f"Improvement: {finetuned_results['bleu'] - base_results['bleu']:.2f}")
Best Practices
Training
- Use high-quality data: Bible verses and validated dictionary entries
- Balance dataset: Mix words, phrases, and sentences
- Early stopping: Monitor validation loss to prevent overfitting
- Mixed precision: Use FP16 on GPU for faster training
- Gradient accumulation: Use for larger effective batch sizes on limited memory
Evaluation
- Use chrF for low-resource languages: More stable than BLEU
- Human evaluation: Periodic review by native speakers
- Back-translation: Verify round-trip consistency
- Cultural validation: Ensure cultural concepts are preserved
Deployment
- Quantization: Use 8-bit quantization for faster inference
- Caching: Cache tokenizer and model loading
- Batch processing: Process multiple translations together
- Fallback: Keep base model as fallback if fine-tuned fails
Dependencies
torch>=2.0.0: PyTorch
transformers>=4.57.0: Hugging Face Transformers
datasets>=2.0.0: Hugging Face Datasets
sentencepiece>=0.1.99: Tokenization
sacrebleu>=2.0.0: Evaluation metrics
accelerate>=0.20.0: Training acceleration
Converted and distributed by TomeVault — claim your Tome and manage your conversions.