Modelli di allenamento

Questa guida presuppone che si sia già letto il modelli e strati guida.

In TensorFlow.js sono disponibili due modi per addestrare un modello di machine learning:

  1. utilizzando l'API Layers con LayersModel.fit() o LayersModel.fitDataset() .
  2. utilizzando core API con Optimizer.minimize() .

Innanzitutto, esamineremo l'API Layers, che è un'API di livello superiore per la creazione e l'addestramento di modelli. Quindi, mostreremo come addestrare lo stesso modello utilizzando l'API Core.

introduzione

Un modello apprendimento automatico è una funzione con parametri apprendibili che associa un ingresso ad un'uscita desiderata. I parametri ottimali si ottengono addestrando il modello sui dati.

La formazione prevede diversi passaggi:

  • Ottenere un lotto di dati al modello.
  • Chiedere al modello di fare una previsione.
  • Confrontando quella previsione con il valore "vero".
  • Decidere quanto modificare ogni parametro in modo che il modello possa fare una previsione migliore in futuro per quel batch.

Un modello ben addestrato fornirà una mappatura accurata dall'input all'output desiderato.

Parametri del modello

Definiamo un semplice modello a 2 livelli utilizzando l'API dei livelli:

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

Sotto il cofano, i modelli hanno parametri (spesso definito come pesi) che sono apprendibile attraverso la formazione sui dati. Stampiamo i nomi dei pesi associati a questo modello e le loro forme:

model.weights.forEach(w => {
 console.log(w.name, w.shape);
});

Otteniamo il seguente output:

> dense_Dense1/kernel [784, 32]
> dense_Dense1/bias [32]
> dense_Dense2/kernel [32, 10]
> dense_Dense2/bias [10]

Ci sono 4 pesi in totale, 2 per strato denso. Questo è previsto dal strati densi rappresentano una funzione che mappa l'ingresso tensore x ad un'uscita tensore y tramite l'equazione y = Ax + b dove A (kernel) e b (bias) sono parametri dello strato denso.

NOTA: per impostazione predefinita densi strati comprendono un pregiudizio, ma è possibile escludere specificando {useBias: false} nelle opzioni quando si crea un denso strato.

model.summary() è un metodo utile se si desidera avere una panoramica del modello e visualizzare il numero totale di parametri:

Livello (tipo) Forma di uscita Param #
dense_Dense1 (denso) [nullo,32] 25120
dense_Dense2 (Densi) [nullo,10] 330
Parametri totali: 25450
Parametri addestrabili: 25450
Parametri non addestrabili: 0

Ciascun peso nel modello è backend da una Variable oggetto. In TensorFlow.js, una Variable è un virgola mobile Tensor con un metodo aggiuntivo assign() utilizzato per aggiornare i suoi valori. L'API dei livelli inizializza automaticamente i pesi utilizzando le migliori pratiche. Per motivi di dimostrazione, potremmo sovrascrivere i pesi chiamando assign() sulle variabili sottostanti:

model.weights.forEach(w => {
  const newVals = tf.randomNormal(w.shape);
  // w.val is an instance of tf.Variable
  w.val.assign(newVals);
});

Ottimizzatore, perdita e metrica

Prima di fare qualsiasi allenamento, devi decidere tre cose:

  1. Un ottimizzatore. Il compito dell'ottimizzatore è decidere quanto modificare ciascun parametro nel modello, data la previsione del modello corrente. Quando si utilizza l'API Livelli, è possibile fornire sia un identificatore di stringa di un ottimizzatore esistente (ad esempio 'sgd' o 'adam' ), o di un'istanza della Optimizer di classe.
  2. Una funzione di perdita. Un obiettivo che il modello cercherà di minimizzare. Il suo obiettivo è fornire un singolo numero per "quanto fosse sbagliata" la previsione del modello. La perdita viene calcolata su ogni batch di dati in modo che il modello possa aggiornare i propri pesi. Quando si utilizza l'API Livelli, è possibile fornire sia un identificatore di stringa di una funzione di perdita esistente (ad esempio 'categoricalCrossentropy' ), o di qualsiasi funzione che prende un e un vero valore e di reddito previsto una perdita. Vedere un elenco di perdite disponibili nei nostri documentazione API.
  3. Elenco delle metriche. Simile alle perdite, le metriche calcolano un singolo numero, riassumendo quanto sta andando bene il nostro modello. Le metriche sono solitamente calcolate su tutti i dati alla fine di ogni epoca. Per lo meno, vogliamo monitorare che la nostra perdita diminuisca nel tempo. Tuttavia, spesso desideriamo una metrica più a misura d'uomo come l'accuratezza. Quando si utilizza l'API Livelli, è possibile fornire sia un identificatore di stringa di un esistente metrica (come ad esempio 'accuracy' ), o di qualsiasi funzione che prende un e un vero valore e di reddito previsto un punteggio. Vedere una lista di metriche disponibili nei nostri documenti API.

Quando hai deciso, compilare un LayersModel chiamando model.compile() con le opzioni fornite:

model.compile({
  optimizer: 'sgd',
  loss: 'categoricalCrossentropy',
  metrics: ['accuracy']
});

Durante la compilazione, il modello eseguirà alcune convalide per assicurarsi che le opzioni scelte siano compatibili tra loro.

Addestramento

Ci sono due modi per addestrare un LayersModel :

  • Utilizzando model.fit() e fornendo i dati come un unico grande tensore.
  • Utilizzando model.fitDataset() e fornendo i dati attraverso un Dataset oggetto.

modello.fit()

Se i vostri attacchi del set di dati nella memoria principale, ed è disponibile come un unico tensore, è possibile addestrare un modello chiamando il fit() Metodo:

// Generate dummy data.
const data = tf.randomNormal([100, 784]);
const labels = tf.randomUniform([100, 10]);

function onBatchEnd(batch, logs) {
  console.log('Accuracy', logs.acc);
}

// Train for 5 epochs with batch size of 32.
model.fit(data, labels, {
   epochs: 5,
   batchSize: 32,
   callbacks: {onBatchEnd}
 }).then(info => {
   console.log('Final accuracy', info.history.acc);
 });

Sotto il cofano, model.fit() può fare molto per noi:

  • Divide i dati in un treno e un set di convalida e usa il set di convalida per misurare i progressi durante l'addestramento.
  • Mescola i dati ma solo dopo la divisione. Per essere sicuri, si dovrebbe pre-rimescolare i dati prima di passarlo a fit() .
  • Divide la grande tensore dati in piccoli tensori di dimensioni batchSize.
  • Chiamate optimizer.minimize() , mentre calcolando la perdita del modello rispetto alla serie di dati.
  • Può avvisarti all'inizio e alla fine di ogni epoca o batch. Nel nostro caso, siamo comunicati alla fine di ogni batch utilizzando il callbacks.onBatchEnd opzione. Altre opzioni includono: onTrainBegin , onTrainEnd , onEpochBegin , onEpochEnd e onBatchBegin .
  • Cede al thread principale per garantire che le attività in coda nel ciclo di eventi JS possano essere gestite in modo tempestivo.

Per ulteriori informazioni, consultare la documentazione di fit() . Tieni presente che se scegli di utilizzare l'API Core, dovrai implementare tu stesso questa logica.

model.fitDataset()

Se i dati non entra completamente in memoria, o viene trasmesso, si può formare un modello chiamando fitDataset() , che prende un Dataset oggetto. Ecco lo stesso codice di addestramento ma con un set di dati che racchiude una funzione generatore:

function* data() {
 for (let i = 0; i < 100; i++) {
   // Generate one sample at a time.
   yield tf.randomNormal([784]);
 }
}

function* labels() {
 for (let i = 0; i < 100; i++) {
   // Generate one sample at a time.
   yield tf.randomUniform([10]);
 }
}

const xs = tf.data.generator(data);
const ys = tf.data.generator(labels);
// We zip the data and labels together, shuffle and batch 32 samples at a time.
const ds = tf.data.zip({xs, ys}).shuffle(100 /* bufferSize */).batch(32);

// Train the model for 5 epochs.
model.fitDataset(ds, {epochs: 5}).then(info => {
 console.log('Accuracy', info.history.acc);
});

Per ulteriori informazioni sui set di dati, consultare la documentazione di model.fitDataset() .

Prevedere nuovi dati

Una volta che il modello è stato addestrato, è possibile chiamare model.predict() per fare previsioni sui dati invisibile:

// Predict 3 random samples.
const prediction = model.predict(tf.randomNormal([3, 784]));
prediction.print();

API principale

In precedenza, abbiamo detto che esistono due modi per addestrare un modello di machine learning in TensorFlow.js.

La regola generale è provare a utilizzare prima l'API Layers, poiché è modellata sull'API Keras ben adottata. L'API Layers offre anche varie soluzioni pronte all'uso come l'inizializzazione del peso, la serializzazione del modello, 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.
  • E non hai bisogno della serializzazione o puoi implementare la tua logica di serializzazione.

Per ulteriori informazioni su questa API, leggere la sezione "Core API" in Modelli e Livelli guida.

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);
}

Oltre all'API Layers, anche l'API Data funziona perfettamente con l'API Core. Cerchiamo di riutilizzare il set di dati che abbiamo definito in precedenza nella model.fitDataset () sezione, che non mischiare e dosaggio per noi:

const xs = tf.data.generator(data);
const ys = tf.data.generator(labels);
// Zip the data and labels together, shuffle and batch 32 samples at a time.
const ds = tf.data.zip({xs, ys}).shuffle(100 /* bufferSize */).batch(32);

Addestriamo il modello:

const optimizer = tf.train.sgd(0.1 /* learningRate */);
// Train for 5 epochs.
for (let epoch = 0; epoch < 5; epoch++) {
  await ds.forEachAsync(({xs, ys}) => {
    optimizer.minimize(() => {
      const predYs = model(xs);
      const loss = tf.losses.softmaxCrossEntropy(ys, predYs);
      loss.data().then(l => console.log('Loss', l));
      return loss;
    });
  });
  console.log('Epoch', epoch);
}

Il codice sopra è la ricetta standard durante l'addestramento di un modello con l'API Core:

  • Ciclo sul numero di epoche.
  • All'interno di ogni epoca, esegui un ciclo sui tuoi batch di dati. Quando si utilizza un Dataset , dataset.forEachAsync() è un modo conveniente per un ciclo sui batch.
  • Per ciascun lotto, chiamata optimizer.minimize(f) , che esegue f e riduce la sua uscita calcolando gradienti rispetto alle quattro variabili che abbiamo definito in precedenza.
  • f calcola la perdita. Richiama una delle funzioni di perdita predefinite utilizzando la previsione del modello e il valore vero.