Modelli salvati da TF Hub in TensorFlow 2

Il formato SavedModel di TensorFlow 2 è il modo consigliato per condividere modelli pre-addestrati e parti di modelli su TensorFlow Hub. Sostituisce il vecchio formato TF1 Hub e viene fornito con un nuovo set di API.

Questa pagina spiega come riutilizzare TF2 SavedModels in un programma TensorFlow 2 con l'API hub.load() di basso livello e il relativo wrapper hub.KerasLayer . (In genere, hub.KerasLayer è combinato con altri tf.keras.layers per creare un modello Keras o il model_fn di un TF2 Estimator.) Queste API possono anche caricare i modelli legacy in formato TF1 Hub, entro i limiti, vedere la guida alla compatibilità .

Gli utenti di TensorFlow 1 possono eseguire l'aggiornamento a TF 1.15 e quindi utilizzare le stesse API. Le versioni precedenti di TF1 non funzionano.

Utilizzo di modelli salvati da TF Hub

Utilizzo di un modello salvato in Keras

Keras è l'API di alto livello di TensorFlow per la creazione di modelli di deep learning componendo oggetti Keras Layer. La libreria tensorflow_hub fornisce la classe hub.KerasLayer che viene inizializzata con l'URL (o il percorso del filesystem) di un SavedModel e quindi fornisce il calcolo da SavedModel, inclusi i suoi pesi pre-addestrati.

Ecco un esempio di utilizzo di un incorporamento di testo pre-addestrato:

import tensorflow as tf
import tensorflow_hub as hub

hub_url = "https://tfhub.dev/google/nnlm-en-dim128/2"
embed = hub.KerasLayer(hub_url)
embeddings = embed(["A long sentence.", "single-word", "http://example.com"])
print(embeddings.shape, embeddings.dtype)

Da questo, è possibile creare un classificatore di testo nel solito modo Keras:

model = tf.keras.Sequential([
    embed,
    tf.keras.layers.Dense(16, activation="relu"),
    tf.keras.layers.Dense(1, activation="sigmoid"),
])

La collaborazione sulla classificazione del testo è un esempio completo di come addestrare e valutare un classificatore di questo tipo.

I pesi del modello in un hub.KerasLayer sono impostati su non addestrabili per impostazione predefinita. Consulta la sezione sulla messa a punto di seguito per come modificarlo. I pesi sono condivisi tra tutte le applicazioni dello stesso oggetto livello, come al solito in Keras.

Utilizzo di un modello salvato in uno stimatore

Gli utenti dell'API Estimator di TensorFlow per l'addestramento distribuito possono utilizzare SavedModels da TF Hub scrivendo il proprio model_fn in termini di hub.KerasLayer tra gli altri tf.keras.layers .

Dietro le quinte: download e memorizzazione nella cache di SavedModel

Utilizzando un SavedModel da TensorFlow Hub (o altri server HTTPS che implementano il suo protocollo di hosting ) lo scarica e lo decomprime nel file system locale se non è già presente. La variabile di ambiente TFHUB_CACHE_DIR può essere impostata per sovrascrivere la posizione temporanea predefinita per la memorizzazione nella cache dei SavedModels scaricati e non compressi. Per i dettagli, vedere Memorizzazione nella cache .

Utilizzo di un SavedModel in TensorFlow di basso livello

Maniglie modello

I SavedModels possono essere caricati da un handle specificato, dove l' handle è un percorso del filesystem, un URL del modello TFhub.dev valido (ad esempio "https://tfhub.dev/..."). Gli URL dei modelli Kaggle rispecchiano la gestione di TFhub.dev in conformità con i nostri Termini e la licenza associata alle risorse del modello, ad esempio "https://www.kaggle.com/...". Gli handle di Kaggle Models sono equivalenti al corrispondente handle TFhub.dev.

La funzione hub.load(handle) scarica e decomprime un SavedModel (a meno che handle non sia già un percorso del filesystem) e quindi restituisce il risultato del suo caricamento con la funzione integrata di TensorFlow tf.saved_model.load() . Pertanto, hub.load() può gestire qualsiasi SavedModel valido (a differenza del suo predecessore hub.Module per TF1).

