Modelli e strati

Nell'apprendimento automatico, un modello è una funzione con parametri apprendibili che associa un input a un output. I parametri ottimali si ottengono addestrando il modello sui dati. Un modello ben addestrato fornirà una mappatura accurata dall'input all'output desiderato.

In TensorFlow.js esistono due modi per creare un modello di machine learning:

  1. utilizzando l'API Layers in cui crei un modello utilizzando i livelli .
  2. utilizzando l'API Core con operazioni di livello inferiore come tf.matMul() , tf.add() , ecc.

Per prima cosa esamineremo l'API Layers, che è un'API di livello superiore per la creazione di modelli. Quindi, mostreremo come creare lo stesso modello utilizzando l'API Core.

Creazione di modelli con l'API Layers

Esistono due modi per creare un modello utilizzando l'API Layers: un modello sequenziale e un modello funzionale . Le due sezioni successive esaminano ciascun tipo più da vicino.

Il modello sequenziale

Il tipo di modello più comune è il modello Sequential , che è una pila lineare di livelli. Puoi creare un modello Sequential passando un elenco di livelli alla funzione sequential() :

const model = tf.sequential({
 layers: [
   tf.layers.dense({inputShape: [784], units: 32, activation: 'relu'}),
   tf.layers.dense({units: 10, activation: 'softmax'}),
 ]
});

Oppure tramite il metodo add() :

const model = tf.sequential();
model.add(tf.layers.dense({inputShape: [784], units: 32, activation: 'relu'}));
model.add(tf.layers.dense({units: 10, activation: 'softmax'}));

IMPORTANTE: il primo livello nel modello necessita di un inputShape . Assicurati di escludere la dimensione del batch quando fornisci inputShape . Ad esempio, se prevedi di alimentare i tensori del modello di forma [B, 784] , dove B può essere qualsiasi dimensione batch, specifica inputShape come [784] durante la creazione del modello.

È possibile accedere ai livelli del modello tramite model.layers e più specificamente model.inputLayers e model.outputLayers .

Il modello funzionale

Un altro modo per creare un LayersModel è tramite la funzione tf.model() . La differenza fondamentale tra tf.model() e tf.sequential() è che tf.model() ti consente di creare un grafico arbitrario di livelli, purché non abbiano cicli.

Ecco uno snippet di codice che definisce lo stesso modello di cui sopra utilizzando l'API tf.model() :

// Create an arbitrary graph of layers, by connecting them
// via the apply() method.
const input = tf.input({shape: [784]});
const dense1 = tf.layers.dense({units: 32, activation: 'relu'}).apply(input);
const dense2 = tf.layers.dense({units: 10, activation: 'softmax'}).apply(dense1);
const model = tf.model({inputs: input, outputs: dense2});

Chiamiamo apply() su ogni livello per collegarlo all'output di un altro livello. Il risultato di apply() in questo caso è un SymbolicTensor , che agisce come un Tensor ma senza valori concreti.

Tieni presente che, a differenza del modello sequenziale, creiamo un SymbolicTensor tramite tf.input() invece di fornire un inputShape al primo livello.

apply() può anche darti un Tensor concreto, se gli passi un Tensor concreto:

const t = tf.tensor([-2, 1, 0, 5]);
const o = tf.layers.activation({activation: 'relu'}).apply(t);
o.print(); // [0, 1, 0, 5]

Ciò può essere utile quando si testano i livelli isolatamente e si vede il loro output.

Proprio come in un modello sequenziale, puoi accedere ai livelli del modello tramite model.layers e più specificamente model.inputLayers e model.outputLayers .

Validazione

Sia il modello sequenziale che il modello funzionale sono istanze della classe LayersModel . Uno dei principali vantaggi di lavorare con LayersModel è la convalida: ti obbliga a specificare la forma di input e la utilizzerà in seguito per convalidare il tuo input. Il LayersModel esegue anche l'inferenza automatica della forma mentre i dati fluiscono attraverso i livelli. Conoscere la forma in anticipo consente al modello di creare automaticamente i suoi parametri e può dirti se due livelli consecutivi non sono compatibili tra loro.

Riepilogo del modello

Chiama model.summary() per stampare un utile riepilogo del modello, che include:

  • Nome e tipo di tutti i livelli nel modello.
  • Forma di output per ogni livello.
  • Numero di parametri di peso di ogni strato.
  • Se il modello ha una topologia generale (discussa di seguito), gli input ricevuti da ciascun livello
  • Il numero totale di parametri addestrabili e non addestrabili del modello.

Per il modello che abbiamo definito sopra, otteniamo il seguente output sulla console:

Livello (tipo) Forma di uscita Parametro n.
denso_Dense1 (denso) [nullo,32] 25120
denso_Dense2 (denso) [nullo,10] 330
Parametri totali: 25450
Parametri addestrabili: 25450
Parametri non addestrabili: 0

Notare i valori null nelle forme di output dei livelli: un promemoria che il modello si aspetta che l'input abbia una dimensione batch come dimensione più esterna, che in questo caso può essere flessibile a causa del valore null .

Serializzazione

Uno dei principali vantaggi derivanti dall'utilizzo di LayersModel sull'API di livello inferiore è la possibilità di salvare e caricare un modello. Un LayersModel conosce:

  • l'architettura del modello, consentendo di ricreare il modello.
  • i pesi del modello
  • la configurazione dell'allenamento (perdita, ottimizzatore, metriche).
  • lo stato dell'ottimizzatore, consentendo di riprendere l'allenamento.

Per salvare o caricare un modello è sufficiente 1 riga di codice:

const saveResult = await model.save('localstorage://my-model-1');
const model = await tf.loadLayersModel('localstorage://my-model-1');

L'esempio sopra salva il modello nella memoria locale nel browser. Consulta la model.save() documentation e la guida al salvataggio e al caricamento per informazioni su come salvare su supporti diversi (ad esempio archiviazione di file, IndexedDB , attivazione di un download del browser, ecc.)

Livelli personalizzati

I livelli sono gli elementi costitutivi di un modello. Se il tuo modello sta eseguendo un calcolo personalizzato, puoi definire un livello personalizzato, che interagisce bene con il resto dei livelli. Di seguito definiamo un livello personalizzato che calcola la somma dei quadrati:

class SquaredSumLayer extends tf.layers.Layer {
 constructor() {
   super({});
 }
 // In this case, the output is a scalar.
 computeOutputShape(inputShape) { return []; }

 // call() is where we do the computation.
 call(input, kwargs) { return input.square().sum();}

 // Every layer needs a unique name.
 getClassName() { return 'SquaredSum'; }
}

Per testarlo, possiamo chiamare il metodo apply() con un tensore concreto:

const t = tf.tensor([-2, 1, 0, 5]);
const o = new SquaredSumLayer().apply(t);
o.print(); // prints 30

IMPORTANTE: se aggiungi un livello personalizzato, perdi la possibilità di serializzare un modello.

Creazione di modelli con l'API Core

All'inizio di questa guida, abbiamo menzionato che esistono due modi per creare un modello di machine learning in TensorFlow.js.

La regola generale è provare sempre a utilizzare prima l'API Layers, poiché è modellata sull'API Keras ben adottata che segue le migliori pratiche e riduce il carico cognitivo . L'API Layers offre anche varie soluzioni standard come l'inizializzazione del peso, la serializzazione dei modelli, la formazione sul monitoraggio, la portabilità e il controllo della sicurezza.

Potresti voler utilizzare l'API Core ogni volta che:

  • Hai bisogno della massima flessibilità o controllo.
  • Non è necessaria la serializzazione oppure puoi implementare la tua logica di serializzazione.

I modelli nell'API Core sono solo funzioni che accettano uno o più Tensors e restituiscono un Tensor . Lo stesso modello sopra scritto utilizzando l'API Core si presenta così:

// The weights and biases for the two dense layers.
const w1 = tf.variable(tf.randomNormal([784, 32]));
const b1 = tf.variable(tf.randomNormal([32]));
const w2 = tf.variable(tf.randomNormal([32, 10]));
const b2 = tf.variable(tf.randomNormal([10]));

function model(x) {
  return x.matMul(w1).add(b1).relu().matMul(w2).add(b2).softmax();
}

Tieni presente che nella Core API siamo responsabili della creazione e dell'inizializzazione dei pesi del modello. Ogni peso è supportato da una Variable che segnala a TensorFlow.js che questi tensori sono apprendibili. Puoi creare una Variable usando tf.variable() e passando un Tensor esistente.

In questa guida hai familiarizzato con i diversi modi per creare un modello utilizzando i livelli e l'API Core. Successivamente, consulta la guida ai modelli di training per sapere come addestrare un modello.