From 459a868a1e11d2c0818386d56283e77ab36e2e58 Mon Sep 17 00:00:00 2001 From: lewtun Date: Mon, 17 Oct 2022 16:26:10 +0200 Subject: [PATCH] Bump release (#343) --- chapters/de/chapter3/6.mdx | 6 +- chapters/en/chapter7/2.mdx | 4 +- chapters/fr/chapter7/2.mdx | 4 +- chapters/it/_toctree.yml | 10 +- chapters/it/chapter1/10.mdx | 260 ++++++++++++++++++++++++++++++++++ chapters/it/chapter2/3.mdx | 231 ++++++++++++++++++++++++++++++ chapters/it/chapter2/4.mdx | 240 +++++++++++++++++++++++++++++++ chapters/ja/chapter7/2.mdx | 4 +- chapters/vi/chapter7/2.mdx | 4 +- chapters/zh-CN/chapter7/2.mdx | 4 +- utils/validate_translation.py | 10 +- 11 files changed, 759 insertions(+), 18 deletions(-) create mode 100644 chapters/it/chapter1/10.mdx create mode 100644 chapters/it/chapter2/3.mdx create mode 100644 chapters/it/chapter2/4.mdx diff --git a/chapters/de/chapter3/6.mdx b/chapters/de/chapter3/6.mdx index cd82492e7..cd37e7f5c 100644 --- a/chapters/de/chapter3/6.mdx +++ b/chapters/de/chapter3/6.mdx @@ -29,7 +29,7 @@ Teste, was du in diesem Kapitel gelernt hast! correct: true }, { - Text: "Surprise (Überraschung)", + text: "Surprise (Überraschung)", explain: "Überraschung! Probier eine andere!" } ]} @@ -216,7 +216,7 @@ Teste, was du in diesem Kapitel gelernt hast! correct: true }, { - Text: "Es bietet mehr Funktionen zur Optimierung.", + text: "Es bietet mehr Funktionen zur Optimierung.", explain: "Nein, die 🤗 Accelerate Bibliothek stellt keine Optimierungsfunktionen zur Verfügung." } ]} @@ -298,4 +298,4 @@ Teste, was du in diesem Kapitel gelernt hast! ]} /> -{/if} \ No newline at end of file +{/if} diff --git a/chapters/en/chapter7/2.mdx b/chapters/en/chapter7/2.mdx index 16c13770f..af3527558 100644 --- a/chapters/en/chapter7/2.mdx +++ b/chapters/en/chapter7/2.mdx @@ -403,7 +403,7 @@ Since we are working on a token classification problem, we will use the `TFAutoM They should be set by two dictionaries, `id2label` and `label2id`, which contain the mapping from ID to label and vice versa: ```py -id2label = {str(i): label for i, label in enumerate(label_names)} +id2label = {i: label for i, label in enumerate(label_names)} label2id = {v: k for k, v in id2label.items()} ``` @@ -653,7 +653,7 @@ Since we are working on a token classification problem, we will use the `AutoMod They should be set by two dictionaries, `id2label` and `label2id`, which contain the mappings from ID to label and vice versa: ```py -id2label = {str(i): label for i, label in enumerate(label_names)} +id2label = {i: label for i, label in enumerate(label_names)} label2id = {v: k for k, v in id2label.items()} ``` diff --git a/chapters/fr/chapter7/2.mdx b/chapters/fr/chapter7/2.mdx index 653ca7a13..8084e0df9 100644 --- a/chapters/fr/chapter7/2.mdx +++ b/chapters/fr/chapter7/2.mdx @@ -403,7 +403,7 @@ Puisque nous travaillons sur un problème de classification de *tokens*, nous al Elles devraient être définies par deux dictionnaires, `id2label` et `label2id`, qui contiennent la correspondance de l'identifiant à l'étiquette et vice versa : ```py -id2label = {str(i): label for i, label in enumerate(label_names)} +id2label = {i: label for i, label in enumerate(label_names)} label2id = {v: k for k, v in id2label.items()} ``` @@ -653,7 +653,7 @@ Puisque nous travaillons sur un problème de classification de *tokens*, nous al Elles devraient être définies par deux dictionnaires, `id2label` et `label2id`, qui contiennent les correspondances entre identifiants et étiquettes et vice versa : ```py -id2label = {str(i): label for i, label in enumerate(label_names)} +id2label = {i: label for i, label in enumerate(label_names)} label2id = {v: k for k, v in id2label.items()} ``` diff --git a/chapters/it/_toctree.yml b/chapters/it/_toctree.yml index 92b0283b4..c0df904ad 100644 --- a/chapters/it/_toctree.yml +++ b/chapters/it/_toctree.yml @@ -23,6 +23,9 @@ title: Bias e limiti - local: chapter1/9 title: Riassunto + - local: chapter1/10 + title: Quiz di fine capitolo + quiz: 1 - title: 2. Usare i 🤗 Transformers sections: @@ -30,8 +33,11 @@ title: Introduzione - local: chapter2/2 title: Dietro la pipeline + - local: chapter2/3 + title: Modelli + - local: chapter2/4 + title: Tokenizers - - title: 3. Affinamento di un modello pre-addestrato sections: - local: chapter3/1 @@ -102,4 +108,4 @@ title: Parte 2 completata! - local: chapter8/7 title: Quiz di fine capitolo - quiz: 8 + quiz: 8 \ No newline at end of file diff --git a/chapters/it/chapter1/10.mdx b/chapters/it/chapter1/10.mdx new file mode 100644 index 000000000..886706092 --- /dev/null +++ b/chapters/it/chapter1/10.mdx @@ -0,0 +1,260 @@ + + +# Quiz di fine capitolo + + + + +In questo capitolo abbiamo parlato di molti argomenti! Non preoccuparti se non hai capito tutto nel dettaglio: i prossimi capitoli ti aiuteranno a capire come molte di queste cose funzionano dietro le quinte. + +Prima di procedere, però, verifichiamo cos'hai imparato in questo capitolo! + + +### 1. Esplora l'Hub e cerca il checkpoint `roberta-large-mnli`. Quale compito svolge? + + +roberta-large-mnli page." + }, + { + text: "Classificazione testuale", + explain: "Più precisamente, determina se due frasi sono connesse logicamente su tre livelli associati alle etichette 'contradiction', 'neutral' e 'entailment'. Questo compito viene detto anche natural language inference.", + correct: true + }, + { + text: "Generazione testuale", + explain: "Rivisita il link e prova di nuovo: roberta-large-mnli page." + } + ]} +/> + +### 2. Cosa restituisce il codice seguente? + +```py +from transformers import pipeline + +ner = pipeline("ner", grouped_entities=True) +ner("My name is Sylvain and I work at Hugging Face in Brooklyn.") +``` + +sentiment-analysis." + }, + { + text: "Genera e restituisce testo che completa la frase di partenza.", + explain: "Sbagliato! Se così fosse, si tratterebbe di una pipeline di tipo text-generation.", + }, + { + text: "Restituisce i termini che rappresentano persone, organizzazioni o luoghi.", + explain: "Inoltre, grazie a grouped_entities=True, la pipeline è in grado di raggruppare le parole che appartengono alla stessa entità, come \"Hugging Face\".", + correct: true + } + ]} +/> + +### 3. Cosa dovrebbe rimpiazzare "..." in questo estratto di codice? + +```py +from transformers import pipeline + +filler = pipeline("fill-mask", model="bert-base-cased") +result = filler("...") +``` + + aspetta te.", + explain: "Sbagliato. Controlla la card del modello bert-base-cased e cerca di capire il tuo errore." + }, + { + text: "Questo [MASK] aspetta te.", + explain: "Corretto! Il mask token utilizzato dal modello è [MASK].", + correct: true + }, + { + text: "Questo signore aspetta te.", + explain: "Sbagliato. Questa pipeline completa parole nascoste, quindi necessita di un mask token nell'input." + } + ]} +/> + +### 4. Perché questo codice non funziona? + +```py +from transformers import pipeline + +classifier = pipeline("zero-shot-classification") +result = classifier("This is a course about the Transformers library") +``` + +candidate_labels=[...].", + correct: true + }, + { + text: "Questa pipeline richiede diverse frasi, non solo una.", + explain: "Sbagliato, anche se quando usata correttamente, questa pipeline può tranquillamente processare una lista di frasi (come tutte le altre pipeline)." + }, + { + text: "Come al solito, la libreria Transformer di 🤗 non funziona.", + explain: "Ci rifiutiamo di commentare la tua risposta!" + }, + { + text: "Questa pipeline richiede un input più lungo. Quello fornito è troppo corto.", + explain: "Sbagliato. Sappi che per processare testi molto lunghi, questa pipeline li deve troncare." + } + ]} +/> + +### 5. Cosa significa "transfer learning"? + + + +### 6. Vero o falso? Solitamente un modello linguistico non richiede etichette in fase di pre-addestramento. + + +self-supervised, il che significa che le etichette sono create direttamente a partire dall'input (come quando una pipeline predice la parola seguente o indovina parole nascoste).", + correct: true + }, + { + text: "Falso", + explain: "La risposta non è corretta." + } + ]} +/> + +### 7. Seleziona la frase che meglio descrive i termini "modello," "architettura," e "pesi." + + + + +### 8. Quale dei seguenti modelli utilizzeresti per completare dei prompt con testo generato? + + + +### 9. Quale dei seguenti modelli utilizzeresti per riassumere testi? + + + +### 10. Quale dei seguenti modelli utilizzeresti per classificare input testuali sulla base di determinate etichette? + + + +### 11. Qual è la possibile origine di un bias osservato in un modello? + + diff --git a/chapters/it/chapter2/3.mdx b/chapters/it/chapter2/3.mdx new file mode 100644 index 000000000..644f37755 --- /dev/null +++ b/chapters/it/chapter2/3.mdx @@ -0,0 +1,231 @@ + + +# Models + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +{#if fw === 'pt'} + +{:else} + +{/if} + +{#if fw === 'pt'} +In questa sezione vedremo da vicino come creare e usare un modello. Utilizzeremo la classe `AutoModel`, utile quando si vuole istanziare qualsiasi modello da un checkpoint. + +La classe `AutoModel` e tutti i suoi derivati sono in realtà semplici involucri dell'ampia varietà di modelli disponibili nella libreria. Si tratta di un involucro intelligente, in quanto è in grado di indovinare automaticamente l'architettura del modello appropriata per il checkpoint e successivamente di istanziare un modello con questa architettura. + +{:else} +In questa sezione vedremo da vicino come creare e usare un modello. Utilizzeremo la classe `TFAutoModel`, utile quando si vuole istanziare qualsiasi modello da un checkpoint. + +La classe `TFAutoModel` e tutti i suoi derivati sono in realtà semplici involucri dell'ampia varietà di modelli disponibili nella libreria. Si tratta di un involucro intelligente, in quanto è in grado di indovinare automaticamente l'architettura del modello appropriata per il checkpoint e successivamente di istanziare un modello con questa architettura. + +{/if} + +Tuttavia, se si conosce il tipo di modello che si vuole utilizzare, si può usare direttamente la classe che ne definisce l'architettura. Vediamo come funziona con un modello BERT. + +## Creare un trasformatore + +La prima cosa da fare per inizializzare un modello BERT è caricare un oggetto di configurazione: + +{#if fw === 'pt'} +```py +from transformers import BertConfig, BertModel + +# Creazione della configurazione +config = BertConfig() + +# Creare il modello dalla configurazione +model = BertModel(config) +``` +{:else} +```py +from transformers import BertConfig, TFBertModel + +# Creazione della configurazione +config = BertConfig() + +# Creare il modello dalla configurazione +model = TFBertModel(config) +``` +{/if} + +La configurazione contiene molti attributi che vengono utilizzati per costruire il modello: + +```py +print(config) +``` + +```python out +BertConfig { + [...] + "hidden_size": 768, + "intermediate_size": 3072, + "max_position_embeddings": 512, + "num_attention_heads": 12, + "num_hidden_layers": 12, + [...] +} +``` + +Anche se non si è ancora visto cosa fanno tutti questi attributi, se ne dovrebbero riconoscere alcuni: l'attributo `hidden_size` definisce la dimensione del vettore `hidden_states`, e l'attributo `num_hidden_layers` definisce il numero di livelli del modello Transformer. + +### Diversi metodi di caricamento + +La creazione di un modello dalla configurazione predefinita lo inizializza con valori casuali: + +{#if fw === 'pt'} +```py +from transformers import BertConfig, BertModel + +config = BertConfig() +model = BertModel(config) + +# Il modello è inizializzato in modo casuale! +``` +{:else} +```py +from transformers import BertConfig, TFBertModel + +config = BertConfig() +model = TFBertModel(config) + +# Il modello è inizializzato in modo casuale! +``` +{/if} + +Il modello può essere utilizzato in questo stato, ma produrrà risultati incomprensibili; è necessario addestrarlo prima. + +Potremmo addestrare il modello da zero sul compito da svolgere, ma come si è visto in [Capitolo 1](/course/chapter1), questo richiederebbe molto tempo e molti dati, oltre ad avere un impatto ambientale non trascurabile. Per evitare sforzi inutili, è indispensabile poter condividere e riutilizzare modelli già addestrati. + +Caricare un modello Transformer già addestrato è semplice: lo si può fare usando il metodo `from_pretrained()`: + +{#if fw === 'pt'} +```py +from transformers import BertModel + +model = BertModel.from_pretrained("bert-base-cased") +``` + +Come abbiamo visto in precedenza, possiamo sostituire `BertModel` con la classe equivalente `AutoModel`. Lo faremo d'ora in poi, perché in questo modo si ottiene un codice cosiddetto "checkpoint-agnostic"; se il codice funziona per un checkpoint, dovrebbe funzionare senza problemi anche con un altro. Questo vale anche se l'architettura è diversa, purché il checkpoint sia stato addestrato per un compito simile (per esempio, un compito di sentiment analysis). + +{:else} +```py +from transformers import TFBertModel + +model = TFBertModel.from_pretrained("bert-base-cased") +``` +Come abbiamo visto in precedenza, possiamo sostituire `TFBertModel` con la classe equivalente `TFAutoModel`. Lo faremo d'ora in poi, perché in questo modo si ottiene un codice cosiddetto "checkpoint-agnostic"; se il codice funziona per un checkpoint, dovrebbe funzionare senza problemi anche con un altro. Questo vale anche se l'architettura è diversa, purché il checkpoint sia stato addestrato per un compito simile (per esempio, un compito di sentiment analysis). + +{/if} + +Nell'esempio di codice precedente non abbiamo usato `BertConfig` e abbiamo invece caricato un modello pre-addestrato tramite l'identificatore `bert-base-cased`. Si tratta di un checkpoint che è stato addestrato dagli stessi autori di BERT; si possono trovare maggiori dettagli su di esso nella sua [scheda modello](https://huggingface.co/bert-base-cased). + +Questo modello è ora inizializzato con tutti i pesi del checkpoint. Può essere utilizzato direttamente per effettuare inferenza sui compiti su cui è stato addestrato e può anche essere messo adattato ad un nuovo compito, tramite il fine tuning. Allenandosi con i pesi pre-addestrati piuttosto che partendo da zero, si possono ottenere rapidamente buoni risultati. + +I pesi sono stati scaricati e messi in cache (in modo che le future chiamate al metodo `from_pretrained()` non li scarichino di nuovo) nella cartella della cache, che per impostazione predefinita è *~/.cache/huggingface/transformers*. È possibile personalizzare la cartella della cache impostando la variabile d'ambiente `HF_HOME`. + +L'identificatore usato per caricare il modello può essere l'identificatore di qualsiasi modello presente nel Model Hub, purché sia compatibile con l'architettura del BERT. L'elenco completo dei checkpoint BERT disponibili è disponibile [qui](https://huggingface.co/models?filter=bert). + + +### Metodi di salvataggio + +Saving a model is as easy as loading one — we use the `save_pretrained()` method, which is analogous to the `from_pretrained()` method: + +```py +model.save_pretrained("directory_on_my_computer") +``` + +In questo modo si salvano due file sul disco: + +{#if fw === 'pt'} +``` +ls directory_on_my_computer + +config.json pytorch_model.bin +``` +{:else} +``` +ls directory_on_my_computer + +config.json tf_model.h5 +``` +{/if} + +Se si dà un'occhiata al file *config.json*, si riconoscono gli attributi necessari per costruire l'architettura del modello. Questo file contiene anche alcuni metadati, come l'origine del checkpoint e la versione di 🤗 Transformers utilizzata al momento dell'ultimo salvataggio del checkpoint. + +{#if fw === 'pt'} + +Il file *pytorch_model.bin* è noto come *state dictionary*; contiene tutti i pesi del modello. I due file vanno di pari passo: la configurazione è necessaria per conoscere l'architettura del modello, mentre i pesi del modello sono i suoi parametri. + +{:else} + +Il file *tf_model.h5* è noto come *state dictionary*; contiene tutti i pesi del modello. I due file vanno di pari passo: la configurazione è necessaria per conoscere l'architettura del modello, mentre i pesi del modello sono i suoi parametri. + +{/if} + +## Using a Transformer model for inference + +Ora che si sa come caricare e salvare un modello, proviamo a usarlo per fare delle previsioni. I modelli di trasformatori possono elaborare solo numeri - numeri generati dal tokenizer. Ma prima di parlare dei tokenizer, analizziamo quali sono gli input accettati dal modello. + +I tokenizer possono occuparsi di effettuare il casting degli input nei tensori del framework appropriato, ma per aiutarti a capire cosa sta succedendo, daremo una rapida occhiata a ciò che deve essere fatto prima di inviare gli input al modello. + +Supponiamo di avere un paio di sequenze: + +```py +sequences = ["Hello!", "Cool.", "Nice!"] +``` + +The tokenizer converts these to vocabulary indices which are typically called *input IDs*. Each sequence is now a list of numbers! The resulting output is: + +```py no-format +encoded_sequences = [ + [101, 7592, 999, 102], + [101, 4658, 1012, 102], + [101, 3835, 999, 102], +] +``` + +Si tratta di una lista di sequenze codificate: una lista di liste. I tensori accettano solo forme rettangolari (si pensi alle matrici). Questo "array" è già di forma rettangolare, quindi convertirlo in un tensore è facile: + +{#if fw === 'pt'} +```py +import torch + +model_inputs = torch.tensor(encoded_sequences) +``` +{:else} +```py +import tensorflow as tf + +model_inputs = tf.constant(encoded_sequences) +``` +{/if} + +### Uso dei tensori come input del modello + +Utilizzare i tensori con il modello è estremamente semplice: basta chiamare il modello con gli input: + +```py +output = model(model_inputs) +``` + +Il modello accetta molti argomenti diversi, ma solo gli ID degli ingressi sono necessari. Spiegheremo in seguito cosa fanno gli altri argomenti e quando sono necessari, ma prima dobbiamo dare un'occhiata più da vicino ai tokenizer che costruiscono gli input che un modello Transformer può comprendere. \ No newline at end of file diff --git a/chapters/it/chapter2/4.mdx b/chapters/it/chapter2/4.mdx new file mode 100644 index 000000000..5cd002b5e --- /dev/null +++ b/chapters/it/chapter2/4.mdx @@ -0,0 +1,240 @@ + + +# Tokenizers + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + + + +I tokenizer sono uno dei componenti fondamentali della pipeline NLP. Servono a uno scopo: tradurre il testo in dati che possono essere elaborati dal modello. I modelli possono elaborare solo numeri, quindi i tokenizer devono convertire i nostri input testuali in dati numerici. In questa sezione analizzeremo cosa succede esattamente nella pipeline di tokenizzazione. + +Nelle attività di NLP, i dati che vengono generalmente processati sono testi non elaborati, grezzi. Ecco un esempio di testo grezzo: + +``` +Jim Henson was a puppeteer +``` + +Tuttavia, i modelli possono elaborare solo numeri, quindi dobbiamo trovare un modo per convertire il testo non elaborato in numeri. Questo è ciò che fanno i tokenizer, e ci sono molti modi per farlo. L'obiettivo è trovare la rappresentazione più significativa, cioè quella che ha più senso per il modello, e, se possibile, la rappresentazione più piccola. + +Vediamo alcuni esempi di algoritmi di tokenizzazione e cerchiamo di rispondere ad alcune domande sulla tokenizzazione. + +## Tokenizer basati sulle parole + + + +Il primo tipo di tokenizzatore che viene in mente è quello _basato sulle parole_. In genere è molto facile da configurare e utilizzare con poche regole e spesso produce risultati decenti. Ad esempio, nell'immagine qui sotto, l'obiettivo è dividere il testo non elaborato in parole e trovare una rappresentazione numerica per ciascuna di esse: + +
+ Un esempio di tokenizzazione basata sulle parole. + +
+ +Esistono diversi modi per dividere il testo. Ad esempio, si possono usare gli spazi bianchi per suddividere il testo in parole, applicando la funzione `split()` di Python: + +```py +tokenized_text = "Jim Henson was a puppeteer".split() +print(tokenized_text) +``` + +```python out +['Jim', 'Henson', 'was', 'a', 'puppeteer'] +``` + +Esistono anche varianti di tokenizzatori di parole che prevedono regole aggiuntive per la punteggiatura. Con questo tipo di tokenizer, possiamo ritrovarci con "vocabolari" piuttosto grandi, dove un vocabolario è definito dal numero totale di token indipendenti che abbiamo nel nostro corpus. + +A ogni parola viene assegnato un ID, a partire da 0 fino alla dimensione del vocabolario. Il modello utilizza questi ID per identificare ogni parola. + +Se vogliamo coprire completamente una lingua con un tokenizzatore basato sulle parole, dovremo avere un identificatore per ogni parola della lingua, il che genererà un'enorme quantità di token. Per esempio, nella lingua inglese ci sono più di 500.000 parole, quindi per costruire una mappa da ogni parola a un ID di input dovremmo tenere traccia di così tanti ID. Inoltre, parole come "cane" sono rappresentate in modo diverso da parole come "cani", e il modello inizialmente non avrà modo di sapere che "cane" e "cani" sono simili: identificherà le due parole come non correlate. Lo stesso vale per altre parole simili, come "correre" e "correndo", che il modello non vedrà inizialmente come simili. + +Infine, abbiamo bisogno di un token personalizzato per rappresentare le parole che non fanno parte del nostro vocabolario. Questo è noto come token "unknown", spesso rappresentato come "[UNK]" o "<unk>". Se il tokenizer produce molti token di questo tipo è generalmente un brutto segno, perché non è riuscito a trovare una rappresentazione sensata della parola e si stanno perdendo informazioni. L'obiettivo della creazione del vocabolario è quello di fare in modo che il tokenizzatore inserisca il minor numero possibile di parole nel token sconosciuto. + +Un modo per ridurre la quantità di token sconosciuti è quello di andare un livello più in profondità, usando un tokenizer _character-based_. + +## Character-based + + + +I tokenizer basati sui caratteri dividono il testo in caratteri, anziché in parole. Ciò comporta due vantaggi principali: + +- Il vocabolario è molto più ridotto. +- I token fuori vocabolario (sconosciuti) sono molto meno numerosi, poiché ogni parola può essere costruita a partire dai caratteri. + +Ma anche in questo caso sorgono alcune questioni relative agli spazi e alla punteggiatura: + +
+ Un esempio di tokenizzazione basata sui caratteri. + +
+ +Anche questo approccio non è perfetto. Poiché la rappresentazione è ora basata su caratteri anziché su parole, si potrebbe sostenere che, intuitivamente, è meno significativa: ogni carattere non significa molto da solo, mentre è così per le parole. Tuttavia, anche in questo caso il significato varia a seconda della lingua; in cinese, ad esempio, ogni carattere porta con sé più informazioni di un carattere in una lingua latina. + +Un'altra cosa da considerare è che ci ritroveremo con una quantità molto elevata di token da elaborare da parte del nostro modello: mentre una parola sarebbe un singolo token con un tokenizzatore basato sulle parole, può facilmente trasformarsi in 10 o più token quando viene convertita in caratteri. + +Per ottenere il meglio dei due mondi, possiamo utilizzare una terza tecnica che combina i due approcci: la *tokenizzazione delle sottoparole*. + +## Tokenizzazione delle sottoparole + + + +Gli algoritmi di tokenizzazione delle sottoparole si basano sul principio che le parole di uso frequente non devono essere suddivise in sottoparole più piccole, ma le parole rare devono essere scomposte in sottoparole significative. + +Ad esempio, "fastidiosamente" potrebbe essere considerata una parola rara e potrebbe essere scomposta in "fastidioso" e "mente". È probabile che queste due parole compaiano più frequentemente come sottoparole a sé stanti, mentre il significato di "fastidiosamente" viene mantenuto dal significato composito di "fastidioso" e "mente". + +Ecco un esempio che mostra come un algoritmo di tokenizzazione delle sottoparole tokenizzerebbe la sequenza "Let's do tokenization!": + +
+ Un algoritmo di tokenizzazione delle sottoparole. + +
+ +Queste sottoparole finiscono per fornire un significato semantico: per esempio, nell'esempio precedente "tokenization" è stato diviso in "token" e "ization", due token che hanno un significato semantico pur essendo efficienti dal punto di vista dello spazio (sono necessari solo due token per rappresentare una parola lunga). Questo ci permette di avere una copertura relativamente buona con vocabolari piccoli e quasi nessun token sconosciuto. + +Questo approccio è particolarmente utile nelle lingue agglutinanti come il turco, dove è possibile formare parole complesse (quasi) arbitrariamente lunghe mettendo insieme sottoparole. + +### E non solo! + +Non sorprende che esistano molte altre tecniche. Per citarne alcune: + +- Byte-level BPE, utilizzato in GPT-2 +- WordPiece, utilizzato in BERT +- SentencePiece o Unigram, utilizzato in diversi modelli multilingua. + +A questo punto dovresti avere una conoscenza sufficiente di come funzionano i tokenizer per iniziare a usare l'API. + +## Caricamento e salvataggio + +Caricare e salvare i tokenizer è semplice come per i modelli. In realtà, si basa sugli stessi due metodi: `from_pretrained()` e `save_pretrained()`. Questi metodi caricano o salvano l'algoritmo usato dal tokenizer (un po' come l'*architettura* del modello) ed il suo vocabolario (un po' come i *pesi* del modello). + +Il caricamento del tokenizer di BERT, addestrato con lo stesso checkpoint di BERT, avviene nello stesso modo in cui si carica il modello, con la differenza che si usa la classe `BertTokenizer`: + +```py +from transformers import BertTokenizer + +tokenizer = BertTokenizer.from_pretrained("bert-base-cased") +``` + +{#if fw === 'pt'} +In modo simile a `AutoModel`, la classe `AutoTokenizer` prenderà la classe tokenizer appropriata nella libreria in base al nome del checkpoint e può essere usata direttamente con qualsiasi checkpoint: + +{:else} +In modo simile a `TFAutoModel`, la classe `AutoTokenizer` prenderà la classe tokenizer appropriata nella libreria in base al nome del checkpoint e può essere usata direttamente con qualsiasi checkpoint: + +{/if} + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +``` + +Ora possiamo usare il tokenizer come mostrato nella sezione precedente: + +```python +tokenizer("Using a Transformer network is simple") +``` + +```python out +{'input_ids': [101, 7993, 170, 11303, 1200, 2443, 1110, 3014, 102], + 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0], + 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1]} +``` + +Salvare un tokenizer è identico a salvare un modello: + +```py +tokenizer.save_pretrained("directory_on_my_computer") +``` + +Parleremo meglio dei `token_type_ids` nel [Capitolo 3](/course/chapter3) e spiegheremo la chiave `attention_mask` un po' più avanti. Per prima cosa, vediamo come vengono generati gli `input_ids`. Per farlo, dobbiamo esaminare i metodi intermedi del tokenizer. + +## Codifica + + + +La traduzione del testo in numeri è nota come _codifica_. La codifica avviene in due fasi: la tokenizzazione, seguita dalla conversione in input ID. + +Come abbiamo visto, il primo passo consiste nel dividere il testo in parole (o parti di parole, simboli di punteggiatura, ecc.), solitamente chiamate *token*. Ci sono diverse regole che possono governare questo processo, ed è per questo che dobbiamo istanziare il tokenizer usando il nome del modello, per assicurarci di usare le stesse regole che sono state usate quando il modello è stato preaddestrato. + +Il secondo passo consiste nel convertire i token in numeri, in modo da poterne costruire un tensore e darlo in pasto al modello. Per fare questo, il tokenizer ha un *vocabolario*, che è la parte che scarichiamo quando lo istanziamo con il metodo `from_pretrained()`. Anche in questo caso, dobbiamo utilizzare lo stesso vocabolario usato quando il modello è stato preaddestrato. + +Per comprendere meglio le due fasi, le esploreremo separatamente. Si noti che utilizzeremo alcuni metodi che eseguono parti della pipeline di tokenizzazione separatamente per mostrare i risultati intermedi di tali passaggi, ma in pratica si dovrebbe chiamare il tokenizzatore direttamente sui propri input (come mostrato nella sezione 2). + +### Processo di tokenizzazione + +Il processo di tokenizzazione viene eseguito dal metodo `tokenize()` del tokenizer: + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") + +sequence = "Using a Transformer network is simple" +tokens = tokenizer.tokenize(sequence) + +print(tokens) +``` + +L'output di questo metodo è un elenco di stringhe, o token: + +```python out +['Using', 'a', 'transform', '##er', 'network', 'is', 'simple'] +``` + +Questo tokenizzatore è un tokenizzatore di sottoparole: divide le parole fino a ottenere token che possono essere rappresentati dal suo vocabolario. È il caso di `trasformatore`, che viene diviso in due token: `trasforma` e `##tore`. + +### Dai token agli input IDS + +La conversione in ID di input è gestita dal metodo del tokenizer `convert_tokens_to_ids()`: + +```py +ids = tokenizer.convert_tokens_to_ids(tokens) + +print(ids) +``` + +```python out +[7993, 170, 11303, 1200, 2443, 1110, 3014] +``` + +Questi risultati, una volta convertiti nel tensore quadro appropriato, possono essere successivamente utilizzati come input per un modello, come visto in precedenza in questo capitolo. + + + +✏️ **Provaci anche tu!** Replica gli ultimi due passaggi (tokenizzazione e conversione in ID di input) sulle frasi di input utilizzate nella sezione 2 ("I've been waiting for a HuggingFace course my whole life." e "I hate this so much!"). Verificate di ottenere gli stessi ID di input che abbiamo ottenuto in precedenza! + + + +## Decodifica + +La *decodifica* avviene al contrario: dagli indici del vocabolario si vuole ottenere una stringa. Questo può essere fatto con il metodo `decode()` come segue: + +```py +decoded_string = tokenizer.decode([7993, 170, 11303, 1200, 2443, 1110, 3014]) +print(decoded_string) +``` + +```python out +'Using a Transformer network is simple' +``` + +Si noti che il metodo `decode` non solo converte gli indici in token, ma raggruppa anche i token che fanno parte delle stesse parole per produrre una frase leggibile. Questo comportamento sarà estremamente utile quando utilizzeremo modelli che prevedono un nuovo testo (o un testo generato da un prompt, o per problemi di sequenza-sequenza come la traduzione o il riassunto). + +A questo punto si dovrebbero comprendere le operazioni atomiche che un tokenizer può gestire: tokenizzazione, conversione in ID e conversione degli ID in stringhe. Tuttavia, abbiamo solo raschiato la punta dell'iceberg. Nella sezione che segue, vedremo i limiti del nostro approccio e vedremo come superarli. diff --git a/chapters/ja/chapter7/2.mdx b/chapters/ja/chapter7/2.mdx index 82739dbda..5ad6ba398 100644 --- a/chapters/ja/chapter7/2.mdx +++ b/chapters/ja/chapter7/2.mdx @@ -409,7 +409,7 @@ tf_eval_dataset = tokenized_datasets["validation"].to_tf_dataset( id2label` と `label2id` という 2 つの辞書型データがあり、ID からラベル、ラベルから ID へのマッピングを設定することができます。 ```py -id2label = {str(i): label for i, label in enumerate(label_names)} +id2label = {i: label for i, label in enumerate(label_names)} label2id = {v: k for k, v in id2label.items()} ``` @@ -675,7 +675,7 @@ metric.compute(predictions=[all_predictions], references=[all_labels]) id2label` と `label2id` という 2 つの辞書型データがあり、ID からラベル、ラベルから ID へのマッピングを設定することができます。 ```py -id2label = {str(i): label for i, label in enumerate(label_names)} +id2label = {i: label for i, label in enumerate(label_names)} label2id = {v: k for k, v in id2label.items()} ``` diff --git a/chapters/vi/chapter7/2.mdx b/chapters/vi/chapter7/2.mdx index 1346f837a..619d3e932 100644 --- a/chapters/vi/chapter7/2.mdx +++ b/chapters/vi/chapter7/2.mdx @@ -435,7 +435,7 @@ Vì chúng tôi đang giải quyết vấn đề phân loại token, chúng ta s Chúng phải được đặt bởi hai từ điển, `id2label` và `label2id`, chứa ánh xạ từ ID đến nhãn và ngược lại: ```py -id2label = {str(i): label for i, label in enumerate(label_names)} +id2label = {i: label for i, label in enumerate(label_names)} label2id = {v: k for k, v in id2label.items()} ``` @@ -683,7 +683,7 @@ Vì chúng ta đang giải quyết vấn đề phân loại token, chúng ta s Chúng phải được đặt bởi hai từ điển, `id2label` và `label2id`, chứa các ánh xạ từ ID đến nhãn và ngược lại: ```py -id2label = {str(i): label for i, label in enumerate(label_names)} +id2label = {i: label for i, label in enumerate(label_names)} label2id = {v: k for k, v in id2label.items()} ``` diff --git a/chapters/zh-CN/chapter7/2.mdx b/chapters/zh-CN/chapter7/2.mdx index 9ce606af6..c85dd51f8 100644 --- a/chapters/zh-CN/chapter7/2.mdx +++ b/chapters/zh-CN/chapter7/2.mdx @@ -403,7 +403,7 @@ tf_eval_dataset = tokenized_datasets["validation"].to_tf_dataset( 它们应该由两个字典设置, `id2label` 和 `label2id` ,其中包含从 ID 到标签的映射,反之亦然: ```py -id2label = {str(i): label for i, label in enumerate(label_names)} +id2label = {i: label for i, label in enumerate(label_names)} label2id = {v: k for k, v in id2label.items()} ``` @@ -653,7 +653,7 @@ metric.compute(predictions=[all_predictions], references=[all_labels]) 它们应该由两个字典设置, `id2label` 和 `label2id` ,其中包含从 ID 到标签的映射,反之亦然: ```py -id2label = {str(i): label for i, label in enumerate(label_names)} +id2label = {i: label for i, label in enumerate(label_names)} label2id = {v: k for k, v in id2label.items()} ``` diff --git a/utils/validate_translation.py b/utils/validate_translation.py index b4a3f792b..ef28a00fa 100644 --- a/utils/validate_translation.py +++ b/utils/validate_translation.py @@ -14,7 +14,7 @@ def load_sections(language: str): for chapter in toc: for section in chapter["sections"]: sections.append(section["local"]) - return set(sorted(sections)) + return set(sections) if __name__ == "__main__": @@ -24,10 +24,14 @@ def load_sections(language: str): english_sections = load_sections("en") translation_sections = load_sections(args.language) - missing_sections = english_sections.difference(translation_sections) + missing_sections = sorted(english_sections.difference(translation_sections)) if len(missing_sections) > 0: - print("Missing sections:") + print("Completed sesions:\n") + for section in sorted(translation_sections): + print(section) + + print("\nMissing sections:\n") for section in missing_sections: print(section) else: