Pytorch
TensorFlow

#
Models

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.

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:

    from transformers import BertConfig, BertModel

    # Creazione della configurazione
    config = BertConfig()

    # Creare il modello dalla configurazione
    model = BertModel(config)

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

    print(config)

    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:

    from transformers import BertConfig, BertModel

    config = BertConfig()
    model = BertModel(config)

    # Il modello è inizializzato in modo casuale!

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, 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()`:

    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).

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.

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.

###
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:

    model.save_pretrained("directory_on_my_computer")

In questo modo si salvano due file sul disco:

    ls directory_on_my_computer

    config.json pytorch_model.bin

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.

Il file pytorch_model.bin è noto come state dictionary; contiene tutti i pesi del modello. I due file vanno di pari passo: la configurazione è necessaria per conoscere l’architettura del modello, mentre i pesi del modello sono i suoi parametri.

##
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:

    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:

    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:

    import torch

    model_inputs = torch.tensor(encoded_sequences)

###
Uso dei tensori come input del modello

Utilizzare i tensori con il modello è estremamente semplice: basta chiamare il modello con gli input:

    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.