Tokenizzazione in Transformers v5: architettura e guida alla migrazione
Aggiorna a Transformers v5. Una guida pratica al backend unificato in Rust, alle modifiche dell’API e ai pattern di migrazione v4 vs v5 affiancati per encoding e chat.
La tokenizzazione è la parte dello stack HuggingFace Transformer che tendiamo a dare per scontata, finché non comincia a riversarsi nei tuoi output. Una singola particolarità nello spazio bianco può cambiare i confini dei token, il decoding può produrre stringhe inattese e i prompt di chat possono rompersi in silenzio quando si fa templating.
Transformers v5 affronta questi punti dolenti con un redesign della tokenizzazione che standardizza i comportamenti tra le implementazioni, semplifica la superficie dell’API e rende gli internals del tokenizer più facili da ispezionare quando serve fare debug.
In questo tutorial, partirò spiegando gli elementi essenziali di ciò che la tokenizzazione produce e di come funziona la pipeline, poi ti guiderò attraverso ciò che cambia davvero in v5 da una prospettiva pratica orientata alla migrazione. Vedrai affiancati i pattern di codice v4 vs v5 per encoding, decoding, chat template e serializzazione, così potrai aggiornare i tuoi codebase.
Una definizione molto comune di tokenizzazione è che converte il testo in token ID, il che è corretto ma incompleto. In produzione, la tokenizzazione è meglio intesa come un contratto. Dato del testo grezzo, il tokenizer deve produrre una codifica strutturata che il modello possa consumare in sicurezza.
Al minimo, questo contratto include:
input_ids, ossia gli ID di token interi che indicizzano nella tabella di embedding del modello.
Include anche l’attention_mask, che indica quali posizioni corrispondono a token reali rispetto al padding.
Gli offset/allineamenti (se disponibili) mappano gli intervalli di token agli intervalli a livello di carattere o parola nel testo originale, cosa necessaria per highlighting, NER e attribution.
La semantica dei token speciali deve essere preservata, cioè il posizionamento e gli ID di BOS/EOS/PAD/UNK devono rispettare le convenzioni usate durante l’addestramento del modello.
Per i modelli di chat, il formato di chat fa parte del contratto, quindi in genere applichiamo il chat template del modello prima di eseguire la tokenizzazione.
In Transformers, queste responsabilità vivono allo strato del tokenizer (non dentro la forward pass del modello), motivo per cui AutoTokenizer è il punto d’ingresso standard. Ecco un semplice esempio:
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("HuggingFaceTB/SmolLM3-3B")
enc = tokenizer("Hello world")print(enc["input_ids"])print(tokenizer.convert_ids_to_tokens(enc["input_ids"]))Offerto da
Qui, enc è un oggetto BatchEncoding (un contenitore simile a un dict) che contiene i campi pronti per il modello prodotti dal tokenizer (come input_ids e spesso attention_mask). L’output restituisce [9906, 1917], che sono gli ID di token interi per la stringa di input, insieme a ['Hello', 'Ġworld'], che mostra le stringhe di token corrispondenti.
Nota: Il prefisso Ġ è una convenzione comune che indica che il token include uno spazio iniziale, quindi Ġworld rappresenta " world" piuttosto che "world" senza spazio.
Tokenizzazione come pipeline: come v5 la rende debuggabile
I problemi di tokenizzazione di solito si manifestano come piccole anomalie, come spazi extra, strane suddivisioni Unicode, un improvviso aumento del conteggio dei token o prompt di chat che non rispettano correttamente i ruoli.
Il modo più semplice per fare debug di questi problemi è trattare la tokenizzazione come una pipeline di stadi. Una volta che sai quale stadio è responsabile di cosa, puoi isolare rapidamente i problemi invece di andare a tentoni. Ecco alcuni suggerimenti da tenere a mente:
La tokenizzazione è una pipeline componibile
Il primo obiettivo è sfatare l’idea comune che un tokenizer sia solo un WordPiece. Invece, è una sequenza di stadi di trasformazione distinti, tra cui normalizzazione, pre-tokenizzazione, modellazione subword, post-processing e decoding. Ogni stadio controlla una parte diversa del comportamento finale.
Un modello mentale che si può fare debug
Scomporre la tokenizzazione in stadi ci dà una mappa affidabile per la risoluzione dei problemi:
Le particolarità degli spazi bianchi di solito provengono dal pre-tokenizer o dal decoder
I problemi Unicode in genere originano nel normalizer.
Le esplosioni di token sono spesso causate dal modello subword, insieme al suo vocab/merges
Gli errori di formattazione della chat provengono principalmente dai template o dal post-processing
Esplicita e ispezionabile by design
Transformers v5 rende i tokenizer più facili da ispezionare, soprattutto per quelli basati sul motore tokenizers in Rust.
Quando si usa il backend in Rust, possiamo ispezionare le componenti sottostanti tramite tokenizer._tokenizer (normalizer, pre-tokenizer, model, post-processor, decoder). Non usiamo _tokenizer tutti i giorni, ma torna utile con la release v5, che rende visibili gli internals quando dobbiamo fare debug.
Questo porta naturalmente alla distinzione engine vs wrapper:
Engine (tokenizers): l’implementazione di basso livello in Rust che esegue le meccaniche di base come normalizzazione, splitting, segmentazione subword e produzione dei token ID (e degli offset quando disponibili).
Wrapper (transformers): è lo strato rivolto al modello che trasforma queste meccaniche in input pronti per il modello, applicando convenzioni come la gestione dei token speciali, i chat template, le regole di padding/truncation e gli output tensoriali specifici del framework.
Cosa è cambiato in Transformers v5?
Transformers v5 è una major release di standardizzazione, e la tokenizzazione è una delle aree con cambiamenti visibili agli utenti. La release riduce le implementazioni duplicate, rende il comportamento dei tokenizer più coerente tra i modelli e li rende più facili da ispezionare e (in alcuni casi) da addestrare da zero. Di seguito i cambiamenti che hanno il maggiore impatto nell’uso quotidiano.
Una sola implementazione di tokenizer per modello
Nelle release precedenti, molti modelli avevano:
un tokenizer Python lento
un’implementazione veloce supportata da Rust
In v5, Transformers consolida a un singolo file di tokenizer per modello e preferisce il percorso supportato da Rust. Ecco perché il tokenizer basato su Rust funziona:
Rimuove le implementazioni duplicate lente vs veloci.
Riduce i bug di parità causati da sottili discrepanze di comportamento tra tali implementazioni.
Questa implementazione del tokenizer riduce e semplifica la superficie di test, dato che c’è un’unica code path primaria da validare.
Stabilisce anche un’unica “fonte di verità” per il comportamento del tokenizer tra i modelli.
Migrazione dell’API di encoding
L’API v4 encode_plus() è deprecata a favore della chiamata diretta al tokenizer. Ecco la differenza tra v4 e v5:
versione v4
enc = tokenizer.encode_plus(
text,
truncation=True,
padding="max_length",
max_length=128,
return_tensors="pt",)Offerto da
versione v5
enc = tokenizer(
text,
truncation=True,
padding="max_length",
max_length=128,
return_tensors="pt",)Offerto da
Passare da encode_plus() a un unico punto d’ingresso tokenizer() riduce modalità di errore reali che emergono nel codice in produzione.
In v4, avere metodi di encoding multipli significava che sottili differenze in padding, truncation, batching o conversione a tensori potevano comparire a seconda del percorso usato, spesso emergendo solo passando da input singoli a workload batch.
v5 standardizza tutto su un unico percorso di encoding che restituisce sempre un BatchEncoding, rendendo il comportamento più prevedibile e riducendo sia i bug ai margini sia la quantità di codice necessaria per mantenere coerenti le pipeline di tokenizzazione.
Migrazione dell’API di decoding
v5 unifica il decoding, quindi decode() gestisce sia input singoli che batch, allineando il comportamento del decode a quello dell’encode.
versione v4
texts = tokenizer.batch_decode(batch_ids, skip_special_tokens=True)Offerto da
versione v5
texts = tokenizer.decode(batch_ids, skip_special_tokens=True)Offerto da
In v5, il decoding è progettato per rispecchiare l’encoding. Proprio come tokenizer() può accettare una singola stringa o un batch di stringhe, decode() può accettare una singola sequenza di token ID o un batch di sequenze.
La cosa principale qui è il tipo di ritorno: se passi una sequenza, otterrai una singola stringa, ma se passi un batch (come list[list[int]]), otterrai una lista di stringhe. Questo rende l’API più pulita in generale, ma significa anche che qualsiasi codice che assume che decode() restituisca sempre una stringa dovrebbe essere aggiornato per gestire entrambi i casi.
Chat template
In v4, apply_chat_template restituiva input_ids grezzi per compatibilità all’indietro. In v5, restituisce un BatchEncoding come gli altri metodi del tokenizer.
versione v4
input_ids = tokenizer.apply_chat_template(messages, return_tensors="pt")Offerto da
In v5, apply_chat_template() è trattata come un vero punto d’ingresso del tokenizer piuttosto che come un helper speciale. Invece di restituire solo input_ids, restituisce un oggetto BatchEncoding completo (con campi come input_ids e attention_mask).
Questo è importante perché gli input formattati per la chat ora si inseriscono nello stesso flusso di batching, padding, truncation e ritorno dei tensori della tokenizzazione normale. Quindi non serve più codice extra per ricostruire le mask o allineare manualmente i formati prima di inviare gli input al modello.
Serializzazione del tokenizer
In v5, la serializzazione del tokenizer è semplificata consolidando i metadati dei token speciali e dei token aggiunti in meno artefatti, pur supportando i file legacy per compatibilità all’indietro. Questo riduce il rischio che più file “fonte di verità” vadano fuori sincronia e rende le risorse del tokenizer più facili da caricare e riutilizzare in strumenti downstream che operano al di fuori della libreria Transformers.
Tokenizer come architetture configurabili
In v5, il cambiamento chiave è che un tokenizer è trattato come una pipeline definita insieme ad artefatti appresi, invece di essere solo qualcosa che carichiamo da file serializzati.
La classe del tokenizer specifica come il testo viene normalizzato, suddiviso in chunk, convertito in token subword e infine decodificato di nuovo in testo.
Il vocabolario e le regole di merge sono artefatti appresi, cioè sono i pezzi addestrati che determinano quali token esistono e come il testo è compresso in token ID.
Questa separazione abilita workflow “architecture-first”. Per i tokenizer supportati, puoi istanziare un tokenizer che segue il design di un modello e poi caricare o addestrare separatamente vocab/merge, rendendo la personalizzazione e il riaddestramento molto più lineari.
Considerazioni finali
La tokenizzazione in Transformers v5 è un grande passo verso standardizzazione e semplificazione. Ora c’è un percorso di comportamento più canonico (riducendo la divergenza slow/fast), una superficie d’API semplificata, templating di chat che restituisce lo stesso oggetto strutturato BatchEncoding della tokenizzazione normale e una serializzazione consolidata che riduce assunzioni fragili a livello di file.
Promuove anche un modello mentale “architecture-first” in cui i tokenizer sono più facili da ispezionare e, nei casi supportati, da addestrare da zero. Per migrare senza intoppi da v4, sostituisci encode_plus() con tokenizer(), sostituisci batch_decode() con decode(), aggiorna i punti di chiamata di apply_chat_template() per lavorare con BatchEncoding, evita di hardcodare i nomi file legacy del tokenizer in fase di salvataggio e aspettati che eventuali particolarità dei tokenizer lenti convergano verso il comportamento basato su tokenizers.
Devo ancora scegliere tra classi di tokenizer "Fast" (Rust) e "Slow" (Python)?⌄
No. Transformers v5 consolida tutto in un’unica implementazione per modello. La libreria ora usa di default il backend in Rust altamente ottimizzato (libreria tokenizers) per tutti i modelli supportati, eliminando la necessità di scegliere manualmente tra LlamaTokenizerFast e LlamaTokenizer.
Il mio codice esistente con encode_plus smetterà di funzionare subito?⌄
Non immediatamente, ma è deprecato. Anche se v5 può attualmente supportare encode_plus con un avviso, è fortemente consigliato passare al metodo diretto tokenizer(__call__). Questo ti garantisce i nuovi comportamenti unificati di batching e mette al riparo il tuo codebase per il futuro.
Perché apply_chat_template ora restituisce un dict BatchEncoding invece di una stringa?⌄
Per trattare gli input di chat come qualsiasi altro input del modello. Restituendo un dizionario (contenente input_ids e attention_mask), v5 consente ai dati formattati per la chat di essere immediatamente batchati, paddati e troncati senza richiedere un secondo passaggio di tokenizzazione.
Posso ancora usare return_tensors="tf" o return_tensors="jax"?⌄
No. Come parte dei cambiamenti di architettura in v5, Transformers ha rimosso il supporto ufficiale per i backend TensorFlow e Flax/JAX per concentrarsi interamente su PyTorch. Dovrai fare affidamento sul backend PyTorch o esportare i modelli in formati come ONNX/GGUF per altri framework.
Come faccio a fare debug di errori di tokenizzazione "silenziosi" in v5?⌄
Usa gli internals ispezionabili. In v5 puoi accedere alla pipeline sottostante in Rust tramite tokenizer._tokenizer. Questo ti permette di controllare stadi specifici—come il Normalizer o il Pre-tokenizer—isolatamente, per vedere esattamente dove una stringa viene divisa o modificata in modo inatteso.
Sono una Google Developers Expert in ML (Gen AI), una Kaggle 3x Expert e una Women Techmakers Ambassador con oltre 3 anni di esperienza nel tech. Ho co-fondato una startup health-tech nel 2020 e sto conseguendo un master in informatica al Georgia Tech, con specializzazione in machine learning.
Scopri i 15 migliori server MCP remoti che stanno trasformando lo sviluppo AI nel 2026. Scopri come migliorano automazione, ragionamento, sicurezza e velocità dei workflow.
Scopri i modelli di IA open source, i dataset e le app più recenti, crea agenti di IA e metti a punto gli LLM con Hugging Face. Entra oggi nella più grande community di IA!
La tokenizzazione è la parte dello stack HuggingFace Transformer che tendiamo a dare per scontata, finché non comincia a riversarsi nei tuoi output. Una singola particolarità nello spazio bianco può cambiare i confini dei token, il decoding può produrre stringhe inattese e i prompt di chat possono rompersi in silenzio quando si fa templating.
Transformers v5 affronta questi punti dolenti con un redesign della tokenizzazione che standardizza i comportamenti tra le implementazioni, semplifica la superficie dell’API e rende gli internals del tokenizer più facili da ispezionare quando serve fare debug.
In questo tutorial, partirò spiegando gli elementi essenziali di ciò che la tokenizzazione produce e di come funziona la pipeline, poi ti guiderò attraverso ciò che cambia davvero in v5 da una prospettiva pratica orientata alla migrazione. Vedrai affiancati i pattern di codice v4 vs v5 per encoding, decoding, chat template e serializzazione, così potrai aggiornare i tuoi codebase.
Se sei nuovo alla tokenizzazione, ti consiglio di dare un’occhiata al corso Introduction to Natural Language Processing in Python.
Che cos’è la tokenizzazione?
Una definizione molto comune di tokenizzazione è che converte il testo in token ID, il che è corretto ma incompleto. In produzione, la tokenizzazione è meglio intesa come un contratto. Dato del testo grezzo, il tokenizer deve produrre una codifica strutturata che il modello possa consumare in sicurezza.
Al minimo, questo contratto include:
input_ids, ossia gli ID di token interi che indicizzano nella tabella di embedding del modello.attention_mask, che indica quali posizioni corrispondono a token reali rispetto al padding.BOS/EOS/PAD/UNKdevono rispettare le convenzioni usate durante l’addestramento del modello.In Transformers, queste responsabilità vivono allo strato del tokenizer (non dentro la forward pass del modello), motivo per cui
AutoTokenizerè il punto d’ingresso standard. Ecco un semplice esempio:Ecco l’output atteso:
Qui,
encè un oggettoBatchEncoding(un contenitore simile a un dict) che contiene i campi pronti per il modello prodotti dal tokenizer (comeinput_idse spessoattention_mask). L’output restituisce[9906, 1917], che sono gli ID di token interi per la stringa di input, insieme a['Hello', 'Ġworld'], che mostra le stringhe di token corrispondenti.Nota: Il prefisso Ġ è una convenzione comune che indica che il token include uno spazio iniziale, quindi Ġworld rappresenta " world" piuttosto che "world" senza spazio.
Tokenizzazione come pipeline: come v5 la rende debuggabile
I problemi di tokenizzazione di solito si manifestano come piccole anomalie, come spazi extra, strane suddivisioni Unicode, un improvviso aumento del conteggio dei token o prompt di chat che non rispettano correttamente i ruoli.
Il modo più semplice per fare debug di questi problemi è trattare la tokenizzazione come una pipeline di stadi. Una volta che sai quale stadio è responsabile di cosa, puoi isolare rapidamente i problemi invece di andare a tentoni. Ecco alcuni suggerimenti da tenere a mente:
La tokenizzazione è una pipeline componibile
Il primo obiettivo è sfatare l’idea comune che un tokenizer sia solo un WordPiece. Invece, è una sequenza di stadi di trasformazione distinti, tra cui normalizzazione, pre-tokenizzazione, modellazione subword, post-processing e decoding. Ogni stadio controlla una parte diversa del comportamento finale.
Un modello mentale che si può fare debug
Scomporre la tokenizzazione in stadi ci dà una mappa affidabile per la risoluzione dei problemi:
Esplicita e ispezionabile by design
Transformers v5 rende i tokenizer più facili da ispezionare, soprattutto per quelli basati sul motore tokenizers in Rust.
Quando si usa il backend in Rust, possiamo ispezionare le componenti sottostanti tramite
tokenizer._tokenizer(normalizer, pre-tokenizer, model, post-processor, decoder). Non usiamo_tokenizertutti i giorni, ma torna utile con la release v5, che rende visibili gli internals quando dobbiamo fare debug.Questo porta naturalmente alla distinzione engine vs wrapper:
tokenizers): l’implementazione di basso livello in Rust che esegue le meccaniche di base come normalizzazione, splitting, segmentazione subword e produzione dei token ID (e degli offset quando disponibili).transformers): è lo strato rivolto al modello che trasforma queste meccaniche in input pronti per il modello, applicando convenzioni come la gestione dei token speciali, i chat template, le regole di padding/truncation e gli output tensoriali specifici del framework.Cosa è cambiato in Transformers v5?
Transformers v5 è una major release di standardizzazione, e la tokenizzazione è una delle aree con cambiamenti visibili agli utenti. La release riduce le implementazioni duplicate, rende il comportamento dei tokenizer più coerente tra i modelli e li rende più facili da ispezionare e (in alcuni casi) da addestrare da zero. Di seguito i cambiamenti che hanno il maggiore impatto nell’uso quotidiano.
Una sola implementazione di tokenizer per modello
Nelle release precedenti, molti modelli avevano:
In v5, Transformers consolida a un singolo file di tokenizer per modello e preferisce il percorso supportato da Rust. Ecco perché il tokenizer basato su Rust funziona:
Migrazione dell’API di encoding
L’API v4
encode_plus()è deprecata a favore della chiamata diretta al tokenizer. Ecco la differenza tra v4 e v5:versione v4
versione v5
Passare da
encode_plus()a un unico punto d’ingressotokenizer()riduce modalità di errore reali che emergono nel codice in produzione.In v4, avere metodi di encoding multipli significava che sottili differenze in padding, truncation, batching o conversione a tensori potevano comparire a seconda del percorso usato, spesso emergendo solo passando da input singoli a workload batch.
v5 standardizza tutto su un unico percorso di encoding che restituisce sempre un
BatchEncoding, rendendo il comportamento più prevedibile e riducendo sia i bug ai margini sia la quantità di codice necessaria per mantenere coerenti le pipeline di tokenizzazione.Migrazione dell’API di decoding
v5 unifica il decoding, quindi
decode()gestisce sia input singoli che batch, allineando il comportamento del decode a quello dell’encode.versione v4
versione v5
In v5, il decoding è progettato per rispecchiare l’encoding. Proprio come
tokenizer()può accettare una singola stringa o un batch di stringhe,decode()può accettare una singola sequenza di token ID o un batch di sequenze.La cosa principale qui è il tipo di ritorno: se passi una sequenza, otterrai una singola stringa, ma se passi un batch (come
list[list[int]]), otterrai una lista di stringhe. Questo rende l’API più pulita in generale, ma significa anche che qualsiasi codice che assume chedecode()restituisca sempre una stringa dovrebbe essere aggiornato per gestire entrambi i casi.Chat template
In v4,
apply_chat_templaterestituivainput_idsgrezzi per compatibilità all’indietro. In v5, restituisce unBatchEncodingcome gli altri metodi del tokenizer.versione v4
versione v5
In v5,
apply_chat_template()è trattata come un vero punto d’ingresso del tokenizer piuttosto che come un helper speciale. Invece di restituire soloinput_ids, restituisce un oggettoBatchEncodingcompleto (con campi comeinput_idseattention_mask).Questo è importante perché gli input formattati per la chat ora si inseriscono nello stesso flusso di batching, padding, truncation e ritorno dei tensori della tokenizzazione normale. Quindi non serve più codice extra per ricostruire le mask o allineare manualmente i formati prima di inviare gli input al modello.
Serializzazione del tokenizer
In v5, la serializzazione del tokenizer è semplificata consolidando i metadati dei token speciali e dei token aggiunti in meno artefatti, pur supportando i file legacy per compatibilità all’indietro. Questo riduce il rischio che più file “fonte di verità” vadano fuori sincronia e rende le risorse del tokenizer più facili da caricare e riutilizzare in strumenti downstream che operano al di fuori della libreria Transformers.
Tokenizer come architetture configurabili
In v5, il cambiamento chiave è che un tokenizer è trattato come una pipeline definita insieme ad artefatti appresi, invece di essere solo qualcosa che carichiamo da file serializzati.
Considerazioni finali
La tokenizzazione in Transformers v5 è un grande passo verso standardizzazione e semplificazione. Ora c’è un percorso di comportamento più canonico (riducendo la divergenza slow/fast), una superficie d’API semplificata, templating di chat che restituisce lo stesso oggetto strutturato
BatchEncodingdella tokenizzazione normale e una serializzazione consolidata che riduce assunzioni fragili a livello di file.Promuove anche un modello mentale “architecture-first” in cui i tokenizer sono più facili da ispezionare e, nei casi supportati, da addestrare da zero. Per migrare senza intoppi da v4, sostituisci
encode_plus()contokenizer(), sostituiscibatch_decode()condecode(), aggiorna i punti di chiamata diapply_chat_template()per lavorare conBatchEncoding, evita di hardcodare i nomi file legacy del tokenizer in fase di salvataggio e aspettati che eventuali particolarità dei tokenizer lenti convergano verso il comportamento basato su tokenizers.Se vuoi saperne di più sulle release recenti, qui trovi le note di rilascio. Consiglio anche lo skill track Hugging Face Fundamentals per fare pratica hands-on.