Vai al contenuto principale

Fine-tuning di GPT-4o Mini: guida passo dopo passo

Personalizza il modello GPT-4o Mini per classificare i post di Reddit con etichette "stressante" e "non stressante".
· 13 min leggi

Scopri con l'IA

Prima di iniziare il fine-tuning del modello GPT-4o Mini, ti consigliamo di studiare prompt engineering, prompt chaining e function calling per personalizzare le risposte del modello e ottenere risposte specifiche per il tuo dominio.

Il fine-tuning è necessario quando vuoi adattare stile, tono o formato. Serve a migliorare affidabilità e accuratezza, gestire prompt complessi o svolgere un nuovo compito che il prompt engineer non è riuscito a ottenere.

In questo tutorial, effettueremo il fine-tuning del modello GPT-4o Mini per classificare il testo con etichette "stress" e "non stress". Successivamente, accederemo al modello ottimizzato tramite l'API di OpenAI e l'OpenAI playground. Infine, valuteremo il modello confrontandone le prestazioni prima e dopo il tuning usando varie metriche di classificazione.

Immagine di copertina del fine-tuning di GPT-4o Mini

Immagine dell'autore

Introduzione a GPT-4o Mini

GPT-4o Mini è il modello linguistico generale più conveniente disponibile. Ottiene l'82% su MMLU e attualmente supera Claude 3.5 Sonnet nelle preferenze chat della leaderboard LMSYS. Costa 15 cent per milione di token in input e 60 cent per milione di token in output, il 60% in meno rispetto a GPT-3.5 Turbo.

GPT-4o mini attualmente supporta testo e immagini come input. Il modello ha una finestra di contesto di 128K token, supporta fino a 16K token in output per richiesta e ha conoscenze fino all'ottobre 2023. GPT-4o Mini può gestire testo non inglese, dato che usa il tokenizer di GPT-4o. Otteniamo il meglio di entrambi i mondi a basso costo.

Scopri casi d'uso, API di chat completion e benchmark dettagliati di GPT-4o Mini leggendo il nostro blog, Cos'è GPT-4o Mini?

Configurare l'API di OpenAI

Vai sul sito di OpenAI e crea un account. Il fine-tuning è costoso e usare GPT-4o Mini via API richiede che tu abbia un metodo di pagamento associato al tuo account. Per evitare intoppi, assicurati di avere almeno 10 USD di credito sul tuo account prima di tentare il fine-tuning del modello.

Vai alla dashboard principale, clicca sulla scheda "API keys" e genera la chiave segreta dell'API di OpenAI.

generazione della chiave API di OpenAI

Useremo il DataLab di DataCamp come editor di codice. Per impostare la variabile d'ambiente della chiave API di OpenAI, vai alla scheda dell'ambiente e clicca sull'opzione per le variabili d'ambiente. Poi aggiungi la variabile d'ambiente per la chiave API e attivala come mostrato sotto.

Impostazione della variabile d'ambiente in DataLab

Installa il pacchetto Python di OpenAI per accedere a GPT-4o Mini.

%%capture
%pip install openai

Crea il client usando la chiave API di OpenAI e genera una risposta con il prompt di esempio. La funzione di chat completion richiede il nome del modello e i messaggi in una lista di dizionari.

from IPython.display import Markdown, display
from openai import OpenAI
import os

openai_api_key = os.environ["OPENAI_API_KEY"]

client = OpenAI(api_key=openai_api_key)

response = client.chat.completions.create(
  model="gpt-4o-mini",
  messages=[
    {"role": "system", "content": "You are a great philosopher."},
    {"role": "user", "content": "What is the meaning of life?"}
  ]
)
display(Markdown(response.choices[0].message.content))

La nostra API di OpenAI è completamente configurata e siamo pronti ad avviare il job di fine-tuning.

Generazione della risposta usando GPT-4o-mini

Nuovo all'API di OpenAI? Puoi seguire il tutorial semplice e dettagliato GPT-4o API Tutorial: iniziare con l'API di OpenAI per capire come scrivere poche righe di codice e accedere a modelli all'avanguardia.

Fine-tuning di GPT-4o Mini

In questa sezione effettueremo il fine-tuning del modello GPT-4o Mini sul dataset Stress Detection from the Social Media Articles di Kaggle. Il dataset contiene post da Reddit e Twitter, classificati con etichette stress e non stress.

Creare il dataset

Ora caricheremo ed elaboreremo il dataset.

  1. Carica le prime 200 righe dal dataset dei post di Reddit.
  2. Elimina tutte le colonne tranne 'title' e 'label'.
  3. Mappa la colonna delle etichette per convertire 0 e 1 in etichette "non stress" e "stress".
  4. Suddividi il dataset in training e validation set.
  5. Salva sia il training set che il validation set in formato JSONL.

Nota: Assicurati del formato corretto del dataset, che include il prompt di sistema, la richiesta dell'utente e la risposta. La risposta sarà l'etichetta.

import pandas as pd
import json
from sklearn.model_selection import train_test_split

# Load the CSV file with the correct delimiter
file_path = 'Reddit_Title.csv'  # Change this to your local path
data = pd.read_csv(file_path, sep=';')

# Clean up and drop unnecessary columns, and select the top 200 rows
data_cleaned = data[['title', 'label']].head(200)

# Mapping the 'label' column to more human-readable text
label_mapping = {0: "non-stress", 1: "stress"}
data_cleaned['label'] = data_cleaned['label'].map(label_mapping)

# Split the data into training and validation sets (80% train, 20% validation)
train_data, validation_data = train_test_split(data_cleaned, test_size=0.2, random_state=42)

def save_to_jsonl(data, output_file_path):
    jsonl_data = []
    for index, row in data.iterrows():
        jsonl_data.append({
            "messages": [
                {"role": "system", "content": "Given a social media post, classify whether it indicates 'stress' or 'non-stress'."},
                {"role": "user", "content": row['title']},
                {"role": "assistant", "content": f"\"{row['label']}\""}
            ]
        })

    # Save to JSONL format
    with open(output_file_path, 'w') as f:
        for item in jsonl_data:
            f.write(json.dumps(item) + '\n')

# Save the training and validation sets to separate JSONL files
train_output_file_path = 'stress_detection_train.jsonl' 
validation_output_file_path = 'stress_detection_validation.jsonl'

save_to_jsonl(train_data, train_output_file_path)
save_to_jsonl(validation_data, validation_output_file_path)

print(f"Training dataset save to {train_output_file_path}")
print(f"Validation dataset save to {validation_output_file_path}")

Output: 

Training dataset save to stress_detection_train.jsonl
Validation dataset save to stress_detection_validation.jsonl

Caricare il dataset

Ora useremo il client di OpenAI per caricare i dataset di training e validation per il fine-tuning.

train_file = client.files.create(
  file=open(train_output_file_path, "rb"),
  purpose="fine-tune"
)

valid_file = client.files.create(
  file=open(validation_output_file_path, "rb"),
  purpose="fine-tune"
)

print(f"Training file Info: {train_file}")
print(f"Validation file Info: {valid_file}")

L'API di OpenAI prima convaliderà il dataset, poi caricherà i file e genererà i metadati che potremo usare per il fine-tuning del modello. 

Training file Info: FileObject(id='file-b2lo2chod6xuMhYg9JcEsnp6', bytes=48563, created_at=1727133513, filename='stress_detection_train.jsonl', object='file', purpose='fine-tune', status='processed', status_details=None)
Validation file Info: FileObject(id='file-Fae0AVSUhTGr49qhQz8d2yyp', bytes=12284, created_at=1727133514, filename='stress_detection_validation.jsonl', object='file', purpose='fine-tune', status='processed', status_details=None)

Per verificare che il dataset sia stato caricato correttamente nel cloud, vai alla Dashboard e clicca sulla scheda "Storage". Troverai i due file pronti all'uso.

Caricamento dei dataset di training e validation.

Avviare il job di fine-tuning

Crea il job di fine-tuning usando l'API del client. La funzione di fine-tuning richiede l'ID del file di training, l'ID del file di validation, il nome del modello e gli iperparametri. Effettueremo il fine-tuning per tre epoche. Per migliorare le prestazioni del modello, puoi sempre addestrare sull'intero dataset con almeno 5 epoche. 

model = client.fine_tuning.jobs.create(
  training_file=train_file.id, 
  validation_file=valid_file.id,
  model="gpt-4o-mini-2024-07-18", 
  hyperparameters={
    "n_epochs": 3,
	"batch_size": 3,
	"learning_rate_multiplier": 0.3
  }
)
job_id = model.id
status = model.status

print(f'Fine-tuning model with jobID: {job_id}.')
print(f"Training Response: {model}")
print(f"Training Status: {status}")

Una volta eseguita la funzione, il job di fine-tuning si avvierà e mostrerà i log. 

Fine-tuning model with jobID: ftjob-rgIMFxZSsWDqCNfOev54e4Jq.
Training Response: FineTuningJob(id='ftjob-rgIMFxZSsWDqCNfOev54e4Jq', created_at=1727135628, error=Error(code=None, message=None, param=None), fine_tuned_model=None, finished_at=None, hyperparameters=Hyperparameters(n_epochs=3, batch_size=3, learning_rate_multiplier=0.3), model='gpt-4o-mini-2024-07-18', object='fine_tuning.job', organization_id='org-jLXWbL5JssIxj9KNgoFBK7Qi', result_files=[], seed=748607710, status='validating_files', trained_tokens=None, training_file='file-b2lo2chod6xuMhYg9JcEsnp6', validation_file='file-Fae0AVSUhTGr49qhQz8d2yyp', estimated_finish=None, integrations=[], user_provided_suffix=None)
Training Status: validating_files

Possiamo visualizzare lo stato del job di fine-tuning sulla dashboard cliccando sulla scheda "Fine-tuning" e poi sull'ID del job.

Fine-tuning del modello

Oppure possiamo controllare lo stato del job di fine-tuning usando la funzione jobs.retrieve. 

# Retrieve the state of a fine-tune
client.fine_tuning.jobs.retrieve(job_id)

Output: 

FineTuningJob(id='ftjob-rgIMFxZSsWDqCNfOev54e4Jq', created_at=1727135628, error=Error(code=None, message=None, param=None), fine_tuned_model=None, finished_at=None, hyperparameters=Hyperparameters(n_epochs=3, batch_size=3, learning_rate_multiplier=0.3), model='gpt-4o-mini-2024-07-18', object='fine_tuning.job', organization_id='org-jLXWbL5JssIxj9KNgoFBK7Qi', result_files=[], seed=748607710, status='running', trained_tokens=None, training_file='file-b2lo2chod6xuMhYg9JcEsnp6', validation_file='file-Fae0AVSUhTGr49qhQz8d2yyp', estimated_finish=1727135943, integrations=[], user_provided_suffix=None)

Se pensi che la loss non stia diminuendo, puoi sempre annullare il job usando la funzione jobs.cancel.

# Cancel a job
client.fine_tuning.jobs.cancel(job_id)

Quando il job di fine-tuning è completato, riceverai un'email che ti avvisa che il modello ottimizzato è pronto per l'uso.

Ricezione dell'email sullo stato del job di fine-tuning.

Accedere al modello ottimizzato tramite API

Per accedere al modello ottimizzato, dobbiamo ottenere il nome del modello. Per farlo, recupereremo le informazioni su tutti i job di fine-tuning, selezioneremo l'ultimo e poi il nome del modello.

result = client.fine_tuning.jobs.list()

# Retrieve the fine tuned model
fine_tuned_model = result.data[0].fine_tuned_model
print(fine_tuned_model)

Questo è il nome del nostro modello ottimizzato. 

ft:gpt-4o-mini-2024-07-18:personal::AAnFfX5q

Genera la risposta fornendo alla funzione di chat completion il nome del modello ottimizzato, i messaggi con un corretto system prompt e un campione dal dataset.

completion = client.chat.completions.create(
  model = fine_tuned_model,
  messages=[
    {"role": "system", "content": "Given a social media post, classify whether it indicates 'stress' or 'non-stress'."},
    {"role": "user", "content": "Just went to my first homecoming, and they played a song I've always wanted to dance to at an official dance. Sorry for the terrible quality, but my happiness in this moment couldn't be exaggerated!"}
  ]
)
print(completion.choices[0].message.content)

Fatto! Ho previsto l'etichetta correttamente.

"non-stress"

Se non sei soddisfatto del tuo modello, puoi sempre eliminarlo con il seguente comando. Noi non lo faremo perché dobbiamo prima eseguire ulteriori valutazioni del modello.

# Delete a fine-tuned model (must be an owner of the org the model was created in)
client.models.delete(fine_tuned_model)

Accedere al modello ottimizzato con il Playground

C'è un altro modo per accedere al modello ottimizzato e testarlo su vari prompt in modo più efficiente.

Vai alla dashboard di OpenAI, clicca sulla scheda "Fine-tuning", seleziona il job eseguito di recente e poi clicca sul pulsante "Playground" in basso a destra.

Accesso al modello ottimizzato con il playground.

Verrai reindirizzato all'applicazione chatbot. Lì puoi fornire un system prompt e iniziare a digitare il post di Reddit di esempio. 

Prova del modello ottimizzato.

Puoi anche eseguire lo stesso prompt e confrontarlo con un altro modello per un'analisi migliore. 

Valutazione del modello

Abbiamo effettuato il fine-tuning del modello e pensiamo che sia abbastanza buono. Ma hai considerato se non fosse già migliore all'inizio? Non abbiamo ancora fatto un confronto dettagliato prima e dopo. 

In questa sezione, useremo i dati di validazione per prevedere le etichette con il modello base e poi le confronteremo con quelle del modello ottimizzato. Confronteremo entrambi i modelli in base ad accuratezza, classification report e confusion matrix. 

Valutazione del modello prima del fine-tuning

Crea una funzione predict che prenda in input il dataset e il nome del modello per generare una lista di etichette previste. Usa gli stessi messaggi di sistema e i titoli dei post dal dataset.

def predict(test, model):
    y_pred = []
    categories = ["non-stress", "stress"]

    for index, row in test.iterrows():
        response = client.chat.completions.create(
            model=model,
            messages=[
                {
                    "role": "system",
                    "content": "Given a social media post, classify whether it indicates 'stress' or 'non-stress'.",
                },
                {"role": "user", "content": row["title"]},
            ],
        )

        answer = response.choices[0].message.content

        # Determine the predicted category

        for category in categories:
            if category.lower() in answer.lower():
                y_pred.append(category)
                break
        else:
            y_pred.append("none")
    return y_pred

Poi creeremo la funzione evaluate, che userà le etichette previste e quelle reali per generare accuracy, classification report e confusion matrix.

from sklearn.metrics import accuracy_score, classification_report, confusion_matrix
import numpy as np


def evaluate(y_true, y_pred):
    labels = ["non-stress", "stress"]
    mapping = {label: idx for idx, label in enumerate(labels)}

    def map_func(x):
        return mapping.get(
            x, -1
        )  # Map to -1 if not found, but should not occur with correct data

    y_true_mapped = np.vectorize(map_func)(y_true)
    y_pred_mapped = np.vectorize(map_func)(y_pred)

    # Calculate accuracy

    accuracy = accuracy_score(y_true=y_true_mapped, y_pred=y_pred_mapped)
    print(f"Accuracy: {accuracy:.3f}")

    # Generate accuracy report

    unique_labels = set(y_true_mapped)  # Get unique labels

    for label in unique_labels:
        label_indices = [
            i for i in range(len(y_true_mapped)) if y_true_mapped[i] == label
        ]
        label_y_true = [y_true_mapped[i] for i in label_indices]
        label_y_pred = [y_pred_mapped[i] for i in label_indices]
        label_accuracy = accuracy_score(label_y_true, label_y_pred)
        print(f"Accuracy for label {labels[label]}: {label_accuracy:.3f}")
    # Generate classification report

    class_report = classification_report(
        y_true=y_true_mapped,
        y_pred=y_pred_mapped,
        target_names=labels,
        labels=list(range(len(labels))),
    )
    print("\nClassification Report:")
    print(class_report)

    # Generate confusion matrix

    conf_matrix = confusion_matrix(
        y_true=y_true_mapped, y_pred=y_pred_mapped, labels=list(range(len(labels)))
    )
    print("\nConfusion Matrix:")
    print(conf_matrix)

Passa alla funzione predict il dataset di validazione e il nome del modello base. Poi fornisci le etichette previste e reali alla funzione evaluate per generare un report di valutazione del modello.

y_pred = predict(validation_data, "gpt-4o-mini-2024-07-18")
y_true = validation_data["label"]
evaluate(y_true, y_pred)

Il nostro modello base è piuttosto bravo a classificare il testo. Abbiamo raggiunto un'accuratezza del 92,5%.

Accuracy: 0.925
Accuracy for label non-stress: 0.947
Accuracy for label stress: 0.905

Classification Report:
              precision    recall  f1-score   support

  non-stress       0.90      0.95      0.92        19
      stress       0.95      0.90      0.93        21

    accuracy                           0.93        40
   macro avg       0.93      0.93      0.92        40
weighted avg       0.93      0.93      0.93        40


Confusion Matrix:
[[18  1]
 [ 2 19]]

Valutazione del modello dopo il fine-tuning

Usiamo la funzione predict con il nome del modello ottimizzato per generare le etichette di stress. Poi, con le etichette previste e quelle reali, generiamo il report dettagliato di valutazione del modello.

fine_tuned_model = "ft:gpt-4o-mini-2024-07-18:personal::AAnFfX5q"

y_pred = predict(validation_data,fine_tuned_model)
evaluate(y_true, y_pred)

Le prestazioni del nostro modello sono migliorate. Abbiamo raggiunto un'accuratezza del 97,5%, un miglioramento significativo.

Accuracy: 0.975
Accuracy for label non-stress: 1.000
Accuracy for label stress: 0.952

Classification Report:
              precision    recall  f1-score   support

  non-stress       0.95      1.00      0.97        19
      stress       1.00      0.95      0.98        21

    accuracy                           0.97        40
   macro avg       0.97      0.98      0.97        40
weighted avg       0.98      0.97      0.98        40


Confusion Matrix:
[[19  0]
 [ 1 20]]

Il fine-tuning su determinate attività può migliorare significativamente l'accuratezza. Questo era solo un test di esempio, ma nei progetti reali il fine-tuning migliora accuratezza e prestazioni del modello in compiti di classificazione, stile e output strutturati.

Se riscontri problemi nell'eseguire il codice sopra, fai riferimento allo workspace DataLab: Fine-tuning di GPT-4 Mini.

Il prossimo passo del tuo percorso è usare questo modello ottimizzato per creare una vera applicazione di AI. Puoi imparare come farlo seguendo il code along: Creare assistenti AI con GPT-4o.

Conclusione

In questo tutorial, abbiamo effettuato con successo il fine-tuning del modello GPT-4o mini per classificare il testo con etichette "stress" e "non stress". Abbiamo quindi avuto accesso a questo modello tramite l'API di OpenAI e l'OpenAI playground, consentendo applicazioni pratiche e ulteriori test.

La valutazione del modello ottimizzato ha fornito risultati interessanti, mostrando un miglioramento delle prestazioni di classificazione su varie metriche rispetto al modello base. Questo processo ha evidenziato il valore del fine-tuning per ottenere output più affidabili e accurati, soprattutto in compiti come la classificazione del testo.

Se stai cercando di usare un modello open-source gratuito, abbiamo un ottimo tutorial chiamato Fine-tuning di Llama 3.2 e uso in locale: guida passo dopo passo. In questa guida mostriamo come effettuare il fine-tuning dell'ultimo modello Llama e convertirlo in formato GGUF per l'uso locale sul tuo laptop.

Abid Ali Awan

Autore

Abid Ali Awan

In quanto data scientist certificato, sono appassionato di sfruttare tecnologie all’avanguardia per creare applicazioni di machine learning innovative. Con una solida esperienza in riconoscimento vocale, analisi e reportistica dei dati, MLOps, AI conversazionale e NLP, ho affinato le mie competenze nello sviluppo di sistemi intelligenti in grado di avere un impatto concreto. Oltre alla mia expertise tecnica, sono anche un comunicatore efficace, con il talento di rendere chiari e sintetici concetti complessi. Di conseguenza, sono diventato un blogger molto seguito in ambito data science, condividendo idee ed esperienze con una community in crescita di professionisti dei dati. Attualmente mi concentro sulla creazione e sull’editing di contenuti, lavorando con large language model per sviluppare contenuti potenti e coinvolgenti che possano aiutare aziende e singoli a valorizzare al meglio i propri dati.

Argomenti

Correlato