jstAnotherCapi's picture
Upload folder using huggingface_hub
ba3ecf1 verified
Raw
History Blame Contribute Delete
5.76 kB
import os
from sklearn.model_selection import train_test_split
import numpy as np
import matplotlib.pyplot as plt
import logging
import sys
import traceback
from datetime import datetime
from datasets import load_dataset
from sentence_transformers import SentenceTransformer, losses
from sentence_transformers.evaluation import EmbeddingSimilarityEvaluator,TripletEvaluator,SequentialEvaluator
from sentence_transformers.similarity_functions import SimilarityFunction
from sentence_transformers.trainer import SentenceTransformerTrainer
from sentence_transformers.training_args import SentenceTransformerTrainingArguments
import torch
from sentence_transformers.training_args import BatchSamplers
import pandas as pd
from arabert.preprocess import ArabertPreprocessor
from pathlib import Path
# Configure logging to write to logs.txt
logging.basicConfig(
format="%(asctime)s - %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
level=logging.INFO,
handlers=[
logging.FileHandler("logs.txt")
]
)
class Tee:
def __init__(self, *files):
self.files = files
def write(self, obj):
for f in self.files:
f.write(obj)
f.flush()
def flush(self):
for f in self.files:
f.flush()
def isatty(self):
return False
log_file = open("logs.txt", "a")
sys.stdout = Tee(sys.stdout, log_file)
train_batch_size = 64
model_name = "bert-base-arabertv02"
model_nickname = "arabert"
timestamp = datetime.now().strftime("%Y%m%d_%H%M")
output_dir = f"output/{model_nickname}_{timestamp}"
device = "cuda" if torch.cuda.is_available() else "cpu"
model = SentenceTransformer(model_name, device=device)
print(f"Model is running on: {device}")
logging.info("Reading the training and eval dataset")
train_dataset = load_dataset("csv", data_files="train.csv")
eval_dataset = load_dataset("csv", data_files="val.csv")
test_dataset = load_dataset("csv", data_files="test.csv")
logging.info(train_dataset)
logging.info(eval_dataset)
logging.info(test_dataset)
# Add this line before the 'evaluators = []' loop
eval_subset = eval_dataset["train"].shuffle(seed=42).select(range(250000))
# Training loss
matryoshka_dims = [768, 512, 256, 128, 64]
inner_train_loss = losses.MultipleNegativesRankingLoss(model=model)
train_loss = losses.MatryoshkaLoss(model, inner_train_loss, matryoshka_dims=matryoshka_dims)
# Evaluators for validation
evaluators = []
for dim in matryoshka_dims:
evaluators.append(
TripletEvaluator(
anchors=eval_subset["anchor"],
positives=eval_subset["positive"],
negatives=eval_subset["negative"],
name=f"dev-{dim}",
truncate_dim=dim,
)
)
dev_evaluator = SequentialEvaluator(evaluators, main_score_function=lambda scores: scores[0])
dev_evaluator(model)
args = SentenceTransformerTrainingArguments(
# --- Output & Identity ---
output_dir=output_dir, # Where the model and checkpoints are saved
seed=42, # Ensures results are reproducible (shuffling/init)
# --- Epochs & Batching (L40S Optimized) ---
num_train_epochs=2, # Increased to 2 for better convergence
per_device_train_batch_size=train_batch_size, # High batch size to saturate the L40S 48GB VRAM
per_device_eval_batch_size=train_batch_size, # Matching eval batch size for speed
gradient_accumulation_steps=2, # Effective batch size = 128 (64 * 2)
# --- Optimization & Precision ---
bf16=True, # Set to True for L40S; faster and more stable than FP16
fp16=False, # Disabled in favor of BF16
learning_rate=2e-5, # Standard "safe" learning rate for Transformers
lr_scheduler_type="linear", # Gently reduces learning rate to 0 over training
warmup_ratio=0.1, # Ramps up LR for the first 10% of steps to prevent spikes
weight_decay=0.01, # Regularization to prevent overfitting
# --- Data Handling ---
batch_sampler=BatchSamplers.NO_DUPLICATES, # Essential for MNR/Matryoshka loss to avoid bad negatives
dataloader_num_workers=8, # Use 8 CPU cores to keep the GPU fed with data
# --- Evaluation & Saving (Safety) ---
eval_strategy="steps", # Evaluate every X steps
eval_steps=6000, # Increased from 10; L40S processes data very fast
save_strategy="steps", # Save checkpoints every X steps
save_steps=6000, # Usually matches eval_steps
save_total_limit=2, # Keep only the top 3 checkpoints to save disk space
# --- Tracking & Debugging ---
report_to="tensorboard", # Send live metrics to TensorBoard
logging_steps=200, # Print/Log stats every 200 steps (prevents messy logs)
logging_dir="arabvert02-matryoshka/runs", # Specific folder for TensorBoard event files
)
trainer = SentenceTransformerTrainer(
model=model,
args=args,
train_dataset=train_dataset,
eval_dataset=eval_dataset,
loss=train_loss,
evaluator=dev_evaluator,
)
trainer.train()
# Save final model
final_output_dir = f"{output_dir}/final"
model.save(final_output_dir)
print("model saved successfully")
# Test evaluation
evaluators = []
for dim in matryoshka_dims:
evaluators.append(
TripletEvaluator(
anchors=test_dataset["train"]["anchor"],
positives=test_dataset["train"]["positive"],
negatives=test_dataset["train"]["negative"],
name=f"test-{dim}",
truncate_dim=dim,
)
)
test_evaluator = SequentialEvaluator(evaluators)
test_evaluator(model)