# Course

## Docs

- [Fine della parte 1!](https://huggingface.co/learn/course/it/chapter4/5.md)
- [L'Hub di Hugging Face](https://huggingface.co/learn/course/it/chapter4/1.md)
- [Condividere modelli pre-addestrati](https://huggingface.co/learn/course/it/chapter4/3.md)
- [Quiz di fine capitolo](https://huggingface.co/learn/course/it/chapter4/6.md)
- [Generare un cartellino del modello](https://huggingface.co/learn/course/it/chapter4/4.md)
- [Usare modelli pre-addestrati](https://huggingface.co/learn/course/it/chapter4/2.md)
- [Affinamento, Fatto!](https://huggingface.co/learn/course/it/chapter3/5.md)
- [Introduzione](https://huggingface.co/learn/course/it/chapter3/1.md)
- [Affinare il modello con la Trainer API](https://huggingface.co/learn/course/it/chapter3/3.md)
- [Quiz di fine capitolo](https://huggingface.co/learn/course/it/chapter3/6.md)
- [Affinare un modell usando Keras](https://huggingface.co/learn/course/it/chapter3/3_tf.md)
- [Un addestramento completo](https://huggingface.co/learn/course/it/chapter3/4.md)
- [Processare i dati](https://huggingface.co/learn/course/it/chapter3/2.md)
- [Come scrivere un issue correttamente](https://huggingface.co/learn/course/it/chapter8/5.md)
- [Introduzione](https://huggingface.co/learn/course/it/chapter8/1.md)
- [Asking for help on the forums](https://huggingface.co/learn/course/it/chapter8/3.md)
- [Parte 2 completata!](https://huggingface.co/learn/course/it/chapter8/6.md)
- [Fare il debug della training pipeline](https://huggingface.co/learn/course/it/chapter8/4.md)
- [Quiz di fine capitolo](https://huggingface.co/learn/course/it/chapter8/7.md)
- [Fare il debug di una training pipeline](https://huggingface.co/learn/course/it/chapter8/4_tf.md)
- [Cosa fare quando si riceve un errore](https://huggingface.co/learn/course/it/chapter8/2.md)
- [Introduzione a Gradio](https://huggingface.co/learn/course/it/chapter9/1.md)
- [Capire la classe Interface](https://huggingface.co/learn/course/it/chapter9/3.md)
- [Creare la tua prima demo](https://huggingface.co/learn/course/it/chapter9/2.md)
- [Creare il proprio dataset](https://huggingface.co/learn/course/it/chapter5/5.md)
- [Introduzione](https://huggingface.co/learn/course/it/chapter5/1.md)
- [È arrivato il momento di tagliuzzare](https://huggingface.co/learn/course/it/chapter5/3.md)
- [Ricerca semantica con FAISS](https://huggingface.co/learn/course/it/chapter5/6.md)
- [Quiz di fine capitolo](https://huggingface.co/learn/course/it/chapter5/8.md)
- [Big data? Ci pensa 🤗 Datasets!](https://huggingface.co/learn/course/it/chapter5/4.md)
- [🤗 Datasets, check!](https://huggingface.co/learn/course/it/chapter5/7.md)
- [E se il mio dataset non è sull'Hub?](https://huggingface.co/learn/course/it/chapter5/2.md)
- [Gestione di sequenze multiple](https://huggingface.co/learn/course/it/chapter2/5.md)
- [Introduzione](https://huggingface.co/learn/course/it/chapter2/1.md)
- [Models](https://huggingface.co/learn/course/it/chapter2/3.md)
- [Mettiamo insieme i pezzi](https://huggingface.co/learn/course/it/chapter2/6.md)
- [Tokenizers](https://huggingface.co/learn/course/it/chapter2/4.md)
- [Uso di base completato!](https://huggingface.co/learn/course/it/chapter2/7.md)
- [Dietro la pipeline](https://huggingface.co/learn/course/it/chapter2/2.md)
- [Introduzione](https://huggingface.co/learn/course/it/chapter0/1.md)
- [Riassunto](https://huggingface.co/learn/course/it/chapter1/9.md)
- [Modelli encoder](https://huggingface.co/learn/course/it/chapter1/5.md)
- [Introduzione](https://huggingface.co/learn/course/it/chapter1/1.md)
- [Cosa fanno i Transformer?](https://huggingface.co/learn/course/it/chapter1/3.md)
- [Modelli decoder](https://huggingface.co/learn/course/it/chapter1/6.md)
- [Quiz di fine capitolo](https://huggingface.co/learn/course/it/chapter1/10.md)
- [Bias e limiti](https://huggingface.co/learn/course/it/chapter1/8.md)
- [Come funzionano i Transformer?](https://huggingface.co/learn/course/it/chapter1/4.md)
- [Modelli sequence-to-sequence](https://huggingface.co/learn/course/it/chapter1/7.md)
- [Natural Language Processing](https://huggingface.co/learn/course/it/chapter1/2.md)

### Fine della parte 1!
https://huggingface.co/learn/course/it/chapter4/5.md

# Fine della parte 1!

<CourseFloatingBanner
    chapter={4}
    classNames="absolute z-10 right-0 top-0"
/>

Questa è la dine della prima parte del corso! La seconda parte sarà rilasciata il 15 Novembre durante un grande evento della comunità. Per maggiori informazioni [vedere qui](https://huggingface.co/blog/course-launch-event).

A questo punto dovreste essere in grado di affinare un modello pre-addestrato per un problema di classificazione tesutale (a frase signola o doppia), e caricare il risultato sull'Hub dei Modelli (Model Hub). Per assicurarvi di padroneggiare i contenuti di questa prima sezione, dovreste provare a fare esattamente questo su un problema che vi interessi (e non necessariamente in Inglese se parlate un'altra lingua)! Potete trovare aiuto nel [forum di Hugging Face](https://discuss.huggingface.co/), e quando avete finito potete condividere il vostro progetto in [questo topic](https://discuss.huggingface.co/t/share-your-projects/6803).

Non vediamo l'ora di scoprire cosa costruirete!


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter4/5.mdx" />

### L'Hub di Hugging Face
https://huggingface.co/learn/course/it/chapter4/1.md

# L'Hub di Hugging Face

<CourseFloatingBanner
    chapter={4}
    classNames="absolute z-10 right-0 top-0"
/>

L'Hub di Hugging Face -- il nostro sito web principale -- è la piattaforma che permette a chiunque di scoprire, utilizzare, e proporre nuovi modelli e dataset. Contiene una vasta varietà di modelli, con più di 10.000 modelli pubblicamente disponibili. In questo capitolo ci concentreremo sui modelli, mentre approfondiremo i dataset nel capitolo 5.

I modelli disponibili nell'Hub non sono limitati ai 🤗 Transformers, o ai modelli di analisi del linguaggio naturale (Natural Language Processing - NLP). Ci sono infatti modelli sviluppati da [Flair](https://github.com/flairNLP/flair) e [AllenNLP](https://github.com/allenai/allennlp) per l'NLP, ma anche modelli di [Asteroid](https://github.com/asteroid-team/asteroid) e [pyannote](https://github.com/pyannote/pyannote-audio) per la fonologia, e [timm](https://github.com/rwightman/pytorch-image-models) per l'analisi di immagini.

Ognuno di questi modelli è disponibile come un repository Git, che permette di tracciarne le versioni e rendere reproducibili i risultati. Condividere un modello nell'Hub significa renderlo accessibile a tutta la comunità e consentire a chiunque di usarlo facilmente. Questo evita la necessità di addestrare un modello da soli e ne semplifica la diffusione e l'uso.

In aggiunta, condividere un modello nell'Hub automaticamente pubblica una interfaccia programmatica (Application Programming Interface - API) di inferenza per quel modello. Qualsiasi utente della comunità può quindi provare il modello direttamente dalla sua pagina web con input personalizzati attraverso una interfaccia dedicata.

La parte migliore è che condividere e usare qualsiasi modello pubblico nell'Hub è completamente gratuito! Esistono anche dei [piani a pagamento](https://huggingface.co/pricing) se si desidera condividere i modelli in maniera privata.

Il video sottostante mostra come navigare l'Hub.

<Youtube id="XvSGPZFEjDY"/>

Avere un account huggingface.co è necessario per seguire questo capitolo, poiché creeremo e gestiremo dei repository sull'Hub di Hugging Face: [crea un account](https://huggingface.co/join)

<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter4/1.mdx" />

### Condividere modelli pre-addestrati
https://huggingface.co/learn/course/it/chapter4/3.md

# Condividere modelli pre-addestrati

{#if fw === 'pt'}

<CourseFloatingBanner chapter={4}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/it/chapter4/section3_pt.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/it/chapter4/section3_pt.ipynb"},
]} />

{:else}

<CourseFloatingBanner chapter={4}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/it/chapter4/section3_tf.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/it/chapter4/section3_tf.ipynb"},
]} />

{/if}

Nei passi seguenti illustreremo i modi più semplici e veloci per condividere modelli pre-addestrati sull'🤗 Hub. Vedremo degli strumenti e delle utility che rendono semplice condividere e aggiornare modelli direttamente sull'🤗 Hub.

<Youtube id="9yY3RB_GSPM"/>

Incoraggiamo tutti gli utenti che addestrano un modello a contribuire alla comunità condividendolo -- anche se i vostri modelli sono addestrati su dati molto specifici, possono comunque aiutare gli altri a risparmiare tempo e risorse computazionali. A vostra volta, potrete beneficiare del lavoro che gli altri hanno fatto!

Ci sono tre modi per creare un nuovo repository di un modello:

- Usando la funzione `push_to_hub` dell'API
- Usando la libreria Python `huggingface_hub`
- Usando l'interfaccia web

Una volta che avrete creato un repository, potrete caricarvi i file attraverso git e git-lfs. Nelle sezioni seguenti vedremo in dettaglio come creare un repository e aggiungervi i file.


## Utilizzando la funzione `push_to_hub` dell'API

{#if fw === 'pt'}

<Youtube id="Zh0FfmVrKX0"/>

{:else}

<Youtube id="pUh5cGmNV8Y"/>

{/if}

Il modo più semplice di caricare file sull'Hub è attraverso la funzione `push_to_hub` dell'API.

Prima di continuare sarà necessario generare un token di autenticazione così che l'API `huggingface_hub` sappia chi siete e a quali namespace avete accesso in scrittura. Assicuratevi di essere in un ambiente in cui la libreria `transformers` è installata (vedi [Installazione](/course/chapter0)). Se state utilizzando un notebook, potete usare la seguente funzione per effettuare il login:

```python
from huggingface_hub import notebook_login

notebook_login()
```

In una finestra del terminale, potete eseguire:

```bash
huggingface-cli login
```

In entrambi i casi, vi verrà chiesto di inserire il vostro nome utente e la password, che sono gli stessi che utilizzate per accedere all'Hub. Se non avete ancora un profilo sull'Hub, potete crearne uno [qui](https://huggingface.co/join).

Perfetto! Ora il token di autenticazione è salvato nella cartella di cache, e possiamo creare dei nuovi repository!

{#if fw === 'pt'}

Se avete usato la API `Trainer` per addestrare un modello, il modo più semplice per caricarlo sull'Hub è impostare il parametro `push_to_hub=True` quando definite i `TrainingArguments` (parametri di addestramento):

```py
from transformers import TrainingArguments

training_args = TrainingArguments(
    "bert-finetuned-mrpc", save_strategy="epoch", push_to_hub=True
)
```

Invocando la funzione `trainer.train()`, l'oggetto `Trainer` caricherà il modello sull'Hub ad ogni salvataggio (nell'esempio dopo ogni epoca) all'interno di un repository nel vostro namespace. Il repository avrà come nome la stessa stringa che avete scelto come nome per la cartella di output (qui `bert-finetuned-mrpc`), ma è possibile scegliere un nome diverso impostando il parametro `hub_model_id = "un_nome_diverso"`.

Volendo caricare il modello nello spazio di una organizzazione di cui si è membri, sarà sufficiente impstare il parametro `hub_model_id = "nome_organizzazione/nome_repository"`.

Alla fine dell'addestramento, sarà necessario invocare per l'ultima volta la funzione `trainer.push_to_hub()` per caricare la versione definitiva del modello. Questa azione genererà automaticamente anche un cartellino del modello, con tutti i metadati rilevanti, riportando anche gli iper-parametri utilizzati e i risultati della valutazione finale. Questo è un esempio del contenuto di uno di questi cartellini:

<div class="flex justify-center">
  <img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter4/model_card.png" alt="An example of an auto-generated model card." width="100%"/>
</div>

{:else}

Se si sta addestrando il modello con Keras, il modo più semplice per caricarlo sull'Hub è passare come parametro una funzione `PushToHubCallback` quando si invoca la funzione `model.fit()`:

```py
from transformers import PushToHubCallback

callback = PushToHubCallback(
    "bert-finetuned-mrpc", save_strategy="epoch", tokenizer=tokenizer
)
```

Dovrete poi impostare il parametro `callbacks=[callback]` nella invocazione della funzione `model.fit()`. Questa funzione callback caricherà il modello sull'Hub ad ogni salvataggio (nell'esempio dopo ogni epoca) all'interno di un repository nel vostro namespace. Il repository avrà come nome la stessa stringa che avete scelto come nome per la cartella di output (qui `bert-finetuned-mrpc`), ma è possibile scegliere un nome diverso impostando il parametro `hub_model_id = "un_nome_diverso"`.

Volendo caricare il modello nello spazio di una organizzazione di cui si è membri, sarà sufficiente impstare il parametro `hub_model_id = "nome_organizzazione/nome_repository"`.

{/if}

In ogni caso, quando si lavora con modelli, tokenizers, e oggetti di configurazione, è comunque possibile accedere all'Hub dei modelli direttamente ulizzando il rispettivo methodo `push_to_hub()`. Questo metodo si occupa di creare il repository e caricarvi i file del modello e tokenizer. Non è necessario gestire manualmente questa operazione, a differenza dell'API che vedremo più avanti.

Per farvi una idea di come funziona questo processo, inizializzate un modello e un tokenizer:

{#if fw === 'pt'}
```py
from transformers import AutoModelForMaskedLM, AutoTokenizer

checkpoint = "camembert-base"

model = AutoModelForMaskedLM.from_pretrained(checkpoint)
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
```
{:else}
```py
from transformers import TFAutoModelForMaskedLM, AutoTokenizer

checkpoint = "camembert-base"

model = TFAutoModelForMaskedLM.from_pretrained(checkpoint)
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
```
{/if}

A questo punto, siete liberi di fare quello che volete con questi oggetti - aggiungere token diversi al tokenizer, addestrare il modello, affinarlo. Quando siete soddisfatti con il modello, i pesi e il tokenizer ottenuti, potrete usare il methodo `push_to_hub()` direttamente disponibile sul oggetto `model`:

```py
model.push_to_hub("dummy-model")
```

Questo genererà un nuovo repository `dummy-model` nel vostro profilo, e lo popolerà con i file del modello.
Ripetete la stessa operazione con il tokenizer, così tutti i file saranno disponibili nel repository:

```py
tokenizer.push_to_hub("dummy-model")
```

Se siete affiliati con una organizzazione, basterà specificare il parametro `organization` per caricare i file nel namespace dell'organizzazione:

```py
tokenizer.push_to_hub("dummy-model", organization="huggingface")
```

Se desiderate utilizzare uno specifico token di autenticazione di Hugging Face, è possibile specificarlo durante l'invocazione del metodo `push_to_hub()`:

```py
tokenizer.push_to_hub("dummy-model", organization="huggingface", use_auth_token="<TOKEN>")
```

Ora potete dirigervi alla pagina del Model Hub per trovare il vostro nuovo modello appena caricato: *https://huggingface.co/user-or-organization/dummy-model*.

Cliccando sulla scheda "Files and versions" dovreste vedere la lista dei file caricati, come nell'immagine sottostante:

{#if fw === 'pt'}
<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter4/push_to_hub_dummy_model.png" alt="Dummy model containing both the tokenizer and model files." width="80%"/>
</div>
{:else}
<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter4/push_to_hub_dummy_model_tf.png" alt="Dummy model containing both the tokenizer and model files." width="80%"/>
</div>
{/if}

<Tip>

✏️ **Prova tu!** Prendi il modello e il tokenizer associati con il cehckpoint `bert-base-cased` e caricali in un repository nel tuo namespace usando il metodo `push_to_hub()`. Verifica che il repository appaia correttamente sulla tua pagina prima di cancellarlo.

</Tip>

Come avete visto, il metodo `push_to_hub()` accetta numerosi parametri, rendendo possible caricare i file su uno specifico repository o in un namespace di una organizzazione, o utilizzare un qualunque API token. Consigliamo di leggere la documentazione disponibile alla pagina [🤗 Transformers documentation](https://huggingface.co/transformers/model_sharing.html) per farsi una idea di tutte le possibilità offerte dal metodo.

`push_to_hub()` è supportato dal package [`huggingface_hub`](https://github.com/huggingface/huggingface_hub) di Python, che offre una API diretta per interagire con l'Hub di Hugging Face. È integrato in 🤗 Transformers e in numerosi altre librirerie di machine learning, come [`allenlp`](https://github.com/allenai/allennlp). In questo capitolo ci siamo soffermati sull'integrazione con 🤗 Transformers, ma integrarlo nel proprio codice o libreria è semplice.

Saltate all'ultima sezione per vedere come caricare i file nel repository appena creato!

## Utilizzando la libreria Python `huggingface_hub`

La libreria Python `huggingface_hub` offre una varietà di strumenti per interfacciarsi con gli hub di modelli e dataset. Fornisce delle classi e dei metodi semplici per operazioni comuni come
ottenere informazioni e gestire repository sull'hub. Fornisce anche delle semplici API che sfruttano git per gestire i contenuti dei repository e integrare l'Hub 
nei propri prgetti e librerie.

Come per la funzione `push_to_hub`, anche questo approccio richiede di avere un API token salvato nella propria cartella di cache. Per ottenerlo, sarà necessario usare il comando `login` dalla interfaccia da riga di comando (CLI), come indicato nella sezione precedente (assicuratevi di inserire il carattere `!` prima di questi comandi se li state eseguendo in Google Colab):

```bash
huggingface-cli login
```

La libreria `huggingface_hub` offre molte classi e metodi utili al nostro scopo. In primo luogo, ci sono alcuni metodi per gestire operazioni quali creazione e cancellazione di repository:

```python no-format
from huggingface_hub import (
    # User management
    login,
    logout,
    whoami,

    # Repository creation and management
    create_repo,
    delete_repo,
    update_repo_visibility,

    # And some methods to retrieve/change information about the content
    list_models,
    list_datasets,
    list_metrics,
    list_repo_files,
    upload_file,
    delete_file,
)
```


È inoltre offerta una classe `Repository` molto completa per gestire un repository locale. Nelle seguenti sezioni li esploreremo e capiremo come utilizzarli.

Il metodo `create_repo` può essere utilizzato per creare un nuovo repository sull'hub:

```py
from huggingface_hub import create_repo

create_repo("dummy-model")
```

Questo genererà un nuovo repository `dummy-model` nel vostro namespace. Potete anche specificare un'organizzazione a cui il repository dovrebbe appartenere utilizzando il parametro `organization`:

```py
from huggingface_hub import create_repo

create_repo("dummy-model", organization="huggingface")
```

Che genererà il repository `dummy_model` all'interno del namespace `huggingface`, assumendo che apperteniate a questa organizzazione.
Altri parametri che possono tornare utili sono:

- `private`, che permette di specificare se il repository dovrebbe essere visibile da altri oppure no.
- `token`, che permette di specificare un token di autenticazione diverso da quello salvato nella propria cartella di cache.
- `repo_type`, che permette di creare un `dataset` o un `space` (spazio) invece di un modello. I valori accettati sono `"dataset"` e `"space"`.

Una volta creato il repository, dovremo aggiungere file al suo interno! Saltate alla sezione successiva per vedere tre modi per farlo.


## Usando l'interfaccia web

L'interfaccia we offre strumenti per gestire i repository direttamente sull'Hub. Usando questa interfaccia potrete facilmente creare repository, aggiungere file (anche grandi!), esplorare modelli, visualizzare differenze tra file, e molto altro.

Per creare un nuovo repository visitate la pagina [huggingface.co/new](https://huggingface.co/new):

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter4/new_model.png" alt="Page showcasing the model used for the creation of a new model repository." width="80%"/>
</div>

Per prima cosa sarà necessario specificare chi sia il proprietario del repository: questi potete essere voi, o qualunque delle organizzazioni a cui siete affiliati. Se scegliete un'organizzazione, il modello sarà presente sulla pagina dell'organizzazione e tutti i membri dell'organizzazione avranno la possibilità di contribuire al repository.

Ora potete inserire il nome del vostro modello. Questo sarà anche il nome del repository. Infine, potete specificare se volete che il vostro modello sia pubblico o privato. I modelli privati sono nascosti al pubblico. 

Dopo aver creato il repository del vostro modello, dovreste vedere una pagina come questa:

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter4/empty_model.png" alt="An empty model page after creating a new repository." width="80%"/>
</div>

Qui è dove il vostro modello sarà reso disponibile. Per iniziare a popolarlo, potete aggiungere un file README direttamente dalla interfaccia web.

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter4/dummy_model.png" alt="The README file showing the Markdown capabilities." width="80%"/>
</div>

Il file README è in formato Markdown — sentitevi liberi di sbizzarrirvi col README! La terza parte di questo capitolo è dedicata alla generazione del cartellino del modello. Questi cartellini sono estremamente importanti nel valorizzare il vostro modello, poiché è qui che potrete comunicare agli altri le potenzialità del vostro modello.

Nella scheda "Files and versions" (File e versioni), vedrete che non ci sono ancora molti file — solo il *README.md* che avete appena creato e il file *.gitattributes* che tiene traccia dei file grandi.

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter4/files.png" alt="The 'Files and versions' tab only shows the .gitattributes and README.md files." width="80%"/>
</div>

Vedremo ora come aggiungere nuovi file.

## Caricare i file del modello

Il sistema di gestione dei file sull'Hub di Hugging Face è basato su git per file normali, e su git-lfs ([Git Large File Storage](https://git-lfs.github.com/)) per file più grandi.

Nella sezione seguente, illustreremo tre diversi modi per caricare file sull'Hub: attraverso `huggingface_hub` e attraverso comandi git.

### Usando `upload_file`

Caricare file utilizzando `upload_file` non richiede di avere git e git-lfs installati sul proprio sistema. Infatti questo metodo trasferisce i file sul 🤗 Hub attraverso richieste HTTP POST. Una limitazione di questo approccio è che non può gestire file di dimensioni più grandi di 5GB.
Se i vostri file sono più grandi di 5GB, seguite gli altri due metodi dettagliati sotto.

La API può essere usata in questo modo:

```py
from huggingface_hub import upload_file

upload_file(
    "<path_to_file>/config.json",
    path_in_repo="config.json",
    repo_id="<namespace>/dummy-model",
)
```

Questo caricherà il file `config.json`, locato in `<path_to_file>`, nella cartella di base (root) del repository come `config.json`, nel repository `dummy-model`.
Altri parametri che possono essere utili sono:

- `token`, che permette di utilizzare un token di autenticazione specifico invece di quello salvato nella vostra cartella di cache.
- `repo_type`, che permette di caricare un file in un `dataset` o uno `space` invece di un modello. Valori accettati sono `"dataset"` e `"space"`.


### La classe `Repository`

La classe `Repository` gestisce un repository locale in un modo simile a git. Elimina la maggior parte della complessità che un utente potrebbe incontrare con git, per fornire tutte le funzionalità di cui abbiamo bisogno.

Questa classe necessità di git e git-lfs, quindi assicuratevi di averli installati (vedere [qui](https://git-lfs.github.com/) per le istruzioni di installazione) e di averli configurati prima di iniziare.

In order to start playing around with the repository we have just created, we can start by initialising it into a local folder by cloning the remote repository:
Per iniziare a sperimentare con il repository appena creato, possiamo iniziallizzare il repository in una cartella locale clonando il repository remoto:

```py
from huggingface_hub import Repository

repo = Repository("<path_to_dummy_folder>", clone_from="<namespace>/dummy-model")
```

Questa azione crea la cartella `<path_to_dummy_folder>` nella cartella di lavoro corrente (working directory). Questa cartella contiene solo il file `.gitattributes` poichè quello è l'unico file che viene creato quando si istanzia un repository attraverso il metodo `create_repo`.

Da questo punto possiamo usare molti dei metodi classici di git.

```py
repo.git_pull()
repo.git_add()
repo.git_commit()
repo.git_push()
repo.git_tag()
```

E molti altri! Consigliamo di leggere la documentazione della classe `Repository` disponibile [qui](https://github.com/huggingface/huggingface_hub/tree/main/src/huggingface_hub#advanced-programmatic-repository-management) per una panoramica dei metodi disponibili.

In questo momento abbiamo un modello e un tokenizer che vorremmo caricare sull'hub. Avendo correttamente clonato il repository, possiamo salvare i file al suo interno.

Assicuriamoci prima che il nostro clone locale sia aggiornato scaricando (pulling) gli ultimi cambiamenti:

```py
repo.git_pull()
```

Fatto questo, salviamo i file del modello e del tokenizer:

```py
model.save_pretrained("<path_to_dummy_folder>")
tokenizer.save_pretrained("<path_to_dummy_folder>")
```

La cartella `<path_to_dummy_folder>` ora conteine tutti i file del modello e del tokenizer. Possiamo seguire la sequenza di operazioni (workflow) standard di git, aggiungendo file alla staging area, utilizzando git commit e git push per caricarli sull'hub:

```py
repo.git_add()
repo.git_commit("Add model and tokenizer files")
repo.git_push()
```

Congratulazioni! Avete appena caricato i vostri primi file sull'hub.

### L'approccio basato su git

Questo è un approccio molto minimalista al caricamento dei file: utilizzeremo git e git-lfs direttamente. Gli approcci precedenti rimuovevano la maggior parte della complessità utilizzando astrazioni. Siccome ci sono alcune limitazioni con questo metodo, mostreremo un caso di utilizzo più complesso. 

Questo metodo richeide git e git-lfs, quindi assicuratevi di averli installati (vedere [qui](https://git-lfs.github.com/) per le istruzioni di installazione) e di averli configurati prima di iniziare.

Per prima cosa inizializziamo git-lfs:

```bash
git lfs install
```

```bash
Updated git hooks.
Git LFS initialized.
```

Fatto questo, il primo passo è clonare il repository del proprio modello:

```bash
git clone https://huggingface.co/<namespace>/<your-model-id>
```

Il mio nome utente è `lysandre` e ho usato il nome `dummy` per il modello, quindi per me il comando da eseguire diventa:

```
git clone https://huggingface.co/lysandre/dummy
```

Adesso ho una cartella chiamata *dummy* nella mia cartella di lavoro corrente (working directory). Posso spostarmi nella cartella usando `cd` ed esaminare i contenuti:

```bash
cd dummy && ls
```

```bash
README.md
```

Se avete appena creato la repository usando il metodo `create_repo` di Hugging Face Hub, questa cartella dovrebbe contenere solo un file nascosto `.gitattributes`. Se avete seguito le istruzioni nella sezione precedente per creare una repository usando l'interfaccia web, la cartella dovrebbe contenere un singolo file *README.md* assieme al file nascosto `.gitattributes`, come mostrato qui.

Per aggiungere un file di taglia regolare, come un file di configurazione, un file vocabolario, o in genere qualsiasi file di taglia inferiore a qualche megabyte, si procede nello stesso modo di un qualunque systema basato su git. Tuttavia, i file più grandi devono essere registrati con git-lfs per poter essere caricati su *huggingface.co*.

Tornando a Python per un momento, generiamo un modello e un tokenizer che vorremmo caricare sul nostro repository dummy:

{#if fw === 'pt'}
```py
from transformers import AutoModelForMaskedLM, AutoTokenizer

checkpoint = "camembert-base"

model = AutoModelForMaskedLM.from_pretrained(checkpoint)
tokenizer = AutoTokenizer.from_pretrained(checkpoint)

# Do whatever with the model, train it, fine-tune it...

model.save_pretrained("<path_to_dummy_folder>")
tokenizer.save_pretrained("<path_to_dummy_folder>")
```
{:else}
```py
from transformers import TFAutoModelForMaskedLM, AutoTokenizer

checkpoint = "camembert-base"

model = TFAutoModelForMaskedLM.from_pretrained(checkpoint)
tokenizer = AutoTokenizer.from_pretrained(checkpoint)

# Do whatever with the model, train it, fine-tune it...

model.save_pretrained("<path_to_dummy_folder>")
tokenizer.save_pretrained("<path_to_dummy_folder>")
```
{/if}

Adesso che abbiamo salvato gli artefatti del modello e del tokenizer, esaminiamo la cartella *dummy*:

```bash
ls
```

{#if fw === 'pt'}
```bash
config.json  pytorch_model.bin  README.md  sentencepiece.bpe.model  special_tokens_map.json tokenizer_config.json  tokenizer.json
```

Guardando le dimensioni dei file (ad esempio con `ls -lh`), possiamo vedere che il file contenente lo stato del modello (model state dict file) (*pytorch_model.bin*) è l'unico file anomalo, occupando più di 400 MB.

{:else}
```bash
config.json  README.md  sentencepiece.bpe.model  special_tokens_map.json  tf_model.h5  tokenizer_config.json  tokenizer.json
```

Guardando le dimensioni dei file (ad esempio con `ls -lh`), possiamo vedere che il file contenente lo stato del modello (model state dict file) (*t5_model.h5*) è l'unico file anomalo, occupando più di 400 MB.

{/if}

<Tip>
✏️ When creating the repository from the web interface, the *.gitattributes* file is automatically set up to consider files with certain extensions, such as *.bin* and *.h5*, as large files, and git-lfs will track them with no necessary setup on your side.
✏️ Creando il reposiotry dall'interfaccia web, il file *.gitattributes*  viene automaticamente configurato per considerare file con alcune estensioni, come *.bin* e *.h5*, come file grandi, e git-lfs li traccerà senza necessità di configurazione da parte dell'utente.
</Tip> 

Possiamo quindi procedere come faremo per un repository Git tradizionale. Possiamo aggiungere tutti i file all'ambiente di staging di Git con il comando `git add`:

```bash
git add .
```

Possiamo quindi vedere i file che sono attualmente in staging:

```bash
git status
```

{#if fw === 'pt'}
```bash
On branch main
Your branch is up to date with 'origin/main'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
  modified:   .gitattributes
	new file:   config.json
	new file:   pytorch_model.bin
	new file:   sentencepiece.bpe.model
	new file:   special_tokens_map.json
	new file:   tokenizer.json
	new file:   tokenizer_config.json
```
{:else}
```bash
On branch main
Your branch is up to date with 'origin/main'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
  modified:   .gitattributes
  	new file:   config.json
	new file:   sentencepiece.bpe.model
	new file:   special_tokens_map.json
	new file:   tf_model.h5
	new file:   tokenizer.json
	new file:   tokenizer_config.json
```
{/if}

Allo stesso modo possiamo assucurarci che git-lfs stia tenendo traccia dei file giusti utilizzando il comando `status`:

```bash
git lfs status
```

{#if fw === 'pt'}
```bash
On branch main
Objects to be pushed to origin/main:


Objects to be committed:

	config.json (Git: bc20ff2)
	pytorch_model.bin (LFS: 35686c2)
	sentencepiece.bpe.model (LFS: 988bc5a)
	special_tokens_map.json (Git: cb23931)
	tokenizer.json (Git: 851ff3e)
	tokenizer_config.json (Git: f0f7783)

Objects not staged for commit:


```

Possiamo notare che tutti i file hanno `Git` come gestore (handler), ad eccezione di *pytorch_model.bin* e *sentencepiece.bpe.model*, che invece hanno `LFS`. Perfetto!

{:else}
```bash
On branch main
Objects to be pushed to origin/main:


Objects to be committed:

	config.json (Git: bc20ff2)
	sentencepiece.bpe.model (LFS: 988bc5a)
	special_tokens_map.json (Git: cb23931)
	tf_model.h5 (LFS: 86fce29)
	tokenizer.json (Git: 851ff3e)
	tokenizer_config.json (Git: f0f7783)

Objects not staged for commit:


```

Possiamo notare che tutti i file hanno `Git` come gestore (handler), ad eccezione di *t5_model.h5*, che invece ha `LFS`. Perfetto!

{/if}

Possiamo quindi procedere al passo finale, utilizzando i comandi commit e push per caricare i file sul repository remoto *huggingface.co*:

```bash
git commit -m "First model version"
```

{#if fw === 'pt'}
```bash
[main b08aab1] First model version
 7 files changed, 29027 insertions(+)
  6 files changed, 36 insertions(+)
 create mode 100644 config.json
 create mode 100644 pytorch_model.bin
 create mode 100644 sentencepiece.bpe.model
 create mode 100644 special_tokens_map.json
 create mode 100644 tokenizer.json
 create mode 100644 tokenizer_config.json
```
{:else}
```bash
[main b08aab1] First model version
 6 files changed, 36 insertions(+)
 create mode 100644 config.json
 create mode 100644 sentencepiece.bpe.model
 create mode 100644 special_tokens_map.json
 create mode 100644 tf_model.h5
 create mode 100644 tokenizer.json
 create mode 100644 tokenizer_config.json
```
{/if}

L'operazione di push può richiedere un po' di tempo, a seconda della velocità della connessione a internet e della dimensione dei file:

```bash
git push
```

```bash
Uploading LFS objects: 100% (1/1), 433 MB | 1.3 MB/s, done.
Enumerating objects: 11, done.
Counting objects: 100% (11/11), done.
Delta compression using up to 12 threads
Compressing objects: 100% (9/9), done.
Writing objects: 100% (9/9), 288.27 KiB | 6.27 MiB/s, done.
Total 9 (delta 1), reused 0 (delta 0), pack-reused 0
To https://huggingface.co/lysandre/dummy
   891b41d..b08aab1  main -> main
```

{#if fw === 'pt'}
Alla fine di questa operazione, possiamo controllare il repository e vedere tutti i file aggiunti di recente:

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter4/full_model.png" alt="The 'Files and versions' tab now contains all the recently uploaded files." width="80%"/>
</div>

L'interfaccia permette di esplorare i file e le commit, e visualizzare le differenze (file diff) introdotte da ogni commit:

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter4/diffs.gif" alt="The diff introduced by the recent commit." width="80%"/>
</div>
{:else}
Alla fine di questa operazione, possiamo controllare il repository e vedere tutti i file aggiunti di recente:

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter4/full_model_tf.png" alt="The 'Files and versions' tab now contains all the recently uploaded files." width="80%"/>
</div>

L'interfaccia permette di esplorare i file e le commit, e visualizzare le differenze (file diff) introdotte da ogni commit:

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter4/diffstf.gif" alt="The diff introduced by the recent commit." width="80%"/>
</div>
{/if}


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter4/3.mdx" />

### Quiz di fine capitolo
https://huggingface.co/learn/course/it/chapter4/6.md

# Quiz di fine capitolo

<CourseFloatingBanner
    chapter={4}
    classNames="absolute z-10 right-0 top-0"
/>

Mettiamo alla prova quello che avete imparato in questo capitolo!
  
### 1. Quali modelli si possono caricare sull'Hub?

<Question
	choices={[
		{
			text: "Modelli dalla libreria 🤗 Transformers.",
			explain: "I modelli della libreria 🤗 Transformers sono supportati dall'Hub di Hugging Face, ma non sono gli unici!"
		},
		{
			text: "Tutti i modelli con una interfaccia simile ai 🤗 Transformers.",
			explain: "Non ci sono requisiti relativi all'interfaccia quando si carica un modello sull'Hub di Hugging Face. "
		},
		{
			text: "Non ci sono limiti.",
			explain: "Esatto! Non ci sono limiti quando si carica un modello sull'Hub.",
            correct: true
		},
        {
			text: "Modelli che sono in qualche modo relativi all'NLP.",
			explain: "Non ci sono requisiti relativi al campo di applicazione!"
		}
	]}
/>

### 2. Come si gestisce un modello sull'Hub?

<Question
	choices={[
		{
			text: "Attraverso un account GCP.",
			explain: "Sbagliato!"
		},
		{
			text: "Attraverso un sistema di distribuzione peer-to-peer.",
			explain: "Sbagliato!"
		},
		{
			text: "Attraverso git e git-lfs.",
			explain: "Corretto! I modelli sull'Hub sono semplici repository Git, che usano <code>git-lfs</code> per i file di grandi dimensioni.",
            correct: true
		}
	]}
/>

### 3. Cosa si può fare attraverso l'interfacca web di Hugging Face Hub? 

<Question
	choices={[
		{
			text: "Effettuare un fork di un repository esistente.",
			explain: "Non è possibile effettuare fork di repository sull'Hugging Face Hub."
		},
		{
			text: "Creare un nuvo repository di un modello.",
			explain: "Corretto! Però si può fare anche altro.",
            correct: true
		},
		{
			text: "Gestire ed editare file.",
			explain: "Corretto! Ma non è l'unica risposta giusta.",
            correct: true
		},
        {
			text: "Caricare file.",
			explain: "Giusto! Ma non è tutto.",
            correct: true
		},
        {
			text: "Visualizzare le differenze tra le versioni.",
			explain: "Corretto! Però si può fare anche altro.",
            correct: true
		}
	]}
/>

### 4. Cos'è il cartellino del modello?

<Question
	choices={[
		{
			text: "Una descrizione approssimativa del modello, e pertanto meno importante dei file del modello e del tokenizer.",
			explain: "È effettivamente una descrizione del modello, ma è molto importante: se incompleto o mancante, l'utilità del modello è ridotta drasticamente."
		},
		{
			text: "Un modo per assicurare riproducibilità, riutilizzo, e correttezza.",
			explain: "Corretto! Condividere le informazioni giuste sul cartellino aiuterà gli utenti a utilizzare il vostro modello ed essere a conoscenza dei suoi limiti e bias.",
            correct: true
		},
		{
			text: "Un file Python che può essere eseguito per ottenere informazioni sul modello.",
			explain: "I cartellini sono semplici file Markdown."
		}
	]}
/>

### 5. QUali di questi oggetti della libreria 🤗 Transformers può essere direttamente condiviso sull'Hub con `push_to_hub()`?

{#if fw === 'pt'}
<Question
	choices={[
		{
			text: "Un tokenizer",
			explain: "Corretto! Tutti i tokenizers hanno il metodo <code>push_to_hub</code>, che carica tutti i file del tokenizer (vocabolario, architettura del tokenizer, ecc.) su un repository specificatoo. Questa non è l'unica risposta giusta però!",
            correct: true
		},
		{
			text: "La configurazione di un modello",
			explain: "Vero! Gli oggetti di contennti la configurazione di tutti i modelli hanno il metodo <code>push_to_hub</code>, che li carica su un repository specificato. Cosa altro si può condividere?",
            correct: true
		},
		{
			text: "Un modello",
			explain: "Corretto! Tutti i modelli hanno il metodo <code>push_to_hub</code>, e utilizzandolo si possono caricare, insieme ai loro file di configurazione, su un repository specificato. Si possono condividere anche altre cose.",
            correct: true
		},
        {
			text: "Un Trainer",
			explain: "Giusto — l'oggetto <code>Trainer</code> implementa il metodo <code>push_to_hub</code>, e utilizzandolo, si possono caricare modello, configurazione, tokenizer, e cartellino su un repository specificato. Prova un'altra risposta!",
            correct: true
		}
	]}
/>
{:else}
<Question
	choices={[
		{
			text: "Un tokenizer",
			explain: "Corretto! Tutti i tokenizers hanno il metodo <code>push_to_hub</code>, che carica tutti i file del tokenizer (vocabolario, architettura del tokenizer, ecc.) su un repository specificatoo. Questa non è l'unica risposta giusta però!",
            correct: true
		},
		{
			text: "La configurazione di un modello",
			explain: "Vero! Gli oggetti di contennti la configurazione di tutti i modelli hanno il metodo <code>push_to_hub</code>, che li carica su un repository specificato. Cosa altro si può condividere?",
            correct: true
		},
		{
			text: "Un modello",
			explain: "Corretto! Tutti i modelli hanno il metodo <code>push_to_hub</code>, e utilizzandolo si possono caricare, insieme ai loro file di configurazione, su un repository specificato. Si possono condividere anche altre cose.",
            correct: true
		},
		{
			text: "Tutti i precedenti, usando una callback dedicata",
			explain: "Giusto — la callback <code>PushToHubCallback</code> caricherà tutti questi oggetti su un repository regolarmente durante l'addestramento.",
            correct: true
		}
	]}
/>
{/if}

### 6. Qual è il primo passo da fare quando si usano il metodo `push_to_hub()` o gli strumenti da riga di comando (CLI)?

<Question
	choices={[
		{
			text: "Log in sul sito web.",
			explain: "Questo non vi sarà utile mentre lavorate sulla vostra macchina locale."
		},
		{
			text: "Eseguire 'huggingface-cli login' in un terminale.",
			explain: "Corretto — questo scaricherà e salverà in una cartella di cache il vostro token di autenticazione personale.",
            correct: true
		},
		{
			text: "Eseguire 'notebook_login()' in un notebook.",
			explain: "Corretto — questo mostrerà un widget che permette di autenticarsi.",
            correct: true
		},
	]}
/>

### 7. Se state usando un modello e un tokenizer — come li caricate sull'Hub?

<Question
	choices={[
		{
			text: "Usando direttamente il metodo push_to_hub su modello e tokenizer.",
			explain: "Corretto!",
            correct: true
		},
		{
			text: "All'interno di un runtime di Python, facendo wrapping di entrambi con l'utility <code>huggingface_hub</code>.",
			explain: "Modelli e tokenizer beneficiano già delle utilities di <code>huggingface_hub</code>: non c'è bisogno di wrapping addizionale!"
		},
		{
			text: "Salvandoli su disco e invocando il comando <code>transformers-cli upload-model</code>",
			explain: "Il commando <code>upload-model</code> non esiste."
		}
	]}
/>

### 8. Quali operazioni di git si possono fare con la classe `Repository`?

<Question
	choices={[
		{
			text: "git commit.",
			explain: "Corretto, il metodo <code>git_commit()</code> è li per questo.",
            correct: true
		},
		{
			text: "git pull",
			explain: "Questa è la funzione del metodo <code>git_pull()</code>.",
            correct: true
		},
		{
			text: "git push",
			explain: "Il metodo <code>git_push()</code> fa esattamente questo.",
            correct: true
		},
		{
			text: "git merge",
			explain: "No, questa operazione non è possibile con questa API."
		}
	]}
/>


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter4/6.mdx" />

### Generare un cartellino del modello
https://huggingface.co/learn/course/it/chapter4/4.md

# Generare un cartellino del modello

<CourseFloatingBanner
    chapter={4}
    classNames="absolute z-10 right-0 top-0"
/>

Il cartellino del modello (model card) è un file di importanza pari ai file del modello e del tokenizer in un repository. Contiene la definizione del modello, assicurando la possibilità di riutilizzarlo e riprodurre i risultati da parte dei membri della comunità, e facendo si che il modello sia una piattaforma su cui gli altri membri possono costruire i loro artefatti.

Documentare il processo di addestramento e valutazione aiuta gli altri a capire cosa aspettarsi dal modello — inoltre, fornire informazioni accurate sui dati utilizzati e sulle operazioni di pre e post elaborazione (preprocessing e postprocessing), assicura che si possano identificare e comprenere le limitazioni, i bias, e i contesti in cui il modello è utile, e quelli in cui non lo è.

Per questo creare un cartellino del modello che descriva chiaramente il modello, è un passo estremamente importante. Qui, forniamo alcuni suggerimenti per farlo. Il cartellino del modello viene creato tramite il file *README.md*, visto in precedenza, che è un file Markdown.

Il concetto del cartellino trae origine dalla ricerca svolta a Google, e pubblicata per la prima volta nell'articolo ["Model Cards for Model Reporting"](https://arxiv.org/abs/1810.03993) di Margaret Mitchell et al. Molte informazioni contenute qui sono basate su quell'artictolo, e raccomandiamo a tutti di leggerlo per capire l'importanza del cartellino del modello in un mondo che valorizza la reproduzione, la riutilizzabilità e l'equità.

Il cartellino solitamente inizia con una breve introduzione, che descrive ad alto livello per quale scopo il modello è stato creato, ed è seguita da informazioni aggiuntive nelle sezioni seguenti:

- Descrizione del modello
- Usi previsti e limitazioni
- Istruzioni d'uso
- Limitazioni e bias
- Dati di addestramento
- Procedura di addestramento
- Risultati della valutazione

Approfondiamo ora i contenuti di ciascuna sezione.

### Descrizione del modello

La descrizione del modello fornisce i dettagli di base. Questi includono l'architettura, la versione, informazioni sull'articolo scientifico in cui il modello è stato presentato (se disponibile), se sia disponibile una implementazione originale, l'autore, ed altre informazioni di carattere generale. Qualsiasi copyright deve essere attribuito qui. Informazioni generali sulle procedure di addestramento, i parametri, ed anche dichiarazioni di non responsabilità possono essere inserite in questa sezione.

### Usi previsti e limitazioni

In questa sezione vengono descritti gli utilizzi per cui il modello è inteso, inclusi i linguaggi e i domini di applicazione del modello. Questa sezione del cartellino puó anche descrivere situazioni che sono fuori dall'ambito previsto del modello, o dove é probabile che il modello non funzioni in maniera ottimale.

### Istruzioni d'uso

Questa sezione dovrebbe includere alcuni esempi che mostrino come usare il modello. Questi esempi possono includere l'utilizzo attraverso la funzione `pipeline()`, l'utilizzo delle classi modello e tokenizer, e qualsiasi altro esempio di codice che possa essere utile. 

### Dati di addestramento

Questa parte dovrebbe indicare su quali dataset il modello è stato addestrato. È anche consigliabile aggiungere una breve descrizione dei dataset.

### Procedura di addestramento

In questa sezione dovreste descrivere tutti i dettagli del processo di addestramento rilevanti dal punto di vista della riproducibilitá. 

### Variabili e metriche di valutazione

In questa sezione é opportuno descrivere le metriche utilizzate per la valutazione e differenti fattori che vengono misurati. Riportare quali metriche ssono state usate, e su quali dataset e relative partizioni (dataset split), rende facile comparare le performance del proprio modello con gli altri. Le informazioni in questa sezione dovrebbero coprire i casi d'uso riportati nelle sezioni precedenti.

### Risultati della valutazione

Per finire, si dovrebbero riportare i risultati della valutazione di come si comporta il modello sul dataset di valutazione. Se il modello utilizza una soglia di decisione (decision threshold), è opportuno riportare o la soglia di decisione utilizzata nella fase di valutazione, o riportare i risultati per differenti soglie di decisione per gli usi previsti. 

## Esempio

Consigliamo di guardare i seguenti esempi di cartellini ben curati:

- [`bert-base-cased`](https://huggingface.co/bert-base-cased)
- [`gpt2`](https://huggingface.co/gpt2)
- [`distilbert`](https://huggingface.co/distilbert-base-uncased)

Esempi aggiuntivi, da parte di altre organizzazioni e compagnie, sono disponibili [qui](https://github.com/huggingface/model_card/blob/master/examples.md).

## Nota

Includere il cartellino del modello non è un requisito obbligatorio durante la pubblicazione di un modello, e inoltre non è necessario includere tutte le sezioni elencate in precedenza quando si crea un cartellino. Tuttavia, una documentazione esplicita del modello può solo portare benefici agli utilizzatori futuri, e per questo raccomandiamo di compilare quante più sezioni possibili, al meglio delle proprie conoscenze e capacità.

## Metadati del cartellino del modello

Se avete esplorato l'Hugging Face Hub, potreste aver notato che alcuni modelli appartengono a determinate categorie: è possibile filtrarli per task, lingue, librerie, ecc. Le categorie a cui appartiene un modello sono identificate in base ai metadati aggiunti nell'intestazione (header) del cartellino.

Prendendo ad esempio [il cartellino di `camembert-base`](https://huggingface.co/camembert-base/blob/main/README.md), dovreste vedere le seguenti righe nell'intestazione del cartellino:

```
---
language: fr
license: mit
datasets:
- oscar
---
```

This metadata is parsed by the Hugging Face Hub, which then identifies this model as being a French model, with an MIT license, trained on the Oscar dataset. 
Questi metadati vengono elaborati dall'Hub di Hugging Face, che identifica questo modello come un modello Francese, con una licenza MIT, addestrato sul dataset Oscar.

La [specifica completa dei cartellini](https://github.com/huggingface/hub-docs/blame/main/modelcard.md) permette di riportare lingue, license, tags, datasets, metriche di valutazione, e anche i risultati della valutazione del modello ottenuti durante l'addestramento.


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter4/4.mdx" />

### Usare modelli pre-addestrati
https://huggingface.co/learn/course/it/chapter4/2.md

# Usare modelli pre-addestrati

{#if fw === 'pt'}

<CourseFloatingBanner chapter={4}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/it/chapter4/section2_pt.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/it/chapter4/section2_pt.ipynb"},
]} />

{:else}

<CourseFloatingBanner chapter={4}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/it/chapter4/section2_tf.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/it/chapter4/section2_tf.ipynb"},
]} />

{/if}

Usando l'Hub diventa molto facile selzionare il modello appropriato, così da poterlo usare in qualsiasi altro framework con solo poche righe di codice. Vediamo ora come usare un di questi modelli, e come contribuire allo sviluppo della comunità.

Ad esempio assumiamo di stare cercando un modello francese sviluppato per ricostruire token mancanti (mask filling).

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter4/camembert.gif" alt="Selecting the Camembert model." width="80%"/>
</div>

Selezioniamo il checkpoint `camembert-base` per provarlo. L'identificatore `camembert-base` è tutto quello che serve per inizializzarlo! Come si è visto in precedenti capitoli, è possibile istanziare il modello usando la funzione `pipeline()`:

```py
from transformers import pipeline

camembert_fill_mask = pipeline("fill-mask", model="camembert-base")
results = camembert_fill_mask("Le camembert est <mask> :)")
```

```python out
[
  {'sequence': 'Le camembert est délicieux :)', 'score': 0.49091005325317383, 'token': 7200, 'token_str': 'délicieux'}, 
  {'sequence': 'Le camembert est excellent :)', 'score': 0.1055697426199913, 'token': 2183, 'token_str': 'excellent'}, 
  {'sequence': 'Le camembert est succulent :)', 'score': 0.03453313186764717, 'token': 26202, 'token_str': 'succulent'}, 
  {'sequence': 'Le camembert est meilleur :)', 'score': 0.0330314114689827, 'token': 528, 'token_str': 'meilleur'}, 
  {'sequence': 'Le camembert est parfait :)', 'score': 0.03007650189101696, 'token': 1654, 'token_str': 'parfait'}
]
```

Come potete vedere, caricare un modello all'interno di una pipeline è molto semplice. L'unico elemento da tenere in considerazione è che il checkpoint scelto sia adatto all'utilizzo che intendete farne. Ad esempio, noi abbiamo caricato il checkpoint `camembert-base` all'interno del pipeline `fill-mask`, che è corretto. Ma se dovessimo caricare questo checkpoint in un pipeline di classificazione del testo (`text-classification`), i risultati non avrebbero senso perché l'head di `camembert-base` non è adatto per questo obiettivo! Si consiglia di usare il filtro per obiettivi nell'interfaccia dell'Hub di Hugging Face per selezionare il checkpoint appropriato:

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter4/tasks.png" alt="The task selector on the web interface." width="80%"/>
</div>

Potete anche istanziare il checkpoint usando direttamente l'architettura del modello:

{#if fw === 'pt'}
```py
from transformers import CamembertTokenizer, CamembertForMaskedLM

tokenizer = CamembertTokenizer.from_pretrained("camembert-base")
model = CamembertForMaskedLM.from_pretrained("camembert-base")
```

Tuttavia, noi consigliamo di usare le [classi `Auto*`](https://huggingface.co/transformers/model_doc/auto.html?highlight=auto#auto-classes) quando possibile, poiché sono progettate per essere agnostiche rispetto al tipo di architettura del modello. Mentre il codice di esempio precedente limita gli utenti a caricare i checkpoint supportati dall'architettura CamemBERT, usare le classi `Auto*` rende facile il passaggio da un checkpoint ad un altro:

```py
from transformers import AutoTokenizer, AutoModelForMaskedLM

tokenizer = AutoTokenizer.from_pretrained("camembert-base")
model = AutoModelForMaskedLM.from_pretrained("camembert-base")
```
{:else}
```py
from transformers import CamembertTokenizer, TFCamembertForMaskedLM

tokenizer = CamembertTokenizer.from_pretrained("camembert-base")
model = TFCamembertForMaskedLM.from_pretrained("camembert-base")
```

Tuttavia, noi consigliamo di usare le [classi `TFAuto*`](https://huggingface.co/transformers/model_doc/auto.html?highlight=auto#auto-classes) quando possibile, poiché sono progettate per essere agnostiche rispetto al tipo di architettura del modello. Mentre il codice di esempio precedente limita gli utenti a caricare i checkpoint supportati dall'architettura CamemBERT, usare le classi `TFAuto*` rende facile il passaggio da un checkpoint ad un altro:

```py
from transformers import AutoTokenizer, TFAutoModelForMaskedLM

tokenizer = AutoTokenizer.from_pretrained("camembert-base")
model = TFAutoModelForMaskedLM.from_pretrained("camembert-base")
```
{/if}

<Tip>
Quando usate un modello pre-addestrato, assicuratevi di controllare come è stato addestrato, su quali dataset, i suoi limiti e i suoi bias. Tutte queste informazioni dovrebbero essere indicate sul cartellino del modello.
</Tip>


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter4/2.mdx" />

### Affinamento, Fatto!
https://huggingface.co/learn/course/it/chapter3/5.md

# Affinamento, Fatto!

Che divertimento. Nei primi due capitoli abbiamo scoperto i modelli e i tokenizzatori, e adesso sapete come affinarli per i vostri dati. Per riassumere, in questo capitolo avete:

{#if fw === 'pt'}
* Scoperto i datasets nel [Hub](https://huggingface.co/datasets)
* Imparato come caricare e preprocessare i datasets, usando anche padding dinamico e funzioni di raccolta
* Implementato il vostro affinamento e valutazione di un modello
* Implementato un ciclo di addestramento di basso livello
* Usato 🤗 Accelerate per adattare in maniera semplice il vostro ciclo di addestramento all'utilizzo di svariate GPU o TPU 

{:else}
* Scoperto i datasets nel [Hub](https://huggingface.co/datasets)
* Imparato come caricare e preprocessare i datasets
* Imparato come affinare e valutare un modello con Keras
* Implementato una metric personalizzata

{/if}


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter3/5.mdx" />

### Introduzione
https://huggingface.co/learn/course/it/chapter3/1.md

# Introduzione

Nel [Capitolo 2](/course/chapter2) abbiamo scoperto come utilizzare i tokenizzatori e i modelli preaddestrati per effettuare delle predizioni. Ma cosa fare se si vuole affinare un modello preaddestrato col tuo dataset? Lo scopriremo in questo capitolo! Impareremo:

{#if fw === 'pt'}
* Come preparare un grande dataset dall'Hub
* Come usare l'API di alto livello `Trainer` per affinare un modello
* Come usare un ciclo di addestramento personalizzato
* Come utilizzare la libreria 🤗 Accelerate per eseguire facilmente quel ciclo di addestramento personalizzato su qualsiasi sistema distribuito

{:else}
* Come preparare un grande dataset dall'Hub
* Come usare Keras per affinare un modello
* Come usare Keras per ottenere delle predizioni
* Come usare una metrica personalizzata

{/if}

Per caricare i checkpoint di addestramento sull'Hub di Hugging Face è necessario un account huggingface.co: [creare un account](https://huggingface.co/join)


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter3/1.mdx" />

### Affinare il modello con la Trainer API
https://huggingface.co/learn/course/it/chapter3/3.md

# Affinare il modello con la Trainer API

<DocNotebookDropdown
  classNames="absolute z-10 right-0 top-0"
  options={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/it/chapter3/section3.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/it/chapter3/section3.ipynb"},
]} />

<Youtube id="nvBXf7s7vTI"/>

🤗 Transformers fornisce una classe `Trainer` (addestratore) per aiutare con l'affinamento di uno qualsiasi dei modelli pre-addestrati nel dataset. Dopo tutto il lavoro di preprocessing nella sezione precedente, rimangono giusto gli ultimi passi per definire il `Trainer`. Probabilmente la parte più complicata sarà preparare l'ambiente per eseguire `Trainer.train()`, poiché sarà molto lento su una CPU. Se non avete una GPU a disposizione, potete avere accesso gratuitamente a GPU o TPU su [Google Colab](https://colab.research.google.com/).

Gli esempi di codice qui sotto partono dal presupposto che gli esempi nella sezione precedente siano già stati eseguiti. Ecco un breve riassunto di cosa serve:

```py
from datasets import load_dataset
from transformers import AutoTokenizer, DataCollatorWithPadding

raw_datasets = load_dataset("glue", "mrpc")
checkpoint = "bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)


def tokenize_function(example):
    return tokenizer(example["sentence1"], example["sentence2"], truncation=True)


tokenized_datasets = raw_datasets.map(tokenize_function, batched=True)
data_collator = DataCollatorWithPadding(tokenizer=tokenizer)
```

### Addestramento

Il primo passo per definire un `Trainer` è la definizione di una classe `TrainingArguments` che contenga tutti gli iperparametri che verranno usati dal `Trainer` per l'addestramento e la valutazione. L'unico parametro da fornire è la cartella dove verranno salvati il modello addestrato e i vari checkpoint. Per tutto il resto si possono lasciare i parametri di default, che dovrebbero funzionare bene per un affinamento di base.

```py
from transformers import TrainingArguments

training_args = TrainingArguments("test-trainer")
```

<Tip>

💡 Se si vuole caricare automaticamente il modello all'Hub durante l'addestramento, basta passare `push_to_hub=True` come parametro nei `TrainingArguments`. Maggiori dettagli verranno forniti nel [Capitolo 4](/course/chapter4/3).

</Tip>

Il secondo passo è definire il modello. Come nel [capitolo precedente](/course/chapter2), utilizzeremo la classe `AutoModelForSequenceClassification` con due label:

```py
from transformers import AutoModelForSequenceClassification

model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2)
```

Diversamente dal [Capitolo 2](/course/chapter2), un avviso di avvertimento verrà visualizzato dopo aver istanziato questo modello pre-addestrato. Ciò avviene perché BERT non è stato pre-addestrato per classificare coppie di frasi, quindi la testa del modello pre-addestrato viene scartata e una nuova testa adeguata per il compito di classificazione di sequenze è stata inserita. Gli avvertimenti indicano che alcuni pesi non verranno usati (quelli corrispondenti alla testa scartata del modello pre-addestrato) e che altri pesi sono stati inizializzati con valori casuali (quelli per la nuova testa). L'avvertimento viene concluso con un'esortazione ad addestrare il modello, che è esattamente ciò che stiamo per fare.  

Una volta ottenuto il modello, si può definire un `Trainer` passandogli tutti gli oggetti costruiti fino ad adesso — il `model`, i `training_args`, i dataset di addestramento e validazione, il `data_collator`, e il `tokenizer`:

```py
from transformers import Trainer

trainer = Trainer(
    model,
    training_args,
    train_dataset=tokenized_datasets["train"],
    eval_dataset=tokenized_datasets["validation"],
    data_collator=data_collator,
    tokenizer=tokenizer,
)
```

Quando si passa l'argomento `tokenizer` come appena fatto, il `data_collator` usato di default dal `Trainer` sarà del tipo `DataCollatorWithPadding`, come definito precedentemente, quindi si potrebbe evitare di specificare l'argomento `data_collator=data_collator` in questa chiamata. Tuttavia era comunque importante mostrare questa parte del processing nella sezione 2!

Per affinare il modello sul nostro dataset, bisogna solo chiamare il metodo `train()` del `Trainer`:

```py
trainer.train()
```

Questo farà partire l'affinamento (che richiederà un paio di minuti su una GPU) e produrrà un report della funzione obiettivo dell'addestramento ogni 500 passi. Tuttavia, non vi farà sapere quanto sia buona (o cattiva) la performance del modello. Ciò è dovuto al fatto che:

1. Non è stato detto al `Trainer` di valutare il modello durante l'addestramento, settando `evaluation_strategy` o al valore `"steps"` (valuta il modello ogni `eval_steps`) oppure al valore `"epoch"` (valuta il modello alla fine di ogni epoca).
2. Non è stato fornito al `Trainer` una funzione `compute_metrics()` per calcolare le metriche di valutazione (altrimenti la valutazione stamperebbe solo il valore della funzione obiettivo, che non è un valore molto intuitivo).


### Valutazione

Vediamo come si può costruire una funzione `compute_metrics()` utile e usarla per il prossimo addestramento. La funzione deve prendere come parametro un oggetto `EvalPrediction` (che è una named tuple avente un campo `predictions` – predizioni – e un campo `label_ids` – id delle etichette –) e restituirà un dizionario che associa stringhe a numeri floating point (le stringhe saranno i nomi delle metriche, i numeri i loro valori). Per ottenere delle predizioni, si può usare il comando `Trainer.predict()`:

```py
predictions = trainer.predict(tokenized_datasets["validation"])
print(predictions.predictions.shape, predictions.label_ids.shape)
```

```python out
(408, 2) (408,)
```

Il risultato del metodo `predict()` è un'altra named tuple con tre campi: `predictions`, `label_ids`, e `metrics`. Il campo `metrics` conterrà solo il valore della funzione obiettivo sul dataset, in aggiunta ad alcune metriche legate al tempo (il tempo necessario per calcolare le predizioni, in totale e in media). Una volta completata la funzione `compute_metrics()` e passata al `Trainer`, quel campo conterrà anche le metriche restituite da `compute_metrics()`.

Come si può vedere, `predictions` è un array bi-dimensionale con dimensioni 408 x 2 (poiché 408 è il numero di elementi nel dataset). Questi sono i logit per ogni elemento del dataset passato a `predict()` (come già visto nel [capitolo precedente](/course/chapter2), tutti i modelli Transformer restituiscono logit). Per trasformarli in predizioni associabili alle etichette, bisogna prendere l'indice col valore massimo sul secondo asse:

```py
import numpy as np

preds = np.argmax(predictions.predictions, axis=-1)
```

Ora si possono paragonare i `preds` con le etichette. Per costruire la funzione `compute_metric()`, verranno utilizzate le metriche dalla libreria 🤗 Dataset. Si possono caricare le metriche associate con il dataset MRPC in maniera semplice, utilizzando la funzione `load_metric()`. L'oggetto restituito ha un metodo `compute()` (calcola) che possiamo usare per calcolare le metriche:

```py
from datasets import load_metric

metric = load_metric("glue", "mrpc")
metric.compute(predictions=preds, references=predictions.label_ids)
```

```python out
{'accuracy': 0.8578431372549019, 'f1': 0.8996539792387542}
```

L'esatto valore dei risultati potrebbe essere diverso nel vostro caso, a casa dell'inizializzazione casuale della testa del modello. In questo caso il nostro modello ha un'accuratezza del 85.78% sul set di validazione e un valore F1 di 89.97. Queste sono le due metriche utilizzate per valutare i risultati sul dataset MRPC per il benchmark GLUE. La tabella nell'[articolo su BERT](https://arxiv.org/pdf/1810.04805.pdf) riportava un F1 di 88.9 per il modello base. Quello era il modello `uncased` (senza distinzione fra minuscole e maiuscole) mentre noi stiamo usando quello `cased`, il che spiega il risultato migliore. 

Mettendo tutto insieme si ottiene la funzione `compute_metrics()`:

```py
def compute_metrics(eval_preds):
    metric = load_metric("glue", "mrpc")
    logits, labels = eval_preds
    predictions = np.argmax(logits, axis=-1)
    return metric.compute(predictions=predictions, references=labels)
```

Per vederla in azione e fare il report delle metriche alla fine di ogni epoca, ecco come si definisce un nuovo `Trainer` che includa questa funzione `compute_metrics()`:

```py
training_args = TrainingArguments("test-trainer", evaluation_strategy="epoch")
model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2)

trainer = Trainer(
    model,
    training_args,
    train_dataset=tokenized_datasets["train"],
    eval_dataset=tokenized_datasets["validation"],
    data_collator=data_collator,
    tokenizer=tokenizer,
    compute_metrics=compute_metrics,
)
```

Da notare che bisogna creare un nuovo oggetto `TrainingArguments` con il valore di `evaluation_strategy` pari a `"epoch"` e un nuovo modello — altrimenti si continuerebbe l'addestramento del modello già addestrato. Per lanciare una nuova esecuzione dell'addestramento si usa:

```
trainer.train()
```

Stavolta vi sarà il report della funzione obiettivo di validazione alla fine di ogni epoca, in aggiunta alla funzione obiettivo dell'addestramento. Di nuovo, i valori esatti di accuratezza/F1 ottenuti da voi potrebbero variare leggermente da quelli mostrati qui a causa dell'inizializzazione casuale della testa del modello, ma dovrebbero essere comparabili. 

Il `Trainer` funzionerà direttamente su svariate GPU e TPU e ha molte opzioni, tra cui addestramento in precisione mista (utilizzare `fp16 = True` negli argomenti). I dettagli delle opzioni verranno esplorati nel Capitolo 10. 

Qui si conclude l'introduzione all'affinamento usando l'API del `Trainer`. Esempi per i compiti più comuni in NLP verranno forniti nel Capitolo 7, ma per ora vediamo come ottenere la stessa cosa usando puramente Pytorch.

<Tip>

✏️ **Prova tu!** Affinare un modello sul dataset GLUE SST-2 utilizzando il processing dei dati già fatto nella sezione 2. 

</Tip>



<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter3/3.mdx" />

### Quiz di fine capitolo
https://huggingface.co/learn/course/it/chapter3/6.md

# Quiz di fine capitolo

Testiamo cosa avete imparato in questo capitolo!

### 1. Il dataset `emotion` contiene messaggi Twitter etichettati con emozioni. Cercalo nel [Hub](https://huggingface.co/datasets) e leggi la carta del dataset. Quale di queste non fa parte delle sue emozioni di base?

<Question
	choices={[
		{
			text: "Joy (Gioia)",
			explain: "Prova ancora — questa emozione è contenuta nel dataset!"
		},
		{
			text: "Love (Amore)",
			explain: "Prova ancora — questa emozione è contenuta nel dataset!"
		},
		{
			text: "Confusion (Confusione)",
			explain: "Corretto! Confusion non è una della sei emozioni di base.",
            correct: true
		},
        {
			text: "Surprise (Sorpresa)",
			explain: "Sorpresa! Prova ancora!"
		}
	]}
/>

### 2. Cerca il dataset `ar_sarcasm` nel [Hub](https://huggingface.co/datasets). Quali compiti supporta?

<Question
	choices={[
		{
			text: "Sentiment classification (Classificazione dei sentimenti)",
			explain: "Corretto! Si capisce dai tag.",
            correct: true
		},
		{
			text: "Machine translation (Traduzione automatica)",
			explain: "Sbagliato — dai un'altra occhiata alla <a href='https://huggingface.co/datasets/ar_sarcasm'>dataset card</a>!"
		},
		{
			text: "Named entity recognition (Riconoscimento di entità con un nome)",
			explain: "Sbagliato — dai un'altra occhiata alla <a href='https://huggingface.co/datasets/ar_sarcasm'>dataset card</a>!"
		},
        {
			text: "Question answering (Risposte a domande)",
			explain: "Purtroppo non hai risposto correttamente. Prova ancora!"
		}
	]}
/>

### 3. Come deve essere preparata una coppia di frasi per essere processata dal modello BERT?

<Question
	choices={[
		{
			text: "Tokens_della_frase_1 [SEP] Tokens_della_frase_2",
			explain: "Un token speciale <code>[SEP]</code> è necessario per separare le due frasi, ma non è l'unica cosa!"
		},
		{
			text: "[CLS] Tokens_della_frase_1 Tokens_della_frase_2",
			explain: "Un token speciale <code>[CLS]</code> è necessario all'inizio, ma non è l'unica cosa!"
		},
		{
			text: "[CLS] Tokens_della_frase_1 [SEP] Tokens_della_frase_2 [SEP]",
			explain: "Corretto!",
            correct: true
		},
        {
			text: "[CLS] Tokens_della_frase_1 [SEP] Tokens_della_frase_2",
			explain: "Un token speciale <code>[CLS]</code> è necessario all'inizio e un token speciale <code>[SEP]</code> è necessario per separare le due frasi, ma non è l'unica cosa!"
		}
	]}
/>

{#if fw === 'pt'}
### 4. Quali sono i benefici del metodo `Dataset.map()`?

<Question
	choices={[
		{
			text: "I risultati della funzione vengono conservati, così la ri-esecuzione del codice sarà rapidissima",
			explain: "Questo è sicuramente uno dei benefici di questo metodo! Ma non è l'unico...",
            correct: true
		},
		{
			text: "È possibile applicare multiprocessing per un'esecuzione più rapida rispetto all'applicazione seriale ad ogni elemento del dataset",
			explain: "Questo è sicuramente uno dei benefici di questo metodo! Ma non è l'unico...",
            correct: true
		},
		{
			text: "Non carica l'intero dataset in memoria, salvando i risultati appena ogni elemento è stato processato.",
			explain: "Questo è sicuramente uno dei benefici di questo metodo! Ma non è l'unico...",
            correct: true
		},
	]}
/>

### 5. Qual è il significato di padding dinamico (dynamic padding)?

<Question
	choices={[
		{
			text: "È quando si applica in ogni batch il padding fino alla lunghezza massima dell'intero dataset",
			explain: "Riguarda il padding per ogni batch, ma non fino alla lunghezza massima dell'intero dataset."
		},
		{
			text: "È quando si applica in ogni batch il padding fino alla lunghezza massima delle frasi in quella batch",
			explain: "Corretto! la parte \"dinamica\" viene dal fatto che la dimensione per ogni batch viene determinata al momento della creazione, e quindi le batch potrebbero avere dimensioni differenti.",
            correct: true
		},
		{
			text: "È quando si applica il padding agli input in modo che ogni frase abbia lo stesso numero di token della frase precedente nel dataset.",
			explain: "Sbagliato. In più non avrebbe senso considerare l'ordine del dataset dato che lo rimischiamo durante l'apprendimento."
		},
	]}
/>

### 6. Qual è lo scopo di una funzione di raccolta (collate function)?

<Question
	choices={[
		{
			text: "Di assicurarsi che tutte le sequenze nel dataset abbiano la stessa lunghezza.",
			explain: "Una funzione di raccolta gestisce solo batch individuali, non l'intero dataset. In più, si sta parlando di funzioni di raccolta in generale, e non specificatamente di <code>DataCollatorWithPadding</code>."
		},
		{
			text: "Di raccogliere tutti i campioni in una batch.",
			explain: "Corretto! Puoi passare la funzione di raccolta come argomento di un <code>DataLoader</code>. Noi abbiamo usato la funzione <code>DataCollatorWithPadding</code>, che applica padding a tutti gli elementi di una batch affinché abbiano la stessa lunghezza.",
            correct: true
		},
		{
			text: "Di preprocessare l'intero dataset",
			explain: "Quella sarebbe una funzione di preprocessing, non di raccolta."
		},
        {
			text: "Di troncare le sequenze nel dataset.",
			explain: "Una funzione di raccolta gestisce solo batch individuali, non l'intero dataset. Se siete interessati al troncamento, potete usare l'argomento <code>truncate</code> del <code>tokenizer</code>."
		}
	]}
/>

### 7. Cosa succede quando una classe di tipo `AutoModelForXxx` viene istanziata con un modello di linguaggio pre-addestrato (come `bert-base-uncased`) che corrisponde ad un compito differente rispetto a quello per cui era stato addestrato?

<Question
	choices={[
		{
			text: "Nulla, ma viene mostrato un avvertimento",
			explain: "L'avvertimento non è 'l'unica cosa!"
		},
		{
			text: "La testa del modello pre-addestrato viene scartata e una nuova testa, appropriata per il compito, viene inserita al suo posto",
			explain: "Corretto. Ad esempio, quando abbiamo usato <code>AutoModelForSequenceClassification</code> con <code>bert-base-uncased</code>, abbiamo ottenuto un avvertimento mentre il modello veniva istanziato. La testa pre-addestrata non viene usata per il compito di classificazione delle sequenze, ma viene scartata e una nuova testa viene istanziata con pesi casuali.",
            correct: true
		},
		{
			text: "La testa del modello pre-addestrato viene scartata",
			explain: "Deve succedere anche qualcos'altro. Prova ancora!"
		},
         	{
			text: "Nulla, dato che il modello può comunque essere affinato per un compito differente.",
			explain: "La testa del modello pre-addestrato non era stata addestrata per risolvere questo compito, quindi dovremmo scartarla!"
		}
	]}
/>

### 8. Qual è lo scopo di `TrainingArguments`?

<Question
	choices={[
		{
			text: "Contiene tutti gli iperparametri usati per l'addestramento e la valutazione con il <code>Trainer</code>.",
			explain: "Corretto!",
            correct: true
		},
		{
			text: "Specifica le dimensioni del modello.",
			explain: "Le dimensioni del modello sono definite dalla configurazione del modello, non dalla classe <code>TrainingArguments</code>."
		},
		{
			text: "Contiene soltanto gli iperparametri usati per la valutazione.",
			explain: "Nell'esempio, abbiamo specificato anche dove salvare il modello e i suoi checkpoint. Prova ancora!"
		},
        {
			text: "Contiene soltanto gli iperparametri usati per l'addestramento.",
			explain: "Nell'esempio, abbiamo usato anche una <code>evaluation_strategy</code> (stragia di valutazione). Prova ancora!"
		}
	]}
/>

### 9. Perché si dovrebbe usare la libreria 🤗 Accelerate?

<Question
	choices={[
		{
			text: "Fornisce l'accesso a modelli più veloci.",
			explain: "No, la libreria 🤗 Accelerate non fornisce l'accesso ad alcun modello"
		},
		{
			text: "Fornisce una API di alto livello, così non devo implementare il mio ciclo di addestramento.",
			explain: "Questa è la funzionalità del <code>Trainer</code>, non della libreria 🤗 Accelerate. Prova ancora!"
		},
		{
			text: "Permette ai nostri cicli di addestramento di venire eseguiti con strategie distribuite.",
			explain: "Corretto! Con 🤗 Accelerate, i tuoi cicli di addestramento funzioneranno con svariate GPU e TPU.",
            correct: true
		},
        {
			text: "Fornisce altre funzioni di ottimizzazione.",
			explain: "No, la libreria 🤗 Accelerate library non fornisce alcuna funzione di ottimizzazione."
		}
	]}
/>

{:else}
### 4. Cosa succede quando una classe di tipo `TFAutoModelForXxx` viene istanziata con un modello di linguaggio pre-addestrato (come `bert-base-uncased`) che corrisponde ad un compito differente rispetto a quello per cui era stato addestrato?

<Question
	choices={[
		{
			text: "Nulla, ma viene mostrato un avvertimento",
			explain: "L'avvertimento non è l'unica cosa!"
		},
		{
			text: "La testa del modello pre-addestrato viene scartata e una nuova testa, appropriata per il compito, viene inserita al suo posto",
			explain: "Corretto. Ad esempio, quando abbiamo usato <code>TFAutoModelForSequenceClassification</code> con <code>bert-base-uncased</code>, abbiamo ottenuto un avvertimento mentre il modello veniva istanziato. La testa pre-addestrata non viene usata per il compito di classificazione delle sequenze, ma viene scartata e una nuova testa viene istanziata con pesi casuali.",
            correct: true
		},
		{
			text: "La testa del modello pre-addestrato viene scartata",
			explain: "Deve succedere anche qualcos'altro. Prova ancora!"
		},
        {
			text: "Nulla, dato che il modello può comunque essere affinato per un compito differente.",
			explain: "La testa del modello pre-addestrato non era stata addestrata per risolvere questo compito, quindi dovremmo scartarla!"
		}
	]}
/>

### 5. I modelli Tensorflow da `transformers` sono già dei modelli Keras. Quali benefici offre ciò?

<Question
	choices={[
		{
			text: "I modelli funzionano automaticamente su una TPU.",
			explain: "Quasi! Sono richiesti alcuni cambiamenti. Ad esempio, bisogna eseguire tutto all'interno di uno scope <code>TPUStrategy</code>, incluso l'inizializzazione del modello"
		},
		{
			text: "Si possono sfruttare metodi già esistenti quali <code>compile()</code>, <code>fit()</code>, e <code>predict()</code>.",
			explain: "Correto! Una volta ottenuti i dati, l'addestramento richiede molto poco sforzo.",
            correct: true
		},
		{
			text: "Puoi imparare Keras in aggiunta ai transformers.",
			explain: "Corretto, anche se cercavamo qualcosa in pù :)",
			correct: true
		},
        {
			text: "Si possono calcolare facilmente delle metriche relative al dataset",
			explain: "Keras è d'aiuto nell'addestramento e valutazione del modello, non nel calcolare metriche relative al dataset."
		}
	]}
/>

### 6. Come si definisce una metrica personalizzata (custom metric)?

<Question
	choices={[
		{
			text: "Creando una sottoclasse di <code>tf.keras.metrics.Metric</code>.",
			explain: "Ottimo!",
			correct: true
		},
		{
			text: "Usando l'API funzionale di Keras",
			explain: "Prova ancora!"
		},
		{
			text: "Utilizzando una funzione con segnatura <code>metric_fn(y_true, y_pred)</code>.",
			explain: "Corretto!",
			correct: true
		},
        {
			text: "Chiedendo a Google",
			explain: "Non è la risposta che cercavamo, ma dovrebbe comunque aiutarvi a risolvere il problema.",
			correct: true
		}
	]}
/>

{/if}


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter3/6.mdx" />

### Affinare un modell usando Keras
https://huggingface.co/learn/course/it/chapter3/3_tf.md

# Affinare un modell usando Keras

<DocNotebookDropdown
  classNames="absolute z-10 right-0 top-0"
  options={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/it/chapter3/section3_tf.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/it/chapter3/section3_tf.ipynb"},
]} />

Dopo tutto il lavoro di preprocessing nella sezione precedente, rimangono giusto gli ultimi passi per addestrare il modello. Attenzione tuttavia che il comando `model.fit()` sarà molto lento su una CPU. Se non avete una GPU a disposizione, potete avere accesso gratuitamente a GPU o TPU su [Google Colab](https://colab.research.google.com/).

Gli esempi di codice qui sotto partono dal presupposto che gli esempi nella sezione precedente siano già stati eseguiti. Ecco un breve riassunto di cosa serve:

```py
from datasets import load_dataset
from transformers import AutoTokenizer, DataCollatorWithPadding
import numpy as np

raw_datasets = load_dataset("glue", "mrpc")
checkpoint = "bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)


def tokenize_function(example):
    return tokenizer(example["sentence1"], example["sentence2"], truncation=True)


tokenized_datasets = raw_datasets.map(tokenize_function, batched=True)

data_collator = DataCollatorWithPadding(tokenizer=tokenizer, return_tensors="tf")

tf_train_dataset = tokenized_datasets["train"].to_tf_dataset(
    columns=["attention_mask", "input_ids", "token_type_ids"],
    label_cols=["labels"],
    shuffle=True,
    collate_fn=data_collator,
    batch_size=8,
)

tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset(
    columns=["attention_mask", "input_ids", "token_type_ids"],
    label_cols=["labels"],
    shuffle=False,
    collate_fn=data_collator,
    batch_size=8,
)
```

### Addestramento

I modelli di TensorFlow importati da 🤗 Transformers sono già dei modelli Keras. Ecco una breve introduzione a Keras.

<Youtube id="rnTGBy2ax1c"/>

Ciò significa che una volta che si hanno i dati, è richiesto poco lavoro aggiuntivo per cominciare l'addestramento. 

<Youtube id="AUozVp78dhk"/>

Come nel [capitolo precedente](/course/chapter2), verrà utilizzata la classe `TFAutoModelForSequenceClassification` con due etichette:

```py
from transformers import TFAutoModelForSequenceClassification

model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2)
```

Diversamente dal [Capitolo 2](/course/chapter2), un avviso di avvertimento verrà visualizzato dopo aver istanziato questo modello pre-addestrato. Ciò avviene perché BERT non è stato pre-addestrato per classificare coppie di frasi, quindi la testa del modello pre-addestrato viene scartata e una nuova testa adeguata per il compito di classificazione di sequenze è stata inserita. Gli avvertimenti indicano che alcuni pesi non verranno usati (quelli corrispondenti alla testa scartata del modello pre-addestrato) e che altri pesi sono stati inizializzati con valori casuali (quelli per la nuova testa). L'avvertimento viene concluso con un'esortazione ad addestrare il modello, che è esattamente ciò che stiamo per fare. 

Per affinare il modello sul dataset, bisogna solo chiamare `compile()` (compila) sul modello e passare i dati al metodo `fit()`. Ciò farà partire il processo di affinamento (che dovrebbe richiedere un paio di minuti su una GPU) e fare il report della funzione obiettivo di addestramento, in aggiunta alla funzione obiettivo di validazione alla fine di ogni epoca. 

<Tip>

I modelli 🤗 Transformers hanno un'abilità speciale che manca alla maggior parte dei modelli Keras – possono usare in maniera automatica una funzione obiettivo appropriata, calcolata internamente. Questa funzione obiettivo verrà usata di default a meno che non venga definito l'argomento di funzione obiettivo nel metodo `compile()`. Per usare la funzione obiettivo interna è necessario passare le etichette come parte dell'input, non separatamente, che è l'approccio normale con i modelli Keras. Verranno mostrati esempi di ciò nella Parte 2 del corso, dove definire la funzione obiettivo correttamente può essere difficile. Per la classificazione di sequenze, invece, la funzione obiettivo standard di Keras funziona bene, quindi verrà utilizzata quella. 

</Tip>

```py
from tensorflow.keras.losses import SparseCategoricalCrossentropy

model.compile(
    optimizer="adam",
    loss=SparseCategoricalCrossentropy(from_logits=True),
    metrics=["accuracy"],
)
model.fit(
    tf_train_dataset,
    validation_data=tf_validation_dataset,
)
```

<Tip warning={true}>

Attenzione ad un errore comune — si *può* passare solo il nome della funzione obiettivo a Keras come una stringa, ma di default Keras si aspetta che softmax sia già stato applicato ai risultati. Molti modelli invece forniscono come risultato i valori prima dell'applicazione del softmax, chiamati *logits*. Bisogna informare la funzione obiettivo che il nostro modello fa esattamente questo, e il solo modo di farlo è invocandola direttamente, non tramite la stringa che rappresenta il suo nome. 

</Tip>


### Migliorare la performance di addestramento

<Youtube id="cpzq6ESSM5c"/>

Il codice presentato qui sopra sicuramente funziona, ma la funzione obiettivo scende in maniera molto lenta e sporadica. La causa principale di ciò è la *learning rate* (tasso di apprendimento). Come con la funzione obiettivo, quando si passa il nome di un ottimizzatore a Keras tramite una stringa, Keras inizializza quell'ottimizzatore con i valori di default per tutti i parametri, inclusa la learning rate. Grazie alla nostra esperienza, però, sappiamo che i modelli transformer beneficiano da una learning rate molto più bassa del valore di default per Adam, che è 1e-3, scritto anche come 10 alla -3, o 0.001. Il valore 5e-5 (0.00005), circa venti volte più basso, è un punto di partenza migliore.

In aggiunta a diminuire la learning rate, abbiamo un secondo asso nella manica: possiamo ridurre lentamente la learning rate durante l'addestramento. Nella letteratura, questo approccio viene spesso indicato come *decaying* (decadimento) o *annealing* (ricottura) della learning rate. In Keras, il modo migliore per ottenere ciò è attraverso un *learning rate scheduler* (pianificatore del tasso di addestramento). Un buon esempio è `PolynomialDecay` (decadimento polinomiale) — nonostante il nome, con le impostazioni di default ha un semplice decadimento lineare dal valore iniziale a quello finale durante l'addestramento, che è esattamente ciò che cerchiamo. Per utilizzare lo scheduler in maniera corretta, però, bisogna dirgli quanto lungo sarà l'addestramento. Lo calcoliamo tramite la variabile `num_train_steps` nell'esempio qui sotto.

```py
from tensorflow.keras.optimizers.schedules import PolynomialDecay

batch_size = 8
num_epochs = 3
# The number of training steps is the number of samples in the dataset, divided by the batch size then multiplied
# by the total number of epochs. Note that the tf_train_dataset here is a batched tf.data.Dataset,
# not the original Hugging Face Dataset, so its len() is already num_samples // batch_size.
num_train_steps = len(tf_train_dataset) * num_epochs
lr_scheduler = PolynomialDecay(
    initial_learning_rate=5e-5, end_learning_rate=0.0, decay_steps=num_train_steps
)
from tensorflow.keras.optimizers import Adam

opt = Adam(learning_rate=lr_scheduler)
```

<Tip>

La libreria 🤗 Transformers fornisce anche una funzione `create_optimizer()` che crea un ottimizzatore `AdamW` con decadimento della learning rate. Questa può essere una scorciatoia utile che verrà presentata nel dettaglio nelle sezioni future del corso.

</Tip>

Adesso che abbiamo il nostro ottimizzatore nuovo di zecca, possiamo provare con un addestramento. Per prima cosa, ricarichiamo il modello, per resettare i cambiamenti ai pesi dall'addestramento precedente, dopodiché lo possiamo compilare con nuovo ottimizzatore.

```py
import tensorflow as tf

model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2)
loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
model.compile(optimizer=opt, loss=loss, metrics=["accuracy"])
```

Ora chiamiamo di nuovo fit

```py
model.fit(tf_train_dataset, validation_data=tf_validation_dataset, epochs=3)
```

<Tip>

💡 Se vuoi caricare il modello in maniera automatica all'Hub durante l'addestramento, puoi passare `PushToHubCallback` al metodo `model.fit()`. Maggiori dettagli verranno forniti nel [Capitolo 4](/course/chapter4/3)

</Tip>

### Predizioni del modello

<Youtube id="nx10eh4CoOs"/>


Vedere la funzione obiettivo che diminuisce durante l'addestramento è bello, ma se volessimo ottenere dei risultati dal modello addestrato, ad esempio per calcolare delle metriche o per usare il modello in produzione? Per questo, si può usare il metodo `predict()`. Questo metodo restituisce i `*logits* dalla testa del modello, uno per classe.

```py
preds = model.predict(tf_validation_dataset)["logits"]
```

I logits possono essere convertiti nelle predizioni delle classi del modello usando `argmax` per trovare il logit più grande, che corrisponde alla classe più probabile.

```py
class_preds = np.argmax(preds, axis=1)
print(preds.shape, class_preds.shape)
```

```python out
(408, 2) (408,)
```

Ora usiamo le `preds` per calcolare delle metriche! Si possono caricare le metriche associate al dataset MRPC in maniera facile tanto quanto caricare il dataset in sé, usando la funzione `load_metric()`. L'oggetto restituito ha un metodo `compute()` che può essere usato per calcolare le metriche.

```py
from datasets import load_metric

metric = load_metric("glue", "mrpc")
metric.compute(predictions=class_preds, references=raw_datasets["validation"]["label"])
```

```python out
{'accuracy': 0.8578431372549019, 'f1': 0.8996539792387542}
```

L'esatto valore dei risultati ottenuti può variare, poiché l'inizializzazione casuale della testa del modello può cambiare le metriche ottenute. Qui vediamo che il nostro modello ha una accuratezza del 87.78% sul validation set e valore F1 di 89.97. Queste sono le due metriche utilizzare per valutare risultati sul dataset MRPC per il benchmark GLUE. La tabella nell'[articolo du BERT](https://arxiv.org/pdf/1810.04805.pdf) riportava un valore F1 di 88.9 per il modello di base. Quello era il modello `uncased`, mentre qui stiamo usando il modello `cased`, il che spiega i migliori risultati.

Questo conclude l'introduzione all'affinamento usando l'API Keras. Un esempio per i compiti di NLP più comuni verrà fornito nel Capitolo 7. Per migliorare le vostre abilità con l'API Keras, provate ad affinare un modello sul dataset GLUE SST-2, usando il processing dei dati spiegato nella sezione 2.


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter3/3_tf.mdx" />

### Un addestramento completo
https://huggingface.co/learn/course/it/chapter3/4.md

# Un addestramento completo

<DocNotebookDropdown
  classNames="absolute z-10 right-0 top-0"
  options={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/it/chapter3/section4.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/it/chapter3/section4.ipynb"},
]} />

<Youtube id="Dh9CL8fyG80"/>

Ora vedremo come ottenere gli stessi risultati della sezione precedente senza utilizzare la classe `Trainer`. Ancora una volta, aver compiuto il processing dei dati spiegato nella sezione 2 è un prerequisito. Ecco un riassunto di tutto ciò di cui avrete bisogno:

```py
from datasets import load_dataset
from transformers import AutoTokenizer, DataCollatorWithPadding

raw_datasets = load_dataset("glue", "mrpc")
checkpoint = "bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)


def tokenize_function(example):
    return tokenizer(example["sentence1"], example["sentence2"], truncation=True)


tokenized_datasets = raw_datasets.map(tokenize_function, batched=True)
data_collator = DataCollatorWithPadding(tokenizer=tokenizer)
```

### Preparazione all'addestramento

Prima di cominciare a scrivere il nostro ciclo di addestramento, dobbiamo definire alcuni oggetti. Per prima cosa, i dataloaders (caricatori di dati) che useremo per iterare sulle batch. Ma prima di poter definire i dataloaders, dobbiamo applicare un po' di postprocessing ai nostri `tokenized_datasets`, per compiere alcune operazione che `Trainer` gestiva in automatico per noi. Nello specifico dobbiamo:

- Rimuovere le colonne corrispondente a valori che il modello non si aspetta (come ad esempio le colonne `sentence1` e `sentence2 `).
- Rinominare la colonna `label` a `labels` (perché il modello si aspetta questo nome).
- Fissare il formato dei datasets in modo che restituiscano tensori Pytorch invece di liste.

L'oggetto `tokenized_datasets` ha un metodo per ciascuno di questi punti:

```py
tokenized_datasets = tokenized_datasets.remove_columns(["sentence1", "sentence2", "idx"])
tokenized_datasets = tokenized_datasets.rename_column("label", "labels")
tokenized_datasets.set_format("torch")
tokenized_datasets["train"].column_names
```

Possiamo poi controllare che il risultato ha solo solo colonne che saranno accettate dal nostro modello:

```python
["attention_mask", "input_ids", "labels", "token_type_ids"]
```

Ora che questo è fatto, possiamo finalmente definire i dataloaders in maniera semplice:

```py
from torch.utils.data import DataLoader

train_dataloader = DataLoader(
    tokenized_datasets["train"], shuffle=True, batch_size=8, collate_fn=data_collator
)
eval_dataloader = DataLoader(
    tokenized_datasets["validation"], batch_size=8, collate_fn=data_collator
)
```

Per controllare velocemente che non ci sono errori nel processing dei dati, possiamo ispezionare una batch in questo modo:

```py
for batch in train_dataloader:
    break
{k: v.shape for k, v in batch.items()}
```

```python out
{'attention_mask': torch.Size([8, 65]),
 'input_ids': torch.Size([8, 65]),
 'labels': torch.Size([8]),
 'token_type_ids': torch.Size([8, 65])}
```

È importante sottolineare che i valori di shape (forma) potrebbero essere leggermente diversi per voi, poiché abbiamo fissato `shuffle=True` (rimescolamento attivo) per i dataloader di apprendimento, e stiamo applicando padding alla lunghezza massima all'interno della batch.

Ora che il preprocessing dei dati è completato (uno scopo soddisfacente ma elusivo per qualunque praticante di ML), focalizziamoci sul modello. Lo istanziamo esattamente come avevamo fatto nella sezione precedente:

```py
from transformers import AutoModelForSequenceClassification

model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2)
```

Per assicurarci che tutto andrà bene durante l'addestramento, passiamo la batch al modello:

```py
outputs = model(**batch)
print(outputs.loss, outputs.logits.shape)
```

```python out
tensor(0.5441, grad_fn=<NllLossBackward>) torch.Size([8, 2])
```

Tutti i modelli 🤗 Transformers restituiscono il valore obiettivo quando vengono fornite loro le `labels`, e anche i logits (due per ciascun input della batch, quindi un tensore di dimensioni 8 x 2). 

Siamo quasi pronti a scrivere il ciclo di addestramento! Mancano solo due cose: un ottimizzatore e un learning rate scheduler. Poiché stiamo tentando di replicare a mano ciò che viene fatto dal `Trainer`, utilizzeremo gli stessi valori di default. L'ottimizzatore utilizzato dal `Trainer` è `AdamW`, che è lo stesso di Adam ma con una variazione per quanto riguarda la regolarizzazione del decadimento dei pesi (rif. ["Decoupled Weight Decay Regularization"](https://arxiv.org/abs/1711.05101) di Ilya Loshchilov e Frank Hutter):

```py
from torch.optim import AdamW

optimizer = AdamW(model.parameters(), lr=5e-5)
```

Infine, il learning rate scheduler usato di default è solo un decadimento lineare dal valore massimo (5e-5) fino a 0. Per definirlo correttamente, dobbiamo sapere il numero di iterazioni per l'addestramento, che è dato dal numero di epoche che vogliamo eseguire moltiplicato per il numero di batch per l'addestramento (ovverosia la lunghezza del dataloader). Il `Trainer` usa 3 epoche di default, quindi:

```py
from transformers import get_scheduler

num_epochs = 3
num_training_steps = num_epochs * len(train_dataloader)
lr_scheduler = get_scheduler(
    "linear",
    optimizer=optimizer,
    num_warmup_steps=0,
    num_training_steps=num_training_steps,
)
print(num_training_steps)
```

```python out
1377
```

### Il ciclo di addestramento

Un'ultima cosa: se si ha accesso ad una GPU è consigliato usarla (su una CPU, l'addestramento potrebbe richiedere svariate ore invece di un paio di minuti). Per usare la GPU, definiamo un `device` su cui spostare il modello e le batch:

```py
import torch

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

```python out
device(type='cuda')
```

Siamo pronti per l'addestramento! Per avere un'intuizione di quando sarà finito, aggiungiamo una barra di progresso sul numero di iterazioni di addestramento, usando la libreria `tqdm`:

```py
from tqdm.auto import tqdm

progress_bar = tqdm(range(num_training_steps))

model.train()
for epoch in range(num_epochs):
    for batch in train_dataloader:
        batch = {k: v.to(device) for k, v in batch.items()}
        outputs = model(**batch)
        loss = outputs.loss
        loss.backward()

        optimizer.step()
        lr_scheduler.step()
        optimizer.zero_grad()
        progress_bar.update(1)
```

Potete vedere che il nocciolo del ciclo di addestramento è molto simile a quello nell'introduzione. Non abbiamo chiesto nessun report, quindi il ciclo non ci informerà su come si sta comportando il modello. Dobbiamo aggiungere un ciclo di valutazione per quello. 


### Il ciclo di valutazione

Come fatto in precedenza, utilizzeremo una metrica fornita dalla libreria 🤗 Datasets. Abbiamo già visto il metodo `metric.compute()`, ma le metriche possono automaticamente accumulare le batch nel ciclo di predizione col metodo `add_batch()`. Una volta accumulate tutte le batch, possiamo ottenere il risultato finale con `metric.compute()`. Ecco come implementare tutto ciò in un ciclo di valutazione:

```py
from datasets import load_metric

metric = load_metric("glue", "mrpc")
model.eval()
for batch in eval_dataloader:
    batch = {k: v.to(device) for k, v in batch.items()}
    with torch.no_grad():
        outputs = model(**batch)

    logits = outputs.logits
    predictions = torch.argmax(logits, dim=-1)
    metric.add_batch(predictions=predictions, references=batch["labels"])

metric.compute()
```

```python out
{'accuracy': 0.8431372549019608, 'f1': 0.8907849829351535}
```

Ancora una volta, i vostri risultati potrebbero essere leggermente diversi a causa della casualità nell'inizializzazione della testa del modello e del ricombinamento dei dati, ma dovrebbero essere nello stesso ordine di grandezza.

<Tip>

✏️ **Prova tu!** Modifica il ciclo di addestramento precedente per affinare il modello sul dataset SST-2.

</Tip>

### Potenzia il tuo ciclo di addestramento con 🤗 Accelerate

<Youtube id="s7dy8QRgjJ0" />

Il ciclo di addestramento che abbiamo definito prima funziona bene per una sola CPU o GPU. Ma grazie alla libreria [🤗 Accelerate](https://github.com/huggingface/accelerate), con alcuni aggiustamenti possiamo attivare l'addestramento distribuito su svariate GPU o TPU. Partendo dalla creazione dei dataloaders di addestramento e validazione, ecco l'aspetto del nostro ciclo di addestramento manuale:

```py
from torch.optim import AdamW
from transformers import AutoModelForSequenceClassification, get_scheduler

model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2)
optimizer = AdamW(model.parameters(), lr=3e-5)

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

num_epochs = 3
num_training_steps = num_epochs * len(train_dataloader)
lr_scheduler = get_scheduler(
    "linear",
    optimizer=optimizer,
    num_warmup_steps=0,
    num_training_steps=num_training_steps,
)

progress_bar = tqdm(range(num_training_steps))

model.train()
for epoch in range(num_epochs):
    for batch in train_dataloader:
        batch = {k: v.to(device) for k, v in batch.items()}
        outputs = model(**batch)
        loss = outputs.loss
        loss.backward()

        optimizer.step()
        lr_scheduler.step()
        optimizer.zero_grad()
        progress_bar.update(1)
```

Ecco i cambiamenti necessari:

```diff
+ from accelerate import Accelerator
  from torch.optim import AdamW
  from transformers import AutoModelForSequenceClassification, get_scheduler

+ accelerator = Accelerator()

  model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2)
  optimizer = AdamW(model.parameters(), lr=3e-5)

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

+ train_dataloader, eval_dataloader, model, optimizer = accelerator.prepare(
+     train_dataloader, eval_dataloader, model, optimizer
+ )

  num_epochs = 3
  num_training_steps = num_epochs * len(train_dataloader)
  lr_scheduler = get_scheduler(
      "linear",
      optimizer=optimizer,
      num_warmup_steps=0,
      num_training_steps=num_training_steps
  )

  progress_bar = tqdm(range(num_training_steps))

  model.train()
  for epoch in range(num_epochs):
      for batch in train_dataloader:
-         batch = {k: v.to(device) for k, v in batch.items()}
          outputs = model(**batch)
          loss = outputs.loss
-         loss.backward()
+         accelerator.backward(loss)

          optimizer.step()
          lr_scheduler.step()
          optimizer.zero_grad()
          progress_bar.update(1)
```

Prima di tutto bisogna inserire la linea di importazione. La seconda linea istanzia un oggetto di tipo `Accelerator` che controllerà e inizializzerà il corretto ambiente distribuito. 🤗 Accelerate gestice il posizionamento sui dispositivi per voi, quindi potete togliere le linee che spostavano il modello sul dispositivo (o, se preferite, cambiare in modo da usare `acceleratore.device` invece di `device`). 

Dopodiché la maggior parte del lavoro è fatta dalla linea che invia i dataloaders, il modello e gli ottimizzatori a `accelerator.prepare()`. Ciò serve a incapsulare queli oggetti nei contenitori appropriati per far sì che l'addestramento distribuito funzioni correttamente. I cambiamenti rimanenti sono la rimozione della linea che sposta la batch sul `device` (dispositivo) (di nuovo, se volete tenerlo potete semplicemente cambiarlo con `accelerator.device`) e lo scambio di `loss.backward()` con `accelerator.backward(loss)`. 

<Tip>
⚠️ Per poter beneficiare dell'accelerazione offerta da Cloud TPUs, è raccomandabile applicare padding ad una lunghezza fissa tramite gli argomenti `padding="max_length"` e `max_length` del tokenizer.
</Tip>

Se volete copiare e incollare il codice per giocarci, ecco un ciclo di addestramento completo che usa 🤗 Accelerate:

```py
from accelerate import Accelerator
from torch.optim import AdamW
from transformers import AutoModelForSequenceClassification, get_scheduler

accelerator = Accelerator()

model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2)
optimizer = AdamW(model.parameters(), lr=3e-5)

train_dl, eval_dl, model, optimizer = accelerator.prepare(
    train_dataloader, eval_dataloader, model, optimizer
)

num_epochs = 3
num_training_steps = num_epochs * len(train_dl)
lr_scheduler = get_scheduler(
    "linear",
    optimizer=optimizer,
    num_warmup_steps=0,
    num_training_steps=num_training_steps,
)

progress_bar = tqdm(range(num_training_steps))

model.train()
for epoch in range(num_epochs):
    for batch in train_dl:
        outputs = model(**batch)
        loss = outputs.loss
        accelerator.backward(loss)

        optimizer.step()
        lr_scheduler.step()
        optimizer.zero_grad()
        progress_bar.update(1)
```

Mettere questo codice in uno script `train.py` lo renderà eseguibile su qualsiasi ambiente distribuito. Per provarlo nel vostro ambiente distribuito, eseguite:

```bash
accelerate config
```

che vi chiederà di rispondere ad alcune domande e inserirà le vostre risposte in un documento di configurazione usato dal comando:

```
accelerate launch train.py
```

che eseguirà l'addestramento distribuito.

Se volete provarlo in un Notebook (ad esempio, per testarlo con le TPUs su Colab), incollate il codice in una `training_function()` ed eseguite l'ultima cella con:

```python
from accelerate import notebook_launcher

notebook_launcher(training_function)
```

Potete trovare altri esempi nella [🤗 Accelerate repo](https://github.com/huggingface/accelerate/tree/main/examples).


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter3/4.mdx" />

### Processare i dati
https://huggingface.co/learn/course/it/chapter3/2.md

# Processare i dati

{#if fw === 'pt'}

<DocNotebookDropdown
  classNames="absolute z-10 right-0 top-0"
  options={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/it/chapter3/section2_pt.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/it/chapter3/section2_pt.ipynb"},
]} />

{:else}

<DocNotebookDropdown
  classNames="absolute z-10 right-0 top-0"
  options={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/it/chapter3/section2_tf.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/it/chapter3/section2_tf.ipynb"},
]} />

{/if}

{#if fw === 'pt'}
Continuando l'esempio del [capitolo precedente](/course/chapter2), ecco come addestrare un classificatore di sequenze su un'unica batch in PyTorch:

```python
import torch
from torch.optim import AdamW
from transformers import AutoTokenizer, AutoModelForSequenceClassification

# Same as before
checkpoint = "bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = AutoModelForSequenceClassification.from_pretrained(checkpoint)
sequences = [
    "I've been waiting for a HuggingFace course my whole life.",
    "This course is amazing!",
]
batch = tokenizer(sequences, padding=True, truncation=True, return_tensors="pt")

# This is new
batch["labels"] = torch.tensor([1, 1])

optimizer = AdamW(model.parameters())
loss = model(**batch).loss
loss.backward()
optimizer.step()
```
{:else}
Continuando l'esempio del [capitolo precedente](/course/chapter2), ecco come addestrare un classificatore di sequenze su un'unica batch in TensorFlow:

```python
import tensorflow as tf
import numpy as np
from transformers import AutoTokenizer, TFAutoModelForSequenceClassification

# Same as before
checkpoint = "bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint)
sequences = [
    "I've been waiting for a HuggingFace course my whole life.",
    "This course is amazing!",
]
batch = dict(tokenizer(sequences, padding=True, truncation=True, return_tensors="tf"))

# This is new
model.compile(optimizer="adam", loss="sparse_categorical_crossentropy")
labels = tf.convert_to_tensor([1, 1])
model.train_on_batch(batch, labels)
```
{/if}

Ovviamente, addestrare il modello su due frasi non porterà a dei risultati molto buoni. Per ottenere risultati migliori, si deve preparare un dataset più grande.

In questa sezione verrà usato come esempio il dataset MRPC (Microsoft Research Paraphrase Corpus), presentato nell'[articolo](https://www.aclweb.org/anthology/I05-5002.pdf) di William B. Dolan e Chris Brockett. Il dataset contiene 5801 coppie di frasi, con una label che indica se l'una è una parafrasi dell'altra (i.e. se hanno lo stesso significato). È stato selezionato per questo capitolo perché è un dataset piccolo, con cui è facile sperimentare durante l'addestramento.

### Caricare un dataset dall'Hub

{#if fw === 'pt'}
<Youtube id="_BZearw7f0w"/>
{:else}
<Youtube id="W_gMJF0xomE"/>
{/if}

L'Hub non contiene solo modelli; contiene anche molti dataset in tante lingue diverse. I dataset possono essere esplorati [qui](https://huggingface.co/datasets), ed è consigliato tentare di caricare e processare un nuovo dataset dopo aver completato questa sezione (cfr. la [documentazione](https://huggingface.co/docs/datasets/loading). Per ora, focalizziamoci sul dataset MRPC! Questo è uno dei 10 dataset che fanno parte del [GLUE benchmark](https://gluebenchmark.com/), che è un benchmark accademico usato per misurare la performance di modelli ML su 10 compiti di classificazione del testo.

La libreria 🤗 Datasets fornisce un comando molto semplice per scaricare e mettere nella cache un dataset sull'Hub. Il dataset MRPC può essere scaricato così:

<Tip>
⚠️ **Attenzione** Assicurati che `datasets` sia installato eseguendo `pip install datasets`. Poi, carica il dataset MRPC e stampalo per vedere cosa contiene.
</Tip>

```py
from datasets import load_dataset

raw_datasets = load_dataset("glue", "mrpc")
raw_datasets
```

```python out
DatasetDict({
    train: Dataset({
        features: ['sentence1', 'sentence2', 'label', 'idx'],
        num_rows: 3668
    })
    validation: Dataset({
        features: ['sentence1', 'sentence2', 'label', 'idx'],
        num_rows: 408
    })
    test: Dataset({
        features: ['sentence1', 'sentence2', 'label', 'idx'],
        num_rows: 1725
    })
})
```

Il risultato è un oggetto di tipo `DatasetDict` che contiene il training set, il validation set, e il test set. Ciascuno di questi contiene svariate colonne, (`sentence1`, `sentence2`, `label`, e `idx`) a un numero variabile di righe, corrispondenti al numero di elementi in ogni set (quindi, vi sono 3668 coppie di frasi nel training set, 408 nel validation set, e 1725 nel test set).

Questo comando scarica il dataset e lo mette in cache, in *~/.cache/huggingface/dataset* secondo l'impostazione predefinita. Nel Capitolo 2 è stato spiegato come personalizzare la cartella di cache impostando la variabile d'ambiente `HF_HOME`.

Ogni coppia di frasi nell'oggetto `raw_datasets` può essere ottenuta tramite il suo indice, come in un dizionario:

```py
raw_train_dataset = raw_datasets["train"]
raw_train_dataset[0]
```

```python out
{'idx': 0,
 'label': 1,
 'sentence1': 'Amrozi accused his brother , whom he called " the witness " , of deliberately distorting his evidence .',
 'sentence2': 'Referring to him as only " the witness " , Amrozi accused his brother of deliberately distorting his evidence .'}
```

Le label sono già numeri interi, quindi non è necessario alcun preprocessing. Per sapere a quale numero corrisponde quale tipo di label, si possono analizzare le `features` del `raw_train_dataset`. Ciò permette di capire la tipologia di ogni colonna:


```py
raw_train_dataset.features
```

```python out
{'sentence1': Value(dtype='string', id=None),
 'sentence2': Value(dtype='string', id=None),
 'label': ClassLabel(num_classes=2, names=['not_equivalent', 'equivalent'], names_file=None, id=None),
 'idx': Value(dtype='int32', id=None)}
```

Dietro le quinte, `label` è del tipo  `ClassLabel`, e la corrispondenza tra i numeri e i nomi delle label è contenuta nella cartella *names*. `0` corrisponde a `not_equivalent` (significato diverso), e `1` corrisponde a `equivalent` (stesso significato).

<Tip>

✏️ **Prova tu!** Quali sono le label dell'elemento 15 del training set, e 87 del validation set?

</Tip>

### Preprocessing del dataset

{#if fw === 'pt'}
<Youtube id="0u3ioSwev3s"/>
{:else}
<Youtube id="P-rZWqcB6CE"/>
{/if}

Per preprocessare il dataset, è necessario convertire il testo in numeri comprensibili al modello. Come dimostrato nel [capitolo precedente](/course/chapter2), ciò viene fatto con un tokenizer (tokenizzatore). Il tokenizer prende come input sia una frase sia una lista di frasi, quindi è possibile effettuare la tokenizzazione di tutte le prime e seconde frasi di ogni coppia in questo modo:

```py
from transformers import AutoTokenizer

checkpoint = "bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
tokenized_sentences_1 = tokenizer(raw_datasets["train"]["sentence1"])
tokenized_sentences_2 = tokenizer(raw_datasets["train"]["sentence2"])
```

Tuttavia, non si possono semplicemente passare al modello due frasi e sperare di predire se l'una è una parafrasi dell'altra o no. Bisogna gestire le due frasi come una coppia, e applicare il preprocessing necessario. Fortunatamente, il tokenizer può anche prendere come input una coppia di frasi e prepararla nel formato atteso dal modello BERT:

```py
inputs = tokenizer("This is the first sentence.", "This is the second one.")
inputs
```

```python out
{ 
  'input_ids': [101, 2023, 2003, 1996, 2034, 6251, 1012, 102, 2023, 2003, 1996, 2117, 2028, 1012, 102],
  'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1],
  'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
}
```

Sono state già discusse nel [Capitolo 2](/course/chapter2) le chiavi `input_ids` e `attention_mask`, ma il discorso su `token_type_ids` era stato rimandato. In questo esempio, ciò può essere usato per indicare al modello quale parte dell'input è la prima frase, e quale la seconda. 

<Tip>

✏️ **Prova tu!** Prendere l'element 15 del training set e tokenizzare le due frasi sia separatamente, sia come coppia. Qual è la differenza tra i due risultati?

</Tip>

Decodificando gli ID in `input_ids` per ritrasformarli in parole:

```py
tokenizer.convert_ids_to_tokens(inputs["input_ids"])
```

si ottiene:

```python out
['[CLS]', 'this', 'is', 'the', 'first', 'sentence', '.', '[SEP]', 'this', 'is', 'the', 'second', 'one', '.', '[SEP]']
```

Perciò è chiaro che il modello si aspetta gli input nella forma `[CLS] frase1 [SEP] frase2 [SEP]` quando vi sono due frasi. Allineando con `token_type_ids` si ottiene:

```python out
['[CLS]', 'this', 'is', 'the', 'first', 'sentence', '.', '[SEP]', 'this', 'is', 'the', 'second', 'one', '.', '[SEP]']
[      0,      0,    0,     0,       0,          0,   0,       0,      1,    1,     1,        1,     1,   1,       1]
```

Le parti dell'input corrispondenti a `[CLS] frase1 [SEP]` hanno tutte un token type ID di `0`, mentre le altre parti, corrispondenti quindi a `frase2 [SEP]`, hanno tutte un token type ID di `1`.

Da notare che se viene selezionato un altro checkpoint, gli input tokenizzati non conterranno necessariamente i `token_type_ids` (ad esempio, non si ottengono usando un modello DistilBERT). I `token_type_ids` si ottengono solo quando il modello saprebbe che farne, avendole già viste in fase di pre-addestramento.

In questo caso, BERT è stato pre-addestrato con i token type IDs, e in aggiunta all'obiettivo di _masked language modeling_ di cui si era parlato nel [Capitolo 1](/course/chapter1), vi è un altro obiettivo che si chiama _next sentence prediction_ (_predire la prossima frase_). Lo scopo di questo task è modellizzare la relazione tra coppie di frasi.

Durante un task di next sentence prediction, il modello riceve una coppia di frasi (con token mascherati in maniera aleatoria) e deve predire se la seconda segue la prima. Per rendere il task meno banale, la metà delle volte le frasi si susseguono nel documento da cui erano state estratte originariamente, l'altra metà delle volte le frasi provengono da due documenti diversi.

In generale, non bisogna preoccuparsi se i `token_type_ids` sono presenti o no negli input tokenizzati: finché viene usato lo stesso checkpoint per il tokenizer e il modello, tutto andrà bene poiché il tokenizer sa cosa fornire al modello.

Ora che abbiamo visto come il tokenizer può gestire una coppia di frasi, possiamo usarlo per tokenizzare l'intero dataset: come nel [capitolo precedente](/course/chapter2), si può fornire al tokenizer una lista di coppie di frasi dando prima la lista delle prime frasi, e poi la lista delle seconde frasi. Questo approcchio è anche compatibile le opzioni di padding e truncation già viste nel [Capitolo 2](/course/chapter2). Perciò, un modo per preprocessare il dataset di addestramento è:

```py
tokenized_dataset = tokenizer(
    raw_datasets["train"]["sentence1"],
    raw_datasets["train"]["sentence2"],
    padding=True,
    truncation=True,
)
```

Questo metodo funziona, ma ha lo svantaggio di restituire un dizionario (avente `input_ids`, `attention_mask`, e `token_type_ids` come chiavi, e delle liste di liste come valori). Oltretutto, questo metodo funziona solo se si ha a disposizione RAM sufficiente per contenere l'intero dataset durante la tokenizzazione (mentre i dataset dalla libreria 🤗 Datasets sono file [Apache Arrow](https://arrow.apache.org/) archiviati su disco, perciò in memoria vengono caricati solo i campioni richiesti).

Per tenere i dati come dataset, utilizzare il metodo [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.map). Ciò permette anche della flessibilità extra, qualora fosse necessario del preprocessing aggiuntivo oltre alla tokenizzazione. Il metodo `map()` applica una funziona ad ogni elemento del dataset, perciò bisogna definire una funzione che tokenizzi gli input:

```py
def tokenize_function(example):
    return tokenizer(example["sentence1"], example["sentence2"], truncation=True)
```

Questa funzione riceve un dizionario (come gli elementi del nostro dataset) e restituisce un nuovo dizionario con input_ids`, `attention_mask`, e `token_type_ids` come chiavi. Funziona anche se il dizionario `example` contiene svariati campioni (ad una chiave corrisponde una lista di frasi) poiché il `tokenizer` funziona con liste di coppie di frasi, come già visto. Ciò permette di usare l'opzione `batched=True` nella chiamata a `map()`, che accelererà di molto la tokenizzazione. Il `tokenizer` si appoggia ad un tokenizer scritto in Rust della libreria [🤗 Tokenizers](https://github.com/huggingface/tokenizers). Questo tokenizer può essere molto veloce, ma solo se gli vengono forniti molti input insieme. 

Per ora non ci siamo preoccupati del parametro `padding` nella nostra funzione di tokenizzazione. Questo perché il padding di tutti i campioni fino a lunghezza massima non è efficiente: è meglio fare il padding dei campioni quando stiamo assemblando una batch, poiché in quel momento è necessario il padding solo fino alla lunghezza massima nel batch, non la lunghezza massima nell'intero dataset. Ciò permette di risparmiare molto tempo e potenza di calcolo nel caso in cui gli input abbiano lunghezze molto varie! 

Ecco come si applica la funzione di tokenizzazione sull'intero dataset. Bisogna usare `batched=True` nella chiamata a `map` in modo tale che la funzione venga applicata a vari elementi del dataset insieme, e non ad ogni elemento separatamente. Ciò permette un preprocessing più rapido. 

```py
tokenized_datasets = raw_datasets.map(tokenize_function, batched=True)
tokenized_datasets
```

La libreria 🤗 Datasets aggiunge nuovi campi ai dataset, uno per ogni chiave nel dizionario restituito dalla funzione di preprocessing:

```python out
DatasetDict({
    train: Dataset({
        features: ['attention_mask', 'idx', 'input_ids', 'label', 'sentence1', 'sentence2', 'token_type_ids'],
        num_rows: 3668
    })
    validation: Dataset({
        features: ['attention_mask', 'idx', 'input_ids', 'label', 'sentence1', 'sentence2', 'token_type_ids'],
        num_rows: 408
    })
    test: Dataset({
        features: ['attention_mask', 'idx', 'input_ids', 'label', 'sentence1', 'sentence2', 'token_type_ids'],
        num_rows: 1725
    })
})
```

Si può anche applicare il multiprocessing durante il preprocessing con la funzione `map()` utilizzando il parametro `num_proc`. Ciò non è stato dimostrato qui perché la libreria 🤗 Tokenizers già utilizza vari thread per tokenizzare i campioni più rapidamente, ma nel caso in cui non venga usato un tokenizer rapido di questa libreria, ciò potrebbe velocizzare il preprocessing. 

La funzione `tokenize_function` restituisce un dizionario con `input_ids`, `attention_mask`, e `token_type_ids` come chiavi, quindi quei tre campi vengono aggiunti a tutti gli split (le parti) del dataset. Si possono anche cambiare i campi esistenti nel caso in cui la funzione di preprocessing restituisca un nuovo valore per una chiave già esistente nel dataset a cui viene applicato `map()`.

L'ultima cosa da fare è il padding di tutti i campioni alla lunghezza dell'elemento più lungo quando sono inseriti in una batch — una tecnica che si chiama *dynamic padding*.

### Dynamic padding

<Youtube id="7q5NyFT8REg"/>

{#if fw === 'pt'}
La funzione responsabile dell'assembramento dei campioni in una batch si chiama *collate function* (*funzione di raccolta*). È uno dei parametri che si possono passare quando si costruisce un `DataLoader`, e il default è la funzione che converte semplicemente i campioni in tensori PyTorch e li concatena (ricorsivamente nel caso in cui gli elementi siano liste, tuple o dizionari). Ciò non sarà possibile nel nostro caso poiché gli input non hanno tutti la stessa lunghezza. Abbiamo rimandato il padding apposta, per poterlo applicare secondo necessità ad ogni batch, evitando quindi input troppo lunghi con molto padding. Ciò accelererà l'addestramento di un bel po', ma può causare problemi se l'addestramento avviene su TPU — le TPU preferiscono dimensioni fisse, anche se ciò richiede del padding in più. 

{:else}

La funzione responsabile dell'assembramento dei campioni in una batch si chiama *collate function* (*funzione di raccolta*). Il collator (raccoglitore) di default è la funzione che converte semplicemente i campioni in tf.Tensor e li concatena (ricorsivamente nel caso in cui gli elementi siano liste, tuple o dizionari). Ciò non sarà possibile nel nostro caso poiché gli input non hanno tutti la stessa lunghezza. Abbiamo rimandato il padding apposta, per poterlo applicare secondo necessità ad ogni batch, evitando quindi input troppo lunghi con molto padding. Ciò accelererà l'addestramento di un bel po', ma può causare problemi se l'addestramento avviene su TPU — le TPU preferiscono dimensioni fisse, anche se ciò richiede del padding in più. 

{/if}

In pratica, bisogna definire una collate function che applichi la giusta quantità di padding agli elementi del dataset in una stessa batch. Fortunatamente, la libreria 🤗 Transformers fornisce questa funziona tramite `DataCollatorWithPadding`. Essa prende in input un tokenizer quando viene istanziata (per individuare quale token da usare per il padding, e se il modello si aspetta padding a sinistra o a destra dell'input) e farà tutto il necessario:

{#if fw === 'pt'}
```py
from transformers import DataCollatorWithPadding

data_collator = DataCollatorWithPadding(tokenizer=tokenizer)
```
{:else}
```py
from transformers import DataCollatorWithPadding

data_collator = DataCollatorWithPadding(tokenizer=tokenizer, return_tensors="tf")
```
{/if}

Per testare questo nuovo gioco, analizziamo alcuni campioni dal set di addestramento da raggruppare in un batch. Adesso togliamo le colonne  `idx`, `sentence1`, e `sentence2` poiché non saranno necessarie e contengono stringhe (e non si possono creare tensori con stringhe), e controlliamo le lunghezze di ogni elemento nel batch:

```py
samples = tokenized_datasets["train"][:8]
samples = {k: v for k, v in samples.items() if k not in ["idx", "sentence1", "sentence2"]}
[len(x) for x in samples["input_ids"]]
```

```python out
[50, 59, 47, 67, 59, 50, 62, 32]
```

Nulla di sorprendente, i campioni hanno lunghezza variabile da 32 a 67. Il padding dinamico significa che i campioni in questo batch dovrebbero tutti ricevere un padding fino alla lunghezza di 67, il massimo nel batch. Senza padding dinamico, tutti i campioni dovrebbero ricevere un padding fino alla lunghezza massima nell'intero dataset, o la lunghezza massima processabile dal modello. Bisogna controllare che il `data_collator` stia applicando un padding dinamico al batch in maniera corretta:

```py
batch = data_collator(samples)
{k: v.shape for k, v in batch.items()}
```

{#if fw === 'tf'}

```python out
{'attention_mask': TensorShape([8, 67]),
 'input_ids': TensorShape([8, 67]),
 'token_type_ids': TensorShape([8, 67]),
 'labels': TensorShape([8])}
```

{:else}

```python out
{'attention_mask': torch.Size([8, 67]),
 'input_ids': torch.Size([8, 67]),
 'token_type_ids': torch.Size([8, 67]),
 'labels': torch.Size([8])}
```

Ottimo! Adesso che siamo passati dal testo grezzo a dei batch che il modello è in grado di trattare, siamo pronti per affinarlo!

{/if}

<Tip>

✏️ **Prova tu!** Replicare il preprocessing sul dataset GLUE SST-2. È leggermente diverso poiche è composto da frasi singole e non da coppie di frasi, ma il resto della procedura dovrebbe essere simile. Per una sfida più complessa, provare a scrivere una funzione di preprocessing che funzioni per qualsiasi dei compiti in GLUE. 

</Tip>

{#if fw === 'tf'}

Ora che sono stati definiti un dataset e un collator di dati, dobbiamo metterli insieme. Si potrebbero caricare e raccogliere i batch manualmente, ma significherebbe molto lavoro e probabilmente una bassa performance. Invece, vi è un metodo semplice che offre una soluzione con buona performance a questo problema: `to_tf_dataset()`. Questo impacchetterà il dataset con `tf.data.Dataset`, con una collate function opzionale.
`tf.data.Dataset` è un formato nativo di TensorFlow che Keras può utilizzare durante `model.fit()`, cosicché questo metodo converte immediatamente un 🤗 Dataset in un formato pronto per l'addestramento. Vediamolo in azione col nostro dataset!


```py
tf_train_dataset = tokenized_datasets["train"].to_tf_dataset(
    columns=["attention_mask", "input_ids", "token_type_ids"],
    label_cols=["labels"],
    shuffle=True,
    collate_fn=data_collator,
    batch_size=8,
)

tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset(
    columns=["attention_mask", "input_ids", "token_type_ids"],
    label_cols=["labels"],
    shuffle=False,
    collate_fn=data_collator,
    batch_size=8,
)
```

Fine! Questi dataset verranno utilizzati nelle prossime lezioni, dove l'addestramento sarà reso piacevolmente immediato dopo tutto questo duro lavoro di preprocessing. 

{/if}


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter3/2.mdx" />

### Come scrivere un issue correttamente
https://huggingface.co/learn/course/it/chapter8/5.md

# Come scrivere un issue correttamente

<CourseFloatingBanner chapter={8}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/it/chapter8/section5.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/it/chapter8/section5.ipynb"},
]} />

Quando si riscontra una cosa che non va in una delle librerie di Hugging Face, dovresti assolutamente farcelo sapere così possiamo correggerla (lo stesso vale per qualsiasi libreria open source, se è per questo). Se non si è del tutto sicuri se il bug risieda nel proprio codice o in una delle nostre librerie, il primo posto da controllare è il [forum](https://discuss.huggingface.co/). La community ti aiuterà a capirlo e anche il team di Hugging Face segue da vicino le discussioni.

<Youtube id="_PAli-V4wj0"/>

Quando si è sicuri di avere un bug tra le mani, il primo passo è creare un minimo esempio riproducibile.

## Creare un minimo esempio riproducibile

È molto importante isolare il pezzo di codice che produce il bug, poiché nessuno del team di Hugging Face è un mago (ancora) e non possono risolvere ciò che non vedono. Un minimo esempio riproducibile dovrebbe, come indica il nome, essere riproducibile. Ciò significa che non deve fare affidamento su file o dati esterni. Prova a sostituire i dati che stai usando con alcuni valori fittizi che assomigliano a quelli reali e producono lo stesso errore.

<Tip>

🚨 Molti issue presenti nel repository di 🤗 Transformers sono irrisolti perché i dati utilizzati per riprodurli non sono accessibili.

</Tip>

Una volta che si ha qualcosa di autocontenuto, si può cercare di ridurlo in un numero ancora minore di righe di codice, costruendo quello che chiamiamo un _minimo esempio riproducibile_. Sebbene questo richieda un po' più di lavoro da parte tua, se fornisci un breve e chiaro esempio di bug, avrai quasi la garanzia di ricevere aiuto e una correzione.

Se ti senti abbastanza a tuo agio, vai a ispezionare il codice sorgente in cui si verifica il tuo bug. Potresti trovare una soluzione al tuo problema (nel qual caso puoi anche fare una pull request per risolverlo), ma più in generale, questo può aiutare i maintainer a capire meglio il codice quando leggono la tua segnalazione.

## Compilare il template di un issue

Quando si segnala un problema, si noterà che c'è un template da compilare. Qui seguiremo quello per [🤗 Transformers issues](https://github.com/huggingface/transformers/issues/new/choose), ma lo stesso tipo di informazioni sarà richiesto se segnali un problema in un altro repository. Non lasciate il template in bianco: prendersi il tempo di compilarlo massimizzerà le possibilità di ottenere una risposta e di risolvere il problema.

In generale, quando si segnala un problema, bisogna sempre essere cortesi. Questo è un progetto open source, quindi state usando software libero e nessuno ha l'obbligo di aiutarvi. Si possono inserire nel problema critiche giustificate, ma i maintainer potrebbero prenderle male e non avere fretta di aiutarvi. Assicuratevi di leggere il [code of conduct](https://github.com/huggingface/transformers/blob/master/CODE_OF_CONDUCT.md) del progetto.

### Includere le informazioni sul tuo ambiente di sviluppo

🤗 Transformers fornisce un'utilità per ottenere tutte le informazioni necessarie sul tuo ambiente di sviluppo. Basta digitare quanto segue nel terminale:

```
transformers-cli env
```

e si dovrebbe ottenere qualcosa di simile:

```out
Copy-and-paste the text below in your GitHub issue and FILL OUT the two last points.

- `transformers` version: 4.12.0.dev0
- Platform: Linux-5.10.61-1-MANJARO-x86_64-with-arch-Manjaro-Linux
- Python version: 3.7.9
- PyTorch version (GPU?): 1.8.1+cu111 (True)
- Tensorflow version (GPU?): 2.5.0 (True)
- Flax version (CPU?/GPU?/TPU?): 0.3.4 (cpu)
- Jax version: 0.2.13
- JaxLib version: 0.1.65
- Using GPU in script?: <fill in>
- Using distributed or parallel set-up in script?: <fill in>
```

Si può anche aggiungere un `!` all'inizio del comando `transformers-cli env` per eseguirlo da una cella del notebook e poi copiare e incollare il risultato all'inizio dell'issue.

### Taggare persone 

Taggare le persone digitando una `@` seguita dal loro handle GitHub invierà loro una notifica, in modo che vedano il problema e possano rispondere più rapidamente. Usa questo metodo con moderazione, perché le persone che tagghi potrebbero non apprezzare di ricevere una notifica per qualcosa a cui non hanno un collegamento diretto. Se hai esaminato il codice sorgente relativo al tuo bug, dovresti taggare l'ultima persona che ha apportato modifiche alla riga che ritieni responsabile del tuo problema (puoi trovare questa informazione guardando la riga in questione su GitHub, selezionandola e facendo clic su "View git blame").

Altrimenti, il template offre suggerimenti sulle persone da taggare. In generale, non taggare mai più di tre persone!

### Includere un esempio riproducibile

Se sei riuscito a creare un esempio autocontenuto che produce il bug, è il momento di includerlo! Scrivi una riga con tre backtick seguiti da `python`, come questa:

```
```python
```

quindi incolla il tuo minimo esempio riproducibile e digita una nuova riga con tre backtick. In questo modo il codice sarà formattato correttamente.

Se non sei riuscito/a a creare un esempio riproducibile, spiega in modo chiaro come sei arrivato/a al tuo problema. Se possibile, includi un link al notebook di Google Colab in cui hai riscontrato l'errore. Più informazioni si condividono, più i maintainer saranno in grado di rispondere.

In ogni caso, è necessario copiare e incollare l'intero messaggio di errore ricevuto. Se lavori in Colab, ricorda che alcuni frame potrebbero essere automaticamente compressi nella stack trace, quindi assicurati di espanderli prima di copiarli. Come nel caso dell'esempio di codice, inserisci il messaggio di errore tra due righe con tre backtick, in modo che sia formattato correttamente.

###  Descrivere il funzionamento atteso

Spiega in poche righe cosa ti aspettavi di ottenere, in modo che i maintainer abbiano una visione completa del problema. Questa parte è generalmente abbastanza ovvia, quindi dovrebbe essere contenuta in una frase, ma in alcuni casi si può avere molto da dire.

## E poi?

Una volta inviato l'issue, assicurati di controllare rapidamente che tutto sia a posto. Puoi modificare l'issue se hai commesso un errore, o anche cambiare il titolo se ti rendi conto che il problema è diverso da quello che pensavi all'inizio.

È inutile sollecitare le persone se non si ottiene una risposta. Se nessuno ti aiuta in pochi giorni, è probabile che nessuno sia in grado di risolvere il tuo problema. Non esitare a rivedere l'esempio riproducibile. Puoi renderlo più breve e più dritto al punto? Se non ricevi una risposta entro una settimana, puoi aggiungere un messaggio in cui chiedi gentilmente aiuto, soprattutto se hai modificato il tuo problema per includere ulteriori informazioni sul problema.


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter8/5.mdx" />

### Introduzione
https://huggingface.co/learn/course/it/chapter8/1.md

# Introduzione

<CourseFloatingBanner
    chapter={8}
    classNames="absolute z-10 right-0 top-0"
/>

Ora che sai come affrontare i problemi più comuni nel campo del NLP con i 🤗 Transformers, dovresti essere in grado d'iniziare a lavorare sui tuoi progetti personali! In questo capitolo descriveremo cosa fare quando si incontra un problema. Imparerai come eseguire il debug del tuo codice o del tuo training e come chiedere aiuto alla community se non riesci a risolvere il problema in autonomia. E, se pensi di aver trovato un bug in una delle librerie di Hugging Face, ti mostreremo il modo migliore per segnalarlo, in modo che il problema venga risolto il più rapidamente possibile.

Più precisamente, in questo capitolo impareremo:

- Cosa fare come prima cosa quando si riceve un errore
- Come chiedere aiuto nei [forum](https://discuss.huggingface.co/)
- Come eseguire il debug della training pipeline
- Come scrivere un issue adeguatamente

Ovviamente, niente di tutto ciò è specifico a 🤗 Transformers o all'ecosistema di Hugging Face; le lezioni di questo capitolo sono applicabili alla maggior parte dei progetti open source!


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter8/1.mdx" />

### Asking for help on the forums
https://huggingface.co/learn/course/it/chapter8/3.md

# Asking for help on the forums

<CourseFloatingBanner chapter={8}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/it/chapter8/section3.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/it/chapter8/section3.ipynb"},
]} />

<Youtube id="S2EEG3JIt2A"/>

Il [forum di Hugging Face](https://discuss.huggingface.co) è un posto ideale per ricevere aiuto dal team open source e dalla più ampia community di Hugging Face. Ecco come appare la pagina principale in un dato giorno:

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter8/forums.png" alt="The Hugging Face forums." width="100%"/>
</div>

Sul lato sinistro si possono vedere tutte le categorie in cui sono raggruppati i vari _topic_, mentre il lato destro mostra i _topic_ più recenti. Un _topic_ è un post che contiene un titolo, una categoria e una descrizione; è abbastanza simile al formato degli _issues_ di GitHub che abbiamo visto quando abbiamo creato il nostro dataset nel [Capitolo 5](/course/chapter5). Come suggerisce il nome, la categoria [Beginners](https://discuss.huggingface.co/c/beginners/5) è diretta principalmente alle persone che iniziano a lavorare con le librerie e l'ecosistema di Hugging Face. Tutte le domande sulle librerie sono benvenute qui, sia che siano per fare debug di codice sia che siano per chiedere aiuto su come fare qualcosa. (Detto questo, se la domanda riguarda una libreria in particolare, è meglio rivolgersi alla categoria corrispondente del forum).

Allo stesso modo, le categorie [Intermediate](https://discuss.huggingface.co/c/intermediate/6) e [Research](https://discuss.huggingface.co/c/research/7) sono per domande più avanzate, ad esempio sulle librerie o su novità nel campo della ricerca del NLP, di cui si vuole discutere.

E naturalmente va menzionata anche la categoria [Course](https://discuss.huggingface.co/c/course/20), dove potrai porre tutte le tue domande relative al corso Hugging Face!

Una volta selezionata la categoria, sarai pronto/a a scrivere il tuo primo _topic_. Nel forum troverai alcune [linee guida](https://discuss.huggingface.co/t/how-to-request-support/3128) su come farlo, e in questa sezione daremo un'occhiata ad alcune delle caratteristiche che contraddistinguono un buon _topic_.

## Scrivere un post nel forum correttamente

Come esempio, supponiamo di voler generare embeddings da articoli di Wikipedia per creare un motore di ricerca personalizzato. Come al solito, carichiamo il tokenizer e il modello come segue:

```python
from transformers import AutoTokenizer, AutoModel

model_checkpoint = "distilbert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(model_checkpoint)
model = AutoModel.from_pretrained(model_checkpoint)
```

Ora supponiamo di provare a creare embeddings per un'intera sezione dell'[articolo di Wikipedia](https://en.wikipedia.org/wiki/Transformers) sui Transformers (il franchise, non la libreria!):

```python
text = """
Generation One is a retroactive term for the Transformers characters that
appeared between 1984 and 1993. The Transformers began with the 1980s Japanese
toy lines Micro Change and Diaclone. They presented robots able to transform
into everyday vehicles, electronic items or weapons. Hasbro bought the Micro
Change and Diaclone toys, and partnered with Takara. Marvel Comics was hired by
Hasbro to create the backstory; editor-in-chief Jim Shooter wrote an overall
story, and gave the task of creating the characthers to writer Dennis O'Neil.
Unhappy with O'Neil's work (although O'Neil created the name "Optimus Prime"),
Shooter chose Bob Budiansky to create the characters.

The Transformers mecha were largely designed by Shōji Kawamori, the creator of
the Japanese mecha anime franchise Macross (which was adapted into the Robotech
franchise in North America). Kawamori came up with the idea of transforming
mechs while working on the Diaclone and Macross franchises in the early 1980s
(such as the VF-1 Valkyrie in Macross and Robotech), with his Diaclone mechs
later providing the basis for Transformers.

The primary concept of Generation One is that the heroic Optimus Prime, the
villainous Megatron, and their finest soldiers crash land on pre-historic Earth
in the Ark and the Nemesis before awakening in 1985, Cybertron hurtling through
the Neutral zone as an effect of the war. The Marvel comic was originally part
of the main Marvel Universe, with appearances from Spider-Man and Nick Fury,
plus some cameos, as well as a visit to the Savage Land.

The Transformers TV series began around the same time. Produced by Sunbow
Productions and Marvel Productions, later Hasbro Productions, from the start it
contradicted Budiansky's backstories. The TV series shows the Autobots looking
for new energy sources, and crash landing as the Decepticons attack. Marvel
interpreted the Autobots as destroying a rogue asteroid approaching Cybertron.
Shockwave is loyal to Megatron in the TV series, keeping Cybertron in a
stalemate during his absence, but in the comic book he attempts to take command
of the Decepticons. The TV series would also differ wildly from the origins
Budiansky had created for the Dinobots, the Decepticon turned Autobot Jetfire
(known as Skyfire on TV), the Constructicons (who combine to form
Devastator),[19][20] and Omega Supreme. The Marvel comic establishes early on
that Prime wields the Creation Matrix, which gives life to machines. In the
second season, the two-part episode The Key to Vector Sigma introduced the
ancient Vector Sigma computer, which served the same original purpose as the
Creation Matrix (giving life to Transformers), and its guardian Alpha Trion.
"""

inputs = tokenizer(text, return_tensors="pt")
logits = model(**inputs).logits
```

```python output
IndexError: index out of range in self
```

Oh-oh, abbiamo un problema -- e il messaggio di errore è molto più criptico di quelli visti nella [sezione 2](/course/chapter8/section2)! Non riusciamo a capire il traceback completo, quindi decidiamo di rivolgerci ai forum di Hugging Face per chiedere aiuto. Come potremmo creare il _topic_?

Per iniziare, dobbiamo cliccare sul pulsante "New Topic" nell'angolo in alto a destra (nota che per creare un _topic_ è necessario aver effettuato il login):

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter8/forums-new-topic.png" alt="Creating a new forum topic." width="100%"/>
</div>

Si apre un'interfaccia di scrittura in cui è possibile inserire il titolo dell'argomento, selezionare una categoria e abbozzare il contenuto:

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter8/forum-topic01.png" alt="The interface for creating a forum topic." width="100%"/>
</div>

Poiché l'errore sembra riguardare esclusivamente 🤗 Transformers, selezioneremo questa categoria. Il nostro primo tentativo di spiegare il problema potrebbe essere simile a questo:

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter8/forum-topic02.png" alt="Drafting the content for a new forum topic." width="100%"/>
</div>

Sebbene questo _topic_ contenga il messaggio di errore per il quale abbiamo bisogno di aiuto, ci sono alcuni problemi nel modo in cui è scritto:

1. Il titolo non è molto descrittivo, quindi chiunque navighi nel forum non sarà in grado di capire di cosa si tratta senza leggere anche il testo completo del _topic_.
2. Il corpo del testo non fornisce abbastanza informazioni su _da dove_ proviene l'errore e _come_ riprodurlo.
3. Nel _topic_ alcune persone sono taggate direttamente con un tono un po' esigente.

_Topic_ come questo non riceveranno probabilmente una risposta rapida (se la otterranno), quindi cerchiamo di capire come possiamo migliorarli. Cominciamo con il primo problema: la scelta di un buon titolo.

### Scegliere un titolo descrittivo

Se si sta cercando di ottenere aiuto per un bug nel codice, una buona regola è quella di includere abbastanza informazioni nel titolo, in modo che gli altri possano determinare rapidamente se pensano di poter rispondere alla domanda o meno. Nel nostro esempio, conosciamo il nome dell'eccezione che viene sollevata e abbiamo qualche indizio sul fatto che viene attivata nel _forward pass_ del modello, dove chiamiamo `model(**inputs)`. Per comunicare tutto ciò, un possibile titolo potrebbe essere:

> Source of IndexError in the AutoModel forward pass?

Questo titolo dice al lettore _da dove_ si pensa che provenga il bug e, se ha già incontrato un `IndexError`, è molto probabile che sappia come risolverlo. Naturalmente, il titolo può essere qualsiasi cosa si voglia, e altre varianti come:

> Why does my model produce an IndexError?

potrebbe anche andare bene. Ora che abbiamo un titolo descrittivo, vediamo di migliorare il corpo del testo.

### Formattare gli snippet di codice

Leggere il codice sorgente è già abbastanza difficile in un IDE, ma lo è ancora di più quando il codice viene copiato e incollato come testo normale! Fortunatamente, i forum di Hugging Face supportano l'uso di Markdown, quindi dovresti sempre racchiudere i vostri blocchi di codice con tre backtick (```) in modo da renderli più facilmente leggibili. Facciamo così per abbellire il messaggio di errore e, già che ci siamo, rendiamo il testo un po' più educato della nostra versione originale:

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter8/forum-topic03.png" alt="Our revised forum topic, with proper code formatting." width="100%"/>
</div>

Come si può vedere nello screeshot, racchiudendo i blocchi di codice tra i backtick si converte il testo grezzo in codice formattato, completo di colore! Si noti anche che i singoli backtick possono essere usati per formattare le variabili inline, come abbiamo fatto per `distilbert-base-uncased`. Questo _topic_ sembra molto migliorato e con un po' di fortuna potremmo trovare qualcuno nella community in grado di indovinare la causa dell'errore. Tuttavia, invece di affidarci alla fortuna, rendiamo la vita più facile includendo il traceback in tutti i suoi dettagli!

### Includere il traceback completo

Poiché l'ultima riga del traceback è spesso sufficiente per il debug del proprio codice, si può essere tentati di fornire solo quella nel proprio _topic_ per "risparmiare spazio". Anche se fatto con buone intenzioni, in realtà questo rende per gli altri il debug del problema _più difficile_, poiché anche le informazioni che si trovano più in alto nel traceback possono essere molto utili. Quindi, è buona pratica copiare e incollare l'_intero_ traceback, assicurandosi che sia ben formattato. Poiché questi traceback possono diventare piuttosto lunghi, alcuni preferiscono mostrarli dopo aver spiegato il codice sorgente. Facciamo così. Ora, il nostro _topic_ del forum ha questo aspetto:

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter8/forum-topic04.png" alt="Our example forum topic, with the complete traceback." width="100%"/>
</div>

Questo è molto più esplicativo e un lettore attento potrebbe notare che il problema sembra essere dovuto al passaggio di un input lungo, grazie a questa riga nel traceback:

> Token indices sequence length is longer than the specified maximum sequence length for this model (583 > 512).

Tuttavia, possiamo rendere le cose ancora più semplici fornendo il codice effettivo che ha generato l'errore. Facciamolo ora.

### Fornire un esempio riproducibile

Se hai mai provato a fare il debug del codice di qualcun altro, probabilmente hai prima cercato di ricreare il problema segnalato, in modo da poter iniziare a lavorare dal traceback per individuare l'errore. Non è diverso quando si tratta di ricevere (o dare) supporto sui forum, quindi è davvero utile poter fornire un piccolo esempio che riproduca l'errore. La metà delle volte, semplicemente facendo questo ti aiuterà a capire cosa non funziona. In ogni caso, il pezzo mancante del nostro esempio è mostrare gli _input_ che abbiamo fornito al modello. In questo modo si ottiene un esempio completo come il seguente:

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter8/forum-topic05.png" alt="The final version of our forum topic." width="100%"/>
</div>

Questo _topic_ contiene ora molte informazioni ed è scritto in modo da attirare l'attenzione della community e ottenere una risposta utile. Con queste linee guida basilari, puoi ora creare ottimi _topic_ per trovare le risposte alle tue domande su 🤗 Transformers!



<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter8/3.mdx" />

### Parte 2 completata!
https://huggingface.co/learn/course/it/chapter8/6.md

# Parte 2 completata!

<CourseFloatingBanner
    chapter={8}
    classNames="absolute z-10 right-0 top-0"
/>

Congratulazioni, hai completato la seconda parte del corso! Stiamo lavorando attivamente alla terza parte, quindi iscrivetevi alla nostra [newsletter](https://huggingface.curated.co/) per essere sicuro/a di non perdere il suo rilascio.

Ora dovresti essere in grado di risolvere una serie di problemi di NLP e di affinare o preaddestrare un modello su di essi. Non dimenticare di condividere i tuoi risultati con la community su [Model Hub](https://huggingface.co/models).

Non vediamo l'ora di vedere cosa svilupperai con le conoscenze acquisite!


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter8/6.mdx" />

### Fare il debug della training pipeline
https://huggingface.co/learn/course/it/chapter8/4.md

# Fare il debug della training pipeline

<CourseFloatingBanner chapter={8}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/it/chapter8/section4.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/it/chapter8/section4.ipynb"},
]} />

Hai scritto un bello script per addestrare o affinare un modello su un determinato compito, seguendo scrupolosamente i consigli del [Capitolo 7](/course/chapter7). Ma quando lanci il comando `trainer.train()`, succede qualcosa di orribile: si ottiene un errore 😱! O peggio, tutto sembra andare bene e il training viene eseguito senza errori, ma il modello che ne risulta fa schifo. In questa sezione mostreremo cosa è possibile fare per eseguire il debug di questo tipo di problemi.

## Fare il debug della training pipeline

<Youtube id="L-WSwUWde1U"/>

Il problema quando si ha un errore da `trainer.train()` è che potrebbe provenire da più fonti, poiché il `Trainer` di solito mette insieme molte cose. Converte i dataset in _dataloader_, quindi l'errore potrebbe essere dato da qualcosa di sbagliato nel dataset stesso, o da un problema qualche problema nel provare a raggruppare in un batch elementi del dataset. Poi prende un batch di dati e lo invia al modello, quindi il problema potrebbe anche essere nel codice del modello. Successivamente, calcola i gradienti ed esegue la fase di ottimizzazione, quindi il problema potrebbe essere nel tuo _optimizer_. E anche se tutto va bene per il training, qualcosa potrebbe andare storto durante la valutazione se c'è un problema con la metrica selezionata.

Il modo migliore per eseguire il debug di un errore che si verifica in `trainer.train()` è quello di esaminare manualmente l'intera pipeline per vedere dove le cose sono andate storte. L'errore è spesso molto facile da risolvere.

Per dimostrarlo, useremo il seguente script che ha lo scopo di affinare un modello DistilBERT sul [dataset MNLI](https://huggingface.co/datasets/glue):

```py
from datasets import load_dataset, load_metric
from transformers import (
    AutoTokenizer,
    AutoModelForSequenceClassification,
    TrainingArguments,
    Trainer,
)

raw_datasets = load_dataset("glue", "mnli")

model_checkpoint = "distilbert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(model_checkpoint)


def preprocess_function(examples):
    return tokenizer(examples["premise"], examples["hypothesis"], truncation=True)


tokenized_datasets = raw_datasets.map(preprocess_function, batched=True)
model = AutoModelForSequenceClassification.from_pretrained(model_checkpoint)

args = TrainingArguments(
    f"distilbert-finetuned-mnli",
    evaluation_strategy="epoch",
    save_strategy="epoch",
    learning_rate=2e-5,
    num_train_epochs=3,
    weight_decay=0.01,
)

metric = load_metric("glue", "mnli")


def compute_metrics(eval_pred):
    predictions, labels = eval_pred
    return metric.compute(predictions=predictions, references=labels)


trainer = Trainer(
    model,
    args,
    train_dataset=raw_datasets["train"],
    eval_dataset=raw_datasets["validation_matched"],
    compute_metrics=compute_metrics,
)
trainer.train()
```

Se provi a eseguirlo, otterrai un errore piuttosto criptico:

```python out
'ValueError: You have to specify either input_ids or inputs_embeds'
```

### Controlla i dati

Non c'è bisogno di dirlo, ma se i dati sono corrotti, il `Trainer` non sarà in grado di formare i batch e tanto meno di addestrare il modello. Quindi, per prima cosa, è necessario dare un'occhiata a cosa c'è nel training set(_insieme di addestramento_).

Per evitare di passare infinite ore a cercare di risolvere qualcosa che non è la fonte del bug, consigliamo di usare `trainer.train_dataset` per controllare l'insieme di dati e nient'altro. Quindi facciamo così:

```py
trainer.train_dataset[0]
```

```python out
{'hypothesis': 'Product and geography are what make cream skimming work. ',
 'idx': 0,
 'label': 1,
 'premise': 'Conceptually cream skimming has two basic dimensions - product and geography.'}
```

Hai notato qualcosa di sbagliato? Questo, insieme al messaggio di errore sulla mancanza di `input_ids`, dovrebbe farci capire che qui abbiamo testo, non numeri che invece il modello può interpretare. In questo caso, l'errore originale è molto fuorviante, perché il `Trainer` rimuove automaticamente le colonne che non corrispondono alla firma del modello (cioè i parametri che il modello si aspetta). Ciò significa che in questo caso tutto, a parte _label_, è stato scartato. Non c'è stato quindi nessun problema nel creare i batch di dati e poi inviarli al modello, invece è il modello che a sua volta si è lamentato di non aver ricevuto l'input corretto.

Perché i dati non sono stati processati? Abbiamo usato il metodo `Dataset.map()` sui set di dati per applicare il tokenizer a ogni campione. Ma se si osserva attentamente il codice, si noterà che abbiamo commesso un errore nel passare i training set e il validation set (_insieme di valutazione_) al `Trainer`. Qui invece di usare `tokenized_datasets`, abbiamo usato `raw_datasets` 🤦. Quindi correggiamo questo errore!

```py
from datasets import load_dataset, load_metric
from transformers import (
    AutoTokenizer,
    AutoModelForSequenceClassification,
    TrainingArguments,
    Trainer,
)

raw_datasets = load_dataset("glue", "mnli")

model_checkpoint = "distilbert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(model_checkpoint)


def preprocess_function(examples):
    return tokenizer(examples["premise"], examples["hypothesis"], truncation=True)


tokenized_datasets = raw_datasets.map(preprocess_function, batched=True)
model = AutoModelForSequenceClassification.from_pretrained(model_checkpoint)

args = TrainingArguments(
    f"distilbert-finetuned-mnli",
    evaluation_strategy="epoch",
    save_strategy="epoch",
    learning_rate=2e-5,
    num_train_epochs=3,
    weight_decay=0.01,
)

metric = load_metric("glue", "mnli")


def compute_metrics(eval_pred):
    predictions, labels = eval_pred
    return metric.compute(predictions=predictions, references=labels)


trainer = Trainer(
    model,
    args,
    train_dataset=tokenized_datasets["train"],
    eval_dataset=tokenized_datasets["validation_matched"],
    compute_metrics=compute_metrics,
)
trainer.train()
```

Questo nuovo codice ora darà un errore diverso (un miglioramento!):

```python out
'ValueError: expected sequence of length 43 at dim 1 (got 37)'
```

Osservando il traceback, si nota che l'errore si verifica nel punto in cui i dati vengono raccolti:

```python out
~/git/transformers/src/transformers/data/data_collator.py in torch_default_data_collator(features)
    105                 batch[k] = torch.stack([f[k] for f in features])
    106             else:
--> 107                 batch[k] = torch.tensor([f[k] for f in features])
    108 
    109     return batch
```

Quindi, bisogna concentrarsi su questo. Prima di farlo, però, finiamo d'ispezionare i nostri dati, per essere sicuri al 100% che siano corretti.

Una cosa da fare sempre quando si esegue il debug di una sessione di addestramento è dare un'occhiata agli input del modello decodificati. Non possiamo dare un senso ai numeri che gli diamo direttamente in pasto, quindi dobbiamo guardare cosa rappresentano quei numeri. Nella computer vision, ad esempio, ciò significa guardare le immagini decodificate dei pixel passati, nel campo del riconoscimento vocale significa ascoltare i campioni audio decodificati e per il nostro esempio di NLP significa usare il nostro tokenizer per decodificare gli input:

```py
tokenizer.decode(trainer.train_dataset[0]["input_ids"])
```

```python out
'[CLS] conceptually cream skimming has two basic dimensions - product and geography. [SEP] product and geography are what make cream skimming work. [SEP]'
```

Questo sembra corretto. Si dovrebbe fare così per tutte le chiavi degli input:

```py
trainer.train_dataset[0].keys()
```

```python out
dict_keys(['attention_mask', 'hypothesis', 'idx', 'input_ids', 'label', 'premise'])
```

Si noti che le chiavi che non corrispondono a input accettati dal modello saranno automaticamente scartate, quindi qui terremo solo `input_ids`, `attention_mask` e `label` (che sarà rinominata `labels`). Per ricontrollare la firma del modello, si può stampare la classe del modello e poi controllare la sua documentazione:

```py
type(trainer.model)
```

```python out
transformers.models.distilbert.modeling_distilbert.DistilBertForSequenceClassification
```

Quindi, nel nostro caso, possiamo controllare i parametri accettati in [questa pagina](https://huggingface.co/transformers/model_doc/distilbert.html#distilbertforsequenceclassification). Il `Trainer` registrerà anche le colonne che sta scartando.

Abbiamo controllato che gli ID in ingresso siano corretti decodificandoli. Il prossimo passo è la `attention_mask`:

```py
trainer.train_dataset[0]["attention_mask"]
```

```python out
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
```

Poiché non abbiamo applicato il padding nel nostro preprocessing, questo sembra perfettamente naturale. Per essere sicuri che non ci siano problemi con la attention mask (_maschera di attenzione_), controlliamo che sia della stessa lunghezza dei nostri ID di input:

```py
len(trainer.train_dataset[0]["attention_mask"]) == len(
    trainer.train_dataset[0]["input_ids"]
)
```

```python out
True
```

Bene! Infine, controlliamo la nostra label:

```py
trainer.train_dataset[0]["label"]
```

```python out
1
```

Come gli ID degli input, si tratta di un numero che non ha senso di per sé. Come abbiamo visto prima, la mappa tra gli interi e i nomi delle label è memorizzata all'interno dell'attributo `names` della corrispondente *feature* del dataset:

```py
trainer.train_dataset.features["label"].names
```

```python out
['entailment', 'neutral', 'contradiction']
```

Quindi `1` significa `neutral` (_neutro_), il che significa che le due frasi viste sopra non sono in contraddizione e che la prima non implica la seconda. Sembra corretto!

Non abbiamo token type ID (_ID del tipo di token_) qui, perché DistilBERT non li prevede; se li hai nel tuo modello, devi anche assicurarti che corrispondano correttamente alla posizione della prima e della seconda frase nell'input.

<Tip>

✏️ **Prova tu!** Controlla che tutto sia corretto nel secondo elemento del training set.

</Tip>

In questo caso, il controllo viene effettuato solo sul training set, ma è necessario ricontrollare allo stesso modo anche il validation set e il test set.

Ora che sappiamo che i nostri set di dati sono corretti, è il momento di verificare la fase successiva della pipeline di addestramento.

### Dai dataset ai dataloader

La prossima cosa che può andare storta nella pipeline di addestramento è quando il `Trainer` cerca di formare dei batch dal training o dal validation set. Una volta che si è sicuri che i set di dati del `Trainer` sono corretti, si può provare a formare manualmente un batch eseguendo quanto segue (sostituire `train` con `eval` per il dataloader di validazione):

```py
for batch in trainer.get_train_dataloader():
    break
```

Questo codice crea il training dataloader (_caricatore di dati di addestramento_), quindi lo itera, fermandosi alla prima iterazione. Se il codice viene eseguito senza errori, si ha il primo batch di addestramento che può essere ispezionato; se il codice dà errore, si sa con certezza che il problema è nel dataloader, come in questo caso:

```python out
~/git/transformers/src/transformers/data/data_collator.py in torch_default_data_collator(features)
    105                 batch[k] = torch.stack([f[k] for f in features])
    106             else:
--> 107                 batch[k] = torch.tensor([f[k] for f in features])
    108 
    109     return batch

ValueError: expected sequence of length 45 at dim 1 (got 76)
```

L'ispezione dell'ultimo frame del traceback dovrebbe essere sufficiente a fornire un indizio, ma cerchiamo di scavare un po' più a fondo. La maggior parte dei problemi durante la creazione dei batch si verifica a causa del raggruppamento degli esempi in un singolo batch, quindi la prima cosa da controllare in caso di dubbio è quale `collate_fn` il tuo `DataLoader` sta usando:

```py
data_collator = trainer.get_train_dataloader().collate_fn
data_collator
```

```python out
<function transformers.data.data_collator.default_data_collator(features: List[InputDataClass], return_tensors='pt') -> Dict[str, Any]>
```

È il `default_data_collator`, ma non è quello che vogliamo in questo caso. Vogliamo che i nostri esempi siano espansi fino ad essere come la frase più lunga del batch, cosa che viene fatta dal collettore `DataCollatorWithPadding`. Questo collatore di dati dovrebbe essere usato di default da `Trainer`, quindi perché non viene usato qui?

La risposta è che non abbiamo passato il `tokenizer` al `Trainer`, quindi non ha potuto creare il `DataCollatorWithPadding` che volevamo. In pratica, non si dovrebbe mai esitare a passare esplicitamente il collettore di dati che si vuole usare, per essere sicuri di evitare questo tipo di errori. Adattiamo il nostro codice per fare esattamente questo:

```py
from datasets import load_dataset, load_metric
from transformers import (
    AutoTokenizer,
    AutoModelForSequenceClassification,
    DataCollatorWithPadding,
    TrainingArguments,
    Trainer,
)

raw_datasets = load_dataset("glue", "mnli")

model_checkpoint = "distilbert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(model_checkpoint)


def preprocess_function(examples):
    return tokenizer(examples["premise"], examples["hypothesis"], truncation=True)


tokenized_datasets = raw_datasets.map(preprocess_function, batched=True)
model = AutoModelForSequenceClassification.from_pretrained(model_checkpoint)

args = TrainingArguments(
    f"distilbert-finetuned-mnli",
    evaluation_strategy="epoch",
    save_strategy="epoch",
    learning_rate=2e-5,
    num_train_epochs=3,
    weight_decay=0.01,
)

metric = load_metric("glue", "mnli")


def compute_metrics(eval_pred):
    predictions, labels = eval_pred
    return metric.compute(predictions=predictions, references=labels)


data_collator = DataCollatorWithPadding(tokenizer=tokenizer)

trainer = Trainer(
    model,
    args,
    train_dataset=tokenized_datasets["train"],
    eval_dataset=tokenized_datasets["validation_matched"],
    compute_metrics=compute_metrics,
    data_collator=data_collator,
    tokenizer=tokenizer,
)
trainer.train()
```

La buona notizia? Non riceviamo più lo stesso errore di prima, il che è sicuramente un miglioramento. La cattiva notizia? Otteniamo invece un famigerato errore CUDA:

```python out
RuntimeError: CUDA error: CUBLAS_STATUS_ALLOC_FAILED when calling `cublasCreate(handle)`
```

Questo è un male perché gli errori di CUDA sono estremamente difficili da debuggare in generale. Vedremo tra poco come risolvere questo problema, ma prima terminiamo l'analisi della creazione di batch.

Se siete sicuri che il tuo collettore di dati è quello giusto, dovresti provare ad applicarlo su un paio di campioni del tuo set di dati:

```py
data_collator = trainer.get_train_dataloader().collate_fn
batch = data_collator([trainer.train_dataset[i] for i in range(4)])
```

Questo codice fallirà perché il `train_dataset` contiene colonne di tipo stringa, che il `Trainer` solitamente rimuove. È possibile rimuoverle manualmente o, se si vuole replicare esattamente ciò che il `Trainer` fa dietro le quinte, si può chiamare il metodo privato `Trainer._remove_unused_columns()` che fa questo:

```py
data_collator = trainer.get_train_dataloader().collate_fn
actual_train_set = trainer._remove_unused_columns(trainer.train_dataset)
batch = data_collator([actual_train_set[i] for i in range(4)])
```

Se l'errore persiste, si potrebbe eseguire manualmente il debug di ciò che accade all'interno del collettore di dati.

Ora che abbiamo eseguito il debug del processo di creazione del batch, è il momento di passarne uno attraverso il modello!

### Passaggio attraverso il modello

Dovrebbe essere possibile ottenere un batch eseguendo il seguente comando:

```py
for batch in trainer.get_train_dataloader():
    break
```

Se si esegue questo codice in un notebook, è possibile che si verifichi un errore CUDA simile a quello visto in precedenza, nel qual caso è necessario riavviare il notebook e rieseguire l'ultimo snippet senza la riga `trainer.train()`. Questa è la seconda cosa più fastidiosa degli errori CUDA: rompono irrimediabilmente il kernel. La cosa più fastidiosa è che sono difficili da debuggare.

Perché? Questo ha a che fare con il modo in cui funzionano le GPU. Sono estremamente efficienti nell'eseguire molte operazioni in parallelo, ma l'inconveniente è che quando una di queste istruzioni produce un errore, non lo si sa immediatamente. È solo quando il programma chiama una sincronizzazione dei processi multipli sulla GPU che esso si accorge che qualcosa è andato storto, quindi l'errore viene effettivamente sollevato in un punto che non ha niente a che fare con ciò che lo ha creato. Per esempio, se guardiamo il nostro traceback precedente, l'errore è stato sollevato durante il backward pass (_percorso discendente_), ma vedremo tra un minuto che in realtà deriva da qualcosa nel forward pass (_percorso ascendente_).

Come si fa a fare il debug di questi errori? La risposta è semplice: non lo facciamo. A meno che l'errore CUDA non sia un errore out-of-memory (il che significa che la memoria della GPU non è sufficiente), si dovrebbe sempre tornare alla CPU per eseguire il debug.

Per fare questo nel nostro caso, dobbiamo semplicemente rimettere il modello sulla CPU e chiamarlo sul nostro batch -- il batch restituito dal `DataLoader` non è ancora stato spostato sulla GPU:

```python
outputs = trainer.model.cpu()(**batch)
```

```python out
~/.pyenv/versions/3.7.9/envs/base/lib/python3.7/site-packages/torch/nn/functional.py in nll_loss(input, target, weight, size_average, ignore_index, reduce, reduction)
   2386         )
   2387     if dim == 2:
-> 2388         ret = torch._C._nn.nll_loss(input, target, weight, _Reduction.get_enum(reduction), ignore_index)
   2389     elif dim == 4:
   2390         ret = torch._C._nn.nll_loss2d(input, target, weight, _Reduction.get_enum(reduction), ignore_index)

IndexError: Target 2 is out of bounds.
```

Quindi, il quadro si fa più chiaro. Invece di avere un errore CUDA, ora abbiamo un `IndexError` nel calcolo della loss (_funzione di perdita_) (quindi niente a che fare con il backward pass, come abbiamo detto prima). Più precisamente, possiamo vedere che è il target 2 a creare l'errore, quindi questo è un ottimo momento per controllare il numero di label del nostro modello:

```python
trainer.model.config.num_labels
```

```python out
2
```

Con due label, solo gli 0 e gli 1 sono ammessi come target, ma secondo il messaggio di errore abbiamo ottenuto un 2. Ottenere un 2 è in realtà normale: se ricordiamo i nomi delle etichette che abbiamo estratto in precedenza, ce n'erano tre, quindi abbiamo gli indici 0, 1 e 2 nel nostro dataset. Il problema è che non l'abbiamo detto al nostro modello, il quale si sarebbe dovuto creare con tre label. Quindi, risolviamo il problema!

```py
from datasets import load_dataset, load_metric
from transformers import (
    AutoTokenizer,
    AutoModelForSequenceClassification,
    DataCollatorWithPadding,
    TrainingArguments,
    Trainer,
)

raw_datasets = load_dataset("glue", "mnli")

model_checkpoint = "distilbert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(model_checkpoint)


def preprocess_function(examples):
    return tokenizer(examples["premise"], examples["hypothesis"], truncation=True)


tokenized_datasets = raw_datasets.map(preprocess_function, batched=True)
model = AutoModelForSequenceClassification.from_pretrained(model_checkpoint, num_labels=3)

args = TrainingArguments(
    f"distilbert-finetuned-mnli",
    evaluation_strategy="epoch",
    save_strategy="epoch",
    learning_rate=2e-5,
    num_train_epochs=3,
    weight_decay=0.01,
)

metric = load_metric("glue", "mnli")


def compute_metrics(eval_pred):
    predictions, labels = eval_pred
    return metric.compute(predictions=predictions, references=labels)


data_collator = DataCollatorWithPadding(tokenizer=tokenizer)

trainer = Trainer(
    model,
    args,
    train_dataset=tokenized_datasets["train"],
    eval_dataset=tokenized_datasets["validation_matched"],
    compute_metrics=compute_metrics,
    data_collator=data_collator,
    tokenizer=tokenizer,
)
```

Non abbiamo ancora incluso la riga `trainer.train()`, per prendere tempo e verificare che tutto sia a posto. Se richiediamo un batch e lo passiamo al nostro modello, ora funziona senza errori!

```py
for batch in trainer.get_train_dataloader():
    break

outputs = trainer.model.cpu()(**batch)
```

Il passo successivo consiste nel tornare a usare la GPU e verificare che tutto funzioni ancora:

```py
import torch

device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")
batch = {k: v.to(device) for k, v in batch.items()}

outputs = trainer.model.to(device)(**batch)
```

Se si verifica ancora un errore, assicurarsi di riavviare il notebook ed eseguire solo l'ultima versione dello script.

### Esecuzione di un passaggio di ottimizzazione

Ora che sappiamo che possiamo costruire batch che passano effettivamente attraverso il modello, siamo pronti per la fase successiva della pipeline di addestramento: calcolare i gradienti ed eseguire una fase di ottimizzazione.

La prima parte consiste nel richiamare il metodo `backward()` sulla loss:

```py
loss = outputs.loss
loss.backward()
```

È abbastanza raro che si verifichi un errore in questa fase, ma se si verifica, assicurati di tornare ad usare la CPU per ottenere un messaggio di errore più utile.

Per eseguire la fase di ottimizzazione, è sufficiente creare l'oggetto `optimizer` e richiamare il suo metodo `step()`:

```py
trainer.create_optimizer()
trainer.optimizer.step()
```

Anche in questo caso, se si utilizza l'ottimizzatore predefinito nel `Trainer`, non si dovrebbe ottenere un errore in questa fase, ma se hai un ottimizzatore personalizzato, potrebbero esserci dei problemi da risolvere. Non dimenticare di tornare alla CPU se ottieni uno strano errore CUDA in questa fase. A proposito di errori CUDA, prima abbiamo menzionato un caso speciale. Vediamo ora questo caso.

### Come gestire gli errori out-of-memory di CUDA

Ogni volta che si riceve un messaggio di errore che inizia con `RuntimeError: CUDA out of memory`, indica che la memoria della GPU è esaurita. Questo errore non è direttamente collegato al codice e può verificarsi anche con uno script che funziona perfettamente. Questo errore significa che si è tentato di mettere troppe cose nella memoria interna della GPU e che si è verificato un errore. Come per altri errori di CUDA, è necessario riavviare il kernel per poter eseguire nuovamente l'allenamento.

Per risolvere questo problema, è sufficiente utilizzare meno spazio sulla GPU, cosa che spesso è più facile a dirsi che a farsi. Per prima cosa, assicuratevi di non avere due modelli sulla GPU contemporaneamente (a meno che non sia necessario per il vostro problema, ovviamente). Poi, è probabile che si debba ridurre la dimensione del batch, in quanto influisce direttamente sulle dimensioni di tutti gli output intermedi del modello e dei loro gradienti. Se il problema persiste, si può considerare di utilizzare una versione più piccola del modello.

<Tip>

Nella prossima parte del corso, esamineremo tecniche più avanzate che possono aiutare a ridurre l'impatto sulla memoria e ad affinare i modelli più grandi.

</Tip>

### Valutazione del modello

Ora che abbiamo risolto tutti i problemi con il nostro codice, tutto è perfetto e l'addestramento dovrebbe girare senza intoppi, giusto? Non così veloce! Se si esegue il comando `trainer.train()`, all'inizio sembrerà tutto a posto, ma dopo un po' si otterrà il seguente risultato:

```py
# This will take a long time and error out, so you shouldn't run this cell
trainer.train()
```

```python out
TypeError: only size-1 arrays can be converted to Python scalars
```

Ti accorgerai che questo errore compare durante la fase di valutazione, quindi è l'ultima cosa che dobbiamo debuggare.

È possibile eseguire il ciclo di valutazione del `Trainer` indipendentemente dall'addestramento, in questo modo:

```py
trainer.evaluate()
```

```python out
TypeError: only size-1 arrays can be converted to Python scalars
```

<Tip>

💡 Bisogna sempre assicurarsi di poter eseguire `trainer.evaluate()` prima di lanciare `trainer.train()`, per evitare di sprecare molte risorse di calcolo prima di incorrere in un errore.

</Tip>

Prima di tentare il debug di un problema nel ciclo di valutazione, è necessario assicurarsi di aver dato un'occhiata ai dati, di essere in grado di generare correttamente un batch e di poter eseguire il modello su di esso. Abbiamo completato tutti questi passaggi, quindi il codice seguente può essere eseguito senza errori:

```py
for batch in trainer.get_eval_dataloader():
    break

batch = {k: v.to(device) for k, v in batch.items()}

with torch.no_grad():
    outputs = trainer.model(**batch)
```

L'errore arriva più tardi, alla fine della fase di valutazione, e se guardiamo il traceback vediamo questo:

```python trace
~/git/datasets/src/datasets/metric.py in add_batch(self, predictions, references)
    431         """
    432         batch = {"predictions": predictions, "references": references}
--> 433         batch = self.info.features.encode_batch(batch)
    434         if self.writer is None:
    435             self._init_writer()
```

Questo ci dice che l'errore ha origine nel modulo `datasets/metric.py`, quindi si tratta di un problema con la nostra funzione `compute_metrics()`. La funzione accetta una tupla con i logit e le label come array NumPy, quindi proviamo a dargliela in pasto:

```py
predictions = outputs.logits.cpu().numpy()
labels = batch["labels"].cpu().numpy()

compute_metrics((predictions, labels))
```

```python out
TypeError: only size-1 arrays can be converted to Python scalars
```

Otteniamo lo stesso errore, quindi il problema risiede sicuramente in quella funzione. Se guardiamo al suo codice, vediamo che sta solo trasferendo le `predictions` e le `labels` a `metric.compute()`. C'è quindi un problema con questo metodo? Non proprio. Diamo una rapida occhiata alle dimensioni:

```py
predictions.shape, labels.shape
```

```python out
((8, 3), (8,))
```

Le nostre previsioni sono ancora dei logit, non le vere previsioni, ed è per questo che la metrica restituisce questo errore (un po' oscuro). La soluzione è abbastanza semplice: basta aggiungere un argmax nella funzione `compute_metrics()`:

```py
import numpy as np


def compute_metrics(eval_pred):
    predictions, labels = eval_pred
    predictions = np.argmax(predictions, axis=1)
    return metric.compute(predictions=predictions, references=labels)


compute_metrics((predictions, labels))
```

```python out
{'accuracy': 0.625}
```

Ora il nostro errore è stato risolto! Questo era l'ultimo, quindi il nostro script ora addestrerà correttamente un modello.

Per riferimento, ecco lo script completamente corretto:

```py
import numpy as np
from datasets import load_dataset, load_metric
from transformers import (
    AutoTokenizer,
    AutoModelForSequenceClassification,
    DataCollatorWithPadding,
    TrainingArguments,
    Trainer,
)

raw_datasets = load_dataset("glue", "mnli")

model_checkpoint = "distilbert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(model_checkpoint)


def preprocess_function(examples):
    return tokenizer(examples["premise"], examples["hypothesis"], truncation=True)


tokenized_datasets = raw_datasets.map(preprocess_function, batched=True)
model = AutoModelForSequenceClassification.from_pretrained(model_checkpoint, num_labels=3)

args = TrainingArguments(
    f"distilbert-finetuned-mnli",
    evaluation_strategy="epoch",
    save_strategy="epoch",
    learning_rate=2e-5,
    num_train_epochs=3,
    weight_decay=0.01,
)

metric = load_metric("glue", "mnli")


def compute_metrics(eval_pred):
    predictions, labels = eval_pred
    predictions = np.argmax(predictions, axis=1)
    return metric.compute(predictions=predictions, references=labels)


data_collator = DataCollatorWithPadding(tokenizer=tokenizer)

trainer = Trainer(
    model,
    args,
    train_dataset=tokenized_datasets["train"],
    eval_dataset=tokenized_datasets["validation_matched"],
    compute_metrics=compute_metrics,
    data_collator=data_collator,
    tokenizer=tokenizer,
)
trainer.train()
```

In questo caso, non ci sono più problemi e il nostro script affinerà un modello che dovrebbe dare risultati ragionevoli. Ma cosa possiamo fare quando l'addestramento procede senza errori e il modello addestrato non funziona affatto bene? Questa è la parte più difficile di machine learning e ti mostreremo alcune tecniche che possono aiutarti.

<Tip>

💡 Se si utilizza un ciclo di addestramento manuale, per il debug della pipeline di addestramento valgono gli stessi passaggi, ma è più facile separarli. Assicurati però di non aver dimenticato il `model.eval()` o il `model.train()` nei punti giusti, o lo `zero_grad()` a ogni passo!

</Tip>

## Debug degli errori silenziosi durante l'addestramento

Cosa possiamo fare per eseguire il debug di un addestramento che viene completato senza errori, ma che non produce buoni risultati? Qui ti daremo alcuni suggerimenti, ma sappi che questo tipo di debugging è la parte più difficile di machine learning e non esiste una soluzione magica.

### Controllare i dati (di nuovo!)

Il tuo modello imparerà qualcosa solo se è effettivamente possibile imparare qualcosa dai tuoi dati. Se c'è un bug che corrompe i dati o le label sono assegnate in modo casuale, è molto probabile che non si riesca ad addestrare il modello sul dataset. Quindi, inizia sempre con un doppio controllo degli input e delle label decodificate e poniti le seguenti domande:

- I dati decodificati sono comprensibili?
- Sei d'accordo con le label?
- C'è una label più comune delle altre?
- Quale dovrebbe essere la funzione di perdita/metrica se il modello predicesse una risposta a caso/sempre la stessa risposta?

<Tip warning={true}>

⚠️ Se effettui un addestramento in modo distribuito, stampa campioni del set di dati in ogni processo e controlla molto attentamente che ottieni la stessa cosa. Un bug comune è la presenza di una qualche fonte di casualità nella creazione dei dati che fa sì che ogni processo abbia una versione diversa del set di dati.

</Tip>

Dopo aver esaminato i dati, esamina alcune previsioni del modello e decodificale. Se il modello prevede sempre la stessa cosa, potrebbe essere perché il tuo set di dati è influenzato verso una categoria (per i problemi di classificazione); tecniche come fare oversampling (_sovra-campionamento_) delle classi rare potrebbero aiutare.

Se la funzione di perdita/metrica ottenuta con il tuo modello iniziale è molto diversa da quella che ci si aspetterebbe per le previsioni casuali, ricontrolla il modo in cui viene calcolata la funzione o la metrica, perché probabilmente c'è un bug. Se si utilizzano diverse funzioni che aggiungi alla fine, assicurati che siano della stessa grandezza.

Quando sei sicuro/a che i dati sono perfetti, puoi verificare se il modello è in grado di addestrarsi su di essi con un semplice test.

### Fare overfitting del modello su un batch

L'overfitting è di solito qualcosa che cerchiamo di evitare durante l'addestramento, poiché significa che il modello non sta imparando a riconoscere le proprietà generali che vogliamo, ma sta invece memorizzando i campioni di addestramento. Tuttavia, provare ad addestrare il modello su un batch più e più volte è un buon test per verificare se il problema così come è stato inquadrato può essere risolto dal modello che si sta cercando di addestrare. Inoltre, ti aiuterà a capire se il learning rate (_tasso di apprendimento_) iniziale è troppo alta.

Una volta definito il `Trainer`, è molto semplice: basta prendere un batch dal training set, ed eseguire un piccolo ciclo di addestramento manuale utilizzando solo quel batch per qualcosa come 20 step:

```py
for batch in trainer.get_train_dataloader():
    break

batch = {k: v.to(device) for k, v in batch.items()}
trainer.create_optimizer()

for _ in range(20):
    outputs = trainer.model(**batch)
    loss = outputs.loss
    loss.backward()
    trainer.optimizer.step()
    trainer.optimizer.zero_grad()
```

<Tip>

💡 Se i dati di addestramento sono sbilanciati, assicurati di creare un batch di dati di addestramento contenente tutte le label.

</Tip>

Il modello risultante dovrebbe avere risultati quasi perfetti sullo stesso `batch`. Calcoliamo la metrica sulle previsioni risultanti:

```py
with torch.no_grad():
    outputs = trainer.model(**batch)
preds = outputs.logits
labels = batch["labels"]

compute_metrics((preds.cpu().numpy(), labels.cpu().numpy()))
```

```python out
{'accuracy': 1.0}
```

100% di accuratezza, questo è un bell'esempio di overfitting (il che significa che se provi il tuo modello su qualsiasi altra frase, molto probabilmente ti darà una risposta sbagliata)!

Se non si riesci a far sì che il modello ottenga risultati perfetti come questo, significa che c'è qualcosa di sbagliato nel modo in cui si è impostato il problema o con i dati, e quindi dovresti risolvere questa cosa. Solo quando riesci a superare il test di overfitting puoi essere sicuro/a che il tuo modello possa effettivamente imparare qualcosa.

<Tip warning={true}>

⚠️ Sarà necessario ricreare il modello e il `Trainer` dopo questo test, poiché il modello ottenuto probabilmente non sarà in grado di recuperare e imparare qualcosa di utile sul set di dati completo.

</Tip>

### Non calibrare niente prima di avere una prima baseline

Hyperparameter tuning (_calibrazione degli iperparametri_) è sempre considerato come la parte più difficile di machine learning, ma è solo l'ultimo passo per aiutarti a migliorare un po' la metrica. Nella maggior parte dei casi, gli iperparametri predefiniti del `Trainer` funzionano bene per dare buoni risultati, quindi non ci si deve lanciare in una ricerca di iperparametri dispendiosa in termini di tempo e di costi, finché non si è ottenuto qualcosa che batta la baseline (_base di partenza_) che si ha sul dataset.

Una volta ottenuto un modello sufficientemente buono, si può iniziare a modificarlo un po'. Non provare a eseguire l'addestramento un migliaio di volte con iperparametri diversi, ma confronta un paio di esecuzioni che hanno valori diversi per un iperparametro così da avere un'idea di quale abbia il maggiore impatto.

Se stai modificando il modello stesso, mantieni le cose semplici e non provare nulla che non possa essere ragionevolmente giustificato. Assicurati sempre di rifare il test di overfitting per verificare che la modifica non abbia avuto conseguenze indesiderate.

### Chiedere aiuto

Speriamo che in questa sezione tu abbia trovato qualche consiglio utile a risolvere il tuo problema, ma se così non fosse, ricordati che puoi sempre chiedere aiuto alla community nei [forum](https://discuss.huggingface.co/). 

Qui di seguito sono riportate alcune risorse aggiuntive che potrebbero rivelarsi utili:

- ["Reproducibility as a vehicle for engineering best practices"](https://docs.google.com/presentation/d/1yHLPvPhUs2KGI5ZWo0sU-PKU3GimAk3iTsI38Z-B5Gw/edit#slide=id.p) di Joel Grus
- ["Checklist for debugging neural networks"](https://towardsdatascience.com/checklist-for-debugging-neural-networks-d8b2a9434f21) di Cecelia Shao
- ["How to unit test machine learning code"](https://medium.com/@keeper6928/how-to-unit-test-machine-learning-code-57cf6fd81765) di Chase Roberts
- ["A Recipe for Training Neural Networks"](http://karpathy.github.io/2019/04/25/recipe/) di Andrej Karpathy

Naturalmente, non tutti i problemi che incontrerai durante l'addestramento delle reti neurali sono colpa tua! Se si incontra qualcosa nella libreria 🤗 Transformers o 🤗 Datasets che non sembra corretto, è possibile che si sia trovato un bug. Dovresti assolutamente segnalarcelo e nella prossima sezione ti spiegheremo esattamente come fare.


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter8/4.mdx" />

### Quiz di fine capitolo
https://huggingface.co/learn/course/it/chapter8/7.md

# Quiz di fine capitolo

<CourseFloatingBanner
    chapter={8}
    classNames="absolute z-10 right-0 top-0"
/>

Mettiamo alla prova quello che hai imparato in questo capitolo!

### 1. In quale ordine si deve leggere un traceback di Python?

<Question
	choices={[
		{
			text: "Dall'alto verso il basso",
			explain: "Riprova -- sebbene la maggior parte degli altri linguaggi di programmazione stampi gli errori in alto, Python è unico in questo senso."
		},
		{
			text: "Dal basso verso l'alto",
			explain: "Corretto! Un vantaggio dei traceback di Python, che mostrano l'errore in fondo, è che è più facile fare il debug quando si lavora nel terminale e questa è l'ultima riga che si vede.",
			correct: true
		}
	]}
/>

### 2. Che cos'è un minimo esempio riproducibile?

<Question
	choices={[
		{
			text: "Una semplice implementazione di un'architettura Transformer tratta da un articolo di ricerca",
			explain: "Anche se è molto formativo implementare i propri modelli Transformer da zero, non è di questo che stiamo parlando."
		},
		{
			text: "Un blocco di codice compatto e autocontenuto che può essere eseguito senza alcuna dipendenza esterna da file o dati privati",
			explain: "Corretto! Minimi esempi riproducibili aiutano i maintainers della libreria a riprodurre il problema che si sta verificando, in modo da trovare soluzioni più velocemente",
			correct: true
		},
		{
			text: "Uno screenshot della traceback di Python",
			explain: "Riprova -- anche se è allettante includere una schermata dell'errore che si sta riscontrando quando si invia un issue, questo rende molto difficile per gli altri riprodurre l'errore"
		},
		{
			text: "Un notebook che contiene la tua analisi intera, comprese le parti non correlate all'errore",
			explain: "Non proprio -- anche se può essere utile condividere un notebook di Google Colab che mostri l'errore, assicurati che sia breve e che contenga solo il codice rilevante"
		}
	]}
/>

### 3. Supponiamo di provare a eseguire il codice seguente, il quale produce un errore:

```py
from transformers import GPT3ForSequenceClassification

# ImportError: cannot import name 'GPT3ForSequenceClassification' from 'transformers' (/Users/lewtun/miniconda3/envs/huggingface/lib/python3.8/site-packages/transformers/__init__.py)
# ---------------------------------------------------------------------------
# ImportError                               Traceback (most recent call last)
# /var/folders/28/k4cy5q7s2hs92xq7_h89_vgm0000gn/T/ipykernel_30848/333858878.py in <module>
# ----> 1 from transformers import GPT3ForSequenceClassification

# ImportError: cannot import name 'GPT3ForSequenceClassification' from 'transformers' (/Users/lewtun/miniconda3/envs/huggingface/lib/python3.8/site-packages/transformers/__init__.py)
```

Quale dei seguenti potrebbe essere una buona scelta per il titolo di un topic del forum per chiedere aiuto?

<Question
	choices={[
		{
			text: "<code>ImportError: cannot import name 'GPT3ForSequenceClassification' from 'transformers' (/Users/lewtun/miniconda3/envs/huggingface/lib/python3.8/site-packages/transformers/__init__.py)</code>",
			explain: "Includere l'ultima riga del traceback può essere esplicativo, ma è meglio riservarlo al corpo principale del topic. Riprov!"
		},
		{
			text: "Problema con <code>from transformers import GPT3ForSequenceClassification</code>",
			explain: "Riprova -- sebbene questo fornisca informazioni utili, è probabilmente meglio riservarle al corpo principale del testo.",
		},
		{
			text: "Perché non posso importare  <code>GPT3ForSequenceClassification</code>?",
			explain: "Ottima scelta! Questo titolo è conciso e dà al lettore un indizio su ciò che potrebbe essere sbagliato (ad esempio, che il GPT-3 non è supportato nei 🤗 Transformers).",
			correct: true
		},
		{
			text: "GPT-3 è supportato in 🤗 Transformers?",
			explain: "Buona questa! Usare domande come titoli dei topic è un ottimo modo per comunicare il problema alla community.",
			correct: true
		}
	]}
/>

### 4. Supponiamo di aver provato a eseguire `trainer.train()` e di trovarci di fronte a un errore criptico che non ci dice esattamente da dove proviene. Quale dei seguenti è il primo posto in cui cercare gli errori nella training pipeline?

<Question
	choices={[
		{
			text: "La fase di ottimizzazione in cui si calcolano i gradienti e si esegue la backpropagation",
			explain: "Anche se potrebbero esserci dei bug nell'ottimizzatore, di solito si tratta di diverse fasi della training pipeline, quindi ci sono altre cose da controllare prima. Riprova!"
		},
		{
			text: "La fase di valutazione in cui si calcolano le metriche",
			explain: "La valutazione è di solito fatta dopo aver fatto training per un'intera epoch, quindi dovresti controllare in qualche punto della training pipeline precedente.",
		},
		{
			text: "I dataset",
			explain: "Corretto! Dare un'occhiata ai dati è quasi sempre la prima cosa da fare, per assicurarsi che il testo sia codificato correttamente, che abbia le dimensioni previste e così via.",
			correct: true
		},
		{
			text: "I dataloader",
			explain: "Prova ancora -- è molto vicino alla prima cosa che si dovrebbe controllare. Ti ricordi quale oggetto forniamo ai dataloader?"
		}
	]}
/>

### 5. Qual è il modo migliore per fare il debug di un errore CUDA?

<Question
	choices={[
		{
			text: "Pubblicare il messaggio di errore sul forum o su GitHub.",
			explain: "Questo non aiuterà nessuno, poiché i messaggi di errore di CUDA sono solitamente poco esplicativi."
		},
		{
			text: "Eseguire lo stesso codice sulla CPU.",
			explain: "Esattamente, questo dovrebbe darti un messaggio di errore migliore!",
			correct: true
		},
		{
			text: "Leggere il traceback per scoprire cosa ha causato l'errore.",
			explain: "È quello che si farebbe per qualsiasi altro errore, ma gli errori di CUDA di solito non vengono segnalati nel punto in cui si sono verificati, perché la maggior parte delle operazioni di CUDA sono asincrone."
		},
		{
			text: "Ridurre la dimensione del batch.",
			explain: "Ridurre la dimensione del batch è di solito una buona strategia per gestire gli errori out-of-memory di CUDA, ma non per questo particolare problema. Riprova!"
		},
		{
			text: "Riavviare il Jupyter kernel.",
			explain: "Riprova -- riavviare il kernel non farà scomparire magicamente l'errore!",
		}
	]}
/>

### 6. Qual è il modo migliore per far risolvere un problema su GitHub?

<Question
	choices={[
		{
			text: "Pubblicare un esempio completo e riproducibile del bug.",
			explain: "Sì, questo è il modo migliore per aiutare i maintainer a trovare il tuo bug. Cos'altro si dovrebbe fare?",
			correct: true
		},
		{
			text: "Chiedere un aggiornamento ogni giorno.",
			explain: "È improbabile che questo ti aiuti; probabilmente la gente ti ignorerà di più.",
		},
		{
			text: "Ispezionare il codice sorgente intorno al bug e cercare di trovare il motivo per cui si verifica. Pubblicare i risultati nel problema.",
			explain: "Questo aiuterà sicuramente i maintainer! E se si trova la fonte del bug e una soluzione, si può anche aprire una pull request. Cos'altro dovreste fare?",
			correct: true
		}
	]}
/>

### 7. Perché l'overfitting di un batch è di solito una buona tecnica di debugging?

<Question
	choices={[
		{
			text: "Non lo è; l'overfitting è sempre un male e va evitato.",
			explain: "Quando si fa l'addestramento sull'intero dataset, l'overfitting può essere un segno che il modello non generalizzerà bene a nuovi esempi. Per il debug, tuttavia, di solito non si addestra sull'intero dataset. Riprova!"
		},
		{
			text: "Ci permette di verificare che il modello sia in grado di ridurre la loss a zero.",
			explain: "Corretto! Con un piccolo batch di soli due esempi, possiamo verificare rapidamente se il modello è in grado di apprendere.",
			correct: true
		},
		{
			text: "Ci permette di verificare che le dimensioni dei tensori dei nostri input e delle nostre label siano corrette.",
			explain: "Prova ancora -- se le dimensioni dei tensori sono scorrette, non sarai certamente in grado di fare l'addestramento, nemmeno su un singolo batch.",
		}
	]}
/>

### 8. Perché è una buona idea includere dettagli sul proprio ambiente di sviluppo con `transformers-cli env` quando si crea un nuovo issue nel repo di 🤗 Transformers?

<Question
	choices={[
		{
			text: "Permette ai maintainer di capire quale versione della libreria si sta utilizzando.",
			explain: "Corretto! Poiché ogni versione principale della libreria può presentare modifiche all'API, sapere quale versione specifica si sta utilizzando può aiutare a circoscrivere il problema. Quali sono gli altri vantaggi?",
			correct: true
		},
		{
			text: "Permette ai maintainer di sapere se il codice viene eseguito su Windows, macOS o Linux.",
			explain: "Corretto! A volte gli errori possono essere causati dallo specifico sistema operativo in uso e saperlo aiuta i maintainer a riprodurli localmente. Ma non è il solo motivo.",
			correct: true
		},
		{
			text: "Permette ai maintainer di sapere se il codice viene eseguito su una GPU o su una CPU.",
			explain: "Corretto! Come abbiamo visto in questo capitolo, il codice eseguito su GPU o CPU può produrre risultati o errori diversi e sapere quale hardware si sta usando può aiutare a concentrare l'attenzione dei maintainer. Ma questo non è l'unico vantaggio...",
			correct: true
		}
	]}
/>


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter8/7.mdx" />

### Fare il debug di una training pipeline
https://huggingface.co/learn/course/it/chapter8/4_tf.md

# Fare il debug di una training pipeline

<CourseFloatingBanner chapter={8}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/it/chapter8/section4_tf.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/it/chapter8/section4_tf.ipynb"},
]} />

Hai scritto un bello script per addestrare o affinare un modello su un determinato compito, seguendo scrupolosamente i consigli del [Capitolo 7](/course/chapter7). Ma quando lanci il comando `model.fit()`, succede qualcosa di orribile: si ottiene un errore 😱! O peggio, tutto sembra andare bene e il training viene eseguito senza errori, ma il modello che ne risulta fa schifo. In questa sezione mostreremo cosa è possibile fare per eseguire il debug di questo tipo di problemi.

## Debugging the training pipeline

<Youtube id="N9kO52itd0Q"/>

Il problema quando si ha un errore da `model.fit()` è che potrebbe provenire da più fonti, poichè la fase di training di solito mette insieme molte cose su cui si è lavorato fino a quel momento. Il problema potrebbe essere qualcosa di sbagliato nel tuo dataset, o qualche problema nel provare a raggruppare in un batch elementi del dataset. E anche se tutto va bene per il training, qualcosa potrebbe andare storto durante la valutazione se c'è un problema con la metrica selezionata.

Il modo migliore per eseguire il debug di un errore che si verifica in `model.fit()` è quello di esaminare manualmente l'intera pipeline per vedere dove le cose sono andate storte. L'errore è spesso molto facile da risolvere.

Per dimostrarlo, useremo il seguente script che ha lo scopo di affinare un modello DistilBERT sul [dataset MNLI](https://huggingface.co/datasets/glue):

```py
from datasets import load_dataset, load_metric
from transformers import (
    AutoTokenizer,
    TFAutoModelForSequenceClassification,
)

raw_datasets = load_dataset("glue", "mnli")

model_checkpoint = "distilbert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(model_checkpoint)


def preprocess_function(examples):
    return tokenizer(examples["premise"], examples["hypothesis"], truncation=True)


tokenized_datasets = raw_datasets.map(preprocess_function, batched=True)

train_dataset = tokenized_datasets["train"].to_tf_dataset(
    columns=["input_ids", "labels"], batch_size=16, shuffle=True
)

validation_dataset = tokenized_datasets["validation_matched"].to_tf_dataset(
    columns=["input_ids", "labels"], batch_size=16, shuffle=True
)

model = TFAutoModelForSequenceClassification.from_pretrained(model_checkpoint)

model.compile(loss="sparse_categorical_crossentropy", optimizer="adam")

model.fit(train_dataset)
```

Se si tenta di eseguirlo, si potrebbero riscontrare alcuni `VisibleDeprecationWarning` durante la conversione del dataset -- si tratta di un problema UX noto, quindi si prega di ignorarlo. Se stai leggendo il corso dopo, diciamo, novembre 2021 e il problema si ripresenta ancora, invia dei tweet di disappunto a @carrigmat finché non lo risolve.

Il problema più grave, però, è che riceviamo un vero e proprio errore. Ed è davvero terribilmente lungo:

```python out
ValueError: No gradients provided for any variable: ['tf_distil_bert_for_sequence_classification/distilbert/embeddings/word_embeddings/weight:0', '...']
```

Che cosa significa? Abbiamo provato ad dare training sui nostri dati, ma non abbiamo ottenuto alcun gradiente? Questo è piuttosto preoccupante; come possiamo iniziare a fare il debug di una cosa del genere? Quando l'errore che si ottiene non suggerisce immediatamente dove sia il problema, la soluzione migliore è spesso quella di procedere in ordine, assicurandosi in ogni fase che tutto sia corretto. Naturalmente, il punto di partenza è sempre...

### Controllare i dati

Non c'è bisogno di dirlo, ma se i dati sono danneggiati, Keras non sarà in grado di risolverli per te. Quindi, per prima cosa, è necessario dare un'occhiata a cosa c'è nel training set.

Anche se c'è la tentazione di guardare in `raw_datasets` e `tokenized_datasets`, si consiglia vivamente di esaminare i dati proprio nel punto in cui entrano nel modello. Ciò significa leggere un output dal `tf.data.Dataset` creato con la funzione `to_tf_dataset()`! Come si fa? Gli oggetti `tf.data.Dataset` ci forniscono volta per volta interi batch e non supportano l'indicizzazione, quindi non possiamo semplicemente chiedere `train_dataset[0]`. Possiamo però chiedere gentilmente un batch:

```py
for batch in train_dataset:
    break
```

`break` termina il ciclo dopo un'iterazione, quindi prende il primo batch che esce da `train_dataset` e lo salva come `batch`. Ora, diamo un'occhiata a ciò che c'è dentro:

```python out
{'attention_mask': <tf.Tensor: shape=(16, 76), dtype=int64, numpy=
 array([[1, 1, 1, ..., 0, 0, 0],
        [1, 1, 1, ..., 0, 0, 0],
        [1, 1, 1, ..., 0, 0, 0],
        ...,
        [1, 1, 1, ..., 1, 1, 1],
        [1, 1, 1, ..., 0, 0, 0],
        [1, 1, 1, ..., 0, 0, 0]])>,
 'label': <tf.Tensor: shape=(16,), dtype=int64, numpy=array([0, 2, 1, 2, 1, 1, 2, 0, 0, 0, 1, 0, 1, 2, 2, 1])>,
 'input_ids': <tf.Tensor: shape=(16, 76), dtype=int64, numpy=
 array([[ 101, 2174, 1010, ...,    0,    0,    0],
        [ 101, 3174, 2420, ...,    0,    0,    0],
        [ 101, 2044, 2048, ...,    0,    0,    0],
        ...,
        [ 101, 3398, 3398, ..., 2051, 2894,  102],
        [ 101, 1996, 4124, ...,    0,    0,    0],
        [ 101, 1999, 2070, ...,    0,    0,    0]])>}
```

Sembra corretto, non è vero? Stiamo passando al modello le `labels`, le `attention_mask` e gli `input_ids`, che dovrebbero essere tutto ciò di cui ha bisogno per calcolare gli output e la loss (_funzione di perdita_). Perché non abbiamo un gradiente? Guarda meglio: stiamo passando un singolo dizionario come input, ma un batch di addestramento è di solito un tensore o un dizionario di input, più un tensore di label. Le label sono solo una chiave del dizionario di input.

È un problema? Non sempre, in realtà! Ma è uno dei problemi più comuni che si incontrano quando si addestrano modelli Transformer con TensorFlow. Tutti i nostri modelli possono calcolare la loss internamente, ma per farlo è necessario passare le label nel dizionario di input. Questa è la funzione che viene utilizzata quando non si specifica un valore di loss in `compile()`. Keras, invece, di solito si aspetta che le label siano passate separatamente dal dizionario di input e le computazioni delle loss di solito falliscono se non lo si fa.

Il problema è ora più chiaro: abbiamo usato un argomento `loss`, il che significa che stiamo chiedendo a Keras di calcolare le loss per noi, ma abbiamo passato le nostre label come input al modello, non come label nel posto in cui Keras se le aspetta! Dobbiamo scegliere l'una o l'altra soluzione: o usiamo la funzione interna del modello e manteniamo le label dove sono, oppure continuiamo a usare le loss di Keras, ma spostiamo le label nel punto in cui Keras se le aspetta. Per semplicità, adottiamo il primo approccio. Cambia la chiamata a `compile()` in:

```py
model.compile(optimizer="adam")
```

Ora utilizzeremo la funzione di perdita interna del modello e il problema dovrebbe essere risolto!

<Tip>

✏️ **Prova tu!** Come sfida opzionale, dopo aver risolto gli altri problemi, puoi provare a tornare a questo passaggio e a far funzionare il modello con la loss originale calcolata da Keras invece che con la loss interna. È necessario aggiungere `"labels"` all'argomento `label_cols` di `to_tf_dataset()` per assicurarsi che le label siano fornite correttamente, in modo da ottenere i gradienti, ma c'è un altro problema con la loss che abbiamo specificato. L'addestramento continuerà a funzionare con questo problema, ma l'apprendimento sarà molto lento e si bloccherà a una loss di addestramento elevata. Riesci a capire di cosa si tratta?

Un suggerimento codificato in ROT13, se sei bloccato/a: Vs lbh ybbx ng gur bhgchgf bs FrdhraprPynffvsvpngvba zbqryf va Genafsbezref, gurve svefg bhgchg vf `ybtvgf`. Jung ner ybtvgf?

E un secondo indizio: Jura lbh fcrpvsl bcgvzvmref, npgvingvbaf be ybffrf jvgu fgevatf, Xrenf frgf nyy gur nethzrag inyhrf gb gurve qrsnhygf. Jung nethzragf qbrf FcnefrPngrtbevpnyPebffragebcl unir, naq jung ner gurve qrsnhygf?

</Tip>

Ora proviamo ad avviare l'addestramento. Ora dovremmo ottenere i gradienti, quindi, se tutto va bene (musica minacciosa), possiamo chiamare `model.fit()` e tutto funzionerà bene!

```python out
  246/24543 [..............................] - ETA: 15:52 - loss: nan
```

Oh no.

`nan` non è un valore di loss molto incoraggiante. Tuttavia, abbiamo controllato i nostri dati e sembrano abbastanza buoni. Se il problema non è questo, come possiamo procedere? Il passo successivo più ovvio è...

### Controllare il modello

`model.fit()` è un'ottima funzionionalità di Keras, ma fa un sacco di cose per te e questo può rendere più difficile trovare esattamente dove si è generato un problema. Se stai facendo il debug del modello, una strategia che può essere molto utile è quella di passare un solo batch al modello e di esaminare in dettaglio gli output di quel batch. Un altro suggerimento molto utile se il modello produce errori è quello di `compile()` il modello con `run_eagerly=True`. Questo lo renderà molto più lento, ma renderà i messaggi di errore molto più comprensibili, perché indicheranno esattamente in quale punto del codice del modello si è verificato il problema.

Per ora, però, non abbiamo bisogno di `run_eagerly`. Passiamo il `batch` che abbiamo ottenuto prima attraverso il modello e vediamo come sono gli output:

```py
model(batch)
```

```python out
TFSequenceClassifierOutput(loss=<tf.Tensor: shape=(16,), dtype=float32, numpy=
array([nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,
       nan, nan, nan], dtype=float32)>, logits=<tf.Tensor: shape=(16, 2), dtype=float32, numpy=
array([[nan, nan],
       [nan, nan],
       [nan, nan],
       [nan, nan],
       [nan, nan],
       [nan, nan],
       [nan, nan],
       [nan, nan],
       [nan, nan],
       [nan, nan],
       [nan, nan],
       [nan, nan],
       [nan, nan],
       [nan, nan],
       [nan, nan],
       [nan, nan]], dtype=float32)>, hidden_states=None, attentions=None)
```

Beh, questo è insidioso. Tutto è `nan`! Ma è strano, non è vero? Come farebbero tutti i nostri logit a diventare `nan`? `nan` significa "not a number" (_"non un numero"_). I valori `nan` si verificano spesso quando si esegue un'operazione vietata, come la divisione per zero. Ma una cosa molto importante da sapere su `nan` in machine learning è che questo valore tende a *propagarsi*. Se si moltiplica un numero per `nan`, anche il risultato sarà `nan`. E se si ottiene un `nan` in un punto qualsiasi dell'output, della loss o del gradiente, questo si diffonderà rapidamente in tutto il modello, perché quando quel valore `nan` si propagherà attraverso la rete, si otterranno gradienti `nan`, e quando gli aggiornamenti dei pesi saranno calcolati con quei gradienti, si otterranno pesi `nan`, e quei pesi calcoleranno ancora più output `nan`! Presto l'intera rete sarà solo un grande blocco di `nan`. Una volta che ciò accade, è piuttosto difficile capire dove sia iniziato il problema. Come possiamo isolare il punto in cui `nan` si è insinuato per la prima volta?

La risposta è provare a *reinizializzare* il nostro modello. Una volta iniziato l'addestramento, abbiamo avuto un `nan` da qualche parte e questo si è rapidamente propagato all'intero modello. Quindi, carichiamo il modello da un checkpoint e non eseguiamo alcun aggiornamento dei pesi, e vediamo dove otteniamo un valore `nan`:

```py
model = TFAutoModelForSequenceClassification.from_pretrained(model_checkpoint)
model(batch)
```

Quando lo si esegue, si ottiene:

```py out
TFSequenceClassifierOutput(loss=<tf.Tensor: shape=(16,), dtype=float32, numpy=
array([0.6844486 ,        nan,        nan, 0.67127866, 0.7068601 ,
              nan, 0.69309855,        nan, 0.65531296,        nan,
              nan,        nan, 0.675402  ,        nan,        nan,
       0.69831556], dtype=float32)>, logits=<tf.Tensor: shape=(16, 2), dtype=float32, numpy=
array([[-0.04761693, -0.06509043],
       [-0.0481936 , -0.04556257],
       [-0.0040929 , -0.05848458],
       [-0.02417453, -0.0684005 ],
       [-0.02517801, -0.05241832],
       [-0.04514256, -0.0757378 ],
       [-0.02656011, -0.02646275],
       [ 0.00766164, -0.04350497],
       [ 0.02060014, -0.05655622],
       [-0.02615328, -0.0447021 ],
       [-0.05119278, -0.06928903],
       [-0.02859691, -0.04879177],
       [-0.02210129, -0.05791225],
       [-0.02363213, -0.05962167],
       [-0.05352269, -0.0481673 ],
       [-0.08141848, -0.07110836]], dtype=float32)>, hidden_states=None, attentions=None)
```

*Adesso* sì che ci capiamo! Non ci sono valori `nan` nei nostri logit, il che è rassicurante. Ma vediamo alcuni valori `nan` nella nostra loss! C'è qualcosa in quei campioni in particolare che sta causando questo problema? Vediamo quali sono (nota che se esegui questo codice da solo/a, potresti ottenere indici diversi perché il dataset è stato rimescolato):

```python
import numpy as np

loss = model(batch).loss.numpy()
indices = np.flatnonzero(np.isnan(loss))
indices
```

```python out
array([ 1,  2,  5,  7,  9, 10, 11, 13, 14])
```

Visualizziamo i campioni associati a questi indici:

```python
input_ids = batch["input_ids"].numpy()
input_ids[indices]
```

```python out
array([[  101,  2007,  2032,  2001,  1037, 16480,  3917,  2594,  4135,
        23212,  3070,  2214, 10170,  1010,  2012,  4356,  1997,  3183,
         6838, 12953,  2039,  2000,  1996,  6147,  1997,  2010,  2606,
         1012,   102,  6838,  2001,  3294,  6625,  3773,  1996,  2214,
         2158,  1012,   102,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0],
       [  101,  1998,  6814,  2016,  2234,  2461,  2153,  1998, 13322,
         2009,  1012,   102,  2045,  1005,  1055,  2053,  3382,  2008,
         2016,  1005,  2222,  3046,  8103,  2075,  2009,  2153,  1012,
          102,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0],
       [  101,  1998,  2007,  1996,  3712,  4634,  1010,  2057,  8108,
         2025,  3404,  2028,  1012,  1996,  2616, 18449,  2125,  1999,
         1037,  9666,  1997,  4100,  8663, 11020,  6313,  2791,  1998,
         2431,  1011,  4301,  1012,   102,  2028,  1005,  1055,  5177,
         2110,  1998,  3977,  2000,  2832,  2106,  2025,  2689,  2104,
         2122,  6214,  1012,   102,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0],
       [  101,  1045,  2001,  1999,  1037, 13090,  5948,  2007,  2048,
         2308,  2006,  2026,  5001,  2043,  2026,  2171,  2001,  2170,
         1012,   102,  1045,  2001,  3564,  1999,  2277,  1012,   102,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0],
       [  101,  2195,  4279,  2191,  2039,  1996,  2181,  2124,  2004,
         1996,  2225,  7363,  1012,   102,  2045,  2003,  2069,  2028,
         2451,  1999,  1996,  2225,  7363,  1012,   102,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0],
       [  101,  2061,  2008,  1045,  2123,  1005,  1056,  2113,  2065,
         2009,  2428, 10654,  7347,  2030,  2009,  7126,  2256,  2495,
         2291,   102,  2009,  2003,  5094,  2256,  2495,  2291,  2035,
         2105,  1012,   102,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0],
       [  101,  2051,  1010,  2029,  3216,  2019,  2503,  3444,  1010,
         6732,  1996,  2265,  2038, 19840,  2098,  2125,  9906,  1998,
         2003,  2770,  2041,  1997,  4784,  1012,   102,  2051,  6732,
         1996,  2265,  2003,  9525,  1998,  4569,  1012,   102,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0],
       [  101,  1996, 10556,  2140, 11515,  2058,  1010,  2010,  2162,
         2252,  5689,  2013,  2010,  7223,  1012,   102,  2043,  1996,
        10556,  2140, 11515,  2058,  1010,  2010,  2252,  3062,  2000,
         1996,  2598,  1012,   102,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0],
       [  101, 13543,  1999,  2049,  6143,  2933,  2443,   102,  2025,
        13543,  1999,  6143,  2933,  2003,  2443,   102,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0,     0,     0,     0,     0,     0,
            0,     0,     0,     0]])
```

Beh, ci sono tante cose qui dentro, ma non c'è nulla che si distingua come insolito. Diamo un'occhiata alle label:

```python out
labels = batch['labels'].numpy()
labels[indices]
```

```python out
array([2, 2, 2, 2, 2, 2, 2, 2, 2])
```

I campioni `nan` hanno tutti la stessa label, ed è la classe 2. Questo è un indizio molto chiaro. Il fatto che si abbia una loss di `nan` solo quando la label è 2 suggerisce che questo è un ottimo momento per verificare il numero di label nel nostro modello:

```python
model.config.num_labels
```

```python out
2
```

Ora vediamo il problema: il modello pensa che ci siano solo due classi, ma le label arrivano a 2, il che significa che in realtà ci sono tre classi (perché anche lo 0 è una classe). Ecco come abbiamo ottenuto un `nan`: cercando di calcolare la loss per una classe inesistente! Proviamo a cambiare il modello e ad adattarlo di nuovo:

```
model = TFAutoModelForSequenceClassification.from_pretrained(model_checkpoint, num_labels=3)
model.compile(optimizer='adam')
model.fit(train_dataset)
```

```python out
  869/24543 [>.............................] - ETA: 15:29 - loss: 1.1032
```

Staimo addestrando! Non ci sono più `nan` e la nostra loss sta diminuendo... più o meno. Se la si osserva per un po', si potrebbe iniziare a spazientirsi, perché il valore della loss rimane ostinatamente alto. Interrompiamo il training e cerchiamo di capire quale potrebbe essere la causa di questo problema. A questo punto, siamo abbastanza sicuri che sia i dati che il modello siano a posto, ma il nostro modello non sta imparando bene. Cos'altro rimane? È ora di...

### Controllare gli iperparametri

Se si guarda al codice precedente, è possibile che non si riesca a vedere alcun iperparametro, a parte forse il `batch_size`, e questo non sembra un possibile problema. Non lasciarti ingannare, però: gli iperparametri ci sono sempre e se non li vedi significa che non conosci il valore a cui sono impostati. In particolare, ricorda una cosa fondamentale di Keras: se imposti una loss, un optimizer (_ottimizzatore_) o una funzione di attivazione con una stringa, _tutti i suoi argomenti saranno impostati ai loro valori predefiniti_. Ciò significa che, anche se usare le stringhe è molto comodo, bisogna fare molta attenzione, perché questa cosa potrebbe facilmente nascondere alcuni aspetti importanti. (Chiunque si cimenti nella sfida opzionale qui sopra dovrebbe prendere nota di questo fatto).

In questo caso, dove abbiamo impostato un argomento con una stringa? Inizialmente settavamo la loss con una stringa, ma ora non lo facciamo più. Tuttavia, impostiamo l'optimizer usando una stringa. Potrebbe nasconderci qualcosa? Diamo un'occhiata ai [suoi argomenti](https://www.tensorflow.org/api_docs/python/tf/keras/optimizers/Adam).

C'è qualcosa che balza all'occhio? Esatto: il learning rate (_tasso di apprendimento_)! Quando usiamo semplicemente la stringa `'adam'`, otterremo il tasso di apprendimento predefinito, che è 0,001, o 1e-3. Questo è decisamente troppo alto per un modello Transformer! In generale, si consiglia di provare learning rate tra 1e-5 e 1e-4 per i modelli; si tratta di un valore tra 10 e 100 volte inferiore a quello che stiamo usando qui. Questo sembra essere un problema importante, quindi proviamo a ridurlo. Per farlo, dobbiamo importare l'oggetto `optimizer`. Già che ci siamo, reinizializziamo il modello dal checkpoint, nel caso in cui il training con un learning rate elevato abbia compromesso i suoi pesi:

```python
from tensorflow.keras.optimizers import Adam

model = TFAutoModelForSequenceClassification.from_pretrained(model_checkpoint)
model.compile(optimizer=Adam(5e-5))
```

<Tip>

💡 È anche possibile importare la funzione `create_optimizer()` da 🤗 Transformers, che fornirà un optimizer AdamW con un corretto weight decay insieme a un learning rate warmup e decay. Questo ottimizzatore spesso produce risultati leggermente migliori di quelli ottenuti con l'ottimizzatore Adam predefinito.

</Tip>

Adess, possiamo tentarde di fare training del modell con il nuovo learning rate migliorato:

```python
model.fit(train_dataset)
```

```python out
319/24543 [..............................] - ETA: 16:07 - loss: 0.9718
```

Ora la nostra loss sta davvero andando da qualche parte! L'addestramento sembra finalmente funzionare. C'è una lezione da imparare: quando il modello funziona, ma la loss non diminuisce, e si è sicuri che i dati siano corretti, è una buona idea controllare gli iperparametri come il learning rate e il weight decay. Impostando uno di questi parametri troppo alto, è molto probabile che l'addestramento si "blocchi" a un valore di loss elevato.

## Altri potenziali problemi 

Abbiamo trattato i problemi dello script di cui sopra, ma ci sono molti altri errori comuni che si possono incontrare. Vediamo un elenco (molto incompleto).

### Gestire gli errori out-of-memory

Il segnale che indica che la memoria è esaurita è un errore del tipo "OOM when allocating tensor" (OOM è l'abbreviazione di "out of memory"). Si tratta di un rischio molto comune quando si ha a che fare con modelli linguistici di grandi dimensioni. In questo caso, una buona strategia è quella di dimezzare le dimensioni del batch e riprovare. Tenete presente, però, che alcuni modelli sono *molto* grandi. Ad esempio, il modello GPT-2 completo ha 1,5B parametri, il che significa che sono necessari 6 GB di memoria solo per memorizzare il modello e altri 6 GB per i suoi gradienti! L'addestramento del modello GPT-2 completo richiede di solito oltre 20 GB di VRAM, indipendentemente dalla dimensione del batch utilizzato, che solo poche GPU hanno. Modelli più leggeri come `distilbert-base-cased` sono molto più facili da eseguire e si addestrano molto più rapidamente.

<Tip>

Nella prossima parte del corso, esamineremo tecniche più avanzate che possono aiutare a ridurre l'impatto sulla memoria e ad affinare i modelli più grandi.

</Tip>

### TensorFlow è molto affamato 🦛

Una particolarità di TensorFlow di cui bisogna essere consapevoli è che alloca *tutta* la memoria della GPU su se stesso non appena si carica un modello o si esegue un addestramento, e poi divide la memoria in base alle esigenze. Questo comportamento è diverso da quello di altri framework, come PyTorch, che allocano la memoria come richiesto con CUDA invece di farlo internamente. Un vantaggio dell'approccio di TensorFlow è che spesso può produrre errori utili quando esaurisci la memoria e può recuperare da questo stato senza mandare in crash l'intero kernel CUDA. Ma c'è anche un importante aspetto negativo: se si eseguono due processi TensorFlow contemporaneamente, allora **sarà un bel guaio**.

Se si esegue su Colab non ci si deve preoccupare di questo, ma se si lavora in locale è sicuramente qualcosa a cui si deve fare attenzione. In particolare, è bene ricordare che la chiusura della scheda di un notebook non comporta necessariamente la chiusura del notebook stesso! Potresti dover selezionare i notebook in esecuzione (quelli con l'icona verde) e chiuderli manualmente nell'elenco della directory. Qualsiasi notebook in esecuzione che utilizzava TensorFlow potrebbe ancora conservare una buona parte della memoria della GPU e ciò significa che qualsiasi nuovo notebook avviato potrebbe presentare problemi molto strani.

Se inizi a ricevere errori relativi a CUDA, BLAS o cuBLAS in un codice che prima funzionava, questa è molto spesso la ragione. Si può usare un comando come `nvidia-smi` per controllare: quando si spegne o si riavvia il notebook usato, la maggior parte della memoria è libera o è ancora in uso? Se è ancora in uso, c'è qualcos'altro che la sta occupando!


### Check your data (again!)

Il tuo modello imparerà qualcosa solo se è effettivamente possibile imparare qualcosa dai tuoi dati. Se c'è un bug che corrompe i dati o le label sono assegnate in modo casuale, è molto probabile che non si riesca ad addestrare il modello sul dataset. In questo caso uno strumento utile è `tokenizer.decode()`. Questo trasformerà gli `input_ids` in stringhe, in modo da poter visualizzare i dati e vedere se i dati di training stanno addestrando ciò che si vuole. Per esempio, dopo aver ottenuto un `batch` dal proprio `tf.data.Dataset` come abbiamo fatto sopra, si può decodificare il primo elemento in questo modo:

```py
input_ids = batch["input_ids"].numpy()
tokenizer.decode(input_ids[0])
```

Poi si può confrontare con la prima label, in questo modo:

```py
labels = batch["labels"].numpy()
label = labels[0]
```

Una volta visualizzati i dati in questo modo, puoi porti le seguenti domande:

- I dati decodificati sono comprensibili?
- Sei d'accordo con le label?
- C'è una label più comune delle altre?
- Quale dovrebbe essere la funzione di perdita/metrica se il modello predicesse una risposta a caso/sempre la stessa risposta?

Dopo aver osservato i dati, esamina alcune previsioni del modello: se il modello produce dei token, prova a decodificare anche quelli! Se il modello prevede sempre la stessa cosa, potrebbe essere perché il tuo set di dati è influenzato verso una categoria (per i problemi di classificazione); tecniche come fare oversampling (_sovra-campionamento_) delle classi rare potrebbero aiutare. In alternativa, ciò può essere causato da problemi di addestramento, come ad esempio una scorretta impostazione degli iperparametri.

Se la funzione di perdita/metrica ottenuta con il tuo modello iniziale è molto diversa da quella che ci si aspetterebbe per le previsioni casuali, ricontrolla il modo in cui viene calcolata la funzione o la metrica, perché probabilmente c'è un bug. Se si utilizzano diverse funzioni che aggiungi alla fine, assicurati che siano della stessa grandezza.

Quando sei sicuro/a che i dati sono perfetti, puoi verificare se il modello è in grado di addestrarsi su di essi con un semplice test.

### Fare overfitting del modello su un batch

L'overfitting è di solito qualcosa che cerchiamo di evitare durante l'addestramento, poiché significa che il modello non sta imparando a riconoscere le proprietà generali che vogliamo, ma sta invece memorizzando i campioni di addestramento. Tuttavia, provare ad addestrare il modello su un batch più e più volte è un buon test per verificare se il problema così come è stato inquadrato può essere risolto dal modello che si sta cercando di addestrare. Inoltre, ti aiuterà a capire se il learning rate iniziale è troppo alta.

Una volta definito il `Trainer`, è molto semplice: basta prendere un batch dal training set, ed eseguire un piccolo ciclo di addestramento manuale utilizzando solo quel `batch` per qualcosa come 20 step:

```py
for batch in train_dataset:
    break

# Make sure you have run model.compile() and set your optimizer,
# and your loss/metrics if you're using them

model.fit(batch, epochs=20)
```

<Tip>

💡 Se i dati di addestramento sono sbilanciati, assicurati di creare un batch di dati di addestramento contenente tutte le label.

</Tip>

Il modello risultante dovrebbe avere risultati quasi perfetti sul `batch`, con una loss che diminuisce rapidamente verso lo 0 (o il valore minimo per la loss che si sta utilizzando).

Se non si riesci a far sì che il modello ottenga risultati perfetti come questo, significa che c'è qualcosa di sbagliato nel modo in cui si è impostato il problema o con i dati, e quindi dovresti risolvere questa cosa. Solo quando riesci a superare il test di overfitting puoi essere sicuro/a che il tuo modello possa effettivamente imparare qualcosa.

<Tip warning={true}>

⚠️ Sarà necessario ricreare il modello e ricompilarlo dopo questo test, poiché il modello ottenuto probabilmente non sarà in grado di recuperare e imparare qualcosa di utile sul set di dati completo.

</Tip>

### Non calibrare niente prima di avere una prima baseline

Hyperparameter tuning (_calibrazione degli iperparametri_) è sempre considerato come la parte più difficile di machine learning, ma è solo l'ultimo passo per aiutarti a migliorare un po' la metrica. Valori *molto* sbagliati di iperparametri, come l'uso del learning rate predefinito di Adam di 1e-3 con un modello Transformer, faranno sì che l'apprendimento proceda molto lentamente o si blocchi completamente, naturalmente, ma la maggior parte delle volte iperparametri "ragionevoli", come un learning rate da 1e-5 a 5e-5, funzioneranno bene per darti buoni risultati. Quindi, non ci si deve lanciare in una ricerca di iperparametri dispendiosa in termini di tempo e di costi, finché non si è ottenuto qualcosa che batta la baseline (_base di partenza_) che si ha sul dataset.

Una volta ottenuto un modello sufficientemente buono, si può iniziare a modificarlo un po'. Non provare a eseguire l'addestramento un migliaio di volte con iperparametri diversi, ma confronta un paio di esecuzioni che hanno valori diversi per un iperparametro così da avere un'idea di quale abbia il maggiore impatto.

Se stai modificando il modello stesso, mantieni le cose semplici e non provare nulla che non possa essere ragionevolmente giustificato. Assicurati sempre di rifare il test di overfitting per verificare che la modifica non abbia avuto conseguenze indesiderate.

### Chiedere aiuto

Speriamo che in questa sezione tu abbia trovato qualche consiglio utile a risolvere il tuo problema, ma se così non fosse, ricordati che puoi sempre chiedere aiuto alla community nei [forum](https://discuss.huggingface.co/). 

Qui di seguito sono riportate alcune risorse aggiuntive che potrebbero rivelarsi utili:

- ["Reproducibility as a vehicle for engineering best practices"](https://docs.google.com/presentation/d/1yHLPvPhUs2KGI5ZWo0sU-PKU3GimAk3iTsI38Z-B5Gw/edit#slide=id.p) di Joel Grus
- ["Checklist for debugging neural networks"](https://towardsdatascience.com/checklist-for-debugging-neural-networks-d8b2a9434f21) di Cecelia Shao
- ["How to unit test machine learning code"](https://medium.com/@keeper6928/how-to-unit-test-machine-learning-code-57cf6fd81765) di Chase Roberts
- ["A Recipe for Training Neural Networks"](http://karpathy.github.io/2019/04/25/recipe/) di Andrej Karpathy

Naturalmente, non tutti i problemi che incontrerai durante l'addestramento delle reti neurali sono colpa tua! Se si incontra qualcosa nella libreria 🤗 Transformers o 🤗 Datasets che non sembra corretto, è possibile che si sia trovato un bug. Dovresti assolutamente segnalarcelo e nella prossima sezione ti spiegheremo esattamente come fare.


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter8/4_tf.mdx" />

### Cosa fare quando si riceve un errore
https://huggingface.co/learn/course/it/chapter8/2.md

# Cosa fare quando si riceve un errore

<CourseFloatingBanner chapter={8}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/it/chapter8/section2.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/it/chapter8/section2.ipynb"},
]} />

In questa sezione esamineremo alcuni errori comuni che possono verificarsi quando si cerca di generare previsioni dal modello Transformer appena affinato. Questo ti preparerà alla [sezione 4](/course/chapter8/section4), in cui esploreremo come eseguire il debug della fase di training.

<Youtube id="DQ-CpJn6Rc4"/>

Per questa sezione, abbiamo preparato un [template repository del modello](https://huggingface.co/lewtun/distilbert-base-uncased-finetuned-squad-d5716d28) e, se vuoi eseguire il codice di questo capitolo, dovrai prima copiare il modello nel tuo account su [Hugging Face Hub](https://huggingface.co). Per farlo, occorre innanzitutto effettuare il login eseguendo una delle seguenti operazioni in un Jupyter notebook:

```python
from huggingface_hub import notebook_login

notebook_login()
```

o il seguente nel tuo terminale preferito:

```bash
huggingface-cli login
```

Questo chiederà di inserire il nome utente e la password e salverà un token in *~/.cache/huggingface/*. Una volta effettuato l'accesso, è possibile copiare il template repository con la seguente funzione:

```python
from distutils.dir_util import copy_tree
from huggingface_hub import Repository, snapshot_download, create_repo, get_full_repo_name


def copy_repository_template():
    # Clone the repo and extract the local path
    template_repo_id = "lewtun/distilbert-base-uncased-finetuned-squad-d5716d28"
    commit_hash = "be3eaffc28669d7932492681cd5f3e8905e358b4"
    template_repo_dir = snapshot_download(template_repo_id, revision=commit_hash)
    # Create an empty repo on the Hub
    model_name = template_repo_id.split("/")[1]
    create_repo(model_name, exist_ok=True)
    # Clone the empty repo
    new_repo_id = get_full_repo_name(model_name)
    new_repo_dir = model_name
    repo = Repository(local_dir=new_repo_dir, clone_from=new_repo_id)
    # Copy files
    copy_tree(template_repo_dir, new_repo_dir)
    # Push to Hub
    repo.push_to_hub()
```

A questo punto, quando si esegue `copy_repository_template()`, verrà creata una copia del template repository nel proprio account.

## Fare il debug della pipeline di 🤗 Transformers

Per iniziare il nostro viaggio nel fantastico mondo del debug dei modelli Transformer, considera lo scenario seguente: stai lavorando con un/a collega a un progetto di risposta alle domande per aiutare i clienti di un sito web di e-commerce a trovare risposte sui prodotti di consumo. Il/La collega ti invia un messaggio del tipo:

> Ciao! Ho appena fatto un esperimento utilizzando le tecniche del [Capitolo 7](/course/chapter7/7) del corso di Hugging Face e ho ottenuto ottimi risultati su SQuAD! Penso che possiamo usare questo modello come punto di partenza per il nostro progetto. L'ID del modello sull'Hub è "lewtun/distillbert-base-uncased-finetuned-squad-d5716d28". Provalo pure :)

e la prima cosa che pensi è di caricare il modello usando la `pipeline` di 🤗 Transformers:

```python
from transformers import pipeline

model_checkpoint = get_full_repo_name("distillbert-base-uncased-finetuned-squad-d5716d28")
reader = pipeline("question-answering", model=model_checkpoint)
```

```python out
"""
OSError: Can't load config for 'lewtun/distillbert-base-uncased-finetuned-squad-d5716d28'. Make sure that:

- 'lewtun/distillbert-base-uncased-finetuned-squad-d5716d28' is a correct model identifier listed on 'https://huggingface.co/models'

- or 'lewtun/distillbert-base-uncased-finetuned-squad-d5716d28' is the correct path to a directory containing a config.json file
"""
```

Oh no, sembra che qualcosa sia andato storto! Se sei alle prime armi con la programmazione, questo tipo di errori può sembrare un po' criptico all'inizio (cos'è un `OSError`?!). L'errore visualizzato qui è solo l'ultima parte di un messaggio di errore molto più ampio, chiamato _Python traceback_ (anche detto stack trace). Per esempio, se si esegue questo codice su Google Colab, si dovrebbe vedere qualcosa di simile alla seguente schermata:

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter8/traceback.png" alt="A Python traceback." width="100%"/>
</div>

Questi messaggi contengono molte informazioni, quindi analizziamo insieme le parti principali. La prima cosa da notare è che i traceback devono essere letti _dal basso verso l'alto_. Questo può sembrare strano se si è abituati a leggere dall'alto verso il basso, ma riflette il fatto che il traceback mostra la sequenza di chiamate delle funzioni che la `pipeline` effettua quando scarica il modello e il tokenizer. (Dai un'occhiata al [Capitolo 2](/course/chapter2) per maggiori dettagli su come funziona la `pipeline`.)

<Tip>

🚨 Hai notato quel riquadro blu intorno a "6 frames" nel traceback di Google Colab? È una funzionalità speciale di Colab, che comprime il traceback in "frame". Se non riesci a trovare l'origine di un errore, assicurati di espandere l'intero traceback facendo clic su quelle due piccole frecce.

</Tip>

Ciò significa che l'ultima riga del traceback indica l'ultimo messaggio di errore e fornisce il nome dell'eccezione sollevata. In questo caso, il tipo di eccezione è `OSError`, che indica un errore legato al sistema. Leggendo il messaggio di errore, si può notare che sembra esserci un problema con il file *config.json* del modello e vengono forniti due suggerimenti per risolverlo:

```python out
"""
Make sure that:

- 'lewtun/distillbert-base-uncased-finetuned-squad-d5716d28' is a correct model identifier listed on 'https://huggingface.co/models'

- or 'lewtun/distillbert-base-uncased-finetuned-squad-d5716d28' is the correct path to a directory containing a config.json file
"""
```

<Tip>

💡 Se vedi un messaggio di errore che è difficile da capire, copia e incolla il messaggio nella barra di ricerca di Google o di [Stack Overflow](https://stackoverflow.com/) (sì, davvero!). C'è una buona probabilità che non sei la prima persona a riscontrare l'errore, e questo è un buon modo per trovare le soluzioni pubblicate da altri utenti della community. Ad esempio, cercando `OSError: Can't load config for` su Stack Overflow si ottengono diversi [risultati](https://stackoverflow.com/search?q=OSError%3A+Can%27t+load+config+for+) che possono essere usati come punto di partenza per risolvere il problema.

</Tip>

Il primo suggerimento ci chiede di verificare se l'ID del modello è effettivamente corretto, quindi la prima cosa da fare è copiare l'identificativo e incollarlo nella barra di ricerca dell'Hub:

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter8/wrong-model-id.png" alt="The wrong model name." width="100%"/>
</div>

Mmm, sembra proprio che il modello del/la nostro/a collega non sia sull'Hub... aha, ma c'è un errore di battitura nel nome del modello! DistilBERT ha solo una "l" nel suo nome, quindi correggiamolo e cerchiamo invece "lewtun/distilbert-base-uncased-finetuned-squad-d5716d28":

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter8/true-model-id.png" alt="The right model name." width="100%"/>
</div>

Ok, questo c'è. Ora proviamo a scaricare di nuovo il modello con l'ID corretto:

```python
model_checkpoint = get_full_repo_name("distilbert-base-uncased-finetuned-squad-d5716d28")
reader = pipeline("question-answering", model=model_checkpoint)
```

```python out
"""
OSError: Can't load config for 'lewtun/distilbert-base-uncased-finetuned-squad-d5716d28'. Make sure that:

- 'lewtun/distilbert-base-uncased-finetuned-squad-d5716d28' is a correct model identifier listed on 'https://huggingface.co/models'

- or 'lewtun/distilbert-base-uncased-finetuned-squad-d5716d28' is the correct path to a directory containing a config.json file
"""
```

Argh, è fallito ancora - benvenuti nella routine quotidiana di un machine learning engineer! Poiché abbiamo aggiustato l'ID del modello, il problema deve essere nel repository stesso. Un modo rapido per accedere al contenuto di un repository sul 🤗 Hub è la funzione `list_repo_files()` della libreria `huggingface_hub`:

```python
from huggingface_hub import list_repo_files

list_repo_files(repo_id=model_checkpoint)
```

```python out
['.gitattributes', 'README.md', 'pytorch_model.bin', 'special_tokens_map.json', 'tokenizer_config.json', 'training_args.bin', 'vocab.txt']
```

Interessante: non sembra esserci un file *config.json* nel repository! Non c'è da stupirsi che la nostra `pipeline` non riesca a caricare il modello; il/la nostro/a collega deve aver dimenticato di inserire questo file nell'Hub dopo averlo affinato. In questo caso, il problema sembra abbastanza semplice da risolvere: potremmo chiedere loro di aggiungere il file, oppure, dato che possiamo vedere dall'ID del modello che il modello pre-addestrato usato è [`distilbert-base-uncased`](https://huggingface.co/distilbert-base-uncased), possiamo scaricare la configurazione di questo modello e inserirla nel nostro repository per vedere se questo risolve il problema. Proviamo. Utilizzando le tecniche apprese nel [Capitolo 2](/course/chapter2), possiamo scaricare la configurazione del modello con la classe `AutoConfig`:

```python
from transformers import AutoConfig

pretrained_checkpoint = "distilbert-base-uncased"
config = AutoConfig.from_pretrained(pretrained_checkpoint)
```

<Tip warning={true}>

🚨 L'approccio che stiamo adottando non è infallibile, poiché il/la nostro/a collega potrebbe aver modificato la configurazione di `distilbert-base-uncased` prima di affinare il modello. Nella vita reale, dovremmo verificare prima con loro, ma per lo scopo di questa sezione assumeremo che abbiano usato la configurazione predefinita.

</Tip>

Possiamo quindi inviarlo al nostro repository del modello con la funzione `push_to_hub()` della configurazione:

```python
config.push_to_hub(model_checkpoint, commit_message="Add config.json")
```

Ora possiamo verificare se ha funzionato, caricando il modello dall'ultimo commit del ramo `main`:

```python
reader = pipeline("question-answering", model=model_checkpoint, revision="main")

context = r"""
Extractive Question Answering is the task of extracting an answer from a text
given a question. An example of a question answering dataset is the SQuAD
dataset, which is entirely based on that task. If you would like to fine-tune a
model on a SQuAD task, you may leverage the
examples/pytorch/question-answering/run_squad.py script.

🤗 Transformers is interoperable with the PyTorch, TensorFlow, and JAX
frameworks, so you can use your favourite tools for a wide variety of tasks!
"""

question = "What is extractive question answering?"
reader(question=question, context=context)
```

```python out
{'score': 0.38669535517692566,
 'start': 34,
 'end': 95,
 'answer': 'the task of extracting an answer from a text given a question'}
```

Woohoo, ha funzionato! Riassumiamo quello che hai appena imparato:

- I messaggi di errore in Python sono noti come _traceback_ e vengono letti dal basso verso l'alto. L'ultima riga del messaggio di errore di solito contiene le informazioni necessarie per individuare l'origine del problema.
- Se l'ultima riga non contiene informazioni sufficienti, risali il traceback e vedi se riesci a identificare in quale punto del codice sorgente si verifica l'errore.
- Se nessuno dei messaggi di errore può aiutare a individuare il problema, provare a cercare online una soluzione a un problema simile.
- Il `huggingface_hub'
// 🤗 Hub?
fornisce una serie di strumenti che si possono usare per interagire e fare il debug dei repository su Hub.

Ora che sappiamo come eseguire il debug di una pipeline, diamo un'occhiata a un esempio più complicato nel forward pass del modello stesso.

## Debug del forward pass del modello

Sebbene la `pipeline` sia ottima per la maggior parte delle applicazioni in cui è necessario generare previsioni rapidamente, a volte è necessario accedere ai logit del modello (ad esempio, se si desidera applicare un post-processing personalizzato). Per vedere cosa potrebbe andare storto in questo caso, iniziamo prendendo il modello e il tokenizer dalla nostra `pipeline`:

```python
tokenizer = reader.tokenizer
model = reader.model
```

Poi abbiamo bisogno di una domanda, quindi vediamo se i nostri framework preferiti sono supportati:

```python
question = "Which frameworks can I use?"
```

Come abbiamo visto nel [Capitolo 7](/course/chapter7), i passaggi tipici da svolgere sono la tokenizzazione degli input, l'estrazione dei logit dei token iniziali e finali e la decodifica dell'intervallo di risposta:

```python
import torch

inputs = tokenizer(question, context, add_special_tokens=True)
input_ids = inputs["input_ids"][0]
outputs = model(**inputs)
answer_start_scores = outputs.start_logits
answer_end_scores = outputs.end_logits
# Get the most likely beginning of answer with the argmax of the score
answer_start = torch.argmax(answer_start_scores)
# Get the most likely end of answer with the argmax of the score
answer_end = torch.argmax(answer_end_scores) + 1
answer = tokenizer.convert_tokens_to_string(
    tokenizer.convert_ids_to_tokens(input_ids[answer_start:answer_end])
)
print(f"Question: {question}")
print(f"Answer: {answer}")
```

```python out
"""
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
/var/folders/28/k4cy5q7s2hs92xq7_h89_vgm0000gn/T/ipykernel_75743/2725838073.py in <module>
      1 inputs = tokenizer(question, text, add_special_tokens=True)
      2 input_ids = inputs["input_ids"]
----> 3 outputs = model(**inputs)
      4 answer_start_scores = outputs.start_logits
      5 answer_end_scores = outputs.end_logits

~/miniconda3/envs/huggingface/lib/python3.8/site-packages/torch/nn/modules/module.py in _call_impl(self, *input, **kwargs)
   1049         if not (self._backward_hooks or self._forward_hooks or self._forward_pre_hooks or _global_backward_hooks
   1050                 or _global_forward_hooks or _global_forward_pre_hooks):
-> 1051             return forward_call(*input, **kwargs)
   1052         # Do not call functions when jit is used
   1053         full_backward_hooks, non_full_backward_hooks = [], []

~/miniconda3/envs/huggingface/lib/python3.8/site-packages/transformers/models/distilbert/modeling_distilbert.py in forward(self, input_ids, attention_mask, head_mask, inputs_embeds, start_positions, end_positions, output_attentions, output_hidden_states, return_dict)
    723         return_dict = return_dict if return_dict is not None else self.config.use_return_dict
    724
--> 725         distilbert_output = self.distilbert(
    726             input_ids=input_ids,
    727             attention_mask=attention_mask,

~/miniconda3/envs/huggingface/lib/python3.8/site-packages/torch/nn/modules/module.py in _call_impl(self, *input, **kwargs)
   1049         if not (self._backward_hooks or self._forward_hooks or self._forward_pre_hooks or _global_backward_hooks
   1050                 or _global_forward_hooks or _global_forward_pre_hooks):
-> 1051             return forward_call(*input, **kwargs)
   1052         # Do not call functions when jit is used
   1053         full_backward_hooks, non_full_backward_hooks = [], []

~/miniconda3/envs/huggingface/lib/python3.8/site-packages/transformers/models/distilbert/modeling_distilbert.py in forward(self, input_ids, attention_mask, head_mask, inputs_embeds, output_attentions, output_hidden_states, return_dict)
    471             raise ValueError("You cannot specify both input_ids and inputs_embeds at the same time")
    472         elif input_ids is not None:
--> 473             input_shape = input_ids.size()
    474         elif inputs_embeds is not None:
    475             input_shape = inputs_embeds.size()[:-1]

AttributeError: 'list' object has no attribute 'size'
"""
```

Oh cielo, sembra che ci sia un bug nel nostro codice! Ma non avere paura di un po' di debug. Puoi usare il debugger di Python in un notebook:

<Youtube id="rSPyvPw0p9k"/>

o dal terminale:

<Youtube id="5PkZ4rbHL6c"/>

Qui, leggendo il messaggio di errore vediamo che l'oggetto `'list'` non ha attributo `'size'`, e possiamo vedere una `-->` freccia che punta alla riga in cui il problema è stato sollevato in `model(**inputs)`. Possiamo eseguire il debug interattivo utilizzando il debugger di Python, ma per ora ci limiteremo a stampare una parte di `input` per vedere cosa abbiamo:

```python
inputs["input_ids"][:5]
```

```python out
[101, 2029, 7705, 2015, 2064]
```

Questo sembra certamente una normale `list` di Python, ma ricontrolliamo il `type`:

```python
type(inputs["input_ids"])
```

```python out
list
```

Sì, questa è sicuramente una `list` di Python. Cos'è andato storto? Ricordiamo dal [Capitolo 2](/course/chapter2) che le classi `AutoModelForXxx` in 🤗 Transformers operano su _tensori_ (sia in PyTorch che in TensorFlow), e un'operazione comune è quella di estrarre le dimensioni di un tensore usando `Tensor.size()` in PyTorch, per esempio. Diamo un'altra occhiata al traceback, per vedere quale riga ha causato l'eccezione:

```
~/miniconda3/envs/huggingface/lib/python3.8/site-packages/transformers/models/distilbert/modeling_distilbert.py in forward(self, input_ids, attention_mask, head_mask, inputs_embeds, output_attentions, output_hidden_states, return_dict)
    471             raise ValueError("You cannot specify both input_ids and inputs_embeds at the same time")
    472         elif input_ids is not None:
--> 473             input_shape = input_ids.size()
    474         elif inputs_embeds is not None:
    475             input_shape = inputs_embeds.size()[:-1]

AttributeError: 'list' object has no attribute 'size'
```

Sembra che il nostro codice abbia provato a chiamare `input_ids.size()`, ma questo chiaramente non funziona per una `list`di Python, che è solo un _container_. Come possiamo risolvere questo problema? Cercando il messaggio di errore su Stack Overflow si ottengono alcuni [risultati](https://stackoverflow.com/search?q=AttributeError%3A+%27list%27+object+has+no+attribute+%27size%27&s=c15ec54c-63cb-481d-a749-408920073e8f) pertinenti. Cliccando sul primo, viene visualizzata una domanda simile alla nostra, con la risposta mostrata nello screenshot seguente:

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter8/stack-overflow.png" alt="An answer from Stack Overflow." width="100%"/>
</div>

La risposta raccomanda di aggiungere `return_tensors='pt'` al tokenizer, quindi proviamo se funziona:

```python out
inputs = tokenizer(question, context, add_special_tokens=True, return_tensors="pt")
input_ids = inputs["input_ids"][0]
outputs = model(**inputs)
answer_start_scores = outputs.start_logits
answer_end_scores = outputs.end_logits
# Get the most likely beginning of answer with the argmax of the score
answer_start = torch.argmax(answer_start_scores)
# Get the most likely end of answer with the argmax of the score
answer_end = torch.argmax(answer_end_scores) + 1
answer = tokenizer.convert_tokens_to_string(
    tokenizer.convert_ids_to_tokens(input_ids[answer_start:answer_end])
)
print(f"Question: {question}")
print(f"Answer: {answer}")
```

```python out
"""
Question: Which frameworks can I use?
Answer: pytorch, tensorflow, and jax
"""
```

Bene, ha funzionato! Questo è un ottimo esempio di quanto possa essere utile Stack Overflow: identificando un problema simile, abbiamo potuto beneficiare dell'esperienza di altri membri della community. Tuttavia, una ricerca come questa non sempre produce una risposta pertinente, quindi cosa si può fare in questi casi? Fortunatamente, sul [forum di Hugging Face](https://discuss.huggingface.co/) c'è un'accogliente community di sviluppatori che può aiutarti! Nella prossima sezione, vedremo come creare bene delle domande sul forum che abbiano buona probabilità di ricevere una risposta.

<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter8/2.mdx" />

### Introduzione a Gradio
https://huggingface.co/learn/course/it/chapter9/1.md

# Introduzione a Gradio

<CourseFloatingBanner
    chapter={9}
    classNames="absolute z-10 right-0 top-0"
/>

In questo capitolo scopriremo come creare delle **demo interattive** per i tuoi modelli di machine learning.

Perché costruire una demo o una GUI per il tuo modello di machine learning? Le demo permettono:

- agli **sviluppatori di machine learning** di presentare facilmente il proprio lavoro ad un pubblico più ampio, tra cui i team non tecnici o i clienti
- ai **ricercatori** di riprodurre più facilmente i modelli di machine learning e i loro comportamenti 
- ai **quality tester** o **utenti finali**  per individuare e fare il debug dei difetti dei modelli con maggiore facilità
- a **utenti vari** per scoprire i bias degli algoritmi nei modelli

Utilizzeremo la libreria Gradio per costruire le demo dei nostri modelli. Gradio consente di creare, personalizzare e condividere demo sul web per qualsiasi modello di machine learning, interamente in Python.

Ecco alcuni esempi di demo di machine learning costruite con Gradio:

* Un modello di **riconoscimento di disegni** che riceve uno schizzo di un disegno e restituisce il nome di ciò che pensa sia stato disegnato:

<iframe src="https://course-demos-draw2.hf.space" frameBorder="0" height="450" title="Gradio app" class="container p-0 flex-grow space-iframe" allow="accelerometer; ambient-light-sensor; autoplay; battery; camera; document-domain; encrypted-media; fullscreen; geolocation; gyroscope; layout-animations; legacy-image-formats; magnetometer; microphone; midi; oversized-images; payment; picture-in-picture; publickey-credentials-get; sync-xhr; usb; vr ; wake-lock; xr-spatial-tracking" sandbox="allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-downloads"></iframe>

* Un modello che estrae **risposte alle domande** che prende in considerazione un contesto e una domanda e produce una risposta e la sua probabilità (abbiamo discusso questo tipo di modello [nel capitolo 7](/course/chapter7/7)):

<iframe src="https://course-demos-question-answering-simple.hf.space" frameBorder="0" height="640" title="Gradio app" class="container p-0 flex-grow space-iframe" allow="accelerometer; ambient-light-sensor; autoplay; battery; camera; document-domain; encrypted-media; fullscreen; geolocation; gyroscope; layout-animations; legacy-image-formats; magnetometer; microphone; midi; oversized-images; payment; picture-in-picture; publickey-credentials-get; sync-xhr; usb; vr ; wake-lock; xr-spatial-tracking" sandbox="allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-downloads"></iframe>

* Un modello di **rimozione dello sfondo** che riceve un'immagine e la restituisce con lo sfondo rimosso:

<iframe src="https://course-demos-remove-bg-original.hf.space" frameBorder="0" height="640" title="Gradio app" class="container p-0 flex-grow space-iframe" allow="accelerometer; ambient-light-sensor; autoplay; battery; camera; document-domain; encrypted-media; fullscreen; geolocation; gyroscope; layout-animations; legacy-image-formats; magnetometer; microphone; midi; oversized-images; payment; picture-in-picture; publickey-credentials-get; sync-xhr; usb; vr ; wake-lock; xr-spatial-tracking" sandbox="allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-downloads"></iframe>

Questo capitolo è suddiviso in sezioni che comprendono sia _concetti_ che _applicazioni_. Dopo aver appreso il concetto in ogni sezione, lo applicherai per creare un particolare tipo di demo, dalla classificazione delle immagini al riconoscimento vocale. Al termine di questo capitolo, sarete in grado di creare queste demo (e molte altre!) con poche righe di Python.

<Tip>
👀 Dai un'occhiata a <a href="https://huggingface.co/spaces" target="_blank">Hugging Face Spaces</a> per vedere molti esempi recenti di demo di machine learning costruite dalla community!
</Tip>


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter9/1.mdx" />

### Capire la classe Interface
https://huggingface.co/learn/course/it/chapter9/3.md

# Capire la classe Interface

<CourseFloatingBanner chapter={9}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/chapter9/section3.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/chapter9/section3.ipynb"},
]} />

In questa sezione, daremo un'occhiata più da vicino alla classe `Interface` e scopriremo i
parametri principali che si usano per crearne una.

## Come creare una Interface

Si può notare che la classe `Interface` (_interfaccia_) ha 3 parametri necessari:

`Interface(fn, inputs, outputs, ...)`

Questi parametri sono:

  - `fn`: la funzione per le predizione chi viene utilizzata dall'interfaccia di Gradio. Questa funzione può accettare uno o più parametri e restituire uno o più valori
  - `inputs`: il/i tipo/i dei componenti in input. Gradio fornisce molti componenti predefiniti, come `"image"`(_immagine_) o `"mic"`(_microfono_). 
  - `outputs`: il/i tipo/i dei componenti in output. Anche in questo caso, Gradio fornisce molti componenti predefiniti, come `"image"` o `"label"`. 

Per un elenco completo dei componenti, [consultare la documentazione di Gradio](https://gradio.app/docs). Ogni componente predefinito può essere personalizzato istanziando la classe corrispondente al componente.

Ad esempio, come abbiamo visto nella [sezione precedente](/course/chapter9/2),
invece di passare `"textbox"` al parametro `inputs`, si può passare un componente `Textbox(lines=7, label="Prompt")` per creare una casella di testo con 7 righe e un'etichetta.

Diamo un'occhiata a un altro esempio, questa volta con un componente `Audio`.

## Un semplice esempio con l'audio

Come detto in precedenza, Gradio fornisce molti input e output differenti.
Costruiamo perciò una `Interface` che funziona con l'audio.

In questo esempio, svilupperemo una funzione da audio ad audio che prende un
file audio e semplicemente lo inverte.

Per l'input utilizzeremo il componente `Audio`. Quando si usa il componente `Audio`,
si può specificare se si vuole che la `source` (_sorgente_) dell'audio sia un file
caricato dall'utente o un microfono con cui l'utente può registrare la propria voce. In questo caso,
impostiamo `"microphone"`. Per divertimento, aggiungeremo un'etichetta al nostro `Audio` che dice
"Speak here..." (_"Parla qui..."_). 

Inoltre, vorremmo ricevere l'audio come un numpy array, in modo da poterlo facilmente
"invertire". Impostiamo quindi il `"type"` come `"numpy"`, che passa i dati in input
come una tupla di (`sample_rate`, `data`) alla nostra funzione.

Utilizzeremo anche il componente di output `Audio`, il quale può convertire automaticamente
una tupla formata da una frequenza di campionamento e un numpy array di dati in un file audio riproducibile.
In questo caso, non abbiamo bisogno di fare alcuna personalizzazione, quindi useremo la stringa
`"audio"`.


```py
import numpy as np
import gradio as gr


def reverse_audio(audio):
    sr, data = audio
    reversed_audio = (sr, np.flipud(data))
    return reversed_audio


mic = gr.Audio(source="microphone", type="numpy", label="Speak here...")
gr.Interface(reverse_audio, mic, "audio").launch()
```

Il codice precedente produrrà un'interfaccia come quella qui sotto (se il tuo browser non
chiede il premesso per usare il microfono, <a href="https://huggingface.co/spaces/course-demos/audio-reverse" target="_blank">apri il demo in una tab diversa</a>.)

<iframe src="https://course-demos-audio-reverse.hf.space" frameBorder="0" height="250" title="Gradio app" class="container p-0 flex-grow space-iframe" allow="accelerometer; ambient-light-sensor; autoplay; battery; camera; document-domain; encrypted-media; fullscreen; geolocation; gyroscope; layout-animations; legacy-image-formats; magnetometer; microphone; midi; oversized-images; payment; picture-in-picture; publickey-credentials-get; sync-xhr; usb; vr ; wake-lock; xr-spatial-tracking" sandbox="allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-downloads"></iframe>

A questo punto potresti registrare la tua voce e di sentirti parlare al contrario - spaventoso 👻!

## Lavorare con più input e output

Supponiamo di avere una funzione più complicata, con più input e output.
Nell'esempio seguente, abbiamo una funzione che richiede un elenco a tendina, il valore di uno slider e un numero,
e restituisce il campione audio di una nota musicale.

Osserva come si passa un elenco di componenti di input e di output,
e vedi se riesci a seguire quello che succede.

La questione fondamentale è che quando si passa:
* un elenco di componenti di input, ogni componente corrisponde in ordine a un parametro.
* un elenco di componenti di output, ogni componente corrisponde a un valore restituito.

Lo snippet di codice qui sotto mostra come tre componenti di input si abbinano ai tre argomenti della funzione `generate_tone()`:

```py
import numpy as np
import gradio as gr

notes = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]


def generate_tone(note, octave, duration):
    sr = 48000
    a4_freq, tones_from_a4 = 440, 12 * (octave - 4) + (note - 9)
    frequency = a4_freq * 2 ** (tones_from_a4 / 12)
    duration = int(duration)
    audio = np.linspace(0, duration, duration * sr)
    audio = (20000 * np.sin(audio * (2 * np.pi * frequency))).astype(np.int16)
    return (sr, audio)


gr.Interface(
    generate_tone,
    [
        gr.Dropdown(notes, type="index"),
        gr.Slider(minimum=4, maximum=6, step=1),
        gr.Textbox(type="number", value=1, label="Duration in seconds"),
    ],
    "audio",
).launch()
```

<iframe src="https://course-demos-generate-tone.hf.space" frameBorder="0" height="450" title="Gradio app" class="container p-0 flex-grow space-iframe" allow="accelerometer; ambient-light-sensor; autoplay; battery; camera; document-domain; encrypted-media; fullscreen; geolocation; gyroscope; layout-animations; legacy-image-formats; magnetometer; microphone; midi; oversized-images; payment; picture-in-picture; publickey-credentials-get; sync-xhr; usb; vr ; wake-lock; xr-spatial-tracking" sandbox="allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-downloads"></iframe>


### Il metodo `launch()`

Per ora, abbiamo utilizzato il metodo `launch()` per avviare l'interfaccia, ma
non abbiamo discusso realmente cosa fa.

Di default, il metodo `launch()` avvia la demo in un web server che
che viene eseguito in locale. Se si esegue il codice in un Jupyter o Colab notebook, 
Gradio incorporerà l'interfaccia grafica della demo nel notebook, così da poterla usare facilmente.

È possibile modificare il comportamento di `launch()` attraverso diversi parametri:

  - `inline` - per visualizzare l'interfaccia _inline_ sui notebook di Python.
  - `inbrowser` - per avviare automaticamente l'interfaccia in una nuova scheda del browser di default.
  - `share` - per create un link pubblico per l'interfaccia da condividere dal proprio computer. Un po' come un link di Google Drive!

Il parametro `share` sarà trattato in modo molto più dettagliato nella prossima sezione!

## ✏️ Mettiamolo in pratica!

Costruiamo un'interfaccia che permetta di provare un modello di **riconoscimento vocale**.
Per renderlo interessante, accetteremo un input *qualisiasi* tra un microfono o un file caricato.

Come al solito, caricheremo il nostro modello di riconoscimento vocale usando la funzione `pipeline()` da 🤗 Transformers.
Se si ha bisogno di un ripasso veloce, si può tornare a [quella sezione nel Capitolo 1](/course/chapter1/3).     Quindi, implementeremo una funzione `transcribe_audio()` che elabora l'audio e restituisce la sua trascrizione. Infine, avvolgeremo questa funzione in una `Interface` con i componenti `Audio` per gli input e solo testo per l'output. Il codice completo per questa applicazione è il seguente:

```py
from transformers import pipeline
import gradio as gr

model = pipeline("automatic-speech-recognition")


def transcribe_audio(mic=None, file=None):
    if mic is not None:
        audio = mic
    elif file is not None:
        audio = file
    else:
        return "You must either provide a mic recording or a file"
    transcription = model(audio)["text"]
    return transcription


gr.Interface(
    fn=transcribe_audio,
    inputs=[
        gr.Audio(source="microphone", type="filepath", optional=True),
        gr.Audio(source="upload", type="filepath", optional=True),
    ],
    outputs="text",
).launch()
```

Se il tuo browser non ti chiede i permessi per il microfono, <a href="https://huggingface.co/spaces/course-demos/audio-reverse" target="_blank">apri la demo in una scheda separata</a>.

<iframe src="https://course-demos-asr.hf.space" frameBorder="0" height="550" title="Gradio app" class="container p-0 flex-grow space-iframe" allow="accelerometer; ambient-light-sensor; autoplay; battery; camera; document-domain; encrypted-media; fullscreen; geolocation; gyroscope; layout-animations; legacy-image-formats; magnetometer; microphone; midi; oversized-images; payment; picture-in-picture; publickey-credentials-get; sync-xhr; usb; vr ; wake-lock; xr-spatial-tracking" sandbox="allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-downloads"></iframe>


Ecco fatto! Ora è possibile utilizzare questa interfaccia per trascrivere l'audio. Si osservi che
passando il parametro `optional` come `True`, si permette all'utente di
fornire o un microfono o un file audio (o nessuno dei due, ma questo restituirà un messaggio di errore).

Continua a leggere per scoprire come condividere la tua interfaccia con gli altri!

<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter9/3.mdx" />

### Creare la tua prima demo
https://huggingface.co/learn/course/it/chapter9/2.md

# Creare la tua prima demo

<CourseFloatingBanner chapter={9}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/chapter9/section2.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/chapter9/section2.ipynb"},
]} />

Iniziamo installando Gradio! Essendo una libreria di Python, è sufficiente eseguire:

`$ pip install gradio `

Puoi usare Gradio ovunque, dalla tua IDE Python preferita, ai Jupyter notebook o anche in Google Colab 🤯!
Quindi, installa Gradio in qualsiasi posto in cui usi Python!

Iniziamo con un semplice esempio "Hello World" per prendere familiarità con la sintassi di Gradio:

```py
import gradio as gr


def greet(name):
    return "Hello " + name


demo = gr.Interface(fn=greet, inputs="text", outputs="text")

demo.launch()
```

Analizziamo il codice qui sopra:

- Per prima cosa, definiamo una funzione chiamata `greet()`. In questo caso, si tratta di una semplice funzione che aggiunge "Hello" prima di un nome (_name_), ma questa può essere in generale *qualsiasi* funzione in Python. Ad esempio, nelle applicazioni di machine learning, questa funzione *chiamerebbe un modello per fare una previsione* su un input e restituirebbe l'output.
- Creaiamo puoi una `Interface` (_Interfaccia_) di Gradio con tre argomenti, `fn`, `inputs`, e `outputs`. Questi argomenti definiscono la funzione di predizione e il _tipo_ di componenti di ingresso e di uscita che desideriamo. Nel nostro caso, entrambi i componenti sono semplici caselle di testo.
- Chiamiamo poi il metodo `launch()` sul `Interface` creata.

Se si esegue questo codice, l'interfaccia qui sotto apparirà automaticamente all'interno di un Jupyter/Colab notebook, o comparirà in un browser  **[http://localhost:7860](http://localhost:7860/)** se lanciato in uno script.

<iframe src="https://course-demos-hello-world.hf.space" frameBorder="0" height="250" title="Gradio app" class="container p-0 flex-grow space-iframe" allow="accelerometer; ambient-light-sensor; autoplay; battery; camera; document-domain; encrypted-media; fullscreen; geolocation; gyroscope; layout-animations; legacy-image-formats; magnetometer; microphone; midi; oversized-images; payment; picture-in-picture; publickey-credentials-get; sync-xhr; usb; vr ; wake-lock; xr-spatial-tracking" sandbox="allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-downloads"></iframe>

Prova subito a utilizzare questa GUI con il tuo nome o con un altro input!

Si noterà che in questa GUI, Gradio ha riconosciuto automaticamente il nome del parametro di input (`name`)
e lo applica come etichetta in cima alla casella di testo. E se si volesse cambiarlo?
O se si volesse personalizzare la casella di testo in qualche altro modo? In questo caso, si può
istanziare una classe che rappresenti il componente in input.

Si osservi l'esempio seguente:

```py
import gradio as gr


def greet(name):
    return "Hello " + name


# We instantiate the Textbox class
textbox = gr.Textbox(label="Type your name here:", placeholder="John Doe", lines=2)

gr.Interface(fn=greet, inputs=textbox, outputs="text").launch()
```

<iframe src="https://course-demos-hello-world-custom.hf.space" frameBorder="0" height="300" title="Gradio app" class="container p-0 flex-grow space-iframe" allow="accelerometer; ambient-light-sensor; autoplay; battery; camera; document-domain; encrypted-media; fullscreen; geolocation; gyroscope; layout-animations; legacy-image-formats; magnetometer; microphone; midi; oversized-images; payment; picture-in-picture; publickey-credentials-get; sync-xhr; usb; vr ; wake-lock; xr-spatial-tracking" sandbox="allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-downloads"></iframe>

Qui abbiamo creato una casella di testo di input con un'etichetta (`label`), un segnaposto (`placeholder`) e un numero di righe stabilito (`lines`).
Si potrebbe fare lo stesso per la casella di testo in output, ma per ora ci fermiamo qui.

Abbiamo visto che con poche righe di codice, Gradio consente di creare una semplice interfaccia intorno a qualsiasi funzione
con qualsiasi tipo di input o output. In questa sezione abbiamo iniziato con una 
semplice casella di testo, ma nelle prossime sezioni tratteremo altri tipi di input e output. Vediamo ora di inserire un po' di NLP in un'applicazione Gradio.


## 🤖 Includere le predizioni del modello

Costruiamo ora una semplice interfaccia che consenta di dimostrare come funziona un modello di **generazione del testo** come GPT-2.

Caricheremo il nostro modello usando la funzione `pipeline()` di 🤗 Transformers.
Se hai bisogno di un rapido ripasso, puoi tornare a [quella sezione nel Capitolo 1](/course/chapter1/3#text-generation).

Per prima cosa, definiamo una funzione di predizione che riceve un prompt di testo e restituisce il testo completato:

```py
from transformers import pipeline

model = pipeline("text-generation")


def predict(prompt):
    completion = model(prompt)[0]["generated_text"]
    return completion
```

Questa funzione completa le richieste fornite dall'utente e puoi eseguirla con qualche tuo input per vedere come funziona. Ecco un esempio (potresti ottenere un risultato diverso):

```
predict("My favorite programming language is")
```

```
>> My favorite programming language is Haskell. I really enjoyed the Haskell language, but it doesn't have all the features that can be applied to any other language. For example, all it does is compile to a byte array.
```

Ora che abbiamo una funzione per generare previsioni, possiamo creare e lanciare una `Interface` nello stesso modo in cui abbiamo fatto prima:

```py
import gradio as gr

gr.Interface(fn=predict, inputs="text", outputs="text").launch()
```


Ecco fatto! Ora è possibile utilizzare questa interfaccia per generare testo utilizzando il modello GPT-2 come mostrato qui sotto 🤯.

<iframe src="https://course-demos-gpt-2.hf.space" frameBorder="0" height="300" title="Gradio app" class="container p-0 flex-grow space-iframe" allow="accelerometer; ambient-light-sensor; autoplay; battery; camera; document-domain; encrypted-media; fullscreen; geolocation; gyroscope; layout-animations; legacy-image-formats; magnetometer; microphone; midi; oversized-images; payment; picture-in-picture; publickey-credentials-get; sync-xhr; usb; vr ; wake-lock; xr-spatial-tracking" sandbox="allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-downloads"></iframe>

Continua a leggere per scoprire come costruire altri tipi di demo con Gradio!

<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter9/2.mdx" />

### Creare il proprio dataset
https://huggingface.co/learn/course/it/chapter5/5.md

# Creare il proprio dataset

<CourseFloatingBanner chapter={5}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/it/chapter5/section5.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/it/chapter5/section5.ipynb"},
]} />

A volte il dataset che ti serve per la tua applicazione NLP non esiste, per cui dovrai crearlo da te. In questa sezione ti mostreremo come creare un corpus di [issue da GitHub](https://github.com/features/issues), usate solitamente per tenere traccia dei bug e delle feature nelle repository su GitHub. Questo corpus può essere usato in diversi modi, ad esempio:

* Esplorare il tempo impiegato per chiudere un issue, o per effettuare dei pull
* Addestrare un _classificatore multiclasse_ che assegna a ogni issue dei metadati sulla base della descrizione dell'issue (ad esempio, "bug", "enhancement", "question")
* Creare un motore di ricerca semantico per trovare quale issue corrisponde a una richiesta dell'utente

Ci focalizzeremo sulla creazione del corpus, e nella prossima sezione affronteremo la creazione di un motore di ricerca semantico. Useremo gli issue GitHub associate a un progetto open source molto popolare: 🤗 Datasets! Diamo un'occhiata a come recuperare i dati e come esplorare le informazioni contenute negli issue. 

## Recuperare i dati 

Puoi trovare tutte gli issue in 🤗 Datasets navigando nella [sezione Issues della repository](https://github.com/huggingface/datasets/issues). Come si vede dallo screenshot, al momento della scrittura c'erano 331 issue aperti e 668 issue chiusi.

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter5/datasets-issues.png" alt="The GitHub issues associated with 🤗 Datasets." width="80%"/>
</div>

Se clicchi su una di questi issue vedrai che contiene un titolo, una descrizione, e un set di etichette che caratterizzano l'issue. Un esempio è mostrato nello screenshot successivo.

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter5/datasets-issues-single.png" alt="A typical GitHub issue in the 🤗 Datasets repository." width="80%"/>
</div>

Per scaricare gli issue della repository, useremo la [REST API di GitHub](https://docs.github.com/en/rest) per interrogare l'[endpoint `Issues`](https://docs.github.com/en/rest/reference/issues#list-repository-issues). Questo endpoint restituisce una lista di oggetti JSON, e ogni oggetto contiene un gran numero di campi, tra cui il titolo e la descrizione, così come dei metadati circo lo status dell'issue e altro ancora. 

Una maniera conveniente di scaricare gli issue è attraverso la libreria `requests`, che rappresenta il metodo standard di fare richieste HTTP su Python. Puoi installa la libreria attraverso il codice:

```python
!pip install requests
```

Una volta che la libreria è stata installata, puoi effettuare una richiesta GET all'endpoint `Issues` utilizzando la funzione `requests.get()`. Ad esempio, puoi eseguire il comando mostrato di seguito per recuperare il primo issue nella prima pagina:

```py
import requests

url = "https://api.github.com/repos/huggingface/datasets/issues?page=1&per_page=1"
response = requests.get(url)
```

L'oggetto `response` contiene un sacco di informazioni utili sulla richiesta, compreso il codice di stato HTTP:

```py
response.status_code
```

```python out
200
```

Lo status `200` indica che la richiesta ha avuto buon fine (puoi trovare una lista di codici di stato HTTTP [qui](https://it.wikipedia.org/wiki/Codici_di_stato_HTTP)). Ma ciò che ci interessa davvero è il _payload_, a cui è possibile accedere utilizzando diversi formati come byte, stringh, o JSON. Visto che sappiamo che i nostri issue sono in formato JSON, diamo un'occhiata al payload come segue:

```py
response.json()
```

```python out
[{'url': 'https://api.github.com/repos/huggingface/datasets/issues/2792',
  'repository_url': 'https://api.github.com/repos/huggingface/datasets',
  'labels_url': 'https://api.github.com/repos/huggingface/datasets/issues/2792/labels{/name}',
  'comments_url': 'https://api.github.com/repos/huggingface/datasets/issues/2792/comments',
  'events_url': 'https://api.github.com/repos/huggingface/datasets/issues/2792/events',
  'html_url': 'https://github.com/huggingface/datasets/pull/2792',
  'id': 968650274,
  'node_id': 'MDExOlB1bGxSZXF1ZXN0NzEwNzUyMjc0',
  'number': 2792,
  'title': 'Update GooAQ',
  'user': {'login': 'bhavitvyamalik',
   'id': 19718818,
   'node_id': 'MDQ6VXNlcjE5NzE4ODE4',
   'avatar_url': 'https://avatars.githubusercontent.com/u/19718818?v=4',
   'gravatar_id': '',
   'url': 'https://api.github.com/users/bhavitvyamalik',
   'html_url': 'https://github.com/bhavitvyamalik',
   'followers_url': 'https://api.github.com/users/bhavitvyamalik/followers',
   'following_url': 'https://api.github.com/users/bhavitvyamalik/following{/other_user}',
   'gists_url': 'https://api.github.com/users/bhavitvyamalik/gists{/gist_id}',
   'starred_url': 'https://api.github.com/users/bhavitvyamalik/starred{/owner}{/repo}',
   'subscriptions_url': 'https://api.github.com/users/bhavitvyamalik/subscriptions',
   'organizations_url': 'https://api.github.com/users/bhavitvyamalik/orgs',
   'repos_url': 'https://api.github.com/users/bhavitvyamalik/repos',
   'events_url': 'https://api.github.com/users/bhavitvyamalik/events{/privacy}',
   'received_events_url': 'https://api.github.com/users/bhavitvyamalik/received_events',
   'type': 'User',
   'site_admin': False},
  'labels': [],
  'state': 'open',
  'locked': False,
  'assignee': None,
  'assignees': [],
  'milestone': None,
  'comments': 1,
  'created_at': '2021-08-12T11:40:18Z',
  'updated_at': '2021-08-12T12:31:17Z',
  'closed_at': None,
  'author_association': 'CONTRIBUTOR',
  'active_lock_reason': None,
  'pull_request': {'url': 'https://api.github.com/repos/huggingface/datasets/pulls/2792',
   'html_url': 'https://github.com/huggingface/datasets/pull/2792',
   'diff_url': 'https://github.com/huggingface/datasets/pull/2792.diff',
   'patch_url': 'https://github.com/huggingface/datasets/pull/2792.patch'},
  'body': '[GooAQ](https://github.com/allenai/gooaq) dataset was recently updated after splits were added for the same. This PR contains new updated GooAQ with train/val/test splits and updated README as well.',
  'performed_via_github_app': None}]
```

Wow, quante informazioni! Possiamo vedere alcuni campi utili come `title`, `body` e `number` che descrivono l'issue, così come informazioni sull'utente che l'ha aperto.

<Tip>

✏️ **Prova tu!** Clicca su alcuni degli URL nel payload JSON per farti un'idea del tipo di informazione a cui è collegato ogni issue GitHub.

</Tip>

Come descritto nella [documentazione di GitHub](https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting), le richieste senza autenticazione sono limitate a 60 ogni ora. Benché possiamo aumentare il parametro della query `per_page` per ridurre il numero di richieste, raggiungerai comunque il limite su qualunque repository che ha qualche migliaio di issue. Quindi, dovresti seguire le [istruzioni](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) su come creare un _token di accesso personale_ così che puoi aumentare il limite a 5.000 richieste ogni ora. Una volta che hai ottenuto il tuo token, puoi includerlo come parte dell'header della richiesta:

```py
GITHUB_TOKEN = xxx  # inserisci qui il tuo token GitHub
headers = {"Authorization": f"token {GITHUB_TOKEN}"}
```

<Tip warning={true}>

⚠️ Fai attenzione a non condividere un notebook con il tuo `GITHUB_TOKEN` al suo interno. Ti consigliamo di cancellare l'ultima cella una volta che l'hai eseguita per evitare di far trapelare quest'informazione accidentalmente. Meglio ancora, salva il tuo token in un file *.env* e usa la [libreria `python-dotenv`](https://github.com/theskumar/python-dotenv) per caricarlo automaticamente come una variabile d'ambiente.

</Tip>

Ora che abbiamo il nostro token di accesso, creiamo una funzione che scarichi tutti gli issue da una repository GitHub:

```py
import time
import math
from pathlib import Path
import pandas as pd
from tqdm.notebook import tqdm


def fetch_issues(
    owner="huggingface",
    repo="datasets",
    num_issues=10_000,
    rate_limit=5_000,
    issues_path=Path("."),
):
    if not issues_path.is_dir():
        issues_path.mkdir(exist_ok=True)

    batch = []
    all_issues = []
    per_page = 100  # Numero di issue da restituire per pagina
    num_pages = math.ceil(num_issues / per_page)
    base_url = "https://api.github.com/repos"

    for page in tqdm(range(num_pages)):
        # La query ha state=all per ottenere sia gli issue aperti che quelli chiusi
        query = f"issues?page={page}&per_page={per_page}&state=all"
        issues = requests.get(f"{base_url}/{owner}/{repo}/{query}", headers=headers)
        batch.extend(issues.json())

        if len(batch) > rate_limit and len(all_issues) < num_issues:
            all_issues.extend(batch)
            batch = []  # puliamo la batch per il termine successivo
            print(f"Reached GitHub rate limit. Sleeping for one hour ...")
            time.sleep(60 * 60 + 1)

    all_issues.extend(batch)
    df = pd.DataFrame.from_records(all_issues)
    df.to_json(f"{issues_path}/{repo}-issues.jsonl", orient="records", lines=True)
    print(
        f"Downloaded all the issues for {repo}! Dataset stored at {issues_path}/{repo}-issues.jsonl"
    )
```

Ora quando eseguiremo `fetch_issues()`, scaricherà tutti gli issue in batch per evitare di superare il limite di GitHub del numero di richieste per ora; il risultato sarà conservato in un file _repository_name-issues.jsonl_, in cui ogni linea è un oggetto JSON che rappresenta un issue. Usiamo questa funzione per recuperare tutti gli issue da 🤗 Datasets:

```py
# A seconda della tua connessione internet, ci potrebbe volere qualche secondo...
fetch_issues()
```

Una volta che gli issue sono stati scaricati, possiamo caricarli in locale usando le nuove abilità imparate nella [sezione 2](/course/chapter5/2):

```py
issues_dataset = load_dataset("json", data_files="datasets-issues.jsonl", split="train")
issues_dataset
```

```python out
Dataset({
    features: ['url', 'repository_url', 'labels_url', 'comments_url', 'events_url', 'html_url', 'id', 'node_id', 'number', 'title', 'user', 'labels', 'state', 'locked', 'assignee', 'assignees', 'milestone', 'comments', 'created_at', 'updated_at', 'closed_at', 'author_association', 'active_lock_reason', 'pull_request', 'body', 'timeline_url', 'performed_via_github_app'],
    num_rows: 3019
})
```

Benissimo, abbiamo creato il nostro primo dataset da zero! Ma perché ci sono migliaia di issue quando la [sezione Issues](https://github.com/huggingface/datasets/issues) della repository 🤗 Datasets mostra circa 1,000 issue in totale 🤔? Come indicato nella [documentazione di GitHub](https://docs.github.com/en/rest/reference/issues#list-issues-assigned-to-the-authenticated-user), è perché abbiamo scaricato anche le richieste di pull:

> GitHub's REST API v3 considers every pull request an issue, but not every issue is a pull request. For this reason, "Issues" endpoints may return both issues and pull requests in the response. You can identify pull requests by the `pull_request` key. Be aware that the `id` of a pull request returned from "Issues" endpoints will be an issue id.

(_La REST API v3 di GitHub considera ogni richiesta di pull un issue, ma non ogni issue è una richiesta di pull. Per questa ragione, gli endpoint "Issues" potrebbe tornare sia gli issue che le richieste di pull. È possibile identificare le richieste di pull utilizzando la chiave `pull_request`. Tieni presente che l'`id` di una richiesta di pull resituita dagli endpoint `Issues` sarà un id di un issue._)

Poichè i contenuti degli issue e delle richieste di pull sono molto diversi, facciamo un po' di preprocessing per permetterci di distinguere tra i due.

## Pulire i dati

Il frammento precedente della documentazione di GitHub ci dice che la colonna `pull_request` può essere utilizzata per distinguere gli issue e le richieste di pull. Diamo uno sguardo a un esempio casuale per vedere qual è la differenza. Come abbiamo fatto nella [sezione 3](/course/chapter5/3), concateneremo `Dataset.shuffle()` e `Dataset.select()` per creare un campione random, e poi zipperemo le colonne `html_url` e `pull_request` così da poter paragonare i diversi URL:

```py
sample = issues_dataset.shuffle(seed=666).select(range(3))

# Stampiamo le entrate `URL` e `pull_request`
for url, pr in zip(sample["html_url"], sample["pull_request"]):
    print(f">> URL: {url}")
    print(f">> Pull request: {pr}\n")
```

```python out
>> URL: https://github.com/huggingface/datasets/pull/850
>> Pull request: {'url': 'https://api.github.com/repos/huggingface/datasets/pulls/850', 'html_url': 'https://github.com/huggingface/datasets/pull/850', 'diff_url': 'https://github.com/huggingface/datasets/pull/850.diff', 'patch_url': 'https://github.com/huggingface/datasets/pull/850.patch'}

>> URL: https://github.com/huggingface/datasets/issues/2773
>> Pull request: None

>> URL: https://github.com/huggingface/datasets/pull/783
>> Pull request: {'url': 'https://api.github.com/repos/huggingface/datasets/pulls/783', 'html_url': 'https://github.com/huggingface/datasets/pull/783', 'diff_url': 'https://github.com/huggingface/datasets/pull/783.diff', 'patch_url': 'https://github.com/huggingface/datasets/pull/783.patch'}
```

Possiamo vedere che ogni richiesta di pull è associata a diversi URL, mentre i comuni issue hanno un'entrata `None`. Possiamo usare questa distinzione per crare una nuova colonna `is_pull_request` che controlla se il campo `pull_request` sia `None` o meno:

```py
issues_dataset = issues_dataset.map(
    lambda x: {"is_pull_request": False if x["pull_request"] is None else True}
)
```

<Tip>

✏️ **Prova tu!** Calcola il tempo medio che ci vuole a chiudere un issue su 🤗 Datasets. Potrebbe essere utile usare la funzione `Dataset.filter()` per eliminare le richieste di pull e gli issue aperti, e puoi usare la funzione `Dataset.set_format()` per convertire il dataset in un `DataFrame` così che puoi facilmente manipolare i timestamp `created_at` e `closed_at`. Per dei punti bonus, calcola il tempo medio che ci vuole a chiudere le richieste di pull.

</Tip>

Benché potremmo procedere e pulire ulteriormente il dataset eliminando o rinominando alcune colonne, è solitamente buona prassi lasciare il dataset quando più intatto è possibile in questo stadio, così che può essere utilizzato facilmente in più applicazioni.

Prima di caricare il nostro dataset sull'Hub Hugging Face, dobbiamo occuparci di una cosa che manca: i commenti associati a ogni issue e richiesta di pull. Hai indovinato, li aggiungeremo utilizzando la REST API di GitHub!

## Estendere il dataset 

Come mostrato negli screenshot di seguito, i commenti associati a un issue o una richiesta di pull offrono una fonte molto ricca di informazioni, soprattutto se siamo interessati a costruire un motore di ricerca per rispondere alle richieste degli utenti sulla libreria.

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter5/datasets-issues-comment.png" alt="Comments associated with an issue about 🤗 Datasets." width="80%"/>
</div>

La REST API di GitHub offre un [endpoint `Comments`](https://docs.github.com/en/rest/reference/issues#list-issue-comments) che restituisce tutti i commenti associati con un numero di issue. Testiamo quest'endpoint per vedere cosa restituisce:

```py
issue_number = 2792
url = f"https://api.github.com/repos/huggingface/datasets/issues/{issue_number}/comments"
response = requests.get(url, headers=headers)
response.json()
```

```python out
[{'url': 'https://api.github.com/repos/huggingface/datasets/issues/comments/897594128',
  'html_url': 'https://github.com/huggingface/datasets/pull/2792#issuecomment-897594128',
  'issue_url': 'https://api.github.com/repos/huggingface/datasets/issues/2792',
  'id': 897594128,
  'node_id': 'IC_kwDODunzps41gDMQ',
  'user': {'login': 'bhavitvyamalik',
   'id': 19718818,
   'node_id': 'MDQ6VXNlcjE5NzE4ODE4',
   'avatar_url': 'https://avatars.githubusercontent.com/u/19718818?v=4',
   'gravatar_id': '',
   'url': 'https://api.github.com/users/bhavitvyamalik',
   'html_url': 'https://github.com/bhavitvyamalik',
   'followers_url': 'https://api.github.com/users/bhavitvyamalik/followers',
   'following_url': 'https://api.github.com/users/bhavitvyamalik/following{/other_user}',
   'gists_url': 'https://api.github.com/users/bhavitvyamalik/gists{/gist_id}',
   'starred_url': 'https://api.github.com/users/bhavitvyamalik/starred{/owner}{/repo}',
   'subscriptions_url': 'https://api.github.com/users/bhavitvyamalik/subscriptions',
   'organizations_url': 'https://api.github.com/users/bhavitvyamalik/orgs',
   'repos_url': 'https://api.github.com/users/bhavitvyamalik/repos',
   'events_url': 'https://api.github.com/users/bhavitvyamalik/events{/privacy}',
   'received_events_url': 'https://api.github.com/users/bhavitvyamalik/received_events',
   'type': 'User',
   'site_admin': False},
  'created_at': '2021-08-12T12:21:52Z',
  'updated_at': '2021-08-12T12:31:17Z',
  'author_association': 'CONTRIBUTOR',
  'body': "@albertvillanova my tests are failing here:\r\n```\r\ndataset_name = 'gooaq'\r\n\r\n    def test_load_dataset(self, dataset_name):\r\n        configs = self.dataset_tester.load_all_configs(dataset_name, is_local=True)[:1]\r\n>       self.dataset_tester.check_load_dataset(dataset_name, configs, is_local=True, use_local_dummy_data=True)\r\n\r\ntests/test_dataset_common.py:234: \r\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \r\ntests/test_dataset_common.py:187: in check_load_dataset\r\n    self.parent.assertTrue(len(dataset[split]) > 0)\r\nE   AssertionError: False is not true\r\n```\r\nWhen I try loading dataset on local machine it works fine. Any suggestions on how can I avoid this error?",
  'performed_via_github_app': None}]
```

Possiamo vedere che il commento è archiviato nel campo `body`, quindi possiamo scvrivere una semplice funzione che restituisce tutti i commenti associati con un issue estraendo i contenuti di `body` per ogni elemento in `response.json()`:

```py
def get_comments(issue_number):
    url = f"https://api.github.com/repos/huggingface/datasets/issues/{issue_number}/comments"
    response = requests.get(url, headers=headers)
    return [r["body"] for r in response.json()]


# Testiamo la nostra funzione
get_comments(2792)
```

```python out
["@albertvillanova my tests are failing here:\r\n```\r\ndataset_name = 'gooaq'\r\n\r\n    def test_load_dataset(self, dataset_name):\r\n        configs = self.dataset_tester.load_all_configs(dataset_name, is_local=True)[:1]\r\n>       self.dataset_tester.check_load_dataset(dataset_name, configs, is_local=True, use_local_dummy_data=True)\r\n\r\ntests/test_dataset_common.py:234: \r\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \r\ntests/test_dataset_common.py:187: in check_load_dataset\r\n    self.parent.assertTrue(len(dataset[split]) > 0)\r\nE   AssertionError: False is not true\r\n```\r\nWhen I try loading dataset on local machine it works fine. Any suggestions on how can I avoid this error?"]
```

Sembra andar bene, quindi possiamo usare `Dataset.map()` per aggiungere una nuova colonna `comments` a ogni usse nel nostro dataset:

```py
# A seconda della tua connessione, potrebbe volerci qualche secondo...
issues_with_comments_dataset = issues_dataset.map(
    lambda x: {"comments": get_comments(x["number"])}
)
```

Come passaggio finale, salviamo il dataset esteso assieme ai nostri dati non processati, così da poter caricare entrambi sull'Hub:

```py
issues_with_comments_dataset.to_json("issues-datasets-with-comments.jsonl")
```

## Caricare il dataset sull'Hub Hugging Face 

<Youtube id="HaN6qCr_Afc"/>

Ora che abbiamo il nostro dataset esteso, è arrivato il momento di caricarlo sull'Hub, così da poterlo condividere con la community! Per caricare il dataset useremo la [libreria 🤗 Hub](https://github.com/huggingface/huggingface_hub), che ci permette di interagire con l'Hub di Hugging Face attraverso un'API di Python. 🤗 Hub è preinstallato con 🤗 Transformers, così possiamo usarlo da subito. Ad esempio, possiamo usare la funzione `list_datastes()` per avere informazioni su tutti i dataset pubblici attualmente presenti sull'Hub:

```py
from huggingface_hub import list_datasets

all_datasets = list_datasets()
print(f"Number of datasets on Hub: {len(all_datasets)}")
print(all_datasets[0])
```

```python out
Number of datasets on Hub: 1487
Dataset Name: acronym_identification, Tags: ['annotations_creators:expert-generated', 'language_creators:found', 'languages:en', 'licenses:mit', 'multilinguality:monolingual', 'size_categories:10K<n<100K', 'source_datasets:original', 'task_categories:structure-prediction', 'task_ids:structure-prediction-other-acronym-identification']
```

Possiamo vedere che al momento ci sono circa 1.500 dataset sull'Hub, e la funzione `list_datasets()` inoltre permette di avere alcuni metadati su ciascuna repository.

Per ciò che ci riguarda, la prima cosa che dobbiamo fare è crare una nuova repository nell'Hub. Per far ciò abbiamo bisogno di un token di autentificazione, che pouò essere ottenuto effettuando l'accesso nell'Hub Hugging Face con la funzione `notebook_login()`:

```py
from huggingface_hub import notebook_login

notebook_login()
```

Questo creerà un widget in cui puoi inserire il tuo username e la tua password, e un token API verrà salvato in *~/.huggingface/token*. Se stai eseguendo il codice in un terminale, puoi effettuare l'accesso attraverso il comando:

```bash
huggingface-cli login
```

Una volta fatto questo, possiamo crare una nuova repository con la funzione `create_repo()`:

```py
from huggingface_hub import create_repo

repo_url = create_repo(name="github-issues", repo_type="dataset")
repo_url
```

```python out
'https://huggingface.co/datasets/lewtun/github-issues'
```

In quest'esempio, abbiamo creato una repository vuota chiamata `github-issues` con l'username `lewtun` (l'username dovrebbe essere quello del tuo account Hub quando esegui questo codice!).

<Tip>

✏️ **Prova tu!** Usa le tue credenziali dell'Hub Hugging Face per ottenere un token e creare una repository vuota chiamata `github-issues`. Ricordati di **non salvere mai le tue credenziali** su Colab o qualunque altra repository, perché potrebbero essere recuperate da malintenzionati.

</Tip>

Ora, cloniamo la repository dall'Hub alla nostra macchina e copiamo al suo interno i file del nostro dataset. 🤗 Hub contiene una classe `Repository` che ha al suo interno molti dei comandi più comuni di Git, per cui per clonare la repository in remoto dobbiamo semplicemente fornire l'URL e il percorso locale in cui desideriamo clonare:

```py
from huggingface_hub import Repository

repo = Repository(local_dir="github-issues", clone_from=repo_url)
!cp issues-datasets-with-comments.jsonl github-issues/
```

Di default, diverse estensioni file (ad esempio *.bin*, *.gz* e *.zip*) sono registrate da Git LFS, così che i file di grandi dimensioni possono essere gestiti all'interno dello stesso workflow. Puoi trovare una lista delle estensioni di file monitorati nel file *.gitattributes* della repository. Per includere il formato JSON Lines a questa lista, possiamo utilizzare il comando:

```py
repo.lfs_track("*.jsonl")
```

Ora possiamo usare `Repository.push_to_hub()` per caricare il dataset sull'Hub:

```py
repo.push_to_hub()
```

Se navighiamo fino all'URL contenuto in `repo_url`, vedremo che il file del nostro dataset è stato caricato.

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter5/hub-repo.png" alt="Our dataset repository on the Hugging Face Hub." width="80%"/>
</div>

Da qui, chiunque può scaricare il dataset semplicemente inserendo l'ID della repository come argomento `path` di `load_dataset()`:

```py
remote_dataset = load_dataset("lewtun/github-issues", split="train")
remote_dataset
```

```python out
Dataset({
    features: ['url', 'repository_url', 'labels_url', 'comments_url', 'events_url', 'html_url', 'id', 'node_id', 'number', 'title', 'user', 'labels', 'state', 'locked', 'assignee', 'assignees', 'milestone', 'comments', 'created_at', 'updated_at', 'closed_at', 'author_association', 'active_lock_reason', 'pull_request', 'body', 'performed_via_github_app', 'is_pull_request'],
    num_rows: 2855
})
```

Bene, abbiamo caricato il nostro dataset sull'Hub, e può essere utilizzato da tutti! C'è un'altra cosa importante che dobbiamo fare: aggiungere una _dataset card_ che spiega come è stato creato il corpus, e offre altre informazioni utili per la community.

<Tip>

💡 Puoi caricare un dataset nell'Hub di Hugging Face anche direttamente dal terminale usando `huggingface-cli` e un po' di magia Git. La [guida a 🤗 Datasets](https://huggingface.co/docs/datasets/share#share-a-dataset-using-the-cli) spiega come farlo. 

</Tip>

## Creare una dataset card

I dataset ben-documentati sono più utili agli altri utenti (compreso il futuro te!), poiché spiegano il contesto per permettere agli utenti di decidere se un dataset può essere utile, e valutare gli eventuali bias o rischi associati nell'utilizzo del dataset.

Sull'Hug di Hugging Face, queste informazioni si trovano nel file *README.md* della repository. Ci sono due passaggi principali che dovresti seguire prima di creare questo file:

1. Usa l'[applicatione `datasets-tagging`](https://huggingface.co/datasets/tagging/) per creare tag di metadati in formato YAML. Questi tag sono usato per una serie di funzioni di ricerca sull'Hub di Hugging Face, e assicurano che il tuo dataset possa essere facilmente trovato dai membri della community. Poichè abbiamo creato un nostro dataset, dovrai clonare la repository `datasets-tagging`, ed eseguire l'applicazione in locale. Ecco com'è l'interfaccia:

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter5/datasets-tagger.png" alt="The 'datasets-tagging' interface." width="80%"/>
</div>

2. Leggi la [guida 🤗 Datasets](https://github.com/huggingface/datasets/blob/master/templates/README_guide.md) sulla creazione di dataset card informative, e usala come template.

Puoi creare il file *README.md* direttamente sull'Hub, e puoi trovare un modello per una dataset card nella repository `lewtun/github-issues`. Di seguito è mostrato uno screenshot di una dataset card già compilata.

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter5/dataset-card.png" alt="A dataset card." width="80%"/>
</div>

<Tip>

✏️ **Prova tu!** Usa l'applicazione `dataset-tagging` e la [guida 🤗 Datasets](https://github.com/huggingface/datasets/blob/master/templates/README_guide.md) per completare il file *README.md* per il tuo dataset di issue di GitHub.
</Tip>

È tutto! Abbiamo visto in questa sezione che creare un buon dataset può essere un'impresa, ma per fortuna caricarlo e condividerlo con la community è molto più semplice. Nella prossima sezione useremo il nostro nuovo dataset per creare un motore di ricerca semantico con 🤗 Datasets, che abbina alle domande gli issue e i commenti più rilevanti.

<Tip>

✏️ **Prova tu!** Segui i passi che abbiamo eseguito in questa sezione per creare un dataset di issue GitHub per la tua libreria open source preferita (ovviamente scegli qualcosa di diverso da 🤗 Datasets!). Per punti bonus, esegui il fine-tuning di un classificatore multiclasse per predirre i tag presenti nel campo `labels`.

</Tip>




<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter5/5.mdx" />

### Introduzione
https://huggingface.co/learn/course/it/chapter5/1.md

# Introduzione

<CourseFloatingBanner
    chapter={5}
    classNames="absolute z-10 right-0 top-0"
/>

Nel [Capitolo 3](/course/chapter3) hai mosso i primi passi nella libreria 🤗 Datasets, e hai scoperto i tre passaggi fondamentali nell'ottimizzazione dei modelli:

1. Si carica un dataset dell'Hub Hugging Face.
2. Si processano i dati con `Dataset.map()`.
3. Si caricano e si elaborano le metriche.

Ma questo non è che un assaggio di ciò che 🤗 Datasets è in grado di fare! In questo capitolo approfondiremo le potenzialità della libreria. Durante questo percorso, troverai risposta alle seguenti domande:

* Cosa fare quando un dataset non è presente nell'Hub?
* Come fare a tagliuzzare il dataset? (E cosa succede se devi _proprio_ usare Pandas?)
* Cosa fare quando un dataset è tanto grande da sciogliere la RAM del tuo portatile?
* Cosa cavolo sono il "mappamento di memoria" e Apache Arrow?
* Come fare per creare il proprio dataset e pubblicarlo sull'Hub?

Le tecniche che imparerai ti prepareranno a compiti più avanzati di tokenizzazione e fine-tuning che troverai nei capitoli [Chapter 6](/course/chapter6) e [Chapter 7](/course/chapter7) -- quindi preparati una tazza di caffè e iniziamo!


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter5/1.mdx" />

### È arrivato il momento di tagliuzzare
https://huggingface.co/learn/course/it/chapter5/3.md

# È arrivato il momento di tagliuzzare

<CourseFloatingBanner chapter={5}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/it/chapter5/section3.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/it/chapter5/section3.ipynb"},
]} />

La maggior parte delle volte, i dati su cui lavorerai non saranno perfettamente pronti a essere usati per l'addestramento. In questa sezione esploreremo alcune funzionalità di 🤗 Datasets per pulire i tuoi dataset.

<Youtube id="tqfSFcPMgOI"/>

## Tagliuzzare i tuoi dati

Proprio come Pandas, 🤗 Datasets offre diverse funzionalità per manipolare il contenuto degli oggetti `Dataset` e `DatasetDict`. Abbiamo già visto il metodo `Dataset.map()` nel [Capitolo 3](/course/chapter3), e in questa sezione esploreremo altre funzioni a nostra disposizione.

Ai fini di quest'esempio useremo il [Drug Review Dataset](https://archive.ics.uci.edu/ml/datasets/Drug+Review+Dataset+%28Drugs.com%29), che raccoglie le recensioni di pazienti su vari medicinali, assieme alla condizione curata e a una valutazione da 0 a 10 del grado di soddisfazione del paziente.
Prima di tutto scarichiamo ed estraiamo i dati, utilizzando i comandi `wget` e `unzip`:

```py
!wget "https://archive.ics.uci.edu/ml/machine-learning-databases/00462/drugsCom_raw.zip"
!unzip drugsCom_raw.zip
```

Poiché TSV non è altro che una variante di CSV che usa come separatore tabulatori al posto delle virgole, caricheremo questi file utilizzando lo script `csv` e specificando l'argomento `delimiter` nella funzione `load_dataset()`, come segue:

```py
from datasets import load_dataset

data_files = {"train": "drugsComTrain_raw.tsv", "test": "drugsComTest_raw.tsv"}
# \t rappresenta il tabulatore in Python
drug_dataset = load_dataset("csv", data_files=data_files, delimiter="\t")
```

È buona prassi nell'analisi dati recuperare un piccolo campione casuale per farsi un'idea del tipo di dati con cui si sta lavorando. Utilizzando 🤗 Datasets, possiamo crare un campione casuale concatenando le funzioni `Dataset.shuffle()` e `Dataset.select()`: 

```py
drug_sample = drug_dataset["train"].shuffle(seed=42).select(range(1000))
# Diamo un'occhiata ai primi esempi
drug_sample[:3]
```

```python out
{'Unnamed: 0': [87571, 178045, 80482],
 'drugName': ['Naproxen', 'Duloxetine', 'Mobic'],
 'condition': ['Gout, Acute', 'ibromyalgia', 'Inflammatory Conditions'],
 'review': ['"like the previous person mention, I&#039;m a strong believer of aleve, it works faster for my gout than the prescription meds I take. No more going to the doctor for refills.....Aleve works!"',
  '"I have taken Cymbalta for about a year and a half for fibromyalgia pain. It is great\r\nas a pain reducer and an anti-depressant, however, the side effects outweighed \r\nany benefit I got from it. I had trouble with restlessness, being tired constantly,\r\ndizziness, dry mouth, numbness and tingling in my feet, and horrible sweating. I am\r\nbeing weaned off of it now. Went from 60 mg to 30mg and now to 15 mg. I will be\r\noff completely in about a week. The fibro pain is coming back, but I would rather deal with it than the side effects."',
  '"I have been taking Mobic for over a year with no side effects other than an elevated blood pressure.  I had severe knee and ankle pain which completely went away after taking Mobic.  I attempted to stop the medication however pain returned after a few days."'],
 'rating': [9.0, 3.0, 10.0],
 'date': ['September 2, 2015', 'November 7, 2011', 'June 5, 2013'],
 'usefulCount': [36, 13, 128]}
```

Da notare che abbiamo impostato il seed in `Dataset.shuffle()` per motivi di riproducibilità. `Dataset.select()` ha bisogno di un iterabile di indici, per cui abbiamo utilizzato `range(1000)` per recuperare i primi 1.000 esempi dal dataset mescolato. Da questo campione possiamo già vedere alcune particolarità del nostor dataset:

* La colonna `Unnamed: 0` assomiglia molto a un ID anonimizzato per ognuno dei pazienti.
* La colonna `condizione` include un mix di etichette maiuscole e minuscole.
* Le recensioni sono di diversa lunghezza e contengono un mix di separatori di riga Python (`\r\n`) e di codici di caratteri HTML come `&\#039`.

Ora vediamo come utilizzare 🤗 Datasets per risolvere alcuni di questi problemi. Per confermare l'ipotesi che la colonna `Unnamed: 0` rappresenti gli ID dei pazienti, possiamo usare la funzione `Dataset.unique()` per verificare che il numero di ID corrisponda al numero delle righe in ognuna delle sezioni:


```py
for split in drug_dataset.keys():
    assert len(drug_dataset[split]) == len(drug_dataset[split].unique("Unnamed: 0"))
```

Questo sembra confermare la nostra ipotesi, quindi puliamo un po' il nostro dataset cambiando il nome della colonna `Unnamed: 0` in qualcosa di un po' più comprensibile. Possiamo usare la funzione `DatasetDict.rename_column()` per rinominare la colonna in entrambe le sezioni:


```py
drug_dataset = drug_dataset.rename_column(
    original_column_name="Unnamed: 0", new_column_name="patient_id"
)
drug_dataset
```

```python out
DatasetDict({
    train: Dataset({
        features: ['patient_id', 'drugName', 'condition', 'review', 'rating', 'date', 'usefulCount'],
        num_rows: 161297
    })
    test: Dataset({
        features: ['patient_id', 'drugName', 'condition', 'review', 'rating', 'date', 'usefulCount'],
        num_rows: 53766
    })
})
```

<Tip>

✏️ **Prova tu!** Usa la funzione `Dataset.unique()` per trovare il numero di medicine diverse e condizioni nelle sezioni di addestramento e di test.

</Tip>

Ora, normaliziamo le etichette in `condition` utilizzando `Dataset.map()`. Così come abbiamo fatto con la tokenizzazione nel [Capitolo 3](/course/chapter3), possiamo definire una semplice funzione che può essere applicata a tutte le righe di ogni sezione nel `drug_dataset`:

```py
def lowercase_condition(example):
    return {"condition": example["condition"].lower()}


drug_dataset.map(lowercase_condition)
```

```python out
AttributeError: 'NoneType' object has no attribute 'lower'
```

Oh no, abbiamo incontrato un problema con la nostra funzione! Dall'errore possiamo dedurre che alcuni dei valori nella colonna `condition` sono `None`, che non essendo stringhe non possono essere convertiti in lettere minuscole. Eliminiamo queste righe utilizzando `Dataset.filter()`, che funziona come `Dataset.map()` e accetta una funziona che riceve un singolo esempio del dataset. Invece di scrivere una funzione esplicita come:


```py
def filter_nones(x):
    return x["condition"] is not None
```

e utilizzare `drug_dataset.filter(filter_nones)`, possiamo utilizzare una _funzione lambda_ e completare tutto in un'unica riga. In Python, le funzioni lambda sono funzioni che possiamo definire senza nominarle esplicitamente. Hanno la forma generale:

```
lambda <argomenti> : <espressione>
```

dove `lambda' è una delle [keyword](https://docs.python.org/3/reference/lexical_analysis.html#keywords) speciali di Python, `<argomenti>` è una lista/set di valori separati da virgole che definisce l'input della funzione, e `<espressione>` rappresenta le operazioni che vogliamo eseguire. Ad esempio, posiamo definire una semplice funzione lamda che calcola il quadrato di un numero:

```
lambda x : x * x
```

Per applicare questa funzione a un input, dobbiamo includere sia la funzione che l'input in parentesi:

```py
(lambda x: x * x)(3)
```

```python out
9
```

Allo stesso modo, possiamo definire funzioni lmabda con argomenti multipli separandoli con virgoli. Ad esempio, possiamo calcolare l'area di un triangolo come segue:

```py
(lambda base, altezza: 0.5 * base * altezza)(4, 8)
```

```python out
16.0
```

Le funzioni lambda sono utili quando vogliamo definire piccole funzioni monouso (per maggiori informazioni, invitiamo alla lettura dell'ottimo [tutorial di Real Python](https://realpython.com/python-lambda/) di Andre Burgaud). In 🤗 Datasets, possiamo usare le funzioni lambda per definire semplici operazioni di mappatura e filtraggio. Utilizziamo questo trucchetto per eliminare i valori `None` nel nostro dataset:

```py
drug_dataset = drug_dataset.filter(lambda x: x["condition"] is not None)
```

Una volta rimosse le voci `None`, possiamo normalizzare la colonna `condition`:

```py
drug_dataset = drug_dataset.map(lowercase_condition)
# Check that lowercasing worked
drug_dataset["train"]["condition"][:3]
```

```python out
['left ventricular dysfunction', 'adhd', 'birth control']
```

Funziona! Or ache abbiamo pulito le nostre etichette, diamo un'occhiata a come pulire le recensioni.

## Creare nuove colonne

Quando abbiamo a che fare con le recensioni di clienti, è buona pratica controllare il numero di parole in ogni recensione. Una recensione potrebbe contenere solo una parola com "Ottimo!" o un vero e proprio saggio di migliaia di parole, e a seconda dell'uso che ne farai dovrai affrontare queste situazioni in maniera diversa. Per calculare il numero di parole in ogni recensione, useremo un'euristica grezza basata sulla divisione dei testi sugli spazi.


Definiamo una semplice funzione che conta il numero di parole in ogni recensione:

```py
def compute_review_length(example):
    return {"review_length": len(example["review"].split())}
```

A differenza della nostra funzione `lowercase_condition()`, `compute_review_length()` ritorna un dizionario le cui chiavi non corrispondono a nessuna delle colonne nel dataset. In questo caso, quando `compute_review_length()` è passata a `Dataset.map()`, si applicherà a tutte le righe nel dataset per creare una nuova colonna `review_lenght`;

```py
drug_dataset = drug_dataset.map(compute_review_length)
# Inspect the first training example
drug_dataset["train"][0]
```

```python out
{'patient_id': 206461,
 'drugName': 'Valsartan',
 'condition': 'left ventricular dysfunction',
 'review': '"It has no side effect, I take it in combination of Bystolic 5 Mg and Fish Oil"',
 'rating': 9.0,
 'date': 'May 20, 2012',
 'usefulCount': 27,
 'review_length': 17}
```

Come previsto, una colonna `review_length` è stata aggiunta al nostro set di addestramento. Possiamo ordinare questa nuova colonna utilizzando `Dataset.sort()` per dare un'occhiata ai valori estremi:

```py
drug_dataset["train"].sort("review_length")[:3]
```

```python out
{'patient_id': [103488, 23627, 20558],
 'drugName': ['Loestrin 21 1 / 20', 'Chlorzoxazone', 'Nucynta'],
 'condition': ['birth control', 'muscle spasm', 'pain'],
 'review': ['"Excellent."', '"useless"', '"ok"'],
 'rating': [10.0, 1.0, 6.0],
 'date': ['November 4, 2008', 'March 24, 2017', 'August 20, 2016'],
 'usefulCount': [5, 2, 10],
 'review_length': [1, 1, 1]}
```

Come sospettato, alcune revisioni contengono una sola parola che, benché potrebbe essere utile per la sentiment analysis, non dà informazioni utili per predirre la condizione.

<Tip>

🙋Un altro modo per aggiungere nuove colonne a un dataset è attraverso la funzione `Dataset.add_column()`. Questo ti permette di inserire le colonne come una lista Python o unarray NumPy, e può tornare utile in situazioni in cui `Dataset.map()` non è indicata per le tue analisi. 

</Tip>

Usiamo la funzione `Dataset.filter()` per rimuovere le recensioni che contengono meno di 30 parole. Proprio come abbiamo fatto per la colonna `condizione`, possiamo eliminare le recensioni più brevi aggiungendo un filtro che lascia passare solo le recensioni più lunghe di una certa soglia:

```py
drug_dataset = drug_dataset.filter(lambda x: x["review_length"] > 30)
print(drug_dataset.num_rows)
```

```python out
{'train': 138514, 'test': 46108}
```

Come puoi vedere, questo ha rimosso circa il 15% delle recensioni nelle sezioni di training e di test.

<Tip>

✏️ **Prova tu!** Usa la funzione `Dataset.sort()` per analizzare le revisioni con il maggior numero di parole. Controlla la [documentazione](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.sort) per vedere quali argomenti bisogna usare per ordinare le recensioni in ordine decrescente di lunghezza.

</Tip>

L'ultima cosa che ci resta da risolvere è la presenza di codici HTML di caratteri nelle nostre recensioni. Possiamo usare il modulo Python `html` per sostituirli, così:

```py
import html

text = "I&#039;m a transformer called BERT"
html.unescape(text)
```

```python out
"I'm a transformer called BERT"
```

We'll use `Dataset.map()` to unescape all the HTML characters in our corpus:

```python
drug_dataset = drug_dataset.map(lambda x: {"review": html.unescape(x["review"])})
```
Come puoi vedere, il metodo `Dataset.map()` è molto utile per processare i dati -- e questo non è che la punta dell'iceberg di ciò che è in grado di fare!

## I superpoteri del metodo `map()` 

Il metodo `Dataset.map()` accetta un argomento `batched` che, se impostato su `True`, gli fa inviare un batch di esempi alla funzione map in una sola volta (la grandezza del batch è configurabile, ma di default è impostta a 1.000). Ad esempio, l'esecuzione delle funzione map precedente che ha sostituito tutti i caratteri HTML è stata un po' lenta (puoi leggere il tempo impiegato dalle barre di progresso). Possiamo accelerare questo processo processando diversi elementi in contemporanea usando una comprensione di lista. 

Quando si specifica `batched=True` la funzione riceva un dizionario con i campi del dataset, ma ogni valore è ora una _lista di valori_, e non un valore singolo. Il valore ritornato da `Dataset.map()` dovrebbe essere lo stesso: un dizionario con i campi che vogliano aggiornare o aggiungere al nostro dataset, e una lista di valori. Ad esempio, ecco un altro modo per sostituire tutti i carattere HTML, ma utilizzando `batched=True`:

```python
new_drug_dataset = drug_dataset.map(
    lambda x: {"review": [html.unescape(o) for o in x["review"]]}, batched=True
)
```

Se utilizzi questo codice in un notebook, noterai che questo comando è molto più veloce del precedente. E non perché le nostre recensioni già state preprocessate, se esegui nuovamente le istruzioni della sezione precedente (senza `batched=True'), ci metterà lo stesso tempo di prima. Questo è perchè le comprensioni di lista sono solitamente più veloci delle loro controparti con ciclo `for`, e inoltre abbiamo guadagnato performance permettendo l'accesso a molti elementi in contemporanea invece di uno per volta.

Utilizzare `Dataset.map()` con `batched=True` sarà essenziale per sbloccare la velocità dei tokenizzatori "fast" che incontreremo nel [Capitolo 6](/course/chapter6), che permettono di tokenizzare velocemente grandi liste di testi. Ad esempio, per tokenizzare tutte le recensioni di medicinali con un tokenizzatore veloce, potremmo usare una funzione come questa:

```python
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("bert-base-cased")


def tokenize_function(examples):
    return tokenizer(examples["review"], truncation=True)
```

Come visto nel [Capitolo 3](/course/chapter3), possiamo passare uno o più esempi al tokenizzatore. Le funzione può essere usata con o senza `batched=True`. Approfittiamo di quest'occasione per paragonare la performance delle diverse opzioni. In un notebook, possiamo cronomotrare un'istruzione su una singola riga aggiungendo `%time` prima della riga di codice che desideri cronometrare:

```python no-format
%time tokenized_dataset = drug_dataset.map(tokenize_function, batched=True)
```

Possiamo cronometrare anche un'intera cella inserento `%%time` all'inizio della cella. Sull'hardware che stiamo utilizzando, mostrava 10.8s pe rquest'istruzione (è il numero scritto dopo "Wall time").

<Tip>

✏️ **Prova tu!** Esegui la stessa istruzione con e senza `batched=True`, poi prova con un tokenizzatore lento (aggiungi `add_fast=False` al metodo `AutoTokenizer.from_pretrained()`) così che puoi controllare i tempi sul tuo hardware.
</Tip>

Ecco i risultati che otteniamo con e senza utilizzare batch, con un tokenizzatore lento e uno veloce:

Opzioni         | Tokenizzatore veloce |Tokenizzatore lento
:--------------:|:--------------------:|:-------------:
`batched=True`  | 10.8s                | 4min41s
`batched=False` | 59.2s                | 5min3s

Questo significa che utilizzare un tokenizzatore veloce con l'opzione `batched=True` è 30 volte più veloce della sua controparte lenta con `batched=False` -- ottimo! Questa è la ragione principale per cui i tokenizzatori veloci sono di default utilizzando `AutoTokenizer` (e il motivo per cui vengono chiamati "fast"). Sono in grado di raggiungere certe velocità perché dietro le quinte il codice di tokenizzazione è eseguito in Rust, un linguaggio che rende semplice l'esecuzione di codici in parallelo.

L'esecuzione in parallelo è anche il motivo per l'aumento di velocità x6 che il tokenizzatore veloce ottiene con `batched=True`: non è possibile eseguire in parallelo una sola operazione di tokenizzazione, ma quando vuoi tokenizzare molti testi contemporaneamente puoi dividere l'esecuzione su vari processi, ognuno responsabile dei propri testi.

`Dataset.map()` possiede inoltre alcune capacità di parallelizzazione per conto proprio. Non avendo però Rust alle proprie spalle, non può permettere a un tokenizzatore lento di raggiungere uno veloce, ma possono comunque tornare utili (soprattutto se stai utilizzando un tokenizatore che non possiede una versione veloce). Per abilitare il multiprocessing, usa l'argomenti `num_proc` e specifica il numero di processi da utilizzare quando evoci `Dataset.map()`:

```py
slow_tokenizer = AutoTokenizer.from_pretrained("bert-base-cased", use_fast=False)


def slow_tokenize_function(examples):
    return slow_tokenizer(examples["review"], truncation=True)


tokenized_dataset = drug_dataset.map(slow_tokenize_function, batched=True, num_proc=8)
```

Puoi sperimentare con le tempistiche per determinare il numero ottimale di processi da utilizzare; nel nostro caso 8 sembra produrre i risultati migliori. Ecco i numeri che abbiamo ottenuto con e senza multiprocessing:

Opzioni                       | Tokenizzatore veloce | Tokenizzatore lento
:----------------------------:|:--------------------:|:-------------:
`batched=True`                | 10.8s                | 4min41s
`batched=False`               | 59.2s                | 5min3s
`batched=True`, `num_proc=8`  | 6.52s                | 41.3s
`batched=False`, `num_proc=8` | 9.49s                | 45.2s

Questi sono dei risultati molto più accettabili per il tokenizzatore lento, ma anche la performance dei tokenizzatori veloci è notevolmente migliorata. Notare, comunque, che non è sempre questo il caso: per valori di `num_proc` diversi da 8, i nostri test hanno mostrato che è più veloce utilizzare `batched=True` senza l'opzione `num_proc`. In generale, non raccomandiamo l'utilizzo di multiprocessing Python per tokenizzatori veloci con `batched=True`. 

<Tip>

Utilizzare `num_proc` per accelerare i processi è generalmente una buona idea, a patto che la funzione che stai utilizzando non stia già usando un qualche tipo di multiprocessing per conto proprio.

</Tip>

Tutte queste funzionalità condensate in un unico metodo sono già molto utili, ma c'è altro! Con `Dataset.map()` e `batched=True`, è possibile modificare il numero di elementi nel tuo dataset. È particolarmente utile quando vuoi creare diverse feature di addestramento da un unico esempio, e ne avremo bisogno come parte di preprocessing per molti dei task NLP che affronteremo nel [Capitolo 7](/course/chapter7). 

<Tip>

💡 Nel machine learning, un _esempio_ è solitamente definito come un insieme di _feature_ che diamo in pasto al modello. In alcuni contesti, queste feature saranno l'insieme delle colonne in un `Dataset`, ma in altri casi (come ad esempio questo, o per il question answering), molte feature possono essere estratte da un singolo esempio, e appartenere a una sola colonna.

</Tip>

Diamo un'occhiata a come funziona! Tokenizziamo i nostri esempi e tronchiamoli a una lunghezza massima di 128, ma chiediamo al tokenizzatore di restituire *tutti* i pezzi di testo e non solo il primo. Questo può essere fatto con `return_overflowing_tokens=True`:

```py
def tokenize_and_split(examples):
    return tokenizer(
        examples["review"],
        truncation=True,
        max_length=128,
        return_overflowing_tokens=True,
    )
```

Testiamo questa funzione su un esempio prima di utilizzare `Dataset.map()` sull'intero dataset:

```py
result = tokenize_and_split(drug_dataset["train"][0])
[len(inp) for inp in result["input_ids"]]
```

```python out
[128, 49]
```

Quindi, il nostro primo esempio nel set di train è stato trasformaro in due feature perché tokenizzato in un numero maggiore di token di quelli specificati: il primo gruppo di lunghezza 128 token e il secondo di lunghezza 49. Facciamo la stessa cosa per tutti gli elementi del dataset!

```py
tokenized_dataset = drug_dataset.map(tokenize_and_split, batched=True)
```

```python out
ArrowInvalid: Column 1 named condition expected length 1463 but got length 1000
```

Oh no! Non ha funzionato! Perché? Il messaggio di errore ci dà un indizio: c'è una discordanza tra la lungheza di una delle colonne (una è lunga 1.463 e l'altra 1.000). Se hai guardato la [documentazione](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.map) di `Dataset.map()`, ricorderai che quello è il numero di campioni passati alla funzione map; qui quei 1.000 esempi danno 1.463 nuove feature, che risulta in un errore di shape.

Il problema è che stiamo cercando di mescolare due dataset diversi di grandezze diverse: le colonne del `drug_dataset` avranno un certo numero di esempi (il 1.000 del nostro errore), ma il `tokenized_dataset` che stiamo costruendo ne avrà di più (il 1.463 nel nostro messaggio di errore). Non va bene per un `Dataset`, per cui abbiamo bisogno o di rimuovere le colonne dal dataset vecchio, o renderle della stessa dimensione del nuovo dataset. La prima opzione può essere effettuata utilizzando l'argomento `remove_columns`:


```py
tokenized_dataset = drug_dataset.map(
    tokenize_and_split, batched=True, remove_columns=drug_dataset["train"].column_names
)
```

Ora funziona senza errori. Possiamo controllare che il nostro nuovo dataset contiene più elementi del dataset originale paragonando le lunghezze:

```py
len(tokenized_dataset["train"]), len(drug_dataset["train"])
```

```python out
(206772, 138514)
```
Abbiamo già menzionato che possiamo risolvere il problema delle lunghezze discordanti cambiando la dimenzione delle vecchie colonne. Per far ciò, abbiamo bisogno del campo `overflow_to_sample_mapping` restituito dal tokenizzatore quando impostiamo `return_overflowing_tokens=True`. Così facendo avremo una mappatura degli indici delle nuove feature all'indice di campioni da cui sono state generate. Usando questa mappatura, possiamo associare a ogni chiava presente nel nostro dataset originale una lista di valori delle dimensioni giuste, ripetendo il valore di ogni esempio finché genera nuove feature:

```py
def tokenize_and_split(examples):
    result = tokenizer(
        examples["review"],
        truncation=True,
        max_length=128,
        return_overflowing_tokens=True,
    )
    # Estraiamo la mappatura tra gli indici vecchi e quelli nuovi
    sample_map = result.pop("overflow_to_sample_mapping")
    for key, values in examples.items():
        result[key] = [values[i] for i in sample_map]
    return result
```

Possiamo vedere come funziona con `Dataset.map()` senza aver bisogno di rimuovere le colonne vecchie:

```py
tokenized_dataset = drug_dataset.map(tokenize_and_split, batched=True)
tokenized_dataset
```

```python out
DatasetDict({
    train: Dataset({
        features: ['attention_mask', 'condition', 'date', 'drugName', 'input_ids', 'patient_id', 'rating', 'review', 'review_length', 'token_type_ids', 'usefulCount'],
        num_rows: 206772
    })
    test: Dataset({
        features: ['attention_mask', 'condition', 'date', 'drugName', 'input_ids', 'patient_id', 'rating', 'review', 'review_length', 'token_type_ids', 'usefulCount'],
        num_rows: 68876
    })
})
```

Otteniamo lo stesso numero di feature di addestramento di prima, ma qui abbiamo conservato i campi originali. Se ti servono per un post-processing dopo aver applicato il tuo modello, potresti usare quest'approccio.

Ora abbiamo visto come usare 🤗 Datasets per preprocessare un dataset in diversi modi. Benché le funzioni di processamento di 🤗 Datasets soddisferà la maggior parte delle esigenze del modello che vuoi addestrare, ci saranno momenti in cui avrai bisogno di utilizzare Pandas per avere funzionalità ancora più potenti, come `DataFrame.groupby()` o API di alto livello per visualizzazione. Per fortuna, 🤗 Datasets è progettato per essere utilizzato con librerie come Pandas, NumPy, PyTorch, TensorFlow e JAX. Diamo un'occhiata a come funziona.

## Da `Dataset` a `DataFrame` e ritorno

<Youtube id="tfcY1067A5Q"/>

Per permettere la conversione tra librerie terze, 🤗 Datasets fornisce una funzione `Dataset.set_format()`. Questa funzione cambia il _formato di output_ del dataset, così che puoi passare a un altro formato senza modificare il _formato di dati_ soggiacente, che è Apache Arrow. La formattazione avviene direttamente _in place_. Per provare, convertiamo il nostro dataset per Pandas:

```py
drug_dataset.set_format("pandas")
```

Ora quando accediamo agli elementi del dataset otteniamo un `pandas.DataFrame` e non un dizionario:

```py
drug_dataset["train"][:3]
```

<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>patient_id</th>
      <th>drugName</th>
      <th>condition</th>
      <th>review</th>
      <th>rating</th>
      <th>date</th>
      <th>usefulCount</th>
      <th>review_length</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>95260</td>
      <td>Guanfacine</td>
      <td>adhd</td>
      <td>"My son is halfway through his fourth week of Intuniv..."</td>
      <td>8.0</td>
      <td>April 27, 2010</td>
      <td>192</td>
      <td>141</td>
    </tr>
    <tr>
      <th>1</th>
      <td>92703</td>
      <td>Lybrel</td>
      <td>birth control</td>
      <td>"I used to take another oral contraceptive, which had 21 pill cycle, and was very happy- very light periods, max 5 days, no other side effects..."</td>
      <td>5.0</td>
      <td>December 14, 2009</td>
      <td>17</td>
      <td>134</td>
    </tr>
    <tr>
      <th>2</th>
      <td>138000</td>
      <td>Ortho Evra</td>
      <td>birth control</td>
      <td>"This is my first time using any form of birth control..."</td>
      <td>8.0</td>
      <td>November 3, 2015</td>
      <td>10</td>
      <td>89</td>
    </tr>
  </tbody>
</table>

Creiamo un `pandas.DataFrame` per l'intero set di addestramento selezionando tutti gli elementi di `drug_dataset["train"]`:

```py
train_df = drug_dataset["train"][:]
```

<Tip>

🚨 Dietro le quinte, `Dataset.set_format()` modifica il formato di restituzione del meteodo dunder `__getitem__()` del dataset. Questo significa che quando vogliamo creare un nuovo oggetto come ad esempio `train_df` da un `Dataset` in formato `"pandas"`, abbiamo bisogno di suddividere l'intero dataset per ottenere un `pandas.DataFrame`. Puoi verificare da te che `drug_dataset["train"]` ha come tipo `Dataset`, a prescindere dal formato di output.

</Tip>

Da qui possiamo usare tutte le funzionalità Pandas che vogliamo. Ad esempio, possiamo creare un concatenamento per calcolare la distribuzione delle classi nelle voci `condition`:

```py
frequencies = (
    train_df["condition"]
    .value_counts()
    .to_frame()
    .reset_index()
    .rename(columns={"index": "condition", "count": "frequency"})
)
frequencies.head()
```

<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>condition</th>
      <th>frequency</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>birth control</td>
      <td>27655</td>
    </tr>
    <tr>
      <th>1</th>
      <td>depression</td>
      <td>8023</td>
    </tr>
    <tr>
      <th>2</th>
      <td>acne</td>
      <td>5209</td>
    </tr>
    <tr>
      <th>3</th>
      <td>anxiety</td>
      <td>4991</td>
    </tr>
    <tr>
      <th>4</th>
      <td>pain</td>
      <td>4744</td>
    </tr>
  </tbody>
</table>


E una volta che abbiamo finito con le nostre analisi su Pandas, possiamo sempre creare un nuovo oggetto `Dataset` utilizzando la funzione `Dataset.from_pandas()`:

```py
from datasets import Dataset

freq_dataset = Dataset.from_pandas(frequencies)
freq_dataset
```

```python out
Dataset({
    features: ['condition', 'frequency'],
    num_rows: 819
})
```

<Tip>

✏️ **Prova tu!** Calcola la valutazione media per i medicinali, e salviamo i risultati in un nuovo `Dataset`. 

</Tip>

Questo conclude il nostro tour delle diverse tecniche di prepocessamento disponibile in 🤗 Datasets. Per riepilogare la sezione, creiamo un set di validazione per preparare il dataset su cui addestreremo un classificatore. Prima di far ciò, resettiamo il formato di output di `drug_dataset` da `"pandas"` a `"arrow"`:

```python
drug_dataset.reset_format()
```

## Creare un set di validazione

Pur avendo un set di test che potremmo usare per la valutazione, è buona prassi lasciare il set di test intatto e creare un set di validazione sepearato durante lo sviluppo de lmodello. Una volta che sei soddisfatto della performance del tuo modello sul set di validazione, puoi proseguire con un ultimo check sul set di test. Questo processo aiuta a ridurre i rischi di overfitting sul set di test e di creare un modello che fallisce sui dati del mondo reale. 

🤗 Datasets possiede una funzione `Dataset.train_test_split()`, basata sulla famosa funzionalità da `scikit-learn`. Proviamo a utilizzarla per dividere il nostro set di addestramento in sezioni di `addestramento` e di `validazione` (impostiamo l'argomento `seed` per motivi di riproducibilità):

```py
drug_dataset_clean = drug_dataset["train"].train_test_split(train_size=0.8, seed=42)
# Rinominare la sezione di "test" in "validazione"
drug_dataset_clean["validation"] = drug_dataset_clean.pop("test")
# Aggiungere il set "test" al nostor `DatasetDict`
drug_dataset_clean["test"] = drug_dataset["test"]
drug_dataset_clean
```

```python out
DatasetDict({
    train: Dataset({
        features: ['patient_id', 'drugName', 'condition', 'review', 'rating', 'date', 'usefulCount', 'review_length', 'review_clean'],
        num_rows: 110811
    })
    validation: Dataset({
        features: ['patient_id', 'drugName', 'condition', 'review', 'rating', 'date', 'usefulCount', 'review_length', 'review_clean'],
        num_rows: 27703
    })
    test: Dataset({
        features: ['patient_id', 'drugName', 'condition', 'review', 'rating', 'date', 'usefulCount', 'review_length', 'review_clean'],
        num_rows: 46108
    })
})
```

Bene! Abbiamo preparato un dataset che è pronto per l'addestramento di modelli! Nella [sezione 5](/course/chapter5/5) ti mostreremo come caricare i dataset nell'Hub di Hugging Face, ma per ora concludiamo la nostra analisi esplorando alcuni modi per salvare i dataset sulla tua macchina locale.

## Salvare un dataset

<Youtube id="blF9uxYcKHo"/>

Benché 🤗 Datasets memorizzi in cache tutti i dataset scaricati e le operazioni effettuate, ci sono momenti in cui vorrai salvare un dataset su disco (ad esempio, nel caso la cache venga eliminata). Come mostrato nella tabella successiva, 🤗 Datasets fornisce tre funzioni principali per salvare il tuo dataset in diversi formati:

| Formato dati |        Funzione        |
| :---------: | :--------------------: |
|    Arrow    | `Dataset.save_to_disk()` |
|     CSV     |    `Dataset.to_csv()`    |
|    JSON     |   `Dataset.to_json()`    |

Ad esempio, salviamo il nostro dataset pulito in formato Arrow:

```py
drug_dataset_clean.save_to_disk("drug-reviews")
```

Questo creerà un dizionario con la seguente struttura:

```
drug-reviews/
├── dataset_dict.json
├── test
│   ├── dataset.arrow
│   ├── dataset_info.json
│   └── state.json
├── train
│   ├── dataset.arrow
│   ├── dataset_info.json
│   ├── indices.arrow
│   └── state.json
└── validation
    ├── dataset.arrow
    ├── dataset_info.json
    ├── indices.arrow
    └── state.json
```

dove possiamo vedere che ogni sezione è associata alla propria tavola *dataset.arrow*, e alcuni metadata sono salvati in *dataset_info.json* e *state.json*. Puoi pensare al formato Arrow come a una tavola sofisticata di colonne e righe, ottimizzata per costruire applicazioni ad alte prestazioni che processano e trasportanto grandi dataset.

Una volta che il dataset è stato salvato, possiamo caricarlo utilizzando la funzione `load_from_disk()`:

```py
from datasets import load_from_disk

drug_dataset_reloaded = load_from_disk("drug-reviews")
drug_dataset_reloaded
```

```python out
DatasetDict({
    train: Dataset({
        features: ['patient_id', 'drugName', 'condition', 'review', 'rating', 'date', 'usefulCount', 'review_length'],
        num_rows: 110811
    })
    validation: Dataset({
        features: ['patient_id', 'drugName', 'condition', 'review', 'rating', 'date', 'usefulCount', 'review_length'],
        num_rows: 27703
    })
    test: Dataset({
        features: ['patient_id', 'drugName', 'condition', 'review', 'rating', 'date', 'usefulCount', 'review_length'],
        num_rows: 46108
    })
})
```
Per i formati CSV e JSON, dobbiamo salvare ogni sezione come file separato. Un modo per farlo è iterando sulle chiavi e i valori dell'oggetti `DatasetDict`:

```py
for split, dataset in drug_dataset_clean.items():
    dataset.to_json(f"drug-reviews-{split}.jsonl")
```

Questo salva ogni sezione in [formato JSON Lines](https://jsonlines.org), in cui ogni riga del dataset è salvata come una singola riga di JSON. Ecco come appare il primo esempio:

```py
!head -n 1 drug-reviews-train.jsonl
```

```python out
{"patient_id":141780,"drugName":"Escitalopram","condition":"depression","review":"\"I seemed to experience the regular side effects of LEXAPRO, insomnia, low sex drive, sleepiness during the day. I am taking it at night because my doctor said if it made me tired to take it at night. I assumed it would and started out taking it at night. Strange dreams, some pleasant. I was diagnosed with fibromyalgia. Seems to be helping with the pain. Have had anxiety and depression in my family, and have tried quite a few other medications that haven't worked. Only have been on it for two weeks but feel more positive in my mind, want to accomplish more in my life. Hopefully the side effects will dwindle away, worth it to stick with it from hearing others responses. Great medication.\"","rating":9.0,"date":"May 29, 2011","usefulCount":10,"review_length":125}
```

Possiamo usare le tecniche studiate nella [sezione 2](/course/chapter5/2) per caricare i file JSON come segue:

```py
data_files = {
    "train": "drug-reviews-train.jsonl",
    "validation": "drug-reviews-validation.jsonl",
    "test": "drug-reviews-test.jsonl",
}
drug_dataset_reloaded = load_dataset("json", data_files=data_files)
```
E questo è tutto per la nostra visita nel data wrangling con 🤗 Datasets! Ora che abbiamo un dataset pulito su cui addestrare un modello, ecco alcune idee che potresti testare:

1. Usa le tecniche studiate nel [Capitolo 3](/course/chapter3) per addestrare un classificatore che può predirre la condizione del pazionte sulla base della recensione del medicinale.
2. Usa la pipeline `summarization` del [Capitolo 1](/course/chapter1) per generare riassunti delle recensioni.

In seguito, daremo un'occhiata a come 🤗 Datasets ti permette di lavorare su enormi dataset senza far scoppiare il tuo portatile! 


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter5/3.mdx" />

### Ricerca semantica con FAISS
https://huggingface.co/learn/course/it/chapter5/6.md

# Ricerca semantica con FAISS

{#if fw === 'pt'}

<CourseFloatingBanner chapter={5}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/it/chapter5/section6_pt.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/it/chapter5/section6_pt.ipynb"},
]} />

{:else}

<CourseFloatingBanner chapter={5}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/it/chapter5/section6_tf.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/it/chapter5/section6_tf.ipynb"},
]} />

{/if}

Nella [sezione 5](/course/chapter5/5) abbiamo creato un dataset di issue e commenti dalla repository GitHub di 🤗 Datasets. In questa sezione useremo queste informazioni per costrure un motore di ricerca semantico che ci può aiutare a trovare risposte alle nostre domande urgenti sulla libreria!

<Youtube id="OATCgQtNX2o"/>

## Usare gli embedding per la ricerca semantica 

Come abbiamo visto nel [Capitolo 1](/course/chapter1), i language model basati su Transformer rappresentano ogni token in un testo come un _vettore_, detto _embedding_. È possibile "mettere insieme" i diversi embedding per creare una rappresentazione vettoriale di un'intera frase, paragrafo o (in alcuni casi) documento. Questi embedding possono essere usati per trovare documenti simili in un corpus calcolandone la similarità, ad esempio usando il prodotto scalere (o altre misure di similarità) tra ogni embedding, e restituendo i documenti più simili.

In questa sezione useremo gli embedding per sviluppare un motore di ricerca semantico. Questi motori di ricerca offrono diversi vantagig rispetto ai metodo convenzionali, basati sulla ricerca, all'interno dei documenti, delle parole chiavi presente in una query.

<div class="flex justify-center">
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter5/semantic-search.svg" alt="Semantic search."/>
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter5/semantic-search-dark.svg" alt="Semantic search."/>
</div>

## Caricare e preparare il dataset 

La prima cosa che dobbiamo fare è scaricare il nostro dataset di issue, quindi utilizziamo la libreria 🤗 Hub per scaricare i file usando l'URL dell'Hub Hugging Face: 

```py
from huggingface_hub import hf_hub_url

data_files = hf_hub_url(
    repo_id="lewtun/github-issues",
    filename="datasets-issues-with-comments.jsonl",
    repo_type="dataset",
)
```

Se conseriamo l'URL iin `data_files`, possiamo caricare il dataset utilizzando il metodo introdotto nella [sezione 2](/course/chapter5/2):

```py
from datasets import load_dataset

issues_dataset = load_dataset("json", data_files=data_files, split="train")
issues_dataset
```

```python out
Dataset({
    features: ['url', 'repository_url', 'labels_url', 'comments_url', 'events_url', 'html_url', 'id', 'node_id', 'number', 'title', 'user', 'labels', 'state', 'locked', 'assignee', 'assignees', 'milestone', 'comments', 'created_at', 'updated_at', 'closed_at', 'author_association', 'active_lock_reason', 'pull_request', 'body', 'performed_via_github_app', 'is_pull_request'],
    num_rows: 2855
})
```

Qui abbiamo specificato la sezione di defaul `train` in `load_dataset()`, così che questa funzione resituisce un `Dataset` invece di un `DatasetDict`. La prima cosa da fare è filtrare le richieste di pull, poichè queste tendono a essere usate raramente come risposta alle domande degli utenti, e introdurrebbero rumore nel nostro motore di ricerca. Come dovrebbe esser enoto, possiamo usare la funzione `Dataset.filter()` per escludere questi dati dal nostro dataset. Già che ci siamo, eliminiamo anche le righe senza commenti, poiché queste non presentano nessuna risposta alle domande degli utenti:

```py
issues_dataset = issues_dataset.filter(
    lambda x: (x["is_pull_request"] == False and len(x["comments"]) > 0)
)
issues_dataset
```

```python out
Dataset({
    features: ['url', 'repository_url', 'labels_url', 'comments_url', 'events_url', 'html_url', 'id', 'node_id', 'number', 'title', 'user', 'labels', 'state', 'locked', 'assignee', 'assignees', 'milestone', 'comments', 'created_at', 'updated_at', 'closed_at', 'author_association', 'active_lock_reason', 'pull_request', 'body', 'performed_via_github_app', 'is_pull_request'],
    num_rows: 771
})
```

Possiamo vedere che ci sono molte colonne nel nostro dataset, molte delle quali non servono alla costruzione del nostro motore di ricerca. Da una prospettiva di ricerca, le colonne maggiormente informative sono `title`, `body`, e `comments`, mentre `html_url` ci fornisce un link all'issue originale. Usiamo la funzione `Dataset.remove_columns()` per eliminare le colonne rimanenti:

```py
columns = issues_dataset.column_names
columns_to_keep = ["title", "body", "html_url", "comments"]
columns_to_remove = set(columns_to_keep).symmetric_difference(columns)
issues_dataset = issues_dataset.remove_columns(columns_to_remove)
issues_dataset
```

```python out
Dataset({
    features: ['html_url', 'title', 'comments', 'body'],
    num_rows: 771
})
```

Per crare i nostri embedding arricchiremo ognu commento con il titolo e il corpo dell'issue, visto che questi campi spesso includono informazioni utili sul contesto. Poiché la nostra colonna `comment` è al momento una lista di commenti per ogni issue, dobbiamo "farla esplodere" così che ogni riga consista in una tupla `(html_url, title, body, comment)`. In panda è possibile farlo utilizzando la [funzione `Dataframe.explode()`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.explode.html), che crea una nuova riga per ogni elemento in una colonna in formato di lista, ripetendo i valori di tutte le altre colonne. Per vederlo in azione, prima di tutto passiamo al formato `DataFrame`:

```py
issues_dataset.set_format("pandas")
df = issues_dataset[:]
```

Se diamo un'occhiata alla prima riga di questo `DataFrame`, possiamo vedere che ci sono quattro commenti associati con quest'issue:

```py
df["comments"][0].tolist()
```

```python out
['the bug code locate in ：\r\n    if data_args.task_name is not None:\r\n        # Downloading and loading a dataset from the hub.\r\n        datasets = load_dataset("glue", data_args.task_name, cache_dir=model_args.cache_dir)',
 'Hi @jinec,\r\n\r\nFrom time to time we get this kind of `ConnectionError` coming from the github.com website: https://raw.githubusercontent.com\r\n\r\nNormally, it should work if you wait a little and then retry.\r\n\r\nCould you please confirm if the problem persists?',
 'cannot connect，even by Web browser，please check that  there is some  problems。',
 'I can access https://raw.githubusercontent.com/huggingface/datasets/1.7.0/datasets/glue/glue.py without problem...']
```

Quando "esplodiamo" `df`, ci aspettiamo di avere una riga per ognuno di questi commenti. Controlliamo se è così:

```py
comments_df = df.explode("comments", ignore_index=True)
comments_df.head(4)
```

<table border="1" class="dataframe" style="table-layout: fixed; word-wrap:break-word; width: 100%;">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>html_url</th>
      <th>title</th>
      <th>comments</th>
      <th>body</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>https://github.com/huggingface/datasets/issues/2787</td>
      <td>ConnectionError: Couldn't reach https://raw.githubusercontent.com</td>
      <td>the bug code locate in ：\r\n    if data_args.task_name is not None...</td>
      <td>Hello,\r\nI am trying to run run_glue.py and it gives me this error...</td>
    </tr>
    <tr>
      <th>1</th>
      <td>https://github.com/huggingface/datasets/issues/2787</td>
      <td>ConnectionError: Couldn't reach https://raw.githubusercontent.com</td>
      <td>Hi @jinec,\r\n\r\nFrom time to time we get this kind of `ConnectionError` coming from the github.com website: https://raw.githubusercontent.com...</td>
      <td>Hello,\r\nI am trying to run run_glue.py and it gives me this error...</td>
    </tr>
    <tr>
      <th>2</th>
      <td>https://github.com/huggingface/datasets/issues/2787</td>
      <td>ConnectionError: Couldn't reach https://raw.githubusercontent.com</td>
      <td>cannot connect，even by Web browser，please check that  there is some  problems。</td>
      <td>Hello,\r\nI am trying to run run_glue.py and it gives me this error...</td>
    </tr>
    <tr>
      <th>3</th>
      <td>https://github.com/huggingface/datasets/issues/2787</td>
      <td>ConnectionError: Couldn't reach https://raw.githubusercontent.com</td>
      <td>I can access https://raw.githubusercontent.com/huggingface/datasets/1.7.0/datasets/glue/glue.py without problem...</td>
      <td>Hello,\r\nI am trying to run run_glue.py and it gives me this error...</td>
    </tr>
  </tbody>
</table>

bene, possiamo vedere che le righe sono state duplicate, e che la colonna `comment` contiene i diversi comment! Ora che abbiamo finito con Pandas, possiamo passare velocemente a `Dataset` caricando il `DataFrame` in memoria:

```py
from datasets import Dataset

comments_dataset = Dataset.from_pandas(comments_df)
comments_dataset
```

```python out
Dataset({
    features: ['html_url', 'title', 'comments', 'body'],
    num_rows: 2842
})
```

Perfetto, ora abbiamo qualche migliaio di commenti con cui lavorare!


<Tip>

✏️ **Prova tu!** Prova ad utilizzare `Dataset.map()` per far esplodere la colonna `commenti` di `issues_dataset` _senza_ utilizzare Pandas. È un po' difficile: potrebbe tornarti utile la sezione ["Batch mapping"](https://huggingface.co/docs/datasets/about_map_batch#batch-mapping) della documentazione di 🤗 Datasets.

</Tip>

Ora che abbiamo un commento per riga, creiamo una nuova colonna `comments_length` che contiene il numero di parole per ogni commento:

```py
comments_dataset = comments_dataset.map(
    lambda x: {"comment_length": len(x["comments"].split())}
)
```

Possiamo usare questa nuova colonna per eliminare i commenti brevi, che solitamente includono cose del tipo "cc @lewtun" o "Grazie!", che non sono pertinenti per il nostro motore di ricerca. Non abbiamo un numero preciso da selezionare per questo filtro, ma 15 parole dovrebbero andare bene:

```py
comments_dataset = comments_dataset.filter(lambda x: x["comment_length"] > 15)
comments_dataset
```

```python out
Dataset({
    features: ['html_url', 'title', 'comments', 'body', 'comment_length'],
    num_rows: 2098
})
```

Una volta data una pulizia al nostro dataset, possiamo concatenare il titolo, la descrizione e i commenti delle issue in una nuova colonna `text`. Come al solito , scriveremo una semplice funzione che possiamo passare a `Dataset.map()`:

```py
def concatenate_text(examples):
    return {
        "text": examples["title"]
        + " \n "
        + examples["body"]
        + " \n "
        + examples["comments"]
    }


comments_dataset = comments_dataset.map(concatenate_text)
```

Siamo finalmente pronti a creare degli embedding! Diamo un'occhiata.

## Creare i text embedding

Abbiamo visto nel [Capitolo 2](/course/chapter2) che possiamo ottenere i token embedding utilizando la classe `AutoModel`. Dobbiamo solo scegliere un checkpoint valido da cui caricare il modell. Per fortuna, esiste una libreria chiamata `sentence-transformers`, dedicata alla creazione di embedding. Seguendo la descrizione nella [documentazione](https://www.sbert.net/examples/applications/semantic-search/README.html#symmetric-vs-asymmetric-semantic-search)della libreria, il nostro caso d'uso è un esempio di _asymmetric semantic search_ perché abbiamo una breve query per cui vogliamo trovare risposte in un documento lungo, come ad esempio un commento a un issue. La [scheda di riepilogo dei modelli](https://www.sbert.net/docs/pretrained_models.html#model-overview) nella documentazione ci indica che il checkpoint `multi-qa-mpnet-base-dot-v1` ha mostrato la performance migliore per la ricerca semantica, quindi è quello che useremo per la nostra applicazione. Caricheremo anche il tokenizzatore usando lo stesso checkpoint: 

{#if fw === 'pt'}

```py
from transformers import AutoTokenizer, AutoModel

model_ckpt = "sentence-transformers/multi-qa-mpnet-base-dot-v1"
tokenizer = AutoTokenizer.from_pretrained(model_ckpt)
model = AutoModel.from_pretrained(model_ckpt)
```

Per accelerare il processo di embedding, è bene usare la GPU per il modello e gli input, quindi:

```py
import torch

device = torch.device("cuda")
model.to(device)
```

{:else}

```py
from transformers import AutoTokenizer, TFAutoModel

model_ckpt = "sentence-transformers/multi-qa-mpnet-base-dot-v1"
tokenizer = AutoTokenizer.from_pretrained(model_ckpt)
model = TFAutoModel.from_pretrained(model_ckpt, from_pt=True)
```

Nota che abbiamo impostato `from_pt=True` come argomento del metodo `from_pretrained()`. Questo perchè il checkpoint `multi-qa-mpnet-base-dot-v1` ha solo pesi PyTorch, quindi impostare `from_pt=True` li convertirà automaticamente in formato TensorFlow. Come puoi vedere, è molto facile passare dall'uno all'altro su 🤗 Transformers!

{/if}

Come abbiamo già detto prima, vorremmo rappresentare ogni entrata nel nostro corpus di issue GitHub come un vettore singolo, per cui avremo bisogno di calcolare la media, o il "pool" dei nostri token embedding. Un metodo comune è di effettuare un *CLS pooling* sull'output del nostro modello: questa tecnica su basa sul recuperare semplicemente l'ultimo stato nascosto del token speciale `[CLS]`. La funzione seguente fa proprio questo:

```py
def cls_pooling(model_output):
    return model_output.last_hidden_state[:, 0]
```

Poi, creeremo una funzione di supporto che: tokenizza una lista di documenti, inserire i tensori sulla GPU, li usa come input per il modello, e infine applica il CLS pooling agli output:

{#if fw === 'pt'}

```py
def get_embeddings(text_list):
    encoded_input = tokenizer(
        text_list, padding=True, truncation=True, return_tensors="pt"
    )
    encoded_input = {k: v.to(device) for k, v in encoded_input.items()}
    model_output = model(**encoded_input)
    return cls_pooling(model_output)
```

Possiamo testare la funzione sul primo testo nel nostro corpus, e ispezionandone le dimensioni dell'ouput:

```py
embedding = get_embeddings(comments_dataset["text"][0])
embedding.shape
```

```python out
torch.Size([1, 768])
```

Bene, abbiamo convertito la prima voce del nostro corpus in un vettore a 768 dimensioni! Possiamo usare `Dataset.map()` per applicare la nostra funzione `get_embedding()` a ogni riga del nostro corpus, quindi creiamo una nuova colonna `embedding` così:

```py
embeddings_dataset = comments_dataset.map(
    lambda x: {"embeddings": get_embeddings(x["text"]).detach().cpu().numpy()[0]}
)
```

{:else}

```py
def get_embeddings(text_list):
    encoded_input = tokenizer(
        text_list, padding=True, truncation=True, return_tensors="tf"
    )
    encoded_input = {k: v for k, v in encoded_input.items()}
    model_output = model(**encoded_input)
    return cls_pooling(model_output)
```

Possiamo testare la funzione dandole in input la prima voce testuale del nostro corpus e studiando le dimensioni dell'output:

```py
embedding = get_embeddings(comments_dataset["text"][0])
embedding.shape
```

```python out
TensorShape([1, 768])
```

Bene, abbiamo convertito la prima voce del nostro corpus in un vettore a 768 dimensioni! Possiamo usare `Dataset.map()` per applicare la nostra funzione `get_embedding()` a ogni riga del nostro corpus, quindi creiamo una nuova colonna `embedding` così:

```py
embeddings_dataset = comments_dataset.map(
    lambda x: {"embeddings": get_embeddings(x["text"]).numpy()[0]}
)
```

{/if}

Node che abbiamo convertito gli embedding in array NumPy -- questo perchè 🤗 Datasets ha bisogno di questo formato per indicizzare gli embedding con FAISS, che è ciò che faremo nella prossima sezione. 


## Usare FAISS per ricerca di similarità efficiente 

Ora che abbiamo un dataset di embedding, abbiamo bisogno di un modo per effettuare una ricerca. Per far ciò, useremo una struttura specialie di 🤗 Datasets
chiamato _indice FAISS_. [FAISS](https://faiss.ai/) (Facebook AI Similarity Search) è una libreria che permette di utilizzare algoritmi efficient per ricercare e raggruppare gli embedding.

L'idea di base dietro FAISS è di creare un formato speciale di dati chiamato _indice_ che permette di trovare quali embedding sono simili a un embedding in input. Creare un indice FAISS su 🤗 Datasets è semplice -- usiamo la funzione `Dataset.add_faiss_index()` e specificare quale colonna nel nostro dataset vorremmo indicizzare: 

```py
embeddings_dataset.add_faiss_index(column="embeddings")
```

Ora possiamo eseguire dele query su questo indice effettuando una ricerca degli elementi più vicini usando la funzione `Dataset.get_nearest_examples()`. Testiamolo creando un embedding per una domanda.

{#if fw === 'pt'}

```py
question = "How can I load a dataset offline?"
question_embedding = get_embeddings([question]).cpu().detach().numpy()
question_embedding.shape
```

```python out
torch.Size([1, 768])
```

{:else}

```py
question = "How can I load a dataset offline?"
question_embedding = get_embeddings([question]).numpy()
question_embedding.shape
```

```python out
(1, 768)
```

{/if}

Proprio come con i documenti, ora abbiamo un vettore di 768 dimensioni che rappresenta la query, che possiamo confrontare con l'intero corpus per trovare gli embedding più simili:

```py
scores, samples = embeddings_dataset.get_nearest_examples(
    "embeddings", question_embedding, k=5
)
```

La funzione `Dataset.get_nearest_examples()` restituisce una tupla di valori che valutano la sovrapposizione tra la query e il documento, e un set corrispondente di campioni (in questo caso, le 5 corrispondenze migliori). Salviamole in un `pandas.DataFrame`, così che possiamo ordinarle facilmente:

```py
import pandas as pd

samples_df = pd.DataFrame.from_dict(samples)
samples_df["scores"] = scores
samples_df.sort_values("scores", ascending=False, inplace=True)
```

Ora possiamo iterare sulle prime righe per vedere quanto bene la nostra query corrisponde ai commenti disponibili:

```py
for _, row in samples_df.iterrows():
    print(f"COMMENT: {row.comments}")
    print(f"SCORE: {row.scores}")
    print(f"TITLE: {row.title}")
    print(f"URL: {row.html_url}")
    print("=" * 50)
    print()
```

```python out
"""
COMMENT: Requiring online connection is a deal breaker in some cases unfortunately so it'd be great if offline mode is added similar to how `transformers` loads models offline fine.

@mandubian's second bullet point suggests that there's a workaround allowing you to use your offline (custom?) dataset with `datasets`. Could you please elaborate on how that should look like?
SCORE: 25.505046844482422
TITLE: Discussion using datasets in offline mode
URL: https://github.com/huggingface/datasets/issues/824
==================================================

COMMENT: The local dataset builders (csv, text , json and pandas) are now part of the `datasets` package since #1726 :)
You can now use them offline
\`\`\`python
datasets = load_dataset("text", data_files=data_files)
\`\`\`

We'll do a new release soon
SCORE: 24.555509567260742
TITLE: Discussion using datasets in offline mode
URL: https://github.com/huggingface/datasets/issues/824
==================================================

COMMENT: I opened a PR that allows to reload modules that have already been loaded once even if there's no internet.

Let me know if you know other ways that can make the offline mode experience better. I'd be happy to add them :)

I already note the "freeze" modules option, to prevent local modules updates. It would be a cool feature.

----------

> @mandubian's second bullet point suggests that there's a workaround allowing you to use your offline (custom?) dataset with `datasets`. Could you please elaborate on how that should look like?

Indeed `load_dataset` allows to load remote dataset script (squad, glue, etc.) but also you own local ones.
For example if you have a dataset script at `./my_dataset/my_dataset.py` then you can do
\`\`\`python
load_dataset("./my_dataset")
\`\`\`
and the dataset script will generate your dataset once and for all.

----------

About I'm looking into having `csv`, `json`, `text`, `pandas` dataset builders already included in the `datasets` package, so that they are available offline by default, as opposed to the other datasets that require the script to be downloaded.
cf #1724
SCORE: 24.14896583557129
TITLE: Discussion using datasets in offline mode
URL: https://github.com/huggingface/datasets/issues/824
==================================================

COMMENT: > here is my way to load a dataset offline, but it **requires** an online machine
>
> 1. (online machine)
>
> ```
>
> import datasets
>
> data = datasets.load_dataset(...)
>
> data.save_to_disk(/YOUR/DATASET/DIR)
>
> ```
>
> 2. copy the dir from online to the offline machine
>
> 3. (offline machine)
>
> ```
>
> import datasets
>
> data = datasets.load_from_disk(/SAVED/DATA/DIR)
>
> ```
>
>
>
> HTH.


SCORE: 22.893993377685547
TITLE: Discussion using datasets in offline mode
URL: https://github.com/huggingface/datasets/issues/824
==================================================

COMMENT: here is my way to load a dataset offline, but it **requires** an online machine
1. (online machine)
\`\`\`
import datasets
data = datasets.load_dataset(...)
data.save_to_disk(/YOUR/DATASET/DIR)
\`\`\`
2. copy the dir from online to the offline machine
3. (offline machine)
\`\`\`
import datasets
data = datasets.load_from_disk(/SAVED/DATA/DIR)
\`\`\`

HTH.
SCORE: 22.406635284423828
TITLE: Discussion using datasets in offline mode
URL: https://github.com/huggingface/datasets/issues/824
==================================================
"""
```

Non male! Il nostro secondo risultato sembra soddisfare la nostra richiesta.

<Tip>

✏️ **Prova tu!** Crea la tua query e prova a trovare una risposta tra i documenti raccolti. Potresti aver bisogno di aumentare il parametro `k` in `Dataset.get_nearest_examples()` per allargare la ricerca. 

</Tip>


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter5/6.mdx" />

### Quiz di fine capitolo
https://huggingface.co/learn/course/it/chapter5/8.md

# Quiz di fine capitolo

<CourseFloatingBanner
    chapter={5}
    classNames="absolute z-10 right-0 top-0"
/>

In questo capitolo abbiamo fatto un bel po' di strada! Non preoccuparti se non hai colto tutti i dettagli; i capitoli successivi ti aiuteranno a capire come funzionano le cose dietro le quinte!

Prima di andare oltre, mettiamo alla prova ciò che hai imparato in questo capitolo.

### 1. Usando la funzione `load_dataset()` in 🤗 Datasets, da dove puoi caricare un dataset?

<Question
	choices={[
		{
			text: "In locale, ad esempio dal tuo portatile.",
			explain: "Corretto! Puoi passare i path dei file nell'argomento <code>data_files</code> di <code>load_dataset()</code> per caricare dataset locali.",
			correct: true
		},
		{
			text: "L'Hub Hugging Face.",
			explain: "Corretto! Puoi caricare i dataset presenti sull'Hub fornendo l'ID del dataset, ad esempio <code>load_dataset('emotion')</code>.",
			correct: true
		},
		{
			text: "Un server remoto",
			explain: "Corretto! Puoi passare un URL nell'argomento <code>data_files</code> di <code>load_dataset()</code> per caricare file in remoto.",
			correct: true
		},
	]}
/>

### 2. Immagina di caricare uno dei task GLUE come segue:

```py
from datasets import load_dataset

dataset = load_dataset("glue", "mrpc", split="train")
```

Quale dei comandi seguenti produce un campione di 50 elementi casuali da `dataset`?

<Question
	choices={[
		{
			text: "<code>dataset.sample(50)</code>",
			explain: "Questa risposta è sbagliata -- non esiste nessun metodo <code>Dataset.sample()</code>."
		},
		{
			text: "<code>dataset.shuffle().select(range(50))</code>",
			explain: "Corretto! Come hai visto in questo capitolo, puoi mescolare il dataset e selezionarne i campioni.",
			correct: true
		},
		{
			text: "<code>dataset.select(range(50)).shuffle()</code>",
			explain: "Questa risposta è sbagliata -- anche se il codice verrebbe eseguito, mescolerebbe solo i primi 50 elementi del dataset"
		}
	]}
/>

### 3. Immagina di avere un dataset sugli animali domestici, chiamto `pets_dataset`, che ha una colonna `name` che denota il nome di ogni animale. Quale degli approcci ci permetterebbe di filtrare il dataset e lasciare solo gli animali il cui nome inizia con la lettera "L"?
<Question
	choices={[
		{
			text: "<code>pets_dataset.filter(lambda x : x['name'].startswith('L'))</code>",
			explain: "Corretto! Usare una funzione lambda di Python per questi filtri veloci è un'ottima idea. Riesci a pensare a un'altra soluzione?",
			correct: true
		},
		{
			text: "<code>pets_dataset.filter(lambda x['name'].startswith('L'))</code>",
			explain: "Questa risposta è sbagliata: una funzione lambda ha la forma generica <code>lambda *argomenti* : *espressione*</code>, per cui devi esplicitare gli argomenti in questo caso."
		},
		{
			text: "Creare una funzione come <code>def filter_names(x): return x['name'].startswith('L')</code> ed eseguire <code>pets_dataset.filter(filter_names)</code>.",
			explain: "Corretto! Proprio come <code>Dataset.map()</code>, puoi passare delle funzioni esplicite a <code>Dataset.filter()</code>. Quest'opzione è utile quando hai un'espressione complessa che non è adatta a una funzione lambda. Quale altra soluzione potrebbe funzionare?",
			correct: true
		}
	]}
/>

### 4. Cos'è il memory mapping?

<Question
	choices={[
		{
			text: "Una mappatura tra la RAM CPU e quella GPU",
			explain: "Sbagliato, ritenta!",
		},
		{
			text: "Una mappatura tra la RAM e un archivio in memoria.",
			explain: "Corretto! 🤗 Datasets tratta ogni dataset con un file mappato in memoria. Questo permette alla libreria di accedere  e operare sugli elementi del dataset senza alcun bisogno di caricarlo in memoria.",
			correct: true
		},
		{
			text: "Una mappatura tra due file nella cache 🤗 Datasets" ,
			explain: "Sbagliato, ritenta!"
		}
	]}
/>

### 5. Quali dei seguenti sono i principali vantaggi del memory mapping?

<Question
	choices={[
		{
			text: "Accere ai file mappati in memoria è più veloce che leggere o scrivere da disco.",
			explain: "Corretto! Questo permette a 🤗 Datasets di essere incredibilmente veloce. Ma non è l'unico vantaggio!",
			correct: true
		},
		{
			text: "Le applicazioni possono accedere a segmenti di dati in un file estremamente grando senza dover prima leggere l'intero file in RAM.",
			explain: "Corretto! Questo permette a 🤗 Datasets di caricare dataset grandi molti gigabyte sul tuo portatile senza far scoppiare la tua CPU. Quali altri vantaggi offre il memory mapping?",
			correct: true
		},
		{
			text: "Consuma meno energia, così la tua batteria dura più a lungo.",
			explain: "Sbagliato, ritenta!"
		}
	]}
/>

### 6. Cosa causa un errore nel codice seguente?

```py
from datasets import load_dataset

dataset = load_dataset("allocine", streaming=True, split="train")
dataset[0]
```

<Question
	choices={[
		{
			text: "Cerca di creare uno streaming con un dataset che è troppo grande per la RAM.",
			explain: "Questa risposta è sbagliata -- i dataset in streaming sono decompressi al momenti, e puoi processare dataset grandi terabyte anche con poca RAM!",
		},
		{
			text: "Cerca di accedere a un <code>IterableDataset</code>.",
			explain: "Corretto! Un <code>IterableDataset</code> è un generatore e non un contenitore, per cui puoi accedere ai suoi elementi solo usando <code>next(iter(dataset))</code>.",
			correct: true
		},
		{
			text: "Il dataset <code>allocine</code> non ha una sezione <code>train</code>.",
			explain: "Questa risposta è sbagliata -- controlla le [informazioni sul dataset <code>allocine</code>](https://huggingface.co/datasets/allocine) sull'Hub per vedere quali sezioni contiente."
		}
	]}
/>

### 7. Quali dei seguenti sono i vantaggi principali di creare una dataset card?

<Question
	choices={[
		{
			text: "Offre informazioni sull'uso previsto e i task supportati dal dataset, così altri utenti della community possano prendere una decisione informata su come utilizzarlo.",
			explain: "Corretto! I dataset senza documentazione possono essere usati per addestrare modelli che potrebbero non riflettere le intenzioni dei creatori del dataset, oppure produrre modelli dal dubbio status legale se sono addestrati su dati che violano la privacy o restrizioni di autorizzazioni. Ma questo non è l'unico vantaggio!",
			correct : true
		},
		{
			text: "Aiuta ad attirare l'attenzione ai bias presenti in un corpus.",
			explain: "Corretto! Quasi tutti i dataset hanno qualche forma di bias, che può avere conseguenze negative in corso d'opera. Prestarci attenzione aiuta i creatori di modelli a capire come superare i bias impliciti. A cos'altro possono servire?",
			correct : true
		},
		{
			text: "Aumenta le possibilità che gli altri utenti della community useranno il dataset.",
			explain: "Corretto! Una dataset card ben scritta porterà a un uso maggiore del tuo caro dataset. Quali altri benefici può offrire?",
			correct: true
		},
	]}
/>


### 8. Cos'è la ricerca semantica?

<Question
	choices={[
		{
			text: "Un metodo per ricercare la corrispondenza esatta delle parole in una richiesta e i documenti di un corpus",
			explain: "Questa risposta è sbagliata -- questo tipo di ricerca è chiamata *ricerca lessicale*, ed è quella che tipicamente viene utilizzata nei motori di ricerca tradizionali."
		},
		{
			text: "Un metodo per cercare documenti corrispondenti attraverso la comprensione del signifcato contestuale di una richiesta",
			explain: "Corretto! La ricerca semantica utilizza i vettori di parole per rappresentare le richieste e i documenti, e usa una metrica di similarità per calcolare la sovrapposizione tra queste. Puoi pensare a un altro modo di descrivere la ricerca semantica?",
			correct: true
		},
		{
			text: "Un metodo per migliorare l'acucratezza della ricerca",
			explain: "Corretto! I motori di ricerca semantici riescono a catturare l'intento di una richiesta molto meglio di un sistema a parole chiave, e tipicamente recupera documenti con una precisione maggiore. Ma questa non è l'unica risposta corretta: cos'altro offre la ricerca semantica?",
			correct: true
		}
	]}
/>

### 9. Nelle ricerche semantiche asimmetriche, solitamente si hanno:

<Question
	choices={[
		{
			text: "Una richiesta breve e un paragrafo più lungo che risponde alla richiesta",
			explain: "Corretto!",
			correct : true
		},
		{
			text: "Le richieste e i paragrafi sono più o meno della stessa lunghezza.",
			explain: "Questo è in realtà un esempio di ricerca semantica simmetrica: ritenta!"
		},
		{
			text: "Una richiesta lunga e un paragrafo più breve che risponde alla richiesta",
			explain: "Questa risposta è sbagliata -- ritenta!"
		}
	]}
/>

### 10. Posso usare 🤗 Datasets per caricare dati utilizzabili in altri domini, come processamento del parlato?

<Question
	choices={[
		{
			text: "No",
			explain: "Questa risposta è sbagliata -- al momento 🤗 Datasets supporta dati tabulari, audio e per visione artificale. controlla il <a  href='https://huggingface.co/datasets/mnist'>dataset MNIST</a> sull'Hub per un esempio di dati per visione artificiale."
		},
		{
			text: "Sì",
			explain: "Questa risposta è corretta! Controlla gli eccitanti sviluppi per il parlato e la visione artificiale nella libreria 🤗 Transformers per vedere come è utilizzato 🤗 Datasets in questi domini.",
			correct : true
		},
	]}
/>


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter5/8.mdx" />

### Big data? Ci pensa 🤗 Datasets!
https://huggingface.co/learn/course/it/chapter5/4.md

# Big data? Ci pensa 🤗 Datasets!

<CourseFloatingBanner chapter={5}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/it/chapter5/section4.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/it/chapter5/section4.ipynb"},
]} />


Al giorno d'oggi non è raro trovarsi a lavorare con dataset grandi diversi gigabyte, soprattutto quando si vuole addestrare un transformer come BERT o GPT-2 da zero. In questi casi, persino _caricare_ i dati può essere un'impresa difficile. Ad esempio, il corpus WebText utilizzato per preaddestrare GPT-2 contiente più di 8 milioni di documenti e 40gb di testo -- caricare un dataset del genere sulla RAM del tuo portatile gli farebbe venire un colpo!

Per fortuna, 🤗 Datasets è stato sviluppato per superare queste limitazioni, e può risolvere i problemi relativi alla gestione della memoria trattando i dataset come file _memory-mapped_, e quelli relativi ai limiti del disco rigido attraverso lo _stream processing_ delle voci del corpus.

<Youtube id="JwISwTCPPWo"/>

In questa sezione esploreremo queste funzionalità di 🤗 Datasets con un enorme corpus di 825 GB conosciuto come [Pile](https://pile.eleuther.ai). Iniziamo!

## Cos'è Pile?

The Pile è un corpus testuale creato da [EleutherAI](https://www.eleuther.ai) per addestrare modelli di linguaggio su grande scala. Include un grande varietà di dataset, a partire da articoli scientifici, repository di codici da GitHub, e testi dal web filtrati. Il corpus di addestramento è disponibili in [frammenti da 14 GB](https://the-eye.eu/public/AI/pile/), ed è possibile scaricare diverse delle [componenti singole](https://the-eye.eu/public/AI/pile_preliminary_components/). Iniziamo dando uno sguardo al dataset PubMed Abstracts, un corpus di abstract da 15 milioni di pubblicazioni in ambito biomedico da [PubMed](https://pubmed.ncbi.nlm.nih.gov/). Il dataset è in [formato JSON Lines](https://jsonlines.org) ed è stato compressato usando la libreria `zstandard`, per cui dobbiamo prima installarla:


```py
!pip install zstandard
```

Ora, possiamo caricare il dataset utilizzando il meotodo per file remoti che abbiamo visto nella [sezione 2](/course/chapter5/2):

```py
from datasets import load_dataset

# Ci vuole qualche minuto per l'esecuzione, quindi preparati un tè o un caffè nell'attesa :)
data_files = "https://the-eye.eu/public/AI/pile_preliminary_components/PUBMED_title_abstracts_2019_baseline.jsonl.zst"
pubmed_dataset = load_dataset("json", data_files=data_files, split="train")
pubmed_dataset
```

```python out
Dataset({
    features: ['meta', 'text'],
    num_rows: 15518009
})
```

Possiamo vedere che ci sono 15.518.009 righe e 2 colonne nel nostro dataset -- un bel po'!

<Tip>

✎ Di base, 🤗 Datasets decomprimerà i file necessari a caricare un dataset. Se vuoi risparmiare sullo spazio dell'hard disk, puoi passare `DownloadConfig(delete_extracted_True)` all'argomento `download_config` di `load_dataset()`. Per maggiori dettagli leggi la [documentazione](https://huggingface.co/docs/datasets/package_reference/builder_classes#datasets.DownloadConfig).

</Tip>

Ispezioniamo i contenuti del primo esempio:

```py
pubmed_dataset[0]
```

```python out
{'meta': {'pmid': 11409574, 'language': 'eng'},
 'text': 'Epidemiology of hypoxaemia in children with acute lower respiratory infection.\nTo determine the prevalence of hypoxaemia in children aged under 5 years suffering acute lower respiratory infections (ALRI), the risk factors for hypoxaemia in children under 5 years of age with ALRI, and the association of hypoxaemia with an increased risk of dying in children of the same age ...'}
```

Okay, questo sembra proprio l'abstract di un articolo di medicina. Ora vediamo quanta RAM è stata usata per caricare il dataset!

## La magia del memory mapping 

Un modo semplice per calcolare l'uso di memoria su Python è utilizzando la libreria [`psutil`](https://psutil.readthedocs.io/en/latest/), che può essere installata con `pip` come segue:

```python
!pip install psutil
```

`psutil` offre una classe `Process` che permette di controllare l'utilizzo della memoria del processo attuale come segue::

```py
import psutil

# Process.memory_info mostra i dati in byte, quindi convertiamo in megabyte
print(f"RAM used: {psutil.Process().memory_info().rss / (1024 * 1024):.2f} MB")
```

```python out
RAM used: 5678.33 MB
```

L'attributo `rss` qui fa riferimento alla _grandezza del resident set_, che equivale alla frazione di memoria che il processo occupa nella RAM. Questo valore include inoltre la memoria utilizzata dall'interprete Python e dalle librerie caricate, per cui l'ammontare effettivo utilizzato per caricare il dataset è un po' più piccolo. Per fare un confronto, vediamo quant'è grande il dataset su disco utilizzando l'attributo `dataset_size`. Come prima, il risultato è espresso in byte, e abbiamo bisogno di convertirlo in gigabyte: 

```py
print(f"Number of files in dataset : {pubmed_dataset.dataset_size}")
size_gb = pubmed_dataset.dataset_size / (1024**3)
print(f"Dataset size (cache file) : {size_gb:.2f} GB")
```

```python out
Number of files in dataset : 20979437051
Dataset size (cache file) : 19.54 GB
```

Bene -- nonostante sia grande quasi 30 GB, siamo in grado di caricare e accedere al dataset utilizzando molta meno RAM!

<Tip>

✏️ **Provaci tu!** Scegli uno dei [subset](https://the-eye.eu/public/AI/pile_preliminary_components/) di Pile che è più grande della RAM del tuo PC o del tuo portatile, caricalo utilizzando 🤗 Datasets e calcola la quantità di RAM utilizzata. Nota che per avere un valore preciso, dovrai creare un nuovo processo. Puoi trovare le grandezze decompresse di ogni subset nella Tavola 1 dell'[articolo su Pile](https://arxiv.org/abs/2101.00027)

</Tip>

Se hai dimestichezza con Pandas, questo risultato potrebbe sorprenderti, vista la famosa [regola di Wes Kinney](https://wesmckinney.com/blog/apache-arrow-pandas-internals/), ovvero che, in linea di massima, serve una RAM 5-10 volte più grande del dataset che vuoi caricare. Come fa 🤗 Datasets a risolvere questo problema di gestione della memoria? 🤗 Datasets tratta ogni dataset come un [file mappato in memoria](https://it.wikipedia.org/wiki/File_mappato_in_memoria), il che permette di avere un mapping tra la RAM e l'archiviazione dei file di sistema, che permette alla librera di accedere e operare su elementi del dataset senza doverli caricare completamente in memoria.

I file mappati in memoria possono inoltre essre condivisi su più processi, il che permette a metodi come `Dataset.map()` di poter essere eseguiti in parallelo senza bisogno di spostare o copiare il dataset. Dietro le quinte, tutto ciò è realizzato dal formato di memoria [Apache Arrow](https://arrow.apache.org) e dalla libreria [`pyarrow`](https://arrow.apache.org/docs/python/index.html), che rendono più veloci il caricamento e il processamento dei dati. (per maggiori dettagli su Apache Arrow, e per un confronto con Pandas, dai un'occhiata al [post di Dejan Simic](https://towardsdatascience.com/apache-arrow-read-dataframe-with-zero-memory-69634092b1a).) Per vederlo in azione, eseguiamo un piccolo test di velocità con un loop su tutti gli elementi nel dataset PubMed Abstracts:

```py
import timeit

code_snippet = """batch_size = 1000

for idx in range(0, len(pubmed_dataset), batch_size):
    _ = pubmed_dataset[idx:idx + batch_size]
"""

time = timeit.timeit(stmt=code_snippet, number=1, globals=globals())
print(
    f"Iterated over {len(pubmed_dataset)} examples (about {size_gb:.1f} GB) in "
    f"{time:.1f}s, i.e. {size_gb/time:.3f} GB/s"
)
```

```python out
'Iterated over 15518009 examples (about 19.5 GB) in 64.2s, i.e. 0.304 GB/s'
```

Abbiamo usato il modulo di Python `timeit` per calcolare il tempo di esecuzione impiegato da `code_snippet`. Tipicamente l'iterazione su un dataset impiega un tempo che va da un decimo di GB al secondo, a diversi GB al secondo. Questo funziona perfettamente per la maggior parte delle applicazioni, ma a volte avrai bisogno di lavorare con un dataset che è troppo grande persino per essere salvato sul tuo portatile. Ad esempio, se cercassimo di scaricare Pile per intero, avremo bisogno di 825 GB di spazio libero su disko! In questi casi, 🤗 Datasets permette di utilizzare processi di streaming che ci permettono di scaricare e accedere al volo ai dati, senza bisogno di scaricare l'intero dataset. Diamo un'occhiata a come funziona.

<Tip>

💡 Nei notebook Jupyter, puoi cronometrare le celle utilizzando la [funzione magica `%%timeit`](https://ipython.readthedocs.io/en/stable/interactive/magics.html#magic-timeit)

</Tip>

## Streaming di dataset

Per abilitare lo streaming dei dataset devi semplicemente passare l'argomento `streaming=True` alla funzione `load_dataset()`. Ad esempio, carichiamo un'altra volta il dataset PubMed Abstract, ma in modalità streaming: 

```py
pubmed_dataset_streamed = load_dataset(
    "json", data_files=data_files, split="train", streaming=True
)
```

Invece del solito `Dataset` che abbiamo incontrato in precedenza in questo capitolo, l'oggetto ritornato con `streaming=True' è un `IterableDataset`. Come suggerito dal nome, per accedere agli elementi di un `IterableDataset`, dobbiamo iterare di esso. Possiamo accedere al primo elemento del nostro dataset in streaming come segue: 

```py
next(iter(pubmed_dataset_streamed))
```

```python out
{'meta': {'pmid': 11409574, 'language': 'eng'},
 'text': 'Epidemiology of hypoxaemia in children with acute lower respiratory infection.\nTo determine the prevalence of hypoxaemia in children aged under 5 years suffering acute lower respiratory infections (ALRI), the risk factors for hypoxaemia in children under 5 years of age with ALRI, and the association of hypoxaemia with an increased risk of dying in children of the same age ...'}
```

Gli elementi di un dataset in streaming possono essere processati al volo utilizzando `IterableDataset.map()`, che è utile durante l'addestramento se hai bisogno di tokenizzare gli input. Il processo è uguale a quello che abbiamo utilizzato per tokenizzare il nostro dataset nel [Capitolo 3](/course/chapter3), con l'unica differenza che ora ritorneremo gli output uno alla volta:

```py
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("distilbert-base-uncased")
tokenized_dataset = pubmed_dataset_streamed.map(lambda x: tokenizer(x["text"]))
next(iter(tokenized_dataset))
```

```python out
{'input_ids': [101, 4958, 5178, 4328, 6779, ...], 'attention_mask': [1, 1, 1, 1, 1, ...]}
```

<Tip>

💡 Per velocizzare la tokenizzazione con lo streaming puoi passare `batchet=True`, come abbiamo visto nell'ultima sezione. Questo processerà gli esempi per batch. Di default, la grandezza di un batch è 1.000, e può essere specificata attraverso l'argomento `batch_size`.

</Tip>

È anche possibile mescolare un dataset in streaming utilizzato `Iterabledataset.shuffle()`, ma a differenza di `Dataset.shuffle()`, questo metodo mescola solo gli elementi in un `buffer_size` predefinito:

```py
shuffled_dataset = pubmed_dataset_streamed.shuffle(buffer_size=10_000, seed=42)
next(iter(shuffled_dataset))
```

```python out
{'meta': {'pmid': 11410799, 'language': 'eng'},
 'text': 'Randomized study of dose or schedule modification of granulocyte colony-stimulating factor in platinum-based chemotherapy for elderly patients with lung cancer ...'}
```

In questo esempio, abbiamo selezionato un esempio casuale dai primi 10.000 esempi nel buffer. Una volta che accediamo a un esempio, il suo posto nel buffer è subito occupato dall'esempio successivo nel corpus (in questo caso l'esempio 10.0001). Puoi inoltre selezionare gli elementi da un dataset in streaming utilizzando le funzioni `IterableDataset.take()` a `IterableDataset.skip()`, che funzionano un po' come `Dataset.select()`. Ad esempio, per selezionare i primi 5 esempi nel dataset PubMed Abstract dovremmo fare come segue:

```py
dataset_head = pubmed_dataset_streamed.take(5)
list(dataset_head)
```

```python out
[{'meta': {'pmid': 11409574, 'language': 'eng'},
  'text': 'Epidemiology of hypoxaemia in children with acute lower respiratory infection ...'},
 {'meta': {'pmid': 11409575, 'language': 'eng'},
  'text': 'Clinical signs of hypoxaemia in children with acute lower respiratory infection: indicators of oxygen therapy ...'},
 {'meta': {'pmid': 11409576, 'language': 'eng'},
  'text': "Hypoxaemia in children with severe pneumonia in Papua New Guinea ..."},
 {'meta': {'pmid': 11409577, 'language': 'eng'},
  'text': 'Oxygen concentrators and cylinders ...'},
 {'meta': {'pmid': 11409578, 'language': 'eng'},
  'text': 'Oxygen supply in rural africa: a personal experience ...'}]
```

Allo stesso modo, è possibile utilizzare la funzione `IterableDataset.skip()` per creare sezioni di addestramento e di validazione da un dataset mescolato, come segue:

```py
# Salta i primi 1.000 esempi, il resto viene incluso nell'insieme di addestramento
train_dataset = shuffled_dataset.skip(1000)
# Includi i primi 1.000 esempi nell'insieme di validazione
validation_dataset = shuffled_dataset.take(1000)
```

Concludiamo la nostra ricognizione dello streaming di dataset con un'applicazione comune: la combinazione di più dataset per creare un unico corpus. 🤗 Datasets fornisce una funzione `interleave_datasets()`, che converte una lista di oggetti `IterableDataset` in un unico `IterableDataset`, dove gli elementi del nuovo dataset sono ottenuti alternando tra gli esempi forniti. Questa funzione è particolarmente utile quando cerchiamo di combinare dataset di grandi dimensioni, come esempio possiamo utilizzare in streaming la sezione FreeLaw del Pile, un dataset di 51 GB di pareri legali dai tribunali statunitensi:


```py
law_dataset_streamed = load_dataset(
    "json",
    data_files="https://the-eye.eu/public/AI/pile_preliminary_components/FreeLaw_Opinions.jsonl.zst",
    split="train",
    streaming=True,
)
next(iter(law_dataset_streamed))
```

```python out
{'meta': {'case_ID': '110921.json',
  'case_jurisdiction': 'scotus.tar.gz',
  'date_created': '2010-04-28T17:12:49Z'},
 'text': '\n461 U.S. 238 (1983)\nOLIM ET AL.\nv.\nWAKINEKONA\nNo. 81-1581.\nSupreme Court of United States.\nArgued January 19, 1983.\nDecided April 26, 1983.\nCERTIORARI TO THE UNITED STATES COURT OF APPEALS FOR THE NINTH CIRCUIT\n*239 Michael A. Lilly, First Deputy Attorney General of Hawaii, argued the cause for petitioners. With him on the brief was James H. Dannenberg, Deputy Attorney General...'}
```

Questo dataset è abbastanza grande da mettere sotto sforzo la RAM di molto portatili, ma siamo riusciti a caricarlo e accedervi senza alcun problema! Ora cominiamo gli esempi di FreeLaw e di PubMed Abstracts con la funzione `interleave_datasets()`:

```py
from itertools import islice
from datasets import interleave_datasets

combined_dataset = interleave_datasets([pubmed_dataset_streamed, law_dataset_streamed])
list(islice(combined_dataset, 2))
```

```python out
[{'meta': {'pmid': 11409574, 'language': 'eng'},
  'text': 'Epidemiology of hypoxaemia in children with acute lower respiratory infection ...'},
 {'meta': {'case_ID': '110921.json',
   'case_jurisdiction': 'scotus.tar.gz',
   'date_created': '2010-04-28T17:12:49Z'},
  'text': '\n461 U.S. 238 (1983)\nOLIM ET AL.\nv.\nWAKINEKONA\nNo. 81-1581.\nSupreme Court of United States.\nArgued January 19, 1983.\nDecided April 26, 1983.\nCERTIORARI TO THE UNITED STATES COURT OF APPEALS FOR THE NINTH CIRCUIT\n*239 Michael A. Lilly, First Deputy Attorney General of Hawaii, argued the cause for petitioners. With him on the brief was James H. Dannenberg, Deputy Attorney General...'}]
```

Abbiamo utilizzato la funzione `islice()` del modulo Python `itertools` per selezionare i primi due esempi dai dataset combinati, e abbiamo visto che corrispondono ai primi esempi di ognuno dei due dataset originali.

Infine, se vuoi processare il Pile in streaming, in tutti i suoi 825 GB, puoi recuperare tutti i file preparati, come segue:

```py
base_url = "https://the-eye.eu/public/AI/pile/"
data_files = {
    "train": [base_url + "train/" + f"{idx:02d}.jsonl.zst" for idx in range(30)],
    "validation": base_url + "val.jsonl.zst",
    "test": base_url + "test.jsonl.zst",
}
pile_dataset = load_dataset("json", data_files=data_files, streaming=True)
next(iter(pile_dataset["train"]))
```

```python out
{'meta': {'pile_set_name': 'Pile-CC'},
 'text': 'It is done, and submitted. You can play “Survival of the Tastiest” on Android, and on the web...'}
```

<Tip>

✏️ **Prova tu!** Usa uno dei corpora Common Crawl come [`mc4`](https://huggingface.co/datasets/mc4) oppure [`oscar`](https://huggingface.co/datasets/oscar) per crare un dataset multilingue in streaming, che rappresenta le proporzioni delle lingue parlate in un paese a tua scelta. Ad esempio, le quattro lingue ufficiali in Svizzera sono il tedesco, il francesce, l'italiano e il romancio, per cui potresti creare un corpus della Svizzera raccogliendo i campioni da Oscar, secondo la percentuale di parlanti di ognuna.

</Tip>

Ora hai a tua disposizione tutti gli strumenti per caricare e processare dataset di ogni tipo -- ma a meno che tu non sia estremamente fortunato, arriverà un momento nel tuo cammino in cui dovrai effettivamente creare un dataset per risolvere i tuoi problemi. Questo sarà argomento della prossima sezione!


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter5/4.mdx" />

### 🤗 Datasets, check!
https://huggingface.co/learn/course/it/chapter5/7.md

# 🤗 Datasets, check!

<CourseFloatingBanner
    chapter={5}
    classNames="absolute z-10 right-0 top-0"
/>

Beh, abbiamo fatto un bel giro nella libreria 🤗 Datasets: complimenti per aver raggiunto quest'obiettivo! Con le conoscenze che hai ottenuto da questo capitolo, sei in grado di:
- Caricare dataset da ogni luogo, sia esso l'Hub di Hugging Face, il tuo portatile, o un server in remoto della tua compagnia.
- Fare data-wrangling usando un mix delle funzioni `Dataset.map()` e `Dataset.filter()`.
- Passare velocemente tra diversi formati di dati domce Pandas e NumPy usando `Dataset.set_format()`.
- Creare il tuo dataset e condividerlo sull'Hub Hugging Face.
- Creare embedding dei tuoi documenti usando un modello Transformer, e costruire un motore di ricerca semantico usando FAISS. 

Nel [Capitolo 7](/course/chapter7), faremo buon uso di tutto questo mentre ci avventureremo nei task principali NLP, per i quali i modelli Transformer sono un'ottima soluzione. Prima di andare oltre, però, metti alla prova la tua conoscenza di 🤗 Datasets con un quiz!


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter5/7.mdx" />

### E se il mio dataset non è sull'Hub?
https://huggingface.co/learn/course/it/chapter5/2.md

# E se il mio dataset non è sull'Hub?

<CourseFloatingBanner chapter={5}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/it/chapter5/section2.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/it/chapter5/section2.ipynb"},
]} />

Sai come usare l'[Hub Hugging Face](https://huggingface.co/datasets) per scaricare i dataset, ma spessa dovrai lavorare con dati che si trovano sul tuo computer, o so un server remoto. In questa sezione vederemo come usare 🤗 Datasets per caricare dataset che non sono disponibile nell'Hub Hugging Face.

<Youtube id="HyQgpJTkRdE"/>

## Lavorare con dataset locali e in remoto

🤗 Datasets mette a tua disposizione diversi script per caricare dataset in locale e in remoto. Sono supportati diversi formati di dati, tra cui:

|    Formato dati     | Script |                         Esempio                         |
| :----------------: | :------------: | :-----------------------------------------------------: |
|     CSV & TSV      |     `csv`      |     `load_dataset("csv", data_files="my_file.csv")`     |
|     File di testo     |     `text`     |    `load_dataset("text", data_files="my_file.txt")`     |
| JSON & JSON Lines  |     `json`     |   `load_dataset("json", data_files="my_file.jsonl")`    |
| DataFrame serializzati in Pickle |    `pandas`    | `load_dataset("pandas", data_files="my_dataframe.pkl")` |

Come mostrato nella tabella, per ogni formato di dati abbiamo bisogno di specificare, all'interno della funzione `load_dataset()`, il tipo di script da utilizzare, assieme a `data_files`, che specifica il percorso verso uno o più file. Iniziamo a caricare un dataset proveniente da file locali; più tardi vederemo come fare la stessa cosa con file in remoto.
 
## Caricare un dataset locale

Per questo esempio useremo il [dataset SQuAD-it](https://github.com/crux82/squad-it/), un ampio dataset per il question answering in italiano

Le sezioni di addestramento e di test si trovano su GitHub, quindi possiamo scaricarle con un semplice comando `wget`:

```python
!wget https://github.com/crux82/squad-it/raw/master/SQuAD_it-train.json.gz
!wget https://github.com/crux82/squad-it/raw/master/SQuAD_it-test.json.gz
```

Questo scaricherà due file compressi chiamati *SQuAD_it-train.json.gz* e *SQuAD_it-test.json.gz*, che possiamo decomprimere con il comandi Linux `gzip`:

```python
!gzip -dkv SQuAD_it-*.json.gz
```

```bash
SQuAD_it-test.json.gz:	   87.4% -- replaced with SQuAD_it-test.json
SQuAD_it-train.json.gz:	   82.2% -- replaced with SQuAD_it-train.json
```

Vediamo che i dati compressi sono stati sostituiti da _SQuAD_it-train.json_ e _SQuAD_it-text.json_, e che i dati sono archiviati in formato JSON.

<Tip>

✎ Se ti stai chiedendo perché c'è un `!` nei comandi di shell precedenti, è perché li stiamo eseguendo da un notebook Jupyter. Se vuoi scaricare e decomprimere i dataset da un terminale, non devi fare altro che rimuovere il prefisso.

</Tip>

Per caricare un file JSON con la funzione `load_dataset()`, ci serve solo sapere se abbiamo a che fare con un normale JSON (simile a un dizionario annidato) o con un JSON Lines (JSON separato da righe). Come molti dataset per il question asnwring, SQuAD-it usa il formato annidato, con tutto il testo immagazzinato nel campo `data`. Questo significa che possiamo caricare il dataset specificando l'argomento `field` come segue:

```py
from datasets import load_dataset

squad_it_dataset = load_dataset("json", data_files="SQuAD_it-train.json", field="data")
```

Di default, caricare file locali create un oggetto `DatasetDict` con una sezione `train`. Possiamo vederlo ispezionando l'oggetto `squad_it_dataset`:

```py
squad_it_dataset
```

```python out
DatasetDict({
    train: Dataset({
        features: ['title', 'paragraphs'],
        num_rows: 442
    })
})
```

Questo ci mostra il numero di righe e i nomi delle colonne associate con il set di addestraento. Possiamo vedere uno degli esempi indicizzando la sezione `train`, come segue:

```py
squad_it_dataset["train"][0]
```

```python out
{
    "title": "Terremoto del Sichuan del 2008",
    "paragraphs": [
        {
            "context": "Il terremoto del Sichuan del 2008 o il terremoto...",
            "qas": [
                {
                    "answers": [{"answer_start": 29, "text": "2008"}],
                    "id": "56cdca7862d2951400fa6826",
                    "question": "In quale anno si è verificato il terremoto nel Sichuan?",
                },
                ...
            ],
        },
        ...
    ],
}
```

Benissimo, abbiamo caricare il nostro primo dataset locale! Ma anche se questo ha funzionato per la sezione di addestramento, vogliamo includere entrambe le sezioni `train` e `test` in un unico oggetto `DatasetDict` così da poter applicare le funzioni `Dataset.map()` su entrambi i dataset simultaneamente. Per fare questo, possiamo dare un dizionaro all'argomento `data_files`, per mappare ogni sezione a un file associato con quella sezione: 

```py
data_files = {"train": "SQuAD_it-train.json", "test": "SQuAD_it-test.json"}
squad_it_dataset = load_dataset("json", data_files=data_files, field="data")
squad_it_dataset
```

```python out
DatasetDict({
    train: Dataset({
        features: ['title', 'paragraphs'],
        num_rows: 442
    })
    test: Dataset({
        features: ['title', 'paragraphs'],
        num_rows: 48
    })
})
```

Questo è proprio ciò che volevamo. Ora possiamo applicare diverse tecniche di preprocessamento per pulire i dati, tokenizzare le revisioni, e altro.

<Tip>

L'argomento `data_files` della funzione `load_dataset()` è molto flessibile, e può essere usato con un percorso file singolo, con una lista di percorsi file, o un dizionario che mappa i nomi delle sezioni ai percorsi file. È anche possibile usare comandi glob per recuperare tutti i file che soddisfano uno specifico pattern secondo le regole dello shell di Unix (ad esempio, è possibile recuperare tutti i file JSON presenti in una cartella usando il pattern `data_files="*.json"`). Consulta la [documentazione](https://huggingface.co/docs/datasets/loading#local-and-remote-files) 🤗 Datasets per maggiori informazioni.

</Tip>

Gli script presenti in 🤗 Datasets supportano la decompressione atuomatica dei file in input, quindi possiamo saltare l'uso di `gzip` puntando `data_files` direttamente ai file compressi:

```py
data_files = {"train": "SQuAD_it-train.json.gz", "test": "SQuAD_it-test.json.gz"}
squad_it_dataset = load_dataset("json", data_files=data_files, field="data")
```

Questo può essere utile se non vuoi decomprimere manualmente molti file GZIP. La decompressione automatica si applica inoltre ad altri formati comuni, come ZIP e TAR, basta solo puntare  `data_files` ai file compressi ed è fatta!

Ora che sai come caricare i file locali dal tuo computer, guardiamo come caricare i file remoti.

## Caricare un dataset in remoto

Se lavori come data scientist o come programmatore per un'azienda, ci sono buone probabilità che i dataset da analizzare sono archiaviati su un qualche server in remoto. Per fortuna, caricare file remoti è semplice come caricare quelli locali! Invece di dare un percorso a file locali, puntiamo l'argomento `data_files` di `load_dataset()` a uno o più URL dove si trovano i file in remoto. Ad esempio, per il dataset SQuAD-it presente su GitHub, possiamo puntare `data_files` agli URL _SQuAD_it-*.json.gz_ come segue: 

```py
url = "https://github.com/crux82/squad-it/raw/master/"
data_files = {
    "train": url + "SQuAD_it-train.json.gz",
    "test": url + "SQuAD_it-test.json.gz",
}
squad_it_dataset = load_dataset("json", data_files=data_files, field="data")
```

Questo codice restituisce lo stesso oggetto `DatasetDict` visto in precedenza, ma ci risparmia il passaggio manuale di scaricare e decomprimere i file _SQuAD_it-*.json.gz_. Questo conclude la nostra incursione nei diversi modi di caricare dataset che non sono presenti nell'Hub Hugging Face. Ora che abbiamo un dataset con cui giocare, sporchiamoci le mani con diverse tecniche di data-wrangling!

<Tip>

✏️ **Prova tu!** Scegli un altro dataset presente su GitHub o sulla [Repository di Machine Learning UCI](https://archive.ics.uci.edu/ml/index.php) e cerca di caricare sia in locale che in remoto usando le tecniche introdotte in precedenza. Per punti extra, prova a caricare un dataset archiviato in formato CSV o testuale (vedi la [documentazione](https://huggingface.co/docs/datasets/loading#local-and-remote-files) per ulteriori informazioni su questi formati).

</Tip>




<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter5/2.mdx" />

### Gestione di sequenze multiple
https://huggingface.co/learn/course/it/chapter2/5.md

# Gestione di sequenze multiple

{#if fw === 'pt'}

<CourseFloatingBanner chapter={2}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/en/chapter2/section5_pt.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/en/chapter2/section5_pt.ipynb"},
]} />

{:else}

<CourseFloatingBanner chapter={2}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/en/chapter2/section5_tf.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/en/chapter2/section5_tf.ipynb"},
]} />

{/if}

{#if fw === 'pt'}
<Youtube id="M6adb1j2jPI"/>
{:else}
<Youtube id="ROxrFOEbsQE"/>
{/if}

Nella sezione precedente abbiamo esplorato il più semplice dei casi d'uso: fare inferenza su una singola sequenza di lunghezza ridotta. Tuttavia, emergono già alcune domande:

- Come si gestiscono le sequenze multiple?
- Come gestiamo sequenze multiple *di lunghezza diversa*?
- Gli indici del vocabolario sono gli unici input che permettono a un modello di funzionare bene?
- Esiste una sequenza troppo lunga?

Vediamo quali tipi di problemi pongono queste domande e come possiamo risolverli utilizzando l'API 🤗 Transformers.

## I modelli si aspettano un gruppo di input

Nell'esercizio precedente abbiamo visto come le sequenze vengono tradotte in liste di numeri. Convertiamo questo elenco di numeri in un tensore e inviamolo al modello:

{#if fw === 'pt'}
```py
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)

sequence = "I've been waiting for a HuggingFace course my whole life."

tokens = tokenizer.tokenize(sequence)
ids = tokenizer.convert_tokens_to_ids(tokens)
input_ids = torch.tensor(ids)
# This line will fail.
model(input_ids)
```

```python out
IndexError: Dimension out of range (expected to be in range of [-1, 0], but got 1)
```
{:else}
```py
import tensorflow as tf
from transformers import AutoTokenizer, TFAutoModelForSequenceClassification

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint)

sequence = "I've been waiting for a HuggingFace course my whole life."

tokens = tokenizer.tokenize(sequence)
ids = tokenizer.convert_tokens_to_ids(tokens)
input_ids = tf.constant(ids)
# This line will fail.
model(input_ids)
```

```py out
InvalidArgumentError: Input to reshape is a tensor with 14 values, but the requested shape has 196 [Op:Reshape]
```
{/if}

Oh no! Perché non ha funzionato?

Il problema è che abbiamo inviato una singola sequenza al modello, mentre i modelli 🤗 Transformers si aspettano frasi multiple per impostazione predefinita. Qui abbiamo cercato di fare tutto ciò che il tokenizer ha fatto dietro le quinte, quando lo abbiamo applicato a una `sequenza`. Ma se si osserva attentamente, si noterà che il tokenizer non si è limitato a convertire l'elenco degli ID in ingresso in un tensore, ma ha aggiunto una dimensione:

{#if fw === 'pt'}
```py
tokenized_inputs = tokenizer(sequence, return_tensors="pt")
print(tokenized_inputs["input_ids"])
```

```python out
tensor([[  101,  1045,  1005,  2310,  2042,  3403,  2005,  1037, 17662, 12172,
          2607,  2026,  2878,  2166,  1012,   102]])
```
{:else}
```py
tokenized_inputs = tokenizer(sequence, return_tensors="tf")
print(tokenized_inputs["input_ids"])
```

```py out
<tf.Tensor: shape=(1, 16), dtype=int32, numpy=
array([[  101,  1045,  1005,  2310,  2042,  3403,  2005,  1037, 17662,
        12172,  2607,  2026,  2878,  2166,  1012,   102]], dtype=int32)>
```
{/if}

Proviamo di nuovo e aggiungiamo una nuova dimensione:

{#if fw === 'pt'}
```py
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)

sequence = "I've been waiting for a HuggingFace course my whole life."

tokens = tokenizer.tokenize(sequence)
ids = tokenizer.convert_tokens_to_ids(tokens)

input_ids = torch.tensor([ids])
print("Input IDs:", input_ids)

output = model(input_ids)
print("Logits:", output.logits)
```
{:else}
```py
import tensorflow as tf
from transformers import AutoTokenizer, TFAutoModelForSequenceClassification

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint)

sequence = "I've been waiting for a HuggingFace course my whole life."

tokens = tokenizer.tokenize(sequence)
ids = tokenizer.convert_tokens_to_ids(tokens)

input_ids = tf.constant([ids])
print("Input IDs:", input_ids)

output = model(input_ids)
print("Logits:", output.logits)
```
{/if}

Stampiamo gli ID di input e i logit risultanti —  ecco l'output:


{#if fw === 'pt'}
```python out
Input IDs: [[ 1045,  1005,  2310,  2042,  3403,  2005,  1037, 17662, 12172,  2607, 2026,  2878,  2166,  1012]]
Logits: [[-2.7276,  2.8789]]
```
{:else}
```py out
Input IDs: tf.Tensor(
[[ 1045  1005  2310  2042  3403  2005  1037 17662 12172  2607  2026  2878
   2166  1012]], shape=(1, 14), dtype=int32)
Logits: tf.Tensor([[-2.7276208  2.8789377]], shape=(1, 2), dtype=float32)
```
{/if}

*Il batch* è la procedura di invio di più frasi nel modello, tutte in una volta. Se si ha una sola frase, si può creare un batch con una sola sequenza:

```
batched_ids = [ids, ids]
```

Si tratta di un batch di due sequenze identiche!

<Tip>

✏️ **Try it out!** Convert this `batched_ids` list into a tensor and pass it through your model. Check that you obtain the same logits as before (but twice)!

</Tip>

Il batching consente al modello di funzionare quando si inseriscono più frasi. Utilizzare più sequenze è altrettanto semplice che creare un batch con una singola sequenza. C'è però un secondo problema. Quando si cerca di raggruppare due (o più) frasi, queste potrebbero essere di lunghezza diversa. Se si è già lavorato con i tensori, si sa che devono essere di forma rettangolare, quindi non è possibile convertire direttamente l'elenco degli ID in ingresso in un tensore. Per ovviare a questo problema, di solito, utilizziamo la tecnica del *padding* sugli input.

## Aggiungere il padding all'input

Il seguente elenco di liste non può essere convertito in un tensore:

```py no-format
batched_ids = [
    [200, 200, 200],
    [200, 200]
]
```

Per ovviare a questo problema, useremo il *padding* per dare ai nostri tensori una forma rettangolare. Il padding assicura che tutte le frasi abbiano la stessa lunghezza, aggiungendo una parola speciale chiamata *padding token* alle frasi con meno valori. Ad esempio, se si hanno 10 frasi con 10 parole e 1 frase con 20 parole, il padding assicura che tutte le frasi abbiano 20 parole. Nel nostro esempio, il tensore risultante ha il seguente aspetto:

```py no-format
padding_id = 100

batched_ids = [
    [200, 200, 200],
    [200, 200, padding_id],
]
```

L'ID del token di padding si trova in `tokenizer.pad_token_id`. Utilizziamolo e inviamo le nostre due frasi attraverso il modello singolarmente e insieme:

{#if fw === 'pt'}
```py no-format
model = AutoModelForSequenceClassification.from_pretrained(checkpoint)

sequence1_ids = [[200, 200, 200]]
sequence2_ids = [[200, 200]]
batched_ids = [
    [200, 200, 200],
    [200, 200, tokenizer.pad_token_id],
]

print(model(torch.tensor(sequence1_ids)).logits)
print(model(torch.tensor(sequence2_ids)).logits)
print(model(torch.tensor(batched_ids)).logits)
```

```python out
tensor([[ 1.5694, -1.3895]], grad_fn=<AddmmBackward>)
tensor([[ 0.5803, -0.4125]], grad_fn=<AddmmBackward>)
tensor([[ 1.5694, -1.3895],
        [ 1.3373, -1.2163]], grad_fn=<AddmmBackward>)
```
{:else}
```py no-format
model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint)

sequence1_ids = [[200, 200, 200]]
sequence2_ids = [[200, 200]]
batched_ids = [
    [200, 200, 200],
    [200, 200, tokenizer.pad_token_id],
]

print(model(tf.constant(sequence1_ids)).logits)
print(model(tf.constant(sequence2_ids)).logits)
print(model(tf.constant(batched_ids)).logits)
```

```py out
tf.Tensor([[ 1.5693678 -1.3894581]], shape=(1, 2), dtype=float32)
tf.Tensor([[ 0.5803005  -0.41252428]], shape=(1, 2), dtype=float32)
tf.Tensor(
[[ 1.5693681 -1.3894582]
 [ 1.3373486 -1.2163193]], shape=(2, 2), dtype=float32)
```
{/if}

C'è qualcosa che non va con i logit nelle nostre previsioni raggruppate: la seconda riga dovrebbe essere uguale ai logit della seconda frase, ma abbiamo valori completamente diversi!

Questo perché la caratteristica principale dei modelli Transformer sono i livelli di attenzione che *contestualizzano* ogni token. Questi terranno conto dei token del padding, poiché si occupano di tutti i token di una sequenza. Per ottenere lo stesso risultato quando si passano nel modello singole frasi di lunghezza diversa o quando si passa un gruppo con le stesse frasi e l'applicazione di un padding, occorre dire a questi livelli di attenzione di ignorare i token del padding. Questo si ottiene utilizzando una maschera di attenzione.

## Attention masks

Le *maschere di attenzione* sono tensori con la stessa forma del tensore degli ID in ingresso, riempiti con 0 e 1: 1 indica che i token corrispondenti devono essere presi in considerazione, mentre 0 indica che i token corrispondenti non devono essere presi in considerazione (cioè, devono essere ignorati dagli strati di attenzione del modello).

Completiamo l'esempio precedente con una maschera di attenzione:

{#if fw === 'pt'}
```py no-format
batched_ids = [
    [200, 200, 200],
    [200, 200, tokenizer.pad_token_id],
]

attention_mask = [
    [1, 1, 1],
    [1, 1, 0],
]

outputs = model(torch.tensor(batched_ids), attention_mask=torch.tensor(attention_mask))
print(outputs.logits)
```

```python out
tensor([[ 1.5694, -1.3895],
        [ 0.5803, -0.4125]], grad_fn=<AddmmBackward>)
```
{:else}
```py no-format
batched_ids = [
    [200, 200, 200],
    [200, 200, tokenizer.pad_token_id],
]

attention_mask = [
    [1, 1, 1],
    [1, 1, 0],
]

outputs = model(tf.constant(batched_ids), attention_mask=tf.constant(attention_mask))
print(outputs.logits)
```

```py out
tf.Tensor(
[[ 1.5693681  -1.3894582 ]
 [ 0.5803021  -0.41252586]], shape=(2, 2), dtype=float32)
```
{/if}

Ora otteniamo gli stessi logits per la seconda frase del batch.

Si noti che l'ultimo valore della seconda sequenza è un ID di riempimento, che è un valore 0 nella maschera di attenzione.

<Tip>

✏️ **Provaci anche tu** Applicate manualmente la tokenizzazione alle due frasi utilizzate nella sezione 2 ("I've been waiting for a HuggingFace course my whole life." e "I hate this so much!"). Passatele attraverso il modello e verificate che si ottengano gli stessi logits della sezione 2. A questo punto, batchateli insieme utilizzando il token di padding e successivamente create la maschera di attenzione appropriata. Verificate di ottenere gli stessi risultati passando attraverso il modello!

</Tip>

## Sequenze più lunghe

Con i modelli Transformer, c'è un limite alla lunghezza delle sequenze che possiamo passare ai modelli. La maggior parte dei modelli gestisce sequenze fino a 512 o 1024 token e si blocca quando viene chiesto di elaborare sequenze più lunghe. Esistono due soluzioni a questo problema:

- Utilizzare un modello con una lunghezza di sequenza supportata maggiore.
- Troncare le sequenze.

I modelli hanno diverse lunghezze di sequenza supportate e alcuni sono specializzati nella gestione di sequenze molto lunghe. [Longformer](https://huggingface.co/transformers/model_doc/longformer.html) è un esempio, un altro è [LED](https://huggingface.co/transformers/model_doc/led.html).  Se state lavorando a un'attività che richiede sequenze molto lunghe, vi consigliamo di dare un'occhiata a questi modelli.

Altrimenti, si consiglia di troncare le sequenze specificando il parametro `max_sequence_length`:

```py
sequence = sequence[:max_sequence_length]
```


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter2/5.mdx" />

### Introduzione
https://huggingface.co/learn/course/it/chapter2/1.md

# Introduzione

<CourseFloatingBanner
    chapter={2}
    classNames="absolute z-10 right-0 top-0"
/>

Come si è visto nel [Capitolo 1](/course/chapter1),  I modelli Transformers sono solitamente molto grandi.
Con milioni o decine di *miliardi* di parametri, l'addestramento e la distribuzione di questi modelli è un'impresa complicata.
Inoltre, con i nuovi modelli che vengono rilasciati quasi ogni giorno e ognuno dei quali ha una propria implementazione, provarli tutti non è un lavoro facile.

La libreria 🤗 Transformers è stata creata per risolvere questo problema. Il suo obiettivo è fornire un'unica API attraverso la quale caricare, addestrare e salvare qualsiasi modello Transformer. Le caratteristiche principali della libreria sono:

- **Facilità d'uso**: È possibile scaricare, caricare ed utilizzare un modello NLP all'avanguardia per fare inferenza con appena due righe di codice.
- **Flessibilità**: Al loro interno, tutti i modelli sono semplici classi PyTorch `nn.Module` o TensorFlow `tf.keras.Model` e possono essere gestiti come qualsiasi altro modello nei rispettivi framework di apprendimento automatico (ML).
- **Semplicità**: La libreria non contiene quasi nessuna astrazione. Il concetto di "All in one file" è fondamentale: il forward pass di un modello è interamente definito in un singolo file, in modo che il codice stesso sia comprensibile e violabile.

Quest'ultima caratteristica rende 🤗 Transformers molto diversi da altre librerie ML. I modelli non sono costruiti su moduli condivisi tra i file, ma ogni modello ha i propri layers. Oltre a rendere i modelli più accessibili e comprensibili, questo permette di sperimentare facilmente su un modello senza influenzare gli altri.

Questo capitolo inizierà con un esempio in cui usiamo un modello e un tokenizer insieme per replicare la funzione `pipeline()` introdotta nel [Capitolo 1](/course/chapter1). Successivamente, parleremo dell'API del modello: ci immergeremo nelle classi del modello e della configurazione e mostreremo come caricare un modello e come esso elabora gli input numerici per produrre previsioni.

Successivamente vedremo l'API del tokenizer, che è l'altro componente principale della funzione `pipeline()`. I tokenizer si occupano della prima e dell'ultima fase di elaborazione, gestendo la conversione da testo a input numerici per la rete neurale e la conversione di nuovo in testo quando è necessario. Infine, mostreremo come gestire l'invio di più frasi a un modello in un batch preparato, per poi concludere il tutto con un'analisi più approfondita della funzione di alto livello `tokenizer()`.

<Tip>
⚠️ Per poter usufruire di tutte le funzioni disponibili con il Model Hub e i 🤗 Transformers, si consiglia di <a href="https://huggingface.co/join">creare un account</a>.
</Tip>

<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter2/1.mdx" />

### Models
https://huggingface.co/learn/course/it/chapter2/3.md

# Models

{#if fw === 'pt'}

<DocNotebookDropdown
  classNames="absolute z-10 right-0 top-0"
  options={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/chapter2/section3_pt.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/chapter2/section3_pt.ipynb"},
]} />

{:else}

<DocNotebookDropdown
  classNames="absolute z-10 right-0 top-0"
  options={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/chapter2/section3_tf.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/chapter2/section3_tf.ipynb"},
]} />

{/if}

{#if fw === 'pt'}
<Youtube id="AhChOFRegn4"/>
{:else}
<Youtube id="d3JVgghSOew"/>
{/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 model.safetensors
```
{: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 *model.safetensors* è 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.

<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter2/3.mdx" />

### Mettiamo insieme i pezzi
https://huggingface.co/learn/course/it/chapter2/6.md

# Mettiamo insieme i pezzi

{#if fw === 'pt'}

<CourseFloatingBanner chapter={2}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/en/chapter2/section6_pt.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/en/chapter2/section6_pt.ipynb"},
]} />

{:else}

<CourseFloatingBanner chapter={2}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/en/chapter2/section6_tf.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/en/chapter2/section6_tf.ipynb"},
]} />

{/if}

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:

```py
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:

```py
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:

```py
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

```py
# 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:

```py
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:

```py
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:

```py
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)
```

```python out
[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:

```py
print(tokenizer.decode(model_inputs["input_ids"]))
print(tokenizer.decode(ids))
```

```python out
"[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:

{#if fw === 'pt'}
```py
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)
```
{:else}
```py
import tensorflow as tf
from transformers import AutoTokenizer, TFAutoModelForSequenceClassification

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = TFAutoModelForSequenceClassification.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="tf")
output = model(**tokens)
```
{/if}


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter2/6.mdx" />

### Tokenizers
https://huggingface.co/learn/course/it/chapter2/4.md

# Tokenizers

{#if fw === 'pt'}

<DocNotebookDropdown
  classNames="absolute z-10 right-0 top-0"
  options={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/chapter2/section4_pt.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/chapter2/section4_pt.ipynb"},
]} />

{:else}

<DocNotebookDropdown
  classNames="absolute z-10 right-0 top-0"
  options={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/chapter2/section4_tf.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/chapter2/section4_tf.ipynb"},
]} />

{/if}

<Youtube id="VFp38yj8h3A"/>

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

<Youtube id="nhJxYji1aho"/>

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:

<div class="flex justify-center">
  <img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter2/word_based_tokenization.svg" alt="Un esempio di tokenizzazione basata sulle parole."/>
  <img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter2/word_based_tokenization-dark.svg" alt="Un esempio di tokenizzazione basata sulle parole."/>
</div>

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 "&lt;unk&gt;". 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

<Youtube id="ssLq_EK2jLE"/>

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:

<div class="flex justify-center">
  <img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter2/character_based_tokenization.svg" alt="Un esempio di tokenizzazione basata sui caratteri."/>
  <img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter2/character_based_tokenization-dark.svg" alt="Un esempio di tokenizzazione basata sui caratteri"/>
</div>

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

<Youtube id="zHvTiHr506c"/>

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!":

<div class="flex justify-center">
  <img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter2/bpe_subword.svg" alt="Un algoritmo di tokenizzazione delle sottoparole."/>
  <img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter2/bpe_subword-dark.svg" alt="Un algoritmo di tokenizzazione delle sottoparole."/>
</div>

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

<Youtube id="Yffk5aydLzg"/>

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.

<Tip>

✏️ **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!

</Tip>

## 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.


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter2/4.mdx" />

### Uso di base completato!
https://huggingface.co/learn/course/it/chapter2/7.md

# Uso di base completato!

<CourseFloatingBanner
    chapter={2}
    classNames="absolute z-10 right-0 top-0"
/>

Ottimo lavoro per aver seguito il corso fino a questo punto! Per fare un riassunto, in questo capitolo abbiamo visto:

- Imparare gli elementi di base di un modello Transformer.
- Imparare a conoscere gli elementi che compongono una pipeline di tokenizzazione.
- Hai visto come utilizzare un modello Transformer nella pratica.
- Imparare a sfruttare un tokenizer per convertire il testo in tensori comprensibili dal modello.
- Impostare un tokenizer e un modello insieme per passare dal testo alle previsioni.
- Imparare i limiti degli ID di input e conoscere le maschere di attenzione.
- Abbiamo giocato con metodi di tokenizzazione versatili e configurabili.

D'ora in poi, dovreste essere in grado di navigare liberamente nella documentazione di Transformers 🤗: il vocabolario vi suonerà familiare e avrete già visto i metodi che userete la maggior parte delle volte.


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter2/7.mdx" />

### Dietro la pipeline
https://huggingface.co/learn/course/it/chapter2/2.md

# Dietro la pipeline

{#if fw === 'pt'}

<DocNotebookDropdown
  classNames="absolute z-10 right-0 top-0"
  options={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/it/chapter2/section2_pt.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/it/chapter2/section2_pt.ipynb"},
]} />

{:else}

<DocNotebookDropdown
  classNames="absolute z-10 right-0 top-0"
  options={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/it/chapter2/section2_tf.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/it/chapter2/section2_tf.ipynb"},
]} />

{/if}

<Tip>
   Questa è la prima sezione in cui il contenuto è leggermente diverso a seconda che si utilizzi PyTorch o TensorFlow. Attivate lo switch sopra il titolo per selezionare la tua piattaforma preferita!
</Tip>

{#if fw === 'pt'}
<Youtube id="1pedAIvTWXk"/>
{:else}
<Youtube id="wVN12smEvqg"/>
{/if}

Cominciamo con un esempio completo, dando un'occhiata a ciò che è successo dietro le quinte quando abbiamo eseguito il seguente codice nel [Capitolo 1](/course/chapter1):

```python
from transformers import pipeline

classifier = pipeline("sentiment-analysis")
classifier(
    [
        "I've been waiting for a HuggingFace course my whole life.",
        "I hate this so much!",
    ]
)
```

e ottenuto:

```python out
[{'label': 'POSITIVE', 'score': 0.9598047137260437},
 {'label': 'NEGATIVE', 'score': 0.9994558095932007}]
```

Come abbiamo visto nel [Capitolo 1](/course/chapter1), questa pipeline raggruppa tre fasi: la pre-elaborazione, il passaggio degli input attraverso il modello e la post-elaborazione:

<div class="flex justify-center">
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter2/full_nlp_pipeline.svg" alt="La pipeline NLP completa: tokenizzazione del testo, conversione in ID e inferenza attraverso il modello Transformer ed il modello head."/>
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter2/full_nlp_pipeline-dark.svg" alt="La pipeline NLP completa: tokenizzazione del testo, conversione in ID e inferenza attraverso il modello Transformer ed il modello head.."/>
</div>

Esaminiamo rapidamente ciascuno di essi.

## Preelaborazione con un tokenizer

Come altre reti neurali, i modelli Transformer non possono elaborare direttamente il testo non elaborato, quindi la prima fase della nostra pipeline consiste nel convertire gli input testuali in numeri che il modello possa interpretare. Per fare ciò, utilizziamo un *tokenizer*, che sarà responsabile di:

- Suddivisione dell'input in parole, sottoparole o simboli (come la punteggiatura) che vengono chiamati *token*.
- Mappare ogni token in un numero intero
- Aggiunta di ulteriori input che possono essere utili per il modello

Tutta questa preelaborazione deve essere fatta esattamente nello stesso modo in cui è stato preaddestrato il modello, quindi dobbiamo prima scaricare queste informazioni dal [Model Hub](https://huggingface.co/models). Per farlo, si usa la classe `AutoTokenizer` e il suo metodo `from_pretrained()`. Utilizzando il nome del checkpoint del nostro modello, recupererà automaticamente i dati associati al tokenizer del modello e li metterà in cache (in modo che vengano scaricati solo la prima volta che si esegue il codice sottostante).

Poiché il checkpoint predefinito della pipeline `sentiment-analysis` è `distilbert-base-uncased-finetuned-sst-2-english` (si può vedere la sua scheda modello [qui](https://huggingface.co/distilbert-base-uncased-finetuned-sst-2-english)), eseguiamo quanto segue:

```python
from transformers import AutoTokenizer

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
```

Una volta che abbiamo il tokenizer, possiamo passargli direttamente le nostre frasi e otterremo un dizionario pronto per il nostro modello! L'unica cosa che resta da fare è convertire l'elenco degli ID in ingresso in tensori.

È possibile utilizzare i 🤗 Transformer senza doversi preoccupare di quale framework ML venga utilizzato come backend;potrebbe essere PyTorch o TensorFlow, o Flax per alcuni modelli. Tuttavia, i modelli Transformer accettano solo *tensors* come input. Se è la prima volta che sentite parlare di tensori, potete pensare a loro come array NumPy. Un array NumPy può essere uno scalare (0D), un vettore (1D), una matrice (2D) o avere più dimensioni. Si tratta effettivamente di un tensore; i tensori di altri framework ML si comportano in modo simile e di solito sono semplici da istanziare come gli array NumPy.

Per specificare il tipo di tensori che vogliamo ottenere (PyTorch, TensorFlow o NumPy), usiamo l'argomento `return_tensors`:

{#if fw === 'pt'}
```python
raw_inputs = [
    "I've been waiting for a HuggingFace course my whole life.",
    "I hate this so much!",
]
inputs = tokenizer(raw_inputs, padding=True, truncation=True, return_tensors="pt")
print(inputs)
```
{:else}
```python
raw_inputs = [
    "I've been waiting for a HuggingFace course my whole life.",
    "I hate this so much!",
]
inputs = tokenizer(raw_inputs, padding=True, truncation=True, return_tensors="tf")
print(inputs)
```
{/if}

Non preoccupatevi ancora di padding e truncation; li spiegheremo più avanti.Le cose principali da ricordare sono che si può passare una frase o un elenco di frasi, oltre a specificare il tipo di tensori che si desidera ottenere (se non viene passato alcun tipo, si otterrà una lista di liste come risultato).

{#if fw === 'pt'}

Ecco come appaiono i risultati come tensori PyTorch:

```python out
{
    'input_ids': tensor([
        [  101,  1045,  1005,  2310,  2042,  3403,  2005,  1037, 17662, 12172, 2607,  2026,  2878,  2166,  1012,   102],
        [  101,  1045,  5223,  2023,  2061,  2172,   999,   102,     0,     0,     0,     0,     0,     0,     0,     0]
    ]), 
    'attention_mask': tensor([
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    ])
}
```
{:else}

Ecco come appaiono i risultati come tensori TensorFlow:

```python out
{
    'input_ids': <tf.Tensor: shape=(2, 16), dtype=int32, numpy=
        array([
            [  101,  1045,  1005,  2310,  2042,  3403,  2005,  1037, 17662, 12172,  2607,  2026,  2878,  2166,  1012,   102],
            [  101,  1045,  5223,  2023,  2061,  2172,   999,   102,     0,     0,     0,     0,     0,     0,     0,     0]
        ], dtype=int32)>, 
    'attention_mask': <tf.Tensor: shape=(2, 16), dtype=int32, numpy=
        array([
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
        ], dtype=int32)>
}
```
{/if}

L'output stesso è un dizionario contenente due chiavi, `input_ids` e `attention_mask`. `input_ids` contiene due righe di interi (uno per ogni frase) che sono gli identificatori unici dei token in ogni frase. Spiegheremo cosa sia la `attention_mask` più avanti in questo capitolo.

## Passare attraverso il modello

{#if fw === 'pt'}
Possiamo scaricare il nostro modello preaddestrato nello stesso modo in cui abbiamo fatto con il nostro tokenizer. 🤗 Transformers fornisce una classe `AutoModel` che ha anche un metodo `from_pretrained()`:

```python
from transformers import AutoModel

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
model = AutoModel.from_pretrained(checkpoint)
```
{:else}
Possiamo scaricare il nostro modello preaddestrato nello stesso modo in cui abbiamo fatto con il nostro tokenizer.  🤗 Transformers fornisce una classe `TFAutoModel` che ha anche un metodo `from_pretrained`:

```python
from transformers import TFAutoModel

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
model = TFAutoModel.from_pretrained(checkpoint)
```
{/if}

In questo frammento di codice, abbiamo scaricato lo stesso checkpoint usato in precedenza nella nostra pipeline (in realtà dovrebbe essere già nella cache) e abbiamo istanziato un modello con esso.

Questa architettura contiene solo il modulo Transformer di base: dati alcuni input, produce quelli che chiameremo *hidden states*, noti anche come *features*. Per ogni input del modello, recupereremo un vettore ad alta dimensionalità che rappresenta la **comprensione contestuale di quell'input da parte del modello Transformer**.

Se per te tutto questo non ha senso, non preoccuparti. Ti spiegheremo tutto più avanti.

Anche se questi stati nascosti possono essere utili da soli, di solito sono input di un'altra parte del modello, nota come *head*. Nel [Capitolo 1](/course/chapter1), i diversi compiti potrebbero essere eseguiti con la stessa architettura, ma a ciascuno di essi sarà associata una head diversa.

### Un vettore ad alta dimensionalità?

Il vettore emesso dal modulo Transformer è solitamente di grandi dimensioni. In genere ha tre dimensioni:

- **Dimensione del batch**: Il numero di sequenze elaborate alla volta (2 nel nostro esempio).
- **Lunghezza della sequenza**: La lunghezza della rappresentazione numerica della sequenza (16 nel nostro esempio).
- **Dimensione nascosta**: La dimensione del vettore di ciascun ingresso del modello.

Si dice che è "ad alta dimensionalità" a causa dell'ultimo valore. La dimensione nascosta può essere molto grande (768 è comune per i modelli più piccoli, mentre nei modelli più grandi può arrivare a 3072 o più).

Lo possiamo vedere se alimentiamo il nostro modello con gli input che abbiamo preelaborato:

{#if fw === 'pt'}
```python
outputs = model(**inputs)
print(outputs.last_hidden_state.shape)
```

```python out
torch.Size([2, 16, 768])
```
{:else}
```py
outputs = model(inputs)
print(outputs.last_hidden_state.shape)
```

```python out
(2, 16, 768)
```
{/if}

Si noti che gli output dei modelli 🤗 Transformers si comportano come `namedtuple` o dizionari. Si può accedere agli elementi per attributi (come abbiamo fatto noi) sia per chiave (`outputs["last_hidden_state"]`), sia per indice se si sa esattamente dove si trova ciò che si sta cercando (`outputs[0]`).

### Model heads: Dare un senso ai numeri

Le model head prendono in input il vettore ad alta dimensione degli stati nascosti e lo proiettano su una dimensione diversa. Di solito sono composte da uno o pochi strati lineari:

<div class="flex justify-center">
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter2/transformer_and_head.svg" alt="Una rete di Transformer accanto alla sua head."/>
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter2/transformer_and_head-dark.svg" alt="Una rete di Transformer accanto alla sua head."/>
</div>

Gli output del modello Transformer vengono inviati direttamente alla model head per essere elaborati.

In questo diagramma, il modello è rappresentato dallo strato embeddings e dagli strati successivi. Il livello embeddings converte ogni ID dell'input tokenizzato in un vettore che rappresenta il token associato. I livelli successivi manipolano questi vettori utilizzando il meccanismo di attenzione per produrre la rappresentazione finale delle frasi.

Esistono diverse architetture disponibili nei 🤗 Transformers, ognuna delle quali è stata progettata per affrontare un compito specifico. Ecco un elenco non esaustivo:

- `*Model` (retrieve the hidden states)
- `*ForCausalLM`
- `*ForMaskedLM`
- `*ForMultipleChoice`
- `*ForQuestionAnswering`
- `*ForSequenceClassification`
- `*ForTokenClassification`
- e altre 🤗

{#if fw === 'pt'}
Per il nostro esempio, avremo bisogno di un modello con una classificazion head della sequenza (per poter classificare le frasi come positive o negative). Quindi, non useremo la classe `AutoModel`, ma `AutoModelForSequenceClassification`:

```python
from transformers import AutoModelForSequenceClassification

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
model = AutoModelForSequenceClassification.from_pretrained(checkpoint)
outputs = model(**inputs)
```
{:else}
Per il nostro esempio, avremo bisogno di un modello con una classificazion head della sequenza (per poter classificare le frasi come positive o negative). Quindi, non useremo la classe `TFAutoModel`, ma `TFAutoModelForSequenceClassification`:

```python
from transformers import TFAutoModelForSequenceClassification

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint)
outputs = model(inputs)
```
{/if}

Ora, se osserviamo la forma dei nostri output, la dimensionalità sarà molto più bassa: la model head prende in input i vettori ad alta dimensionalità che abbiamo visto prima e produce vettori contenenti due valori (uno per etichetta):

```python
print(outputs.logits.shape)
```

{#if fw === 'pt'}
```python out
torch.Size([2, 2])
```
{:else}
```python out
(2, 2)
```
{/if}

Dato che abbiamo solo due frasi e due etichette, il risultato che otteniamo dal nostro modello è di forma 2 x 2.

## Postprocessing the output

I valori che otteniamo come output dal nostro modello non hanno necessariamente senso da soli. Diamo un'occhiata:

```python
print(outputs.logits)
```

{#if fw === 'pt'}
```python out
tensor([[-1.5607,  1.6123],
        [ 4.1692, -3.3464]], grad_fn=<AddmmBackward>)
```
{:else}
```python out
<tf.Tensor: shape=(2, 2), dtype=float32, numpy=
    array([[-1.5606991,  1.6122842],
           [ 4.169231 , -3.3464472]], dtype=float32)>
```
{/if}

Il nostro modello ha previsto `[-1.5607, 1.6123]` per la prima frase e `[ 4.1692, -3.3464]` per la seconda. Non si tratta di probabilità ma di *logit*, i punteggi non normalizzati emessi dall'ultimo livello del modello. Per poterli convertire in probabilità, devono passare attraverso un layer [SoftMax](https://en.wikipedia.org/wiki/Softmax_function) (tutti i modelli 🤗 Transformers producono i logits, poiché la funzione di perdita per l'addestramento generalmente fonde l'ultima funzione di attivazione, come SoftMax, con la funzione di perdita effettiva, come la cross entropy):

{#if fw === 'pt'}
```py
import torch

predictions = torch.nn.functional.softmax(outputs.logits, dim=-1)
print(predictions)
```
{:else}
```py
import tensorflow as tf

predictions = tf.math.softmax(outputs.logits, axis=-1)
print(predictions)
```
{/if}

{#if fw === 'pt'}
```python out
tensor([[4.0195e-02, 9.5980e-01],
        [9.9946e-01, 5.4418e-04]], grad_fn=<SoftmaxBackward>)
```
{:else}
```python out
tf.Tensor(
[[4.01951671e-02 9.59804833e-01]
 [9.9945587e-01 5.4418424e-04]], shape=(2, 2), dtype=float32)
```
{/if}

Ora possiamo vedere che il modello ha previsto `[0,0402, 0,9598]` per la prima frase e `[0,9995, 0,0005]` per la seconda. Si tratta di punteggi di probabilità riconoscibili.

Per ottenere le etichette corrispondenti a ogni posizione, si può ispezionare l'attributo `id2label` della configurazione del modello (si veda la prossima sezione):

```python
model.config.id2label
```

```python out
{0: 'NEGATIVE', 1: 'POSITIVE'}
```

Ora possiamo concludere che il modello ha previsto quanto segue:
 
- Prima frase: NEGATIVE: 0.0402, POSITIVE: 0.9598
- Seconda frase: NEGATIVE: 0.9995, POSITIVE: 0.0005

Abbiamo riprodotto con successo le tre fasi della pipeline: preelaborazione con i tokenizer, passaggio degli input attraverso il modello e postelaborazione! Ora prendiamoci un po' di tempo per approfondire ognuna di queste fasi.

<Tip>
✏️ **Provaci anche tu!** Scegli due (o più) testi di tua proprietà e lanciali all'interno della pipeline `sentiment-analysis`. Successivamente, replica i passi che hai visto qui e verifica di aver ottenuto gli stessi risultati!
</Tip>


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter2/2.mdx" />

### Introduzione
https://huggingface.co/learn/course/it/chapter0/1.md

# Introduzione

Benvenuto/a al corso di Hugging Face! In questo capitolo introduttivo, ti aiuteremo a configurare il tuo ambiente di lavoro. Se non hai ancora cominciato il corso, ti consigliamo di dare prima un occhio al [Capitolo 1](/course/chapter1), per poi tornare qui a creare il tuo ambiente e cominciare a lavorare al codice.

Tutte le librerie che useremo in questo corso sono disponibili come pacchetti Python. Qui ti mostreremo dapprima come configurare un ambiente Python e in seguito come installare le librerie di cui avrai bisogno.

Copriremo due modi per configurare un ambiente di lavoro: usando un blocco note Colab, oppure un ambiente virtuale in Python. Sentiti libero/a di scegliere quello che ti sembra più adatto a te. Se sei un/a principiante, ti consigliamo vivamente di cominciare a lavorare con un blocco note Colab.

Nota che non copriremo Windows. Se utilizzi Windows come sistema operativo, il nostro consiglio è di seguire il corso utilizzando un blocco note Colab. Se invece utilizzi Linux oppure macOS, puoi scegliere uno qualsiasi degli approcci descritti qui in seguito.

Buona parte del corso richiede un profilo di Hugging Face. Ti consigliamo dunque di crearne uno al più presto: [Crea un profilo](https://huggingface.co/join).

## Come usare un blocco note Colab di Google

Il modo più semplice di configurare il tuo ambiente di lavoro è utilizzando Google Colab: una volta avviato un blocco note nel browser, puoi iniziare immediatamente a programmare! 

Se non conosci bene Colab, ti raccomandiamo di iniziare dalla seguente [introduzione](https://colab.research.google.com/notebooks/intro.ipynb). Colab permette di utilizzare accelerazioni hardware come GPU o TPU, ed è gratuito per i carichi di lavoro più piccoli.

Quando ti sentirai a tuo agio con Colab, crea un nuovo blocco note e inizia la configurazione:

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter0/new_colab.png" alt="An empty colab notebook" width="80%"/>
</div>

Il passo successivo consiste nell'installare le librerie che utilizzerai in questo corso. Per l'installazione, useremo `pip`, ossia il gestore di pacchetti di Python. In Google Colab, puoi inizializzare i tuoi comandi di sistema facendone precedere il nome dal carattere `!`. La libreria 🤗 Transformers verrà quindi installata come segue:

```
!pip install transformers
```

Puoi assicurarti che il pacchetto sia stato installato correttamente importandolo in Python:

```
import transformers
```

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter0/install.gif" alt="A gif showing the result of the two commands above: installation and import" width="80%"/>
</div>

Quest'operazione installa una versione molto leggera degli 🤗 Transformers che non importa nessun framework (*quadro strutturale*) di machine learning (*apprendimento automatico*), come ad esempio PyTorch o TensorFlow. Dato che useremo numerose features (*caratteristiche*) della libreria, ti raccomandiamo l'installazione della versione per sviluppatori. Questa contiene praticamente tutte le dipendenze possibili e immaginabili:

```
!pip install transformers[sentencepiece]
```

L'operazione richiederà un po' di tempo, ma poi sarai pronto/a per il tutto resto del corso!

## Come usare un ambiente virtuale in Python

Se preferisci utilizzare un ambiente virtuale in Python, il primo passo consiste nell'installazione di Python nel tuo sistema. Ti raccomandiamo di aiutarti con [questa guida](https://realpython.com/installing-python/).

Quando avrai installato Python, dovresti riuscire a eseguire qualsiasi comando in Python sul terminale. Prima di procedere ai passi successivi, prova a eseguire il seguente comando per assicurarti che Python sia installato correttamente: `python --version`. Il comando dovrebbe stampare il nome della versione di Python installata nella tua macchina.

Quando esegui un comando in Python dal terminale, come ad esempio `python --version`, ti consigliamo di considerare il programma che esegue il tuo comando come l'installazione "principale" di Python del tuo sistema. La nostra raccomandazione è di tenere quest'installazione principale libera da pacchetti di ogni tipo, e di usarla per creare ambienti diversi per ogni applicazione alla quale lavorerai. In questo modo, ogni applicazione avrà le proprie dipendenze e i propri pacchetti, e non dovrai preoccuparti di eventuali problemi di compatibilità con altre applicazioni.

In Python, quest'operazione si effettua utilizzando i [virtual environments](https://docs.python.org/3/tutorial/venv.html) (*ambienti virtuali*). Questi ultimi sono degli alberi di directory autonomi che contengono installazioni di Python diverse, ossia particolari versioni di Python unite a tutti i pacchetti richiesti da una certa applicazione. La creazione di ambienti virtuali di questo tipo si può attuare a mezzo di strumenti diversi, anche se qui useremo esclusivamente il pacchetto ufficiale di Python, [`venv`](https://docs.python.org/3/library/venv.html#module-venv).

Innanzitutto, crea la cartella che ospiterà l'applicazione in questione, come ad esempio una cartella di nome *transformer-course* alla radice della tua home directory:

```
mkdir ~/transformer-course
cd ~/transformer-course
```

All'interno di questa cartella, crea un ambiente virtuale utilizzando il modulo `venv` di Python:

```
python -m venv .env
```

A questo punto, dovresti avere una cartella chiamata *.env* in quella che era la tua cartella vuota:

```
ls -a
```

```out
.      ..    .env
```

Puoi entrare e uscire dall'ambiente virtuale utilizzando gli script `activate` e `deactivate`:

```
# Activate the virtual environment
source .env/bin/activate

# Deactivate the virtual environment
deactivate
```

Assicurati che l'ambiente sia configurato correttamente eseguendo il comando `which python`: se come risposta ottieni l'ambiente virtuale, significa che l'hai attivato bene!

```
which python
```

```out
/home/<user>/transformer-course/.env/bin/python
```

### Installazione dipendenze

Come già menzionato nella sezione su Google Colab, il passo successivo consiste nell'installazione dei pacchetti richiesti dal corso. Ancora una volta, ti chiediamo di installare la versione per sviluppatori degli 🤗 Transformers utilizzando il gestore di pacchetti `pip`:

```
pip install "transformers[sentencepiece]"
```

Abbiamo finito con le installazioni! Ora sei pronto/a a iniziare.


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter0/1.mdx" />

### Riassunto
https://huggingface.co/learn/course/it/chapter1/9.md

# Riassunto

<CourseFloatingBanner
    chapter={1}
    classNames="absolute z-10 right-0 top-0"
/>

In questo capitolo, hai scoperto come approcciare diversi compiti di NLP utilizzando la funzione di alto livello `pipeline()` degli 🤗 Transformer. Abbiamo anche visto come cercare e utilizzare i modelli dell'Hub, nonché come usare l'Inference API per testare i modelli direttamente nel tuo browser.

Abbiamo discusso di come i modelli Transformer lavorino a livello alto, e parlato dell'importanza del transfer learning e dell'affinamento. Un aspetto chiave è che è possibile utilizzare l'architettuta completa oppure solo l'encoder o il decoder, dipendentemente dal compito a cui desideri lavorare. La tabella seguente riordina questi concetti:

| Modello         | Esempi                                     | Compiti                                                                          |
|-----------------|--------------------------------------------|----------------------------------------------------------------------------------|
| Encoder         | ALBERT, BERT, DistilBERT, ELECTRA, RoBERTa | Classificazione frasale, riconoscimento delle entità nominate, estrazione di risposte a domande |
| Decoder         | CTRL, GPT, GPT-2, Transformer XL           | Generazione di testi                                                             |
| Encoder-decoder | BART, T5, Marian, mBART                    | Riassunti, traduzione, generazione di risposte a domande                         |


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter1/9.mdx" />

### Modelli encoder
https://huggingface.co/learn/course/it/chapter1/5.md

# Modelli encoder

<CourseFloatingBanner
    chapter={1}
    classNames="absolute z-10 right-0 top-0"
/>

<Youtube id="MUqNwgPjJvQ" />

I modelli encoder utilizzano solo l'encoder di un modello Transformer. In ogni fase, gli attention layer hanno accesso a tutte le parole della frase di partenza. Questi modelli sono spesso caratterizzati come aventi attenzione "bi-direzionale" e chiamati *auto-encoding models*.

Solitamente, il pre-addestramento di questi modelli consiste nel corrompere una determinata frase (ad esempio, nascondendone casualmente alcune parole) e incaricare il modello di ritrovare o ricostruire la frase di partenza.

I modelli encoder sono particolarmente appropriati per compiti che richiedono la comprensione di frasi intere, quali la classificazione di frasi, riconoscimento delle entità nominate (e in senso più ampio, la classificazione di parole), e l'estrazione di risposte da un contesto.

Alcuni esempi di modelli di questo tipo includono:

- [ALBERT](https://huggingface.co/transformers/model_doc/albert.html)
- [BERT](https://huggingface.co/transformers/model_doc/bert.html)
- [DistilBERT](https://huggingface.co/transformers/model_doc/distilbert.html)
- [ELECTRA](https://huggingface.co/transformers/model_doc/electra.html)
- [RoBERTa](https://huggingface.co/transformers/model_doc/roberta.html)


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter1/5.mdx" />

### Introduzione
https://huggingface.co/learn/course/it/chapter1/1.md

# Introduzione

<CourseFloatingBanner
    chapter={1}
    classNames="absolute z-10 right-0 top-0"
/>

## Benvenuto/a al corso di 🤗!

<Youtube id="00GKzGyWFEs" />

Questo corso ti insegnerà a eseguire compiti di Natural Language Processing (NLP, *elaborazione del linguaggio naturale*) utilizzando le librerie dell'ecosistema di [Hugging Face](https://huggingface.co/): [🤗 Transformers](https://github.com/huggingface/transformers), [🤗 Datasets](https://github.com/huggingface/datasets), [🤗 Tokenizers](https://github.com/huggingface/tokenizers), e [🤗 Accelerate](https://github.com/huggingface/accelerate). Ti insegneremo anche ad usare il nostro [Hugging Face Hub](https://huggingface.co/models), che è completamente gratuito e senza pubblicità.


## Contenuti

Eccoti un breve riassunto dei contenuti del corso:

<div class="flex justify-center">
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/summary.svg" alt="Brief overview of the chapters of the course.">
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/summary-dark.svg" alt="Brief overview of the chapters of the course.">
</div>

- I capitoli da 1 a 4 forniscono un'introduzione ai concetti principali della libreria 🤗 Transformers. Alla fine di questa parte del corso, conoscerai come funzionano i modelli Transformers e saprai come utilizzare un modello dell'[Hugging Face Hub](https://huggingface.co/models), affinarlo in un dataset, e condividere i tuoi risultati nell'Hub!
- I capitoli da 5 a 8 insegnano le basi degli 🤗 Dataset e degli 🤗 Tokenizer, per poi esplorare alcuni compiti classici di NLP. Alla fine di questa parte, saprai far fronte ai problemi di NLP più comuni in maniera autonoma.
- I capitoli da 9 a 12 vanno oltre il Natural Language Processing, ed esplorano come i modelli Transformer possano essere utilizzati per affrontare compiti di elaborazione vocale o visione artificiale. Strada facendo, imparerai a costruire e condividere demo (*dimostrazioni*) dei tuoi modelli, e ad ottimizzarli per la produzione. Alla fine di questa parte, sarai pronto ad utilizzare gli 🤗 Transformer per qualsiasi problema di machine learning (*apprendimento automatico*), o quasi!

Questo corso:

* Richiede una buona conoscenza di Python
* Andrebbe seguito di preferenza a seguito di un corso introduttivo di deep learning (*apprendimento profondo*), come ad esempio il [Practical Deep Learning for Coders](https://course.fast.ai/) di [fast.ai](https://www.fast.ai/), oppure uno dei programmi sviluppati da [DeepLearning.AI](https://www.deeplearning.ai/)
* Non richiede conoscenze pregresse di [PyTorch](https://pytorch.org/) o [TensorFlow](https://www.tensorflow.org/), nonostante sia gradita una conoscenza anche superficiale dell'uno o dell'altro

Quando avrai completato questo corso, ti raccomandiamo di passare al [Natural Language Processing Specialization](https://www.coursera.org/specializations/natural-language-processing?utm_source=deeplearning-ai&utm_medium=institutions&utm_campaign=20211011-nlp-2-hugging_face-page-nlp-refresh) di DeepLearning.AI, un corso che copre un ampio spettro di modelli tradizionali di NLP che vale davvero la pena di conoscere, come Naive Bayes e LSTM (*Memoria a breve termine a lungo termine*)!

## Chi siamo?

A proposito degli autori:

**Matthew Carrigan** è Machine Learning Engineer da Hugging Face. Vive a Dublino, in Irlanda, ed in passato è stato ML engineer da Parse.ly, e prima ancora ricercatore postdottorale al Trinity College di Dublin. Nonostante non creda che otterremo l'Intelligenza artificiale forte semplicemente ingrandendo le architetture a nostra disposizione, spera comunque nell'immortalità cibernetica.

**Lysandre Debut** è Machine Learning Engineer da Hugging Face e ha lavorato agli 🤗 Transformer fin dalle primissime tappe del loro sviluppo. Il suo obiettivo è di rendere il NLP accessibile a tutti sviluppando strumenti con un semplice API.

**Sylvain Gugger** è Research Engineer da Hugging Face e uno dei principali manutentori della libreria 🤗 Transformers. In passato, è stato Research Scientist da fast.ai, e ha scritto [Deep Learning for Coders with fastai and PyTorch](https://learning.oreilly.com/library/view/deep-learning-for/9781492045519/) con Jeremy Howard. Il centro principale della sua ricerca consiste nel rendere il deep learning (*apprendimento profondo*) più accessibile, concependo e migliorando tecniche che permettano di allenare modelli velocemente con risorse limitate.

**Merve Noyan** è developer advocate da Hugging Face, e lavora allo sviluppo di strumenti e alla creazione di contenuti ad essi legati per democratizzare l'accesso al deep learning.

**Lucile Saulnier** è machine learning engineer da Hugging Face, e sviluppa e supporta l'utilizzo di strumenti open source. È anche attivamente coinvolta in numerosi progetti di ricerca nell'ambito del NLP, come ad esempio collaborative training e BigScience.

**Lewis Tunstall** è machine learning engineer da Hugging Face che si specializza nello sviluppo di strumenti open-source e la loro distribuzione alla comunità più ampia. È anche co-autore dell'imminente [O’Reilly book on Transformers](https://www.oreilly.com/library/view/natural-language-processing/9781098136789/).

**Leandro von Werra** è machine learning engineer nel team open-source di Hugging Face, nonché co-autore dell'imminente [O’Reilly book on Transformers](https://www.oreilly.com/library/view/natural-language-processing/9781098136789/). Ha tanti anni di esperienza nel portare progetti di NLP in produzione, lavorando a tutti i livelli di esecuzione di compiti di machine learning.

Sei pronto/a a iniziare? In questo capitolo, imparerai:
* Ad utilizzare la funzione `pipeline()` per eseguire compiti di NLP come la generazione e classificazione di testi
* L'architettura dei Transformer
* Come fare la distinzione tra architetture encoder, decoder, encoder-decoder, e casi d'uso


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter1/1.mdx" />

### Cosa fanno i Transformer?
https://huggingface.co/learn/course/it/chapter1/3.md

# Cosa fanno i Transformer?

<CourseFloatingBanner chapter={1}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/it/chapter1/section3.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/it/chapter1/section3.ipynb"},
]} />

In questa sezione, vedremo di cosa sono capaci i modelli Transformer e useremo il nostro primo strumento della libreria 🤗 Transformer: la funzione `pipeline()`.

<Tip>
👀 Lo vedi il pulsante <em>Open in Colab</em> in alto a destra? Cliccalo per aprire il blocco note Colab di Google che contiene tutti gli esempi di codice di questa sezione. Ritroverai il pulsante in ogni sezione che contiene esempi di codice. 

Se intendi compilare gli esempi localmente, ti consigliamo di dare un occhio alla sezione <a href="/course/chapter0">setup</a>.
</Tip>

## I Transformer sono ovunque!

I modelli Transformer sono utilizzati per eseguire qualsiasi compito di NLP, come ad esempio quelli menzionati nelle sezioni precedenti. Ecco alcune delle aziende e organizzazioni che utilizzano Hugging Face e i modelli Transformer, e contribuiscono a loro volta alla comunità condividendo i propri modelli:

<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/companies.PNG" alt="Companies using Hugging Face" width="100%">

La [libreria 🤗 Transformer](https://github.com/huggingface/transformers) fornisce la funzionalità per creare e utilizzare questi modelli condivisi. Il [Model Hub](https://huggingface.co/models) contiene migliaia di modelli pre-addestrati che possono essere scaricati e usati liberamente. Puoi anche caricare i tuoi modelli nell'Hub!

<Tip>
⚠️ L'Hugging Face Hub non si limitata ai soli modelli Transformer. Chiunque può condividere qualsiasi tipo di modello o dataset (<em>insieme di dati</em>)! <a href="https://huggingface.co/join">Crea un profilo huggingface.co</a> per approfittare di tutte le funzioni disponibili!
</Tip>

Prima di scoprire come funzionino i modelli Transformer dietro le quinte, vediamo qualche esempio di come questi possano essere utilizzati per risolvere alcuni problemi interessanti di NLP.

## Lavorare con le pipeline

<Youtube id="tiZFewofSLM" />

L'oggetto più basilare della libreria 🤗 Transformer è la funzione `pipeline()`. Questa connette un modello con tutte le fasi necessarie di preprocessing e postprocessing, permettendoci così di fornire un qualsiasi testo come input diretto e ottenere una risposta intelligibile:

```python
from transformers import pipeline

classifier = pipeline("sentiment-analysis")
classifier("I've been waiting for a HuggingFace course my whole life.")
```

```python out
[{'label': 'POSITIVE', 'score': 0.9598047137260437}]
```

È anche possibile lavorare su più frasi!

```python
classifier(
    ["I've been waiting for a HuggingFace course my whole life.", "I hate this so much!"]
)
```

```python out
[{'label': 'POSITIVE', 'score': 0.9598047137260437},
 {'label': 'NEGATIVE', 'score': 0.9994558095932007}]
```

Per default, questa pipeline seleziona un preciso modello pre-addestrato che è stato affinato per il sentiment analysis in inglese. Quando creiamo l'oggetto `classifier`, il modello viene scaricato e memorizzato nella cache. Se inizializziamo di nuovo il comando, verrà utilizzato il modello salvato nella cache e non ci sarà quindi bisogno di scaricare di nuovo il modello.

Tre passaggi principali sono coinvolti quando passiamo del testo in un pipeline:

1. Il testo è pre-elaborato in un formato che il modello può capire.
2. Gli input pre-elaborati vengono passati al modello.
3. Le previsioni del modello sono post-elaborate in un formato accessibile all'utilizzatore.


Tra le [pipeline disponibili](https://huggingface.co/transformers/main_classes/pipelines.html) al momento ci sono:

- `feature-extraction` (per ottenere la rappresentazione vettoriale di un testo)
- `fill-mask`
- `ner` (riconoscimento delle entità nominate, *named entity recognition*)
- `question-answering`
- `sentiment-analysis`
- `summarization`
- `text-generation`
- `translation`
- `zero-shot-classification`

Proviamo a vederne alcune!

## Classificazione zero-shot

Cominceremo con l'affrontare un compito impegnativo che consiste nella classificazione di testi non etichettati. Si tratta di uno scenario comune in molti progetti pratici perché l'annotazione testuale richiede tempo e competenza settoriale. In questo caso d'uso, la pipeline `zero-shot-classification` è molto potente e permette di specificare le etichette da utilizzare per la classificazione, in modo da non dover fare affidamento sulle etichette del modello pre-addestrato. Abbiamo già visto come il modello riesca a classificare una frase utilizzando le etichette 'positiva' e 'negativa', ma è anche possibile classificare testi utilizzando una qualsiasi serie di etichette di nostra scelta.

```python
from transformers import pipeline

classifier = pipeline("zero-shot-classification")
classifier(
    "This is a course about the Transformers library",
    candidate_labels=["education", "politics", "business"],
)
```

```python out
{'sequence': 'This is a course about the Transformers library',
 'labels': ['education', 'business', 'politics'],
 'scores': [0.8445963859558105, 0.111976258456707, 0.043427448719739914]}
```

Questa pipeline si chiama _zero-shot_ perché non hai bisogno di affinare il modello usando i tuoi dati per poterlo utilizzare. È direttamente in grado di generare una previsione probabilistica per qualsiasi lista di etichette tu voglia!

<Tip>

✏️ **Provaci anche tu!** Divertiti creando sequenze ed etichette e osserva come si comporta il modello.

</Tip>


## Generazione di testi

Vediamo ora come utilizzare la pipeline per generare testi. L'idea è di fornire un prompt (*richiesta*) che verrà auto-completato dal modello, il quale genererà il testo mancante. Si tratta di un compito simile alla funzione di scrittura facilitata che troviamo al giorno d'oggi in molti cellulari. La generazione di testi presenta una componente arbitraria, per cui non essere sorpreso/a se non ottieni gli stessi risultati che mostriamo qui sotto.

```python
from transformers import pipeline

generator = pipeline("text-generation")
generator("In this course, we will teach you how to")
```

```python out
[{'generated_text': 'In this course, we will teach you how to understand and use '
                    'data flow and data interchange when handling user data. We '
                    'will be working with one or more of the most commonly used '
                    'data flows — data flows of various types, as seen by the '
                    'HTTP'}]
```

Usando l'argomento `num_return_sequences` puoi controllare quante sequenze diverse vengono generate e, con l'argomento `max_length`, la lunghezza totale dell'output testuale.

<Tip>

✏️ **Provaci anche tu!** Usa gli argomenti `num_return_sequences` e `max_length` per generare due frasi di 15 parole ciascuna.

</Tip>


## Utilizzo di un qualsiasi modello dell'Hub in una pipeline

Gli esempi precedenti utilizzavano il modello di default per il compito dato, ma puoi anche scegliere un modello particolare dell'Hub da utilizzare in una pipeline per un compito specifico, come ad esempio la generazione testuale. Vai al [Model Hub](https://huggingface.co/models) e clicca sull'etichetta corrispondente a destra, in modo da mostrare solo i modelli supportati per il compito in questione. Dovresti ritrovarti in una pagina come [questa](https://huggingface.co/models?pipeline_tag=text-generation).

Proviamo il modello [`distilgpt2`](https://huggingface.co/distilgpt2)! Ecco come caricarlo nella pipeline usata in precedenza:

```python
from transformers import pipeline

generator = pipeline("text-generation", model="distilgpt2")
generator(
    "In this course, we will teach you how to",
    max_length=30,
    num_return_sequences=2,
)
```

```python out
[{'generated_text': 'In this course, we will teach you how to manipulate the world and '
                    'move your mental and physical capabilities to your advantage.'},
 {'generated_text': 'In this course, we will teach you how to become an expert and '
                    'practice realtime, and with a hands on experience on both real '
                    'time and real'}]
```

Puoi affinare la ricerca di un modello cliccando sulle etichette corrispondenti alle lingue, e scegliere in seguito un modello che generi testo in un'altra lingua. Il Model Hub contiene anche checkpoint per modelli multilingue che supportano numerose lingue.

Quando avrai selezionato un modello cliccando su di esso, vedrai che esiste un widget che ti permette di provarlo direttamente online. In questo modo, puoi testare velocemente le capacità del modello prima di scaricarlo.

<Tip>

✏️ **Provaci anche tu!** Usa i filtri per trovare un modello di generazione testuale per un'altra lingua. Sentiti libero/a di divertirti con il widget e usalo in una pipeline!

</Tip>

### La Inference API

Tutti i modelli possono essere testati direttamente attraverso il tuo browser utilizzando l'Inference API che trovi nel [sito](https://huggingface.co/) di Hugging Face. Puoi divertirti con il modello direttamente in questa pagina, inserendo testo personalizzato e osservando come il modello processi i dati fornitigli.

La Inference API che alimenta il widget è disponibile anche come prodotto a pagamento, il che è comodo se ne hai bisogno per i tuoi flussi di lavoro. Vedi la [pagina dei prezzi](https://huggingface.co/pricing) per maggiori informazioni.

## Mask filling

La prossima pipeline che proverai è `fill-mask`. L'idea di questo compito è di completare gli spazi bianchi in un dato testo:

```python
from transformers import pipeline

unmasker = pipeline("fill-mask")
unmasker("This course will teach you all about <mask> models.", top_k=2)
```

```python out
[{'sequence': 'This course will teach you all about mathematical models.',
  'score': 0.19619831442832947,
  'token': 30412,
  'token_str': ' mathematical'},
 {'sequence': 'This course will teach you all about computational models.',
  'score': 0.04052725434303284,
  'token': 38163,
  'token_str': ' computational'}]
```

L'argomento `top_k` gestisce il numero di possibilità che vuoi mostrare. Nota che qui il modello inserisce la `<mask>` word speciale, la quale viene spesso chiamata *mask token*. Altri modelli di tipo mask-filling potrebbero avere mask token diversi, quindi è sempre bene verificare quale sia la corretta mask word quando esploriamo nuovi modelli. Un modo per verificarla consiste nel trovare la mask word utilizzata nel widget.

<Tip>

✏️ **Provaci anche tu!** Cerca il modello `bert-base-cased` nell'Hub e identifica la sua mask word nel widget dell'Inference API. Cosa predice questo modello per la frase nel nostro esempio `pipeline` qui sopra?

</Tip>

## Riconoscimento delle entità nominate

Il riconoscimento delle entità nominate (*Named entity recognition*, NER) è un compito in cui il modello deve determinare quali parti dell'input testuale corrispondono a entità quali persone, località, o organizzazioni. Guardiamo a un esempio:

```python
from transformers import pipeline

ner = pipeline("ner", grouped_entities=True)
ner("My name is Sylvain and I work at Hugging Face in Brooklyn.")
```

```python out
[{'entity_group': 'PER', 'score': 0.99816, 'word': 'Sylvain', 'start': 11, 'end': 18}, 
 {'entity_group': 'ORG', 'score': 0.97960, 'word': 'Hugging Face', 'start': 33, 'end': 45}, 
 {'entity_group': 'LOC', 'score': 0.99321, 'word': 'Brooklyn', 'start': 49, 'end': 57}
]
```

Qui il modello ha correttamente identificato che Sylvain è una persona (PER), Hugging Face un'organizzazione (ORG), e Brooklyn una località (LOC).

Passiamo l'opzione `grouped_entities=True` nella funzione di creazione della pipeline per raggruppare le parti frasali che corrispondono alla stessa entità: qui il modello raggruppa correttamente "Hugging" e "Face" come singola organizzazione, nonostante il nome sia formato da più parole. A dire il vero, come vedremo nel prossimo capitolo, il preprocessing divide perfino alcune parole in parti più piccole. Ad esempio, `Sylvain` viene suddiviso in quattro parti: `S`, `##yl`, `##va`, and `##in`. Al momento del post-processing, la pipeline raggruppa le parti con successo.

<Tip>

✏️ **Provaci anche tu!** Nel Model Hub, cerca un modello capace di effettuare part-of-speech tagging (comunemente abbreviato come POS) in inglese. Cosa predice il modello per la frase nell'esempio qui sopra?

</Tip>

## Risposta a domande

La pipeline `question-answering` risponde a domande utilizzando informazioni da un contesto prestabilito:

```python
from transformers import pipeline

question_answerer = pipeline("question-answering")
question_answerer(
    question="Where do I work?",
    context="My name is Sylvain and I work at Hugging Face in Brooklyn",
)
```

```python out
{'score': 0.6385916471481323, 'start': 33, 'end': 45, 'answer': 'Hugging Face'}
```

Nota che questa pipeline non genera risposte ma estrae informazioni da un contesto fornito.

## Riassunto

Quello del riassunto è un compito che trasforma un testo in un testo più breve, conservando tutti (o quasi) gli argomenti più importanti del testo di partenza. Ecco un esempio:

```python
from transformers import pipeline

summarizer = pipeline("summarization")
summarizer(
    """
    America has changed dramatically during recent years. Not only has the number of 
    graduates in traditional engineering disciplines such as mechanical, civil, 
    electrical, chemical, and aeronautical engineering declined, but in most of 
    the premier American universities engineering curricula now concentrate on 
    and encourage largely the study of engineering science. As a result, there 
    are declining offerings in engineering subjects dealing with infrastructure, 
    the environment, and related issues, and greater concentration on high 
    technology subjects, largely supporting increasingly complex scientific 
    developments. While the latter is important, it should not be at the expense 
    of more traditional engineering.

    Rapidly developing economies such as China and India, as well as other 
    industrial countries in Europe and Asia, continue to encourage and advance 
    the teaching of engineering. Both China and India, respectively, graduate 
    six and eight times as many traditional engineers as does the United States. 
    Other industrial countries at minimum maintain their output, while America 
    suffers an increasingly serious decline in the number of engineering graduates 
    and a lack of well-educated engineers.
"""
)
```

```python out
[{'summary_text': ' America has changed dramatically during recent years . The '
                  'number of engineering graduates in the U.S. has declined in '
                  'traditional engineering disciplines such as mechanical, civil '
                  ', electrical, chemical, and aeronautical engineering . Rapidly '
                  'developing economies such as China and India, as well as other '
                  'industrial countries in Europe and Asia, continue to encourage '
                  'and advance engineering .'}]
```

Come nella generazione di testi, puoi specificare un `max_length` o `min_length` per il testo da generare.


## Traduzione

Per compiti di traduzione, puoi utilizzare un modello di default indicando la coppia linguistica nel nome del compito (come ad esempio `"translation_en_to_fr"`), anche se il metodo più semplice è di scegliere il modello che desideri utilizzare dal [Model Hub](https://huggingface.co/models). Qui in seguito traduciamo dal francese all'inglese:

```python
from transformers import pipeline

translator = pipeline("translation", model="Helsinki-NLP/opus-mt-fr-en")
translator("Ce cours est produit par Hugging Face.")
```

```python out
[{'translation_text': 'This course is produced by Hugging Face.'}]
```

Come per le funzioni di generazione testuale e riassunto, è possibile specificare un `max_length` o un `min_length` per il risultato.

<Tip>

✏️ **Provaci anche tu!** Cerca modelli di traduzione in altre lingue e prova a tradurre la frase precedente in un paio di lingue diverse.

</Tip>

Finora abbiamo mostrato pipeline a solo scopo dimostrativo. Tali pipeline sono state programmate per compiti ben specifici e non sono in grado di eseguire variazioni di questi ultimi. Nel prossimo capitolo, imparerai cosa si nasconde dentro la funzione `pipeline()` e come personalizzarne il comportamento.


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter1/3.mdx" />

### Modelli decoder
https://huggingface.co/learn/course/it/chapter1/6.md

# Modelli decoder

<CourseFloatingBanner
    chapter={1}
    classNames="absolute z-10 right-0 top-0"
/>

<Youtube id="d_ixlCubqQw" />

I modelli decoder utilizzano solo il decoder di un modello Transformer. Ad ogni passaggio e per una data parola, gli attention layer hanno accesso solo alle parole che la precedono nella frase. Questi modelli sono spesso detti *auto-regressive models*.

Il pre-addestramento dei modelli decoder ha spesso a che fare con la previsione della parola successiva in un contesto frasale.

Questi modelli sono particolarmente adatti a compiti di generazione testuale.

Alcuni rappresentanti di questa famiglia includono:

- [CTRL](https://huggingface.co/transformers/model_doc/ctrl.html)
- [GPT](https://huggingface.co/docs/transformers/model_doc/openai-gpt)
- [GPT-2](https://huggingface.co/transformers/model_doc/gpt2.html)
- [Transformer XL](https://huggingface.co/transformers/model_doc/transfo-xl.html)


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter1/6.mdx" />

### Quiz di fine capitolo
https://huggingface.co/learn/course/it/chapter1/10.md

# Quiz di fine capitolo

<CourseFloatingBanner
    chapter={1}
    classNames="absolute z-10 right-0 top-0"
/>


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?


<Question
	choices={[
		{
			text: "Riassunto testuale",
			explain: "Rivisita il link e prova di nuovo: <a href=\"https://huggingface.co/roberta-large-mnli\">roberta-large-mnli page</a>."
		},
		{
			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 <em>natural language inference</em>.",
			correct: true
		},
		{
			text: "Generazione testuale",
			explain: "Rivisita il link e prova di nuovo: <a href=\"https://huggingface.co/roberta-large-mnli\">roberta-large-mnli page</a>."
		}
	]}
/>

### 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.")
```

<Question
	choices={[
		{
			text: "Restituisce un punteggio associato alla frase, con etichette del tipo \"positive\" o \"negative\".",
			explain: "Sbagliato! Se così fosse, si tratterebbe di una pipeline di tipo <code>sentiment-analysis</code>."
		},
		{
			text: "Genera e restituisce testo che completa la frase di partenza.",
			explain: "Sbagliato! Se così fosse, si tratterebbe di una pipeline di tipo <code>text-generation</code>.",
		},
		{
			text: "Restituisce i termini che rappresentano persone, organizzazioni o luoghi.",
			explain: "Inoltre, grazie a <code>grouped_entities=True</code>, 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("...")
```

<Question
	choices={[
		{
			text: "Questo &#60;mask> aspetta te.",
			explain: "Sbagliato. Controlla la card del modello <code>bert-base-cased</code> 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")
```

<Question
	choices={[
		{
			text: "Questa pipeline richiede che le etichette siano fornite per poter classificare il testo.",
			explain: "Esatto! Per essere corretto, il codice deve includere <code>candidate_labels=[...]</code>.",
			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"?

<Question
	choices={[
		{
			text: "Trasferire la conoscenza di un modello pre-addestrato a un nuovo modello, addestrando quest'ultimo sulla stessa banca dati.",
			explain: "No, in quel caso avremmo a che fare con due versioni dello stesso modello."
		},
		{
			text: "Trasferire la conoscenza di un modello pre-addestrato a un nuovo modello addestrando il secondo con i pesi del primo.",
			explain: "Corretto. Quando il secondo modello viene addestrato ad un nuovo compito, *trasferisce* la conoscenza del primo modello.",
			correct: true
		},
		{
			text: "Trasferire la conoscenza di un modello pre-addestrato a un nuovo modello costruendo il secondo con la stessa architettura del primo.",
			explain: "L'architettuta è semplicemente il modo in cui il modello è costruito. In questo caso, la conoscenza non è né condivisa né trasmessa."
		}
	]}
/>

### 6. Vero o falso? Solitamente un modello linguistico non richiede etichette in fase di pre-addestramento.


<Question
	choices={[
		{
			text: "Vero",
			explain: "Solitamente, il pre-addestramento è <em>self-supervised</em>, 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."

<Question
	choices={[
		{
			text: "Se un modello fosse un palazzo, l'architettura ne sarebbe il progetto e i pesi le persone che ci vivono.",
			explain: "In un caso del genere, i pesi sarebbero piuttosto i mattoni e i materiali utilizzati per costruire il palazzo."
		},
		{
			text: "L'architettura è una cartina per costruire un dato modello, i cui pesi sono le città rappresentate sulla mappa.",
			explain: "Il problema di questa metafora è che, solitamente, una cartina rappresenta un'unica realtà (c'è una sola città in Francia di nome Parigi). Per una data architettura, possono esistere numerosi pesi."
		},
		{
			text: "Un'architettura è una successione di funzioni matematiche usate per costruire un modello; i suoi pesi sono i parametri delle funzioni.",
			explain: "Lo stesso insieme di funzioni matematiche (architettura) può essere utilizzato per costruire modelli diversi utilizzando parametri diversi (pesi).",
			correct: true
		}
	]}
/>


### 8. Quale dei seguenti modelli utilizzeresti per completare dei prompt con testo generato?

<Question
	choices={[
		{
			text: "Un modello encoder",
			explain: "Un modello encoder genera una rappresentazione della frase intera che è più adatta a compiti come la classificazione."
		},
		{
			text: "Un modello decoder",
			explain: "I modelli decoder sono perfetti per generare testo a partire da un prompt.",
			correct: true
		},
		{
			text: "Un modello sequence-to-sequence",
			explain: "I modelli sequence-to-sequence sono più adatti a compiti di generazione di frasi a partire da frasi input, non da un prompt."
		}
	]}
/>

### 9. Quale dei seguenti modelli utilizzeresti per riassumere testi?

<Question
	choices={[
		{
			text: "Un modello encoder",
			explain: "Un modello encoder genera una rappresentazione della frase intera che è più adatta a compiti come la classificazione."
		},
		{
			text: "Un modello decoder",
			explain: "I modelli decoder sono capaci di generare un testo di output (come un riassunto), ma non sono in grado di estrarre conoscenze da un contesto, come ad esempio da un testo da riassumere."
		},
		{
			text: "Un modello sequence-to-sequence",
			explain: "I modelli sequence-to-sequence sono perfetti per compiti di riassunto.",
			correct: true
		}
	]}
/>

### 10. Quale dei seguenti modelli utilizzeresti per classificare input testuali sulla base di determinate etichette?

<Question
	choices={[
		{
			text: "Un modello encoder",
			explain: "Un modello encoder genera una rappresentazione della frase intera che è più adatta a compiti come la classificazione.",
			correct: true
		},
		{
			text: "Un modello decoder",
			explain: "I modelli decoder sono capaci di generare un testo di output, non di estrarre etichette da frasi."
		},
		{
			text: "Un modello sequence-to-sequence",
			explain: "I modelli sequence-to-sequence sono più adatti a compiti in cui si genera testo sulla base di una frase input, non di un'etichetta.",
		}
	]}
/>

### 11. Qual è la possibile origine di un bias osservato in un modello?

<Question
	choices={[
		{
			text: "Il modello è una versione affinata di un modello pre-addestrato, dal quale eredita il bias.",
			explain: "Nel Transfer Learning, i bias di un modello pre-addestrato si osservano anche nel modello affinato.",
			correct: true
		},
		{
			text: "I dati sui quali il modello è stato addetsrato contengono errori.",
			explain: "Questa è la fonte di errori più comune, ma non la sola.",
			correct: true
		},
		{
			text: "La misura ottimizzata dal modello è errata.",
			explain: "Il modo in cui il modello viene addestrato è una causa di errori meno ovvia. Un modello ottimizza ciecamente qualsiasi metrica tu scelga, senza ripensamenti.",
			correct: true
		}
	]}
/>


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter1/10.mdx" />

### Bias e limiti
https://huggingface.co/learn/course/it/chapter1/8.md

# Bias e limiti

<CourseFloatingBanner chapter={1}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/it/chapter1/section8.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/it/chapter1/section8.ipynb"},
]} />

Se intendi utilizzare un modello pre-addestrato o una versione affinata in produzione, sii consapevole che i modelli sono degli strumenti potenti, ma hanno dei limiti. Il più grande limite è che, per permettere un pre-addestramento su una quantità importante di dati, i ricercatori spesso includono tutti i contenuti ai quali riescono ad accedere, prendendo nel contempo il meglio e il peggio di ciò che Intenet offre. 

Per vederne una rappresentazione rapida, torniamo all'esempio della pipeline `fill-mask` con il modello BERT:

```python
from transformers import pipeline

unmasker = pipeline("fill-mask", model="bert-base-uncased")
result = unmasker("This man works as a [MASK].")
print([r["token_str"] for r in result])

result = unmasker("This woman works as a [MASK].")
print([r["token_str"] for r in result])
```

```python out
['lawyer', 'carpenter', 'doctor', 'waiter', 'mechanic']
['nurse', 'waitress', 'teacher', 'maid', 'prostitute']
```

Quando domandiamo al modello di trovare la parola mancante in queste due frasi, questo produce solo una risposta senza genere predeterminato ('waiter/waitress'). Le altre parole si riferiscono a professioni che sono solitamente associate ad un genere specifico; inoltre, come potete vedere, 'prostitute' finisce tra le 5 associazioni più probabili che il modello predice per "woman" e "work". Ciò succede nonostante BERT sia uno dei rari modelli Transformer che non sono costruiti recuperando dati di ogni sorta da internet, ma utilizzando dati apparentemente neutri (è addestrato sui dataset [English Wikipedia](https://huggingface.co/datasets/wikipedia) e [BookCorpus](https://huggingface.co/datasets/bookcorpus)). 

Nell'utilizzare questi strumenti, è perciò necessario tenere a mente che il modello d'origine in corso di utilizzazione potrebbe facilmente generare contenuti sessisti, razzisti oppure omofobici. Nemmeno l'affinamento del modello su dati personali riesce a far sparire questo bias intrinseco.


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter1/8.mdx" />

### Come funzionano i Transformer?
https://huggingface.co/learn/course/it/chapter1/4.md

# Come funzionano i Transformer?

<CourseFloatingBanner
    chapter={1}
    classNames="absolute z-10 right-0 top-0"
/>

In questa sezione, vedremo in maniera approfondita l'architettura dei modelli Transformer.

## Un po' di storia dei Transformer

Ecco alcuni punti di riferimento nella (breve) storia dei modelli Transformer:

<div class="flex justify-center">
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/transformers_chrono.svg" alt="A brief chronology of Transformers models.">
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/transformers_chrono-dark.svg" alt="A brief chronology of Transformers models.">
</div>

L'[architettura Transformer](https://arxiv.org/abs/1706.03762) è stata introdotta in giugno 2017. Il focus della ricerca di partenza era sui compiti di traduzione. A questa seguì l'introduzione di numerosi modelli influenti, tra cui figurano:

- **giugno 2018**: [GPT](https://cdn.openai.com/research-covers/language-unsupervised/language_understanding_paper.pdf), il primo modello Transformer pre-addestrato, viene usato per affinare diversi compiti di NLP e ottiene risultati all'avanguardia

- **ottobre 2018**: [BERT](https://arxiv.org/abs/1810.04805), un altro ampio modello pre-addestrato, questa volta progettato per produrre riassunti di frasi migliori (ne scopriremo di più nel prossimo capitolo!)

- **febbraio 2019**: [GPT-2](https://cdn.openai.com/better-language-models/language_models_are_unsupervised_multitask_learners.pdf), una versione (migliorata e ingrandita) di GPT che non fu distribuita immediatamente al pubblico a causa di preoccupazioni etiche

- **ottobre 2019**: [DistilBERT](https://arxiv.org/abs/1910.01108), una versione distillata di BERT che è il 60% più rapida e il 40% più leggera in memoria, pur conservando il 97% della performance di BERT

- **ottobre 2019**: [BART](https://arxiv.org/abs/1910.13461) e [T5](https://arxiv.org/abs/1910.10683), due grossi modelli pre-addestrati che utilizzano la stessa architettura del modello Transformer originale (nonché i primi a farlo)

- **maggio 2020**, [GPT-3](https://arxiv.org/abs/2005.14165), una versione ancora più ampia di GPT-2, con buone prestazioni in vari compiti e nessun bisogno di fine-tuning (il cosiddetto _zero-shot learning_)

La lista è tutto fuorché esaustiva ed è volta solo a mettere in evidenza alcuni dei diversi tipi di modelli Transformer. In genere, questi possono essere raggruppati in tre categorie:

- Modelli in stile GPT (detti anche modelli Transformer _auto-regressive_)
- Modelli in stile BERT (detti anche modelli Transformer _auto-encoding_) 
- Modelli in stile BART/T5 (detti anche modelli Transformer _sequence-to-sequence_)

Studieremo queste famiglie più nel dettaglio in seguito.

## I Transformer sono modelli linguistici

Tutti i modelli Transformer menzionati qui sopra (GPT, BERT, BART, T5, ecc.) sono stati addestrati come modelli linguistici (*language models*). Ciò significa che sono stati addestrati su grandi quantità di testo grezzo in stile auto-supervisionato (*self-supervising*). L'apprendimento auto-supervisionato è un tipo di apprendimento il cui obbiettivo viene computato direttamente dagli input del modello. Ciò significa che non è richiesto alcun intervento umano per etichettare i dati!

Un modello di questo tipo sviluppa una comprensione statistica della lingua alla quale è stato addestrato, ma non è molto utile in compiti pratici e precisi. Per questa ragione, il modello pre-addestrato generale viene in seguito sottoposto a un processo detto *transfer learning*. Durante questo processo, il modello viene affinato per un determinato compito in maniera supervisionata (ossia utilizzando etichette generate da umani).

Un esempio di compito è la previsione della parola seguente in una frase di cui sono state lette *n* parole precedenti. Quest'operazione si chiama *causal language modeling* perché il suo output dipende dagli input presenti e passati, ma non da quelli futuri.

<div class="flex justify-center">
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/causal_modeling.svg" alt="Example of causal language modeling in which the next word from a sentence is predicted.">
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/causal_modeling-dark.svg" alt="Example of causal language modeling in which the next word from a sentence is predicted.">
</div>

Un altro esempio è il *masked language modeling*, in cui il modello prevede una parola occultata della frase.

<div class="flex justify-center">
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/masked_modeling.svg" alt="Example of masked language modeling in which a masked word from a sentence is predicted.">
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/masked_modeling-dark.svg" alt="Example of masked language modeling in which a masked word from a sentence is predicted.">
</div>

## I Transformers sono modelli enormi

A parte per alcune eccezioni (come DistilBERT), la strategia generale per ottenere performance migliori consiste nell'aumentare la taglia dei modelli, nonché la quantità di dati utilizzati per il pre-addestramento.

<div class="flex justify-center">
<img src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/model_parameters.png" alt="Number of parameters of recent Transformers models" width="90%">
</div>

Sfortunatamente, l'addestramento di un modello, e specialmente di un modello grosso, richiede grandi quantità di dati. Ciò si rivela molto costoso in termini di tempo, risorse informatiche e impatto ambientale, come mostrano i grafici qui sotto.

<div class="flex justify-center">
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/carbon_footprint.svg" alt="The carbon footprint of a large language model.">
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/carbon_footprint-dark.svg" alt="The carbon footprint of a large language model.">
</div>

<Youtube id="ftWlj4FBHTg"/>

Questi dati si riferiscono a un progetto per un modello (molto grande) condotto da un team che provava consciamente a ridurre l'impatto ambientale del pre-addestramento. L'impronta di trials volti a ottenere i miglior iperparamenti possibili sarebbe ancora più importante.

Immagina cosa succederebbe se ogni volta che un gruppo di ricerca, un'organizzazione studentesca o un'azienda vuole addestrare un modello lo facesse da zero! I costi globali sarebbero inutilmente enormi!

Questo è il motivo per cui la condivisione di modelli linguistici è fondamentale: lavorare a partire da modelli già addestrati riduce i costi informatici complessivi e l'impatto ambientale della comunità.


## Transfer Learning

<Youtube id="BqqfQnyjmgg" />

Il pre-addestramento è l'atto di addestrare un modello da zero: i pesi sono inizializzati in maniera casuale, e l'addestramento inizia senza alcuna conoscenza pregressa.

<div class="flex justify-center">
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/pretraining.svg" alt="The pretraining of a language model is costly in both time and money.">
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/pretraining-dark.svg" alt="The pretraining of a language model is costly in both time and money.">
</div>

Questo pre-addestramento è solitamente fatto su enormi quantità di dati. Di conseguenza, l'addestramento richiede un corpus di dati molto ampio e può prendere diverse settimane.

L'affinamento (*fine-tuning*), al contrario, è un addestramento che ha luogo **dopo** che il modello è stato pre-addestrato. Per poter effettuare un fine-tuning, è necessario acquisire un modello linguistico pre-addestrato e addestrarlo ulteriormente con una base dati adatta al compito in questione. Ma perché non addestrare direttamente al compito finale? Esistono alcune ragioni:

*  Il modello pre-addestrato è già addestrato su basi dati che contengono similarità con la base dati usata per il fine-tuning. Il processo di fine-tuning riesce quindi ad beneficiare della conoscenza acquisita dal modello iniziale durante il pre-addestramento (ad esempio, nei problemi di NLP, il modello pre-addestrato avrà già conoscenze statistiche della lingua utilizzata nel compito).
*  Siccome il modello pre-addestrato è stato addestrato usando moltissimi dati, il fine-tuning richiede molto meno dati per ottenere buoni risultati.
*  Per la stessa ragione, occorrono molto meno tempo e risorse per ottenere buoni risultati.

Ad esempio, è possibile approfittare di un modello pre-addestrato per la lingua inglese e poi affinarlo usando un corpus arXiv, ottenendo così un modello specifico per la scienza/ricerca. L'affinamento non richiederà che una quantità limitata di dati: le conoscenze acquisite dal modello pre-addestrato sono "trasferite", come riflette il nome *transfer learning*.

<div class="flex justify-center">
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/finetuning.svg" alt="The fine-tuning of a language model is cheaper than pretraining in both time and money.">
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/finetuning-dark.svg" alt="The fine-tuning of a language model is cheaper than pretraining in both time and money.">
</div>

Il fine-tuning di un modello ha quindi costi ridotti in termini di dati, finanze e impatto ambientale. Iterare su diversi schemi di fine-tuning è anche più rapido e semplice, in quanto l'addestramento è meno restrittivo di un pre-addestramento completo.

Questo processo permette anche di ottenere risultati migliori di un addestramento da zero (a meno di non essere in possesso di moltissimi dati), motivo per cui bisognerebbe sempre partire da un modello pre-addestrato (quanto possibile compatibile con il compito da eseguire) e affinarlo.

## Architettura generale

In questa sezione, vedremo l'architettura generale del modello Transformer. Non preoccuparti se non capisci tutti i concetti: più avanti, troverai sezioni dettagliate per ogni componente.

<Youtube id="H39Z_720T5s" />

## Introduzione

Il modello si compone principalmente di due blocchi:

* **Encoder (sinistra)**: L'encoder riceve un input e ne costruisce una rappresentazione, le features. Ciò significa che il modello è ottimizzato per la comprensione dell'input.
* **Decoder (destra)**: Il decoder utilizza la rappresentazione dell'encoder (le features) assieme ad ulteriori input per generare la sequenza target. Ciò significa che il modello è ottimizzato per la generazione di output.

<div class="flex justify-center">
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/transformers_blocks.svg" alt="Architecture of a Transformers models">
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/transformers_blocks-dark.svg" alt="Architecture of a Transformers models">
</div>

Ognuna di queste parti può essere utilizzata indipendentemente, in base al compito: 

* **Modelli Encoder-only**: Ottimi per compiti che richiedono una comprensione dell'input, come la classificazione frasale e il riconoscimento delle entità nominate.
* **Modelli Decoder-only**: Ottimi per compiti generativi come la generazione testuale.
* **Modelli Encoder-decoder** o **modelli sequence-to-sequence**: Ottimi per compiti generativi che richiedono un input, come la traduzione o il riassunto.

Analizzeremo ciascuna di queste architetture indipendentemente più tardi nel corso.

## Attention layers

Una caratteristica chiave dei modelli Transformer è che sono basati su strati speciali detti *attention layers*. Non a caso, il titolo del paper che introdusse l'architettura Transformer era ["Attention Is All You Need"](https://arxiv.org/abs/1706.03762)! Esploreremo gli attention layer nel dettaglio più avanti in questo corso; per ora, tutto ciò che hai bisogno di sapere è che un layer dirà al modello di prestare particolare attenzione a certe parole nella frase input (ignorando praticamente le altre) quando si occupa della rappresentazione delle singole parole.

Come esempio concreto, pensa ad un compito di traduzione testuale dall'inglese al francese. Dato l'input "You like this course", un modello di traduzione dovrà fare riferimento alla parola adiacente "You" per fornire la traduzione corretta della parola "like", perché in francese la coniugazione del verbo "like" cambia in base al soggetto. Diversamente, il resto della frase non è utile alla sua traduzione di quella precisa parola. In maniera simile, durante la traduzione di "this" il modello dovrà prestare attenzione alla parola "course", in quanto "this" ha traduzioni diverse se associato con nomi femminili o maschili. Di nuovo, il resto delle parole della frase non contribuiscono alla corretta traduzione di "this". Con frasi più complesse (e regole grammaticali più complesse), il modello potrebbe aver bisogno di prestare particolare attenzione a parole ben più lontane nella frase per tradurre correttamente ogni parola.

Lo stesso concetto si applica a qualsiasi compito che ha a che fare con il linguaggio naturale: una parola ha un senso a sé stante, ma tale senso è profondamente influenzato dal contesto, il quale è costituito da una qualsiasi parola (o parole) che precede o segue la parola sotto osservazione.

Ora che sai cosa sono gli attention layer, guardiamo un po' più nel dettaglio all'architettura Transformer.

## L'architettura originale

All'origine, l'architettura Transformer fu creata per la traduzione. In fase di addestramento, l'encoder riceve degli input (frasi) in una certa lingua, mentre il decoder riceve le stesse frasi nella lingua target d'elezione. Nell'encoder, gli attention layer sono in grado di utilizzare qualsiasi parola in una data frase (dato che, come abbiamo appena visto, la traduzione di una determinata parola può dipendere da ciò che la precede o segue nella frase). Diversamente, decoder procede in maniera sequenziale ed è capace di prestare attenzione solo alle parole della frase che ha già tradotto (ossia, solo le parole che precedono la parola che sta generando). Ad esempio, una volta predette le prime tre parole della frase target, le passiamo al decoder  che utilizza tutti gli input dell'encoder per provare a predirre la quarta parola.

Per accelerare il processo di addestramento (quando il modello ha accesso alle frasi target), l'intero target viene fornito al decoder, che però non è in grado di accedere alle parole future (se avesse accesso alla parola in seconda posizione mentre cerca di predirre la parola in seconda posizione, il problema cesserebbe di essere complesso). Ad esempio, mentre prova a predirre la quarta parola, l'attention layer avrà accesso solo alle posizioni tra la prima e la terza.

L'architettura Transformer originale aveva la struttura qui sotto, con l'encoder a sinistra e il decoder a destra:

<div class="flex justify-center">
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/transformers.svg" alt="Architecture of a Transformers models">
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/transformers-dark.svg" alt="Architecture of a Transformers models">
</div>

Nota che il primo attention layer in un *decoder block* presta attenzione a tutti gli input (passati) al decoder, mentre il secondo attention layer utilizza l'output del encoder. Gli è perciò possibile avere accesso a tutta la frase input per meglio prevedere la parola corrente. Questa caratteristica è molto utile in quanto lingue diverse possono avere regole grammaticali diverse piazzano le parole in ordini diversi, oppure perché il contesto che compare più tardi nella frase potrebbe essere utile nella determinazione della migliore traduzione di una data parola.

L'*attention mask* può essere utilizzato anche nell'encoder/decoder per evitare che il modello presti attenzione a certe parole speciali, come ad esempio parole riempitive utilizzate per rendere tutti gli input della stessa lunghezza.

##  Architetture vs. checkpoint

Durante questo viaggio nel mondo dei modelli Transformer, incontrerai menzioni di *architetture* e *checkpoint*, nonché di *modelli*. Questi termini hanno significati leggermente diversi: 

* **Architettura**: Lo scheletro del modello, ossia la definizione di ogni livello e operazione che compare nel modello. 
* **Checkpoint**: I pesi che verranno caricati in una determinata architettura.
* **Modello**: Un termine generico meno preciso di "architettura" o "checkpoint", in quanto può significare entrambi. In questo corso faremo la distinzione tra *architettura* e *checkpoint* quando sarà necessario ridurre le ambiguità.

Ad esempio, BERT è un'architettura, mentre `bert-base-cased`, un set di pesi (*weights*) addestrati dal team di Google per la prima versione di BERT, è un checkpoint. Ciononostante, è possibile dire "il modello BERT" e "il modello `bert-base-cased`."


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter1/4.mdx" />

### Modelli sequence-to-sequence
https://huggingface.co/learn/course/it/chapter1/7.md

# Modelli sequence-to-sequence

<CourseFloatingBanner
    chapter={1}
    classNames="absolute z-10 right-0 top-0"
/>

<Youtube id="0_4KEb08xrE" />

I modelli encoder-decoder (detti anche modelli *sequence-to-sequence*) utilizzano entrambi i componenti dell'architettura Transformer. Ad ogni passaggio, gli attention layer dell'encoder hanno accesso a tutte le parole della frase iniziale, mentre gli attention layer del decoder possono solo accedere alle parole che precedono linearmente una data parola nell'input.

Il pre-addestramento di questi modelli può essere fatto utilizzando gli obiettivi dei modelli encoder o decoder, anche se solitamente include un livello di complessità maggiore. Ad esempio, [T5](https://huggingface.co/t5-base) è pre-addestrato rimpiazzando porzioni random di testo (che possono contenere più di una parola) con una speciale mask word, con l'obiettivo di predirre il testo rimpiazzato dalla mask word stessa.

I modelli sequence-to-sequence sono più adatti ai compiti che hanno a che fare con la generazione di nuove frasi sulla base di un input preciso, come il riassunto, la traduzione, o la generazione di risposte a domande.

Tra i rappresentanti di questa famiglia di modelli ci sono:

- [BART](https://huggingface.co/transformers/model_doc/bart.html)
- [mBART](https://huggingface.co/transformers/model_doc/mbart.html)
- [Marian](https://huggingface.co/transformers/model_doc/marian.html)
- [T5](https://huggingface.co/transformers/model_doc/t5.html)


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter1/7.mdx" />

### Natural Language Processing
https://huggingface.co/learn/course/it/chapter1/2.md

# Natural Language Processing

<CourseFloatingBanner
    chapter={1}
    classNames="absolute z-10 right-0 top-0"
/>

Prima di tuffarci nei modelli Transformer, diamo un'occhiata rapida alla natura del natural language processing (*elaborazione del linguaggio naturale*) e alle ragioni per cui quest'ultimo ci interessa.

## Cosa intendiamo per NLP?

NLP è un campo di linguistica e machine learning (*apprendimento automatico*) che si focalizza sulla comprensione di tutto ciò che è legato al linguaggio umano. L'obiettivo dei compiti di NLP non è semplicemente di capire singole parole individualmente, ma anche di capirne il contesto.

La seguente è una lista dei più comuni compiti di NLP, ognuno accompagnato da esempi:

- **Classificazione di frasi intere**: Capire il tono di una recensione, comprendere se una mail si tratta di spam (*spazzatura*), determinare se una frase è grammaticalmente corretta oppure se due frasi hanno un legame logico
- **Classificazione di parole singole all'interno di una frase**: Identificazione dei componenti grammaticali di una frase (nome, verbo, aggettivo), o di entità denominate (persona, località, organizzazione)
- **Generazione di contenuto testuale**: Completare un prompt a mezzo di testo auto-generato, colmare spazi vuoti in un testo con parole mascherate
- **Estrazione di risposte a partire da un testo**: Dati una domanda e un contesto, estrarre la risposta alla domanda sulla base del contesto fornito
- **Generazione di frasi nuove a partire da un testo input**: Traduzione di un testo in un'altra lingua, riassunto di un testo

NLP non si limita però ai soli testi scritti, e tratta anche sfide complesse in riconoscimento vocale e computer vision (*elaborazione di dati visuali*), quali la generazione di trascrizioni di campioni audio o la descrizione di immagini.

## Perché costituisce una sfida?

I computer non elaborano le informazioni allo stesso modo degli umani. Ad esempio, quando leggiamo la frase "Ho fame," ne capiamo senza difficoltà il senso. Allo stesso modo, date due frasi quali "Ho fame" e "Sono triste," riusciamo facilmente a determinarne il livello di similarità. Per i modelli di machine learning (ML), tali compiti sono più difficili. Il testo deve essere elaborato in un modo che permetta al modello di imparare da esso. E siccome il linguaggio è complesso, il modo in cui l'elaborazione va svolta dev'essere studiato con cura. Molta ricerca è stata fatta su come rappresentare i testi, e nel prossimo capitolo vedremo alcuni di questi metodi.


<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/it/chapter1/2.mdx" />