Argomento avanzato: cosa aspettarsi da SavedModel dopo il caricamento

A seconda del contenuto di SavedModel, il risultato di obj = hub.load(...) può essere invocato in vari modi (come spiegato in modo molto più dettagliato nella SavedModel Guide di TensorFlow:

  • Le firme di servizio di SavedModel (se presenti) sono rappresentate come un dizionario di funzioni concrete e possono essere chiamate come tensors_out = obj.signatures["serving_default"](**tensors_in) , con dizionari di tensori codificati dai rispettivi input e output nomi e soggetti ai vincoli di forma e tipo della firma.

  • I metodi @tf.function -decorated dell'oggetto salvato (se presenti) vengono ripristinati come oggetti tf.function che possono essere chiamati da tutte le combinazioni di argomenti tensoriali e non tensoriali per i quali la funzione tf.function è stata tracciata prima del salvataggio. In particolare, se esiste un metodo obj.__call__ con tracce adeguate, obj stesso può essere chiamato come una funzione Python. Un semplice esempio potrebbe essere output_tensor = obj(input_tensor, training=False) .

Ciò lascia un'enorme libertà nelle interfacce che SavedModels può implementare. L' interfaccia Reusable SavedModels per obj stabilisce convenzioni tali che il codice client, inclusi gli adattatori come hub.KerasLayer , sappia come utilizzare SavedModel.

Alcuni SavedModel potrebbero non seguire tale convenzione, in particolare modelli interi non destinati a essere riutilizzati in modelli più grandi, e fornire semplicemente firme di servizio.

Le variabili addestrabili in un SavedModel vengono ricaricate come addestrabili e tf.GradientTape le controllerà per impostazione predefinita. Consulta la sezione sulla messa a punto di seguito per alcuni avvertimenti e considera di evitarlo per cominciare. Anche se vuoi perfezionare, potresti voler vedere se obj.trainable_variables consiglia di riqualificare solo un sottoinsieme delle variabili originariamente addestrabili.

Creazione di modelli salvati per TF Hub

Panoramica

SavedModel è il formato di serializzazione standard di TensorFlow per modelli addestrati o pezzi di modelli. Memorizza i pesi addestrati del modello insieme alle esatte operazioni TensorFlow per eseguire il calcolo. Può essere utilizzato indipendentemente dal codice che lo ha creato. In particolare, può essere riutilizzato su diverse API di creazione di modelli di alto livello come Keras, poiché le operazioni TensorFlow sono il loro linguaggio di base comune.

Salvataggio da Keras

A partire da TensorFlow 2, tf.keras.Model.save() e tf.keras.models.save_model() utilizzano per impostazione predefinita il formato SavedModel (non HDF5). I SavedModel risultanti che possono essere utilizzati con hub.load() , hub.KerasLayer e adattatori simili per altre API di alto livello non appena diventano disponibili.

Per condividere un modello Keras completo, salvalo con include_optimizer=False .

Per condividere un pezzo di un modello Keras, rendi il pezzo un modello a sé stante e poi salvalo. Puoi disporre il codice in questo modo dall'inizio....

piece_to_share = tf.keras.Model(...)
full_model = tf.keras.Sequential([piece_to_share, ...])
full_model.fit(...)
piece_to_share.save(...)

...oppure ritaglia il pezzo da condividere dopo (se è in linea con la stratificazione del modello completo):

full_model = tf.keras.Model(...)
sharing_input = full_model.get_layer(...).get_output_at(0)
sharing_output = full_model.get_layer(...).get_output_at(0)
piece_to_share = tf.keras.Model(sharing_input, sharing_output)
piece_to_share.save(..., include_optimizer=False)

TensorFlow Models su GitHub utilizza il primo approccio per BERT (vedi nlp/tools/export_tfhub_lib.py , nota la divisione tra core_model per l'esportazione e il pretrainer per ripristinare il checkpoint) e il secondo approccio per ResNet (vedi legacy/image_classification/tfhub_export.py ).

Salvataggio da TensorFlow di basso livello

Ciò richiede una buona familiarità con la Guida SavedModel di TensorFlow.

Se desideri fornire più di una semplice firma di pubblicazione, dovresti implementare l' interfaccia Reusable SavedModel . Concettualmente sembra così

class MyMulModel(tf.train.Checkpoint):
  def __init__(self, v_init):
    super().__init__()
    self.v = tf.Variable(v_init)
    self.variables = [self.v]
    self.trainable_variables = [self.v]
    self.regularization_losses = [
        tf.function(input_signature=[])(lambda: 0.001 * self.v**2),
    ]

  @tf.function(input_signature=[tf.TensorSpec(shape=None, dtype=tf.float32)])
  def __call__(self, inputs):
    return tf.multiply(inputs, self.v)

tf.saved_model.save(MyMulModel(2.0), "/tmp/my_mul")

layer = hub.KerasLayer("/tmp/my_mul")
print(layer([10., 20.]))  # [20., 40.]
layer.trainable = True
print(layer.trainable_weights)  # [2.]
print(layer.losses)  # 0.004

Ritocchi

L'addestramento delle variabili già addestrate di un SavedModel importato insieme a quelle del modello attorno ad esso è chiamato perfezionamento di SavedModel. Ciò può comportare una migliore qualità, ma spesso rende la formazione più impegnativa (può richiedere più tempo, dipendere maggiormente dall'ottimizzatore e dai suoi iperparametri, aumentare il rischio di overfitting e richiedere l'aumento del set di dati, specialmente per le CNN). Consigliamo ai consumatori di SavedModel di esaminare la messa a punto solo dopo aver stabilito un buon regime di formazione e solo se l'editore SavedModel lo consiglia.

L'ottimizzazione modifica i parametri del modello "continuo" addestrati. Non modifica le trasformazioni hardcoded, come la tokenizzazione dell'input di testo e la mappatura dei token alle voci corrispondenti in una matrice di incorporamento.

Per i consumatori SavedModel

Creazione di un hub.KerasLayer simile

layer = hub.KerasLayer(..., trainable=True)

consente la messa a punto del SavedModel caricato dal livello. Aggiunge i pesi addestrabili e i regolarizzatori di peso dichiarati in SavedModel al modello Keras ed esegue il calcolo di SavedModel in modalità training (si pensi al dropout ecc.).

Il laboratorio collettivo di classificazione delle immagini contiene un esempio end-to-end con regolazione fine facoltativa.

Riesportazione del risultato della regolazione fine

Gli utenti esperti potrebbero voler salvare i risultati della messa a punto in un SavedModel che può essere utilizzato al posto di quello originariamente caricato. Questo può essere fatto con un codice simile

loaded_obj = hub.load("https://tfhub.dev/...")
hub_layer = hub.KerasLayer(loaded_obj, trainable=True, ...)

model = keras.Sequential([..., hub_layer, ...])
model.compile(...)
model.fit(...)

export_module_dir = os.path.join(os.getcwd(), "finetuned_model_export")
tf.saved_model.save(loaded_obj, export_module_dir)

Per i creatori di SavedModel

Quando crei un SavedModel per la condivisione su TensorFlow Hub, pensa in anticipo se e come i suoi consumatori dovrebbero ottimizzarlo e fornisci indicazioni nella documentazione.

Il salvataggio da un modello Keras dovrebbe far sì che tutti i meccanismi di messa a punto funzionino (salvataggio delle perdite di regolarizzazione del peso, dichiarazione di variabili addestrabili, tracciamento __call__ sia per training=True che training=False , ecc.)

Scegli un'interfaccia del modello che funzioni bene con il flusso gradiente, ad esempio, log di output invece di probabilità softmax o previsioni top-k.

Se il modello utilizza dropout, normalizzazione batch o tecniche di training simili che coinvolgono iperparametri, impostarli su valori che abbiano senso per molti problemi target e dimensioni batch previsti. (Al momento della stesura di questo articolo, il salvataggio da Keras non semplifica la possibilità da parte dei consumatori di modificarli.)

I regolarizzatori del peso sui singoli livelli vengono salvati (con i relativi coefficienti di forza di regolarizzazione), ma la regolarizzazione del peso dall'interno dell'ottimizzatore (come tf.keras.optimizers.Ftrl.l1_regularization_strength=...) ) viene persa. Informa i consumatori del tuo SavedModel di conseguenza.