Ottimizza EmbeddingGemma

Visualizza su ai.google.dev Esegui in Google Colab Esegui in Kaggle Apri in Vertex AI Visualizza il codice sorgente su GitHub

L'ottimizzazione contribuisce a colmare il divario tra la comprensione generica di un modello e l'accuratezza specializzata e ad alte prestazioni richiesta dalla tua applicazione. Poiché nessun modello è perfetto per ogni attività, il perfezionamento lo adatta al tuo dominio specifico.

Immagina che la tua azienda, "Shibuya Financial", offra vari prodotti finanziari complessi come fondi di investimento, conti NISA (un conto di risparmio con agevolazioni fiscali) e mutui per la casa. Il tuo team di assistenza clienti utilizza una knowledge base interna per trovare rapidamente le risposte alle domande dei clienti.

Configurazione

Prima di iniziare questo tutorial, completa i seguenti passaggi:

  • Accedi a EmbeddingGemma effettuando l'accesso a Hugging Face e selezionando Accetta licenza per un modello Gemma.
  • Genera un token di accesso Hugging Face e utilizzalo per accedere da Colab.

Questo notebook verrà eseguito su CPU o GPU.

Installa i pacchetti Python

Installa le librerie necessarie per eseguire il modello EmbeddingGemma e generare gli embedding. Sentence Transformers è un framework Python per gli incorporamenti di testo e immagini. Per saperne di più, consulta la documentazione di Sentence Transformers.

pip install -U sentence-transformers git+https://github.com/huggingface/transformers@v4.56.0-Embedding-Gemma-preview

Dopo aver accettato la licenza, è necessario un token Hugging Face valido per accedere al modello.

# Login into Hugging Face Hub
from huggingface_hub import login
login()

Carica modello

Utilizza le librerie sentence-transformers per creare un'istanza di una classe di modello con EmbeddingGemma.

import torch
from sentence_transformers import SentenceTransformer

device = "cuda" if torch.cuda.is_available() else "cpu"

model_id = "google/embeddinggemma-300M"
model = SentenceTransformer(model_id).to(device=device)

print(f"Device: {model.device}")
print(model)
print("Total number of parameters in the model:", sum([p.numel() for _, p in model.named_parameters()]))
Device: cuda:0
SentenceTransformer(
  (0): Transformer({'max_seq_length': 2048, 'do_lower_case': False, 'architecture': 'Gemma3TextModel'})
  (1): Pooling({'word_embedding_dimension': 768, 'pooling_mode_cls_token': False, 'pooling_mode_mean_tokens': True, 'pooling_mode_max_tokens': False, 'pooling_mode_mean_sqrt_len_tokens': False, 'pooling_mode_weightedmean_tokens': False, 'pooling_mode_lasttoken': False, 'include_prompt': True})
  (2): Dense({'in_features': 768, 'out_features': 3072, 'bias': False, 'activation_function': 'torch.nn.modules.linear.Identity'})
  (3): Dense({'in_features': 3072, 'out_features': 768, 'bias': False, 'activation_function': 'torch.nn.modules.linear.Identity'})
  (4): Normalize()
)
Total number of parameters in the model: 307581696

Preparare il set di dati di fine tuning

Questa è la parte più importante. Devi creare un set di dati che insegni al modello cosa significa "simile" nel tuo contesto specifico. Questi dati sono spesso strutturati come triplette: (ancora, positivo, negativo)

  • Ancora: la query o la frase originale.
  • Positivo: una frase semanticamente molto simile o identica all'ancora.
  • Negativa: una frase che riguarda un argomento correlato, ma semanticamente distinto.

In questo esempio, abbiamo preparato solo 3 triplette, ma per un'applicazione reale avresti bisogno di un set di dati molto più grande per ottenere buoni risultati.

from datasets import Dataset

dataset = [
    ["How do I open a NISA account?", "What is the procedure for starting a new tax-free investment account?", "I want to check the balance of my regular savings account."],
    ["Are there fees for making an early repayment on a home loan?", "If I pay back my house loan early, will there be any costs?", "What is the management fee for this investment trust?"],
    ["What is the coverage for medical insurance?", "Tell me about the benefits of the health insurance plan.", "What is the cancellation policy for my life insurance?"],
]

# Convert the list-based dataset into a list of dictionaries.
data_as_dicts = [ {"anchor": row[0], "positive": row[1], "negative": row[2]} for row in dataset ]

# Create a Hugging Face `Dataset` object from the list of dictionaries.
train_dataset = Dataset.from_list(data_as_dicts)
print(train_dataset)
Dataset({
    features: ['anchor', 'positive', 'negative'],
    num_rows: 3
})

Prima dell'ottimizzazione

Una ricerca di "investimento esentasse" potrebbe aver restituito i seguenti risultati, con i punteggi di similarità:

  1. Documento: Apertura di un conto NISA (punteggio: 0,45)
  2. Documento: Apertura di un conto di risparmio ordinario (punteggio: 0,48) <- Punteggio simile, potenzialmente fuorviante
  3. Documento: Guida alla richiesta di mutuo per la casa (punteggio: 0,42)
task_name = "STS"

def get_scores(query, documents):
  # Calculate embeddings by calling model.encode()
  query_embeddings = model.encode(query, prompt=task_name)
  doc_embeddings = model.encode(documents, prompt=task_name)

  # Calculate the embedding similarities
  similarities = model.similarity(query_embeddings, doc_embeddings)

  for idx, doc in enumerate(documents):
    print("Document: ", doc, "-> 🤖 Score: ", similarities.numpy()[0][idx])

query = "I want to start a tax-free installment investment, what should I do?"
documents = ["Opening a NISA Account", "Opening a Regular Savings Account", "Home Loan Application Guide"]

get_scores(query, documents)
Document:  Opening a NISA Account -> 🤖 Score:  0.45698774
Document:  Opening a Regular Savings Account -> 🤖 Score:  0.48092696
Document:  Home Loan Application Guide -> 🤖 Score:  0.42127067

Formazione

Utilizzando un framework come sentence-transformers in Python, il modello di base apprende gradualmente le sottili distinzioni nel tuo vocabolario finanziario.

from sentence_transformers import SentenceTransformerTrainer, SentenceTransformerTrainingArguments
from sentence_transformers.losses import MultipleNegativesRankingLoss
from transformers import TrainerCallback

loss = MultipleNegativesRankingLoss(model)

args = SentenceTransformerTrainingArguments(
    # Required parameter:
    output_dir="my-embedding-gemma",
    # Optional training parameters:
    prompts=model.prompts[task_name],    # use model's prompt to train
    num_train_epochs=5,
    per_device_train_batch_size=1,
    learning_rate=2e-5,
    warmup_ratio=0.1,
    # Optional tracking/debugging parameters:
    logging_steps=train_dataset.num_rows,
    report_to="none",
)

class MyCallback(TrainerCallback):
    "A callback that evaluates the model at the end of eopch"
    def __init__(self, evaluate):
        self.evaluate = evaluate # evaluate function

    def on_log(self, args, state, control, **kwargs):
        # Evaluate the model using text generation
        print(f"Step {state.global_step} finished. Running evaluation:")
        self.evaluate()

def evaluate():
  get_scores(query, documents)

trainer = SentenceTransformerTrainer(
    model=model,
    args=args,
    train_dataset=train_dataset,
    loss=loss,
    callbacks=[MyCallback(evaluate)]
)
trainer.train()
Step 3 finished. Running evaluation:
Document:  Opening a NISA Account -> 🤖 Score:  0.6449194
Document:  Opening a Regular Savings Account -> 🤖 Score:  0.44123
Document:  Home Loan Application Guide -> 🤖 Score:  0.46752414
Step 6 finished. Running evaluation:
Document:  Opening a NISA Account -> 🤖 Score:  0.68873787
Document:  Opening a Regular Savings Account -> 🤖 Score:  0.34069622
Document:  Home Loan Application Guide -> 🤖 Score:  0.50065553
Step 9 finished. Running evaluation:
Document:  Opening a NISA Account -> 🤖 Score:  0.7148906
Document:  Opening a Regular Savings Account -> 🤖 Score:  0.30480516
Document:  Home Loan Application Guide -> 🤖 Score:  0.52454984
Step 12 finished. Running evaluation:
Document:  Opening a NISA Account -> 🤖 Score:  0.72614634
Document:  Opening a Regular Savings Account -> 🤖 Score:  0.29255486
Document:  Home Loan Application Guide -> 🤖 Score:  0.5370023
Step 15 finished. Running evaluation:
Document:  Opening a NISA Account -> 🤖 Score:  0.7294032
Document:  Opening a Regular Savings Account -> 🤖 Score:  0.2893038
Document:  Home Loan Application Guide -> 🤖 Score:  0.54087913
Step 15 finished. Running evaluation:
Document:  Opening a NISA Account -> 🤖 Score:  0.7294032
Document:  Opening a Regular Savings Account -> 🤖 Score:  0.2893038
Document:  Home Loan Application Guide -> 🤖 Score:  0.54087913
TrainOutput(global_step=15, training_loss=0.009651281436261646, metrics={'train_runtime': 63.2486, 'train_samples_per_second': 0.237, 'train_steps_per_second': 0.237, 'total_flos': 0.0, 'train_loss': 0.009651281436261646, 'epoch': 5.0})

Dopo l'ottimizzazione

La stessa ricerca ora produce risultati molto più chiari:

  1. Documento: Apertura di un conto NISA (punteggio: 0,72) <- Molto più sicuro
  2. Documento: Apertura di un conto di risparmio ordinario (punteggio: 0,28) <- Chiaramente meno pertinente
  3. Documento: Guida alla richiesta di mutuo per la casa (punteggio: 0,54)
get_scores(query, documents)
Document:  Opening a NISA Account -> 🤖 Score:  0.7294032
Document:  Opening a Regular Savings Account -> 🤖 Score:  0.2893038
Document:  Home Loan Application Guide -> 🤖 Score:  0.54087913

Per caricare il modello su Hugging Face Hub, puoi utilizzare il metodo push_to_hub della libreria Sentence Transformers.

Il caricamento del modello semplifica l'accesso per l'inferenza direttamente dall'hub, la condivisione con altri e il controllo delle versioni del tuo lavoro. Una volta caricato, chiunque può caricare il tuo modello con una sola riga di codice, semplicemente facendo riferimento al suo ID modello univoco <username>/my-embedding-gemma

# Push to Hub
model.push_to_hub("my-embedding-gemma")

Riepilogo e passaggi successivi

Ora hai imparato ad adattare un modello EmbeddingGemma per un dominio specifico eseguendo l'ottimizzazione con la libreria Sentence Transformers.

Scopri cos'altro puoi fare con EmbeddingGemma: