Mettiamo insieme i pezzi
Nelle ultime sezioni abbiamo fatto del nostro meglio per fare la maggior parte del lavoro a mano. Abbiamo esplorato il funzionamento dei tokenizer e abbiamo esaminato la tokenizzazione, la conversione in ID di input, il padding, il troncamento e le maschere di attenzione.
Tuttavia, come abbiamo visto nella sezione 2, l’API 🤗 Transformers può gestire tutto questo con una funzione di alto livello che approfondiremo qui. Quando si chiama il tokenizer
direttamente sulla frase, si ottengono input pronti per passare attraverso il modello:
from transformers import AutoTokenizer
checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
sequence = "I've been waiting for a HuggingFace course my whole life."
model_inputs = tokenizer(sequence)
Qui, la variabile model_inputs
contiene tutto ciò che è necessario per il buon funzionamento del modello. Per DistilBERT, questo include gli ID degli ingressi e la maschera di attenzione. Altri modelli che accettano input aggiuntivi avranno anche questi output dall’oggetto tokenizer
.
Come vedremo in alcuni esempi, questo metodo è molto potente. Innanzitutto, può tokenizzare una singola sequenza:
sequence = "I've been waiting for a HuggingFace course my whole life."
model_inputs = tokenizer(sequence)
Gestisce anche più sequenze alla volta, senza alcuna modifica dell’API:
sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"]
model_inputs = tokenizer(sequences)
Possiamo implementare il padding in diversi modi
# Effettua il padding della sequenza fino allla massima lunghezza della sequenza
model_inputs = tokenizer(sequences, padding="longest")
# Effettua il padding fino alla lunghezza massima del modello
# (512 per BERT o DistilBERT)
model_inputs = tokenizer(sequences, padding="max_length")
# Effettua il padding fino alla lunghezza massima specificata
model_inputs = tokenizer(sequences, padding="max_length", max_length=8)
Può anche troncare le sequenze:
sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"]
# Tronca le sequenze più lunghe della lunghezza massima del modello.
# (512 per BERT o DistilBERT)
model_inputs = tokenizer(sequences, truncation=True)
# Tronca le sequenze più lunghe della lunghezza massima specificata.
model_inputs = tokenizer(sequences, max_length=8, truncation=True)
L’oggetto tokenizer
può gestire la conversione in tensori di framework specifici, che possono successivamente essere inviati direttamente al modello. Per esempio, nel seguente esempio di codice si chiede al tokenizer di restituire i tensori dei diversi framework: "pt"
restituisce i tensori di PyTorch, "tf"
restituisce i tensori di TensorFlow e "np"
restituisce gli array di NumPy:
sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"]
# Ritorna tensori PyTorch
model_inputs = tokenizer(sequences, padding=True, return_tensors="pt")
# Ritorna tensori TensorFlow
model_inputs = tokenizer(sequences, padding=True, return_tensors="tf")
# Ritorna NumPy arrays
model_inputs = tokenizer(sequences, padding=True, return_tensors="np")
Token speciali
Se diamo un’occhiata agli ID di input restituiti dal tokenizer, noteremo che sono leggermente diversi da quelli che avevamo prima:
sequence = "I've been waiting for a HuggingFace course my whole life."
model_inputs = tokenizer(sequence)
print(model_inputs["input_ids"])
tokens = tokenizer.tokenize(sequence)
ids = tokenizer.convert_tokens_to_ids(tokens)
print(ids)
[101, 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012, 102]
[1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012]
Un ID token è stato aggiunto all’inizio e uno alla fine. Decodifichiamo le due sequenze di ID qui sopra per capire di cosa si tratta:
print(tokenizer.decode(model_inputs["input_ids"]))
print(tokenizer.decode(ids))
"[CLS] i've been waiting for a huggingface course my whole life. [SEP]"
"i've been waiting for a huggingface course my whole life."
Il tokenizer ha aggiunto la parola speciale [CLS]
all’inizio e la parola speciale [SEP]
alla fine. Questo perché il modello è stato preaddestrato con queste parole, quindi per ottenere gli stessi risultati per l’inferenza dobbiamo aggiungerle anche noi. Si noti che alcuni modelli non aggiungono parole speciali, o ne aggiungono di diverse; i modelli possono anche aggiungere queste parole speciali solo all’inizio o solo alla fine. In ogni caso, il tokenizer sa quali sono previste e se ne occuperà per voi.
Conclusione: Dal tokenizer al modello
Ora che abbiamo visto tutti i singoli passaggi che l’oggetto tokenizer
utilizza quando viene applicato ai testi, vediamo un’ultima volta come può gestire sequenze multiple (padding!), sequenze molto lunghe (troncamento!) e diversi tipi di tensori con la sua API principale:
import torch
from transformers import AutoTokenizer, AutoModelForSequenceClassification
checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = AutoModelForSequenceClassification.from_pretrained(checkpoint)
sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"]
tokens = tokenizer(sequences, padding=True, truncation=True, return_tensors="pt")
output = model(**tokens)