Fine-Tuning di un Sentence-Transformer per l’Italiano

Nicola Procopio
5 min readDec 29, 2023

--

TL;DR
Questo articolo è basato su “Train and Fine-Tune Sentence Transformers Models”

Cos’è un Sentence-Transformers?

Un Sentence-Transformers mappa un testo in un embedding di dimensione fissa che ne rappresenta il significato.

Come funziona?

Il Sentence-Transformers non è altro che un modello Transformer, di quelli che possiamo scaricare liberamente da HuggingFace al quale viene aggiunto un livello di pooling per ottenere un unico vettore di dimensione fissa in uscita, di solito si usa il mean pooling.

Per alcuni task (es. clustering) a volte viene aggiunto anche un livello di Normalization alla fine ma non è il focus di questo notebook.

Come fare fine-tuning di un Sentence-Transformers

Per addestrare o fare fine tuning di un sentence transformer le prime due cose da conoscere sono:

  • la disponibilità dei dati e la struttura del dataset di addestramento
  • le loss function e la loro relazione con la struttura del dataset

In questo notebook verrà creato un sentence-transformers per l’italiano che alla fine è stato caricato su Huggingface.

!pip install -U sentence-transformers

Scelta del modello

La prima cosa da fare è scegliere il modello adatto al proprio obiettivo, il nostro è costruire un modello per l’italiano, possiamo farlo in due modi:

  1. Prendere un Transformers monolingua già addestrato per il fill-mask
  2. Prendere un multilingua

ho optato per la prima scelta anche se i checkpoint HuggingFace per il fill-mask in italiano sono molto pochi, nelle prossime celle andremo a costruire il Sentence-Transformers sfruttando l’omonima libreria.

from sentence_transformers import SentenceTransformer, models

model_checkpoint = "dbmdz/bert-base-italian-uncased"

word_embedding_model = models.Transformer(model_name_or_path=model_checkpoint)
pooling_model = models.Pooling(word_embedding_model.get_word_embedding_dimension())
model = SentenceTransformer(modules=[word_embedding_model, pooling_model])

Perchè non usiamo direttamente un modello come BERT?

Prepare i dataset

I Sentence Transformers vengono utilizzati per calcolare la similarità tra frasi, quindi il dataset di train deve essere strutturato in modo da far capire al modello quali sono le frasi simili e quanto lo sono.
Esistono diverse strutture di dataset per questo task.

  1. Le coppie di frasi hanno una label (int o float) che indica il grado di similarità
  2. Coppie di frasi simili senza etichetta. Ad esempio: testo->riassunto, domande uguali formulate in modo diverso, testo->traduzione, …
  3. La frase ha una label intera che ne rappresenta il tipo. Il dataset viene formato da triplette [anchor, positive, negative] dove le prime due hanno la stessa label.
  4. Triplette [anchor, positive, negative] ma senza label

In questo caso ho usato il dataset del primo tipo utilizzando la traduzione in italiano di STSbenchmark dataset.

N.B. I casi 1 e 3 sono i più semplici su cui lavorare, il più complesso è il 4.

!pip install datasets
from datasets import load_dataset



dataset_train = load_dataset("stsb_multi_mt", name="it", split="train")
dataset_test = load_dataset("stsb_multi_mt", name="it", split="test")


print("train size: ", dataset_train.shape, "\n", "test size: ", dataset_test.shape)

Train

Come possiamo vedere la similarity score và da 0 a 5, per il fine tuning del modello dobbiamo portarla tra 0 e 1.

Bisogna creare una struttura ([sentence1, sentence2], label) usando l’oggetto InputExample. Il risultato di questo passaggio viene usato come input del DataLoader.

from sentence_transformers import InputExample

train_examples = []

for i in range(dataset_train.shape[0]):
example = dataset_train[i]
train_examples.append(InputExample(texts=[example['sentence1'], example['sentence2']], label = float(example['similarity_score'])/5.0))
from torch.utils.data import DataLoader

train_dataloader = DataLoader(train_examples, shuffle=True, batch_size=16)

Evaluator

La libreria sentence_transformers mette a disposizione diversi costrutti per valutare le performance dei modelli, useremo EmbeddingSimilarityEvaluator che valuta un modello in base alla somiglianza degli embeddings, calcolando la correlazione di Spearman e di Pearson rispetto alle gold standard labels. Le metriche disponibili sono la similarità del coseno, la distanza euclidea e la distanza di Manhattan.

Lo score in output è la correlazione di Spearman.

from sentence_transformers import evaluation

evaluator = evaluation.EmbeddingSimilarityEvaluator(dataset_test['sentence1'], dataset_test['sentence2'], [x/5.0 for x in dataset_test['similarity_score']],
main_similarity = evaluation.SimilarityFunction.COSINE, show_progress_bar=True, write_csv=True)

Losses

A seconda della struttura del dataset che stiamo usando bisogna utilizzare una loss. Nel nostro caso utilizzeremo la CosineSimilarityLoss.

Lascio l’approfondimento delle losses al post originale, qui metto solo lo schema condiviso nello stesso.

Come si vede dallo schema per la nostra tipologia di dataset potevamo scegliere diverse loss, la CosineSimilarityLoss lavora con la label float mentre le altre due con gli interi, da qui la scelta.

from sentence_transformers import losses

train_loss = losses.CosineSimilarityLoss(model = model)

Fit the model

La parte più complicata è finita, ora non ci resta che far partire l’addestramento. Impostiamo alcuni iperparametri, il più interessante è warmup_step. In pratica dopo un certo numero di passi (su molti forum consigliano il 10% del train) il learning rate viene ridotto linearmente fino allo 0.

num_epochs = 10
evaluation_steps = 500

warmup_steps = int(len(train_dataloader) * num_epochs * 0.1) #10% of train data
model.fit(train_objectives=[(train_dataloader, train_loss)], evaluator= evaluator, evaluation_steps = evaluation_steps,
epochs=num_epochs, steps_per_epoch= 1500, warmup_steps=warmup_steps, save_best_model=True)

Alla fine del train il nostro modello sarà pronto per essere salvato e condiviso su Hugging Face Hub.

Il notebook potete trovarlo su Github e su Kaggle.

Potete trovare tutti i miei sentence-transformers per l’italiano su Hugging Face.

Altri riferimenti

--

--

Nicola Procopio

Data Scientist and Open Source enthusiast. After many years of indecision whether to open a medium profile or not, here I am. I write in English and Italian.