# Models

{#if fw === 'pt'}

{:else}

{/if}

{#if fw === 'pt'}

{:else}

{/if}

{#if fw === 'pt'}
In questa sezione vedremo da vicino come creare e usare un modello. Utilizzeremo la classe `AutoModel`, utile quando si vuole istanziare qualsiasi modello da un checkpoint.

La classe `AutoModel` e tutti i suoi derivati sono in realtà semplici involucri dell'ampia varietà di modelli disponibili nella libreria. Si tratta di un involucro intelligente, in quanto è in grado di indovinare automaticamente l'architettura del modello appropriata per il checkpoint e successivamente di istanziare un modello con questa architettura.

{:else}
In questa sezione vedremo da vicino come creare e usare un modello. Utilizzeremo la classe `TFAutoModel`, utile quando si vuole istanziare qualsiasi modello da un checkpoint.

La classe `TFAutoModel` e tutti i suoi derivati sono in realtà semplici involucri dell'ampia varietà di modelli disponibili nella libreria. Si tratta di un involucro intelligente, in quanto è in grado di indovinare automaticamente l'architettura del modello appropriata per il checkpoint e successivamente di istanziare un modello con questa architettura.

{/if}

Tuttavia, se si conosce il tipo di modello che si vuole utilizzare, si può usare direttamente la classe che ne definisce l'architettura. Vediamo come funziona con un modello BERT.

## Creare un trasformatore

La prima cosa da fare per inizializzare un modello BERT è caricare un oggetto di configurazione:

{#if fw === 'pt'}
```py
from transformers import BertConfig, BertModel

# Creazione della configurazione
config = BertConfig()

# Creare il modello dalla configurazione
model = BertModel(config)
```
{:else}
```py
from transformers import BertConfig, TFBertModel

# Creazione della configurazione
config = BertConfig()

# Creare il modello dalla configurazione
model = TFBertModel(config)
```
{/if}

La configurazione contiene molti attributi che vengono utilizzati per costruire il modello:

```py
print(config)
```

```python out
BertConfig {
  [...]
  "hidden_size": 768,
  "intermediate_size": 3072,
  "max_position_embeddings": 512,
  "num_attention_heads": 12,
  "num_hidden_layers": 12,
  [...]
}
```

Anche se non si è ancora visto cosa fanno tutti questi attributi, se ne dovrebbero riconoscere alcuni: l'attributo `hidden_size` definisce la dimensione del vettore `hidden_states`, e l'attributo `num_hidden_layers` definisce il numero di livelli del modello Transformer.

### Diversi metodi di caricamento

La creazione di un modello dalla configurazione predefinita lo inizializza con valori casuali:

{#if fw === 'pt'}
```py
from transformers import BertConfig, BertModel

config = BertConfig()
model = BertModel(config)

# Il modello è inizializzato in modo casuale!
```
{:else}
```py
from transformers import BertConfig, TFBertModel

config = BertConfig()
model = TFBertModel(config)

# Il modello è inizializzato in modo casuale!
```
{/if}

Il modello può essere utilizzato in questo stato, ma produrrà risultati incomprensibili; è necessario addestrarlo prima.

Potremmo addestrare il modello da zero sul compito da svolgere, ma come si è visto in [Capitolo 1](/course/chapter1), questo richiederebbe molto tempo e molti dati, oltre ad avere un impatto ambientale non trascurabile. Per evitare sforzi inutili, è indispensabile poter condividere e riutilizzare modelli già addestrati.

Caricare un modello Transformer già addestrato è semplice: lo si può fare usando il metodo `from_pretrained()`:

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

model = BertModel.from_pretrained("bert-base-cased")
```

Come abbiamo visto in precedenza, possiamo sostituire `BertModel` con la classe equivalente `AutoModel`. Lo faremo d'ora in poi, perché in questo modo si ottiene un codice cosiddetto "checkpoint-agnostic"; se il codice funziona per un checkpoint, dovrebbe funzionare senza problemi anche con un altro. Questo vale anche se l'architettura è diversa, purché il checkpoint sia stato addestrato per un compito simile (per esempio, un compito di sentiment analysis).

{:else}
```py
from transformers import TFBertModel

model = TFBertModel.from_pretrained("bert-base-cased")
```
Come abbiamo visto in precedenza, possiamo sostituire `TFBertModel` con la classe equivalente `TFAutoModel`. Lo faremo d'ora in poi, perché in questo modo si ottiene un codice cosiddetto "checkpoint-agnostic"; se il codice funziona per un checkpoint, dovrebbe funzionare senza problemi anche con un altro. Questo vale anche se l'architettura è diversa, purché il checkpoint sia stato addestrato per un compito simile (per esempio, un compito di sentiment analysis).

{/if}

Nell'esempio di codice precedente non abbiamo usato `BertConfig` e abbiamo invece caricato un modello pre-addestrato tramite l'identificatore `bert-base-cased`. Si tratta di un checkpoint che è stato addestrato dagli stessi autori di BERT; si possono trovare maggiori dettagli su di esso nella sua [scheda modello](https://huggingface.co/bert-base-cased).

Questo modello è ora inizializzato con tutti i pesi del checkpoint. Può essere utilizzato direttamente per effettuare inferenza sui compiti su cui è stato addestrato e può anche essere messo adattato ad un nuovo compito, tramite il fine tuning. Allenandosi con i pesi pre-addestrati piuttosto che partendo da zero, si possono ottenere rapidamente buoni risultati.

I pesi sono stati scaricati e messi in cache (in modo che le future chiamate al metodo `from_pretrained()` non li scarichino di nuovo) nella cartella della cache, che per impostazione predefinita è *~/.cache/huggingface/transformers*. È possibile personalizzare la cartella della cache impostando la variabile d'ambiente `HF_HOME`.

L'identificatore usato per caricare il modello può essere l'identificatore di qualsiasi modello presente nel Model Hub, purché sia compatibile con l'architettura del BERT. L'elenco completo dei checkpoint BERT disponibili è disponibile [qui](https://huggingface.co/models?filter=bert).

### Metodi di salvataggio

Saving a model is as easy as loading one — we use the `save_pretrained()` method, which is analogous to the `from_pretrained()` method:

```py
model.save_pretrained("directory_on_my_computer")
```

In questo modo si salvano due file sul disco:

{#if fw === 'pt'}
```
ls directory_on_my_computer

config.json 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.

