Diese Seite wurde von der Cloud Translation API übersetzt.
Switch to English

Trainingsmodelle

In diesem Handbuch wird davon ausgegangen, dass Sie das Modell- und Ebenenhandbuch bereits gelesen haben.

In TensorFlow.js gibt es zwei Möglichkeiten, ein Modell für maschinelles Lernen zu trainieren:

  1. Verwenden der Layer-API mit LayersModel.fit() oder LayersModel.fitDataset() .
  2. Verwenden der Core-API mit Optimizer.minimize() .

Zunächst betrachten wir die Ebenen-API, eine übergeordnete API zum Erstellen und Trainieren von Modellen. Anschließend zeigen wir, wie Sie dasselbe Modell mithilfe der Core-API trainieren.

Einführung

Ein Maschine Lernmodell ist eine Funktion mit erlernbar Parametern , die einen Eingang, der einen gewünschten Ausgang abbildet. Die optimalen Parameter werden erhalten, indem das Modell auf Daten trainiert wird.

Das Training umfasst mehrere Schritte:

  • Wie Sie einen Batch von Daten an das Modell.
  • Bitten Sie das Modell, eine Vorhersage zu treffen.
  • Vergleich dieser Vorhersage mit dem "wahren" Wert.
  • Entscheiden, wie stark die einzelnen Parameter geändert werden sollen, damit das Modell in Zukunft eine bessere Vorhersage für diesen Stapel treffen kann.

Ein gut trainiertes Modell bietet eine genaue Zuordnung von der Eingabe zur gewünschten Ausgabe.

Modellparameter

Definieren wir ein einfaches 2-Layer-Modell mithilfe der Layer-API:

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

Unter der Haube haben Modelle Parameter (oft als Gewichte bezeichnet ), die durch Training mit Daten erlernbar sind. Drucken wir die Namen der mit diesem Modell verknüpften Gewichte und ihre Formen aus:

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

Wir erhalten folgende Ausgabe:

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

Insgesamt gibt es 4 Gewichte, 2 pro dichte Schicht. Dies wird erwartet, da dichte Schichten eine Funktion darstellen, die den Eingangstensor x über die Gleichung y = Ax + b auf einen Ausgangstensor y abbildet, wobei A (der Kernel) und b (die Vorspannung) Parameter der dichten Schicht sind.

ANMERKUNG: Standardmäßig enthalten dichte Ebenen eine Verzerrung. Sie können diese jedoch ausschließen, indem {useBias: false} beim Erstellen einer dichten Ebene in den Optionen {useBias: false} .

model.summary() ist eine nützliche Methode, wenn Sie sich einen Überblick über Ihr Modell model.summary() und die Gesamtzahl der Parameter model.summary() möchten:

Ebene (Typ) Ausgabeform Param #
dicht_Dense1 (dicht) [null, 32] 25120
dicht_Dense2 (dicht) [null, 10] 330
Gesamtparameter: 25450
Trainierbare Parameter: 25450
Nicht trainierbare Parameter: 0

Jedes Gewicht im Modell wird durch ein Variable Objekt Variable . In TensorFlow.js ist eine Variable ein Gleitkomma- Tensor mit einer zusätzlichen Methode assign() die zum Aktualisieren ihrer Werte verwendet wird. Die Ebenen-API initialisiert die Gewichte automatisch mithilfe von Best Practices. Zur Demonstration könnten wir die Gewichte überschreiben, indem wir assign() für die zugrunde liegenden Variablen aufrufen:

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

Optimierer, Verlust und Metrik

Bevor Sie ein Training absolvieren, müssen Sie sich für drei Dinge entscheiden:

  1. Ein Optimierer . Die Aufgabe des Optimierers besteht darin, zu entscheiden, um wie viel die einzelnen Parameter im Modell unter Berücksichtigung der aktuellen Modellvorhersage geändert werden sollen. Bei Verwendung der Layer-API können Sie entweder eine Zeichenfolgenkennung eines vorhandenen Optimierers (z. B. 'sgd' oder 'adam' ) oder eine Instanz der Optimizer Klasse 'sgd' .
  2. Eine Verlustfunktion . Ein Ziel, das das Modell zu minimieren versucht. Ihr Ziel ist es, eine einzige Zahl für "wie falsch" die Vorhersage des Modells anzugeben. Der Verlust wird für jeden Datenstapel berechnet, damit das Modell seine Gewichte aktualisieren kann. Bei Verwendung der Layer-API können Sie entweder eine Zeichenfolgenkennung einer vorhandenen Verlustfunktion (z. B. 'categoricalCrossentropy' ) oder eine Funktion angeben, die einen vorhergesagten und einen wahren Wert annimmt und einen Verlust zurückgibt. Eine Liste der verfügbaren Verluste finden Sie in unseren API-Dokumenten.
  3. Liste der Metriken. Ähnlich wie bei Verlusten berechnen Metriken eine einzelne Zahl und fassen zusammen, wie gut unser Modell abschneidet. Die Metriken werden normalerweise am Ende jeder Epoche für die gesamten Daten berechnet. Zumindest wollen wir überwachen, dass unser Verlust im Laufe der Zeit sinkt. Wir möchten jedoch häufig eine menschenfreundlichere Metrik wie die Genauigkeit. Bei Verwendung der Ebenen-API können Sie entweder eine Zeichenfolgenkennung einer vorhandenen Metrik (z. B. 'accuracy' ) oder eine beliebige Funktion angeben, die einen vorhergesagten und einen wahren Wert annimmt und eine Punktzahl zurückgibt. Eine Liste der verfügbaren Metriken finden Sie in unseren API-Dokumenten.

Wenn Sie sich entschieden haben, kompilieren Sie ein LayersModel indem Sie model.compile() mit den angegebenen Optionen aufrufen:

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

Während der Kompilierung führt das Modell eine Validierung durch, um sicherzustellen, dass die von Ihnen ausgewählten Optionen miteinander kompatibel sind.

Ausbildung

Es gibt zwei Möglichkeiten, ein LayersModel zu trainieren:

  • Verwenden Sie model.fit() und stellen Sie die Daten als einen großen Tensor model.fit() .
  • Verwenden von model.fitDataset() und Bereitstellen der Daten über ein Dataset Objekt.

model.fit ()

Wenn Ihr Datensatz in den Hauptspeicher passt und als einzelner Tensor verfügbar ist, können Sie ein Modell trainieren, indem Sie die Methode fit() aufrufen:

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

Unter der Haube kann model.fit() viel für uns tun:

  • Teilt die Daten in einen Zug- und Validierungssatz auf und verwendet den Validierungssatz, um den Fortschritt während des Trainings zu messen.
  • Mischt die Daten aber erst nach dem Split. Um sicher zu gehen, sollten Sie die Daten vorab mischen, bevor Sie sie an fit() .
  • Teilt den Tensor für große Daten in kleinere Tensoren der Größe batchSize.
  • Ruft optimizer.minimize() während der Verlust des Modells in Bezug auf den Datenstapel berechnet wird.
  • Es kann Sie zu Beginn und am Ende jeder Epoche oder Charge benachrichtigen. In unserem Fall werden wir am Ende jedes Stapels mit der Option callbacks.onBatchEnd benachrichtigt. Weitere Optionen sind: onTrainBegin , onTrainEnd , onEpochBegin , onEpochEnd und onBatchBegin .
  • Es gibt dem Hauptthread nach, um sicherzustellen, dass Aufgaben, die sich in der JS-Ereignisschleife befinden, zeitnah verarbeitet werden können.

Weitere Informationen finden Sie in der Dokumentation zu fit() . Beachten Sie, dass Sie diese Logik selbst implementieren müssen, wenn Sie die Core-API verwenden.

model.fitDataset ()

Wenn Ihre Daten nicht vollständig in den Speicher passen oder gestreamt werden, können Sie ein Modell trainieren, indem Sie fitDataset() aufrufen, das ein Dataset Objekt verwendet. Hier ist der gleiche Trainingscode, jedoch mit einem Datensatz, der eine Generatorfunktion umschließt:

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

Weitere Informationen zu Datasets finden Sie in der Dokumentation zu model.fitDataset() .

Vorhersage neuer Daten

Sobald das Modell trainiert wurde, können Sie model.predict() aufrufen, um Vorhersagen für unsichtbare Daten zu treffen:

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

Kern-API

Wir haben bereits erwähnt, dass es in TensorFlow.js zwei Möglichkeiten gibt, ein Modell für maschinelles Lernen zu trainieren.

Die allgemeine Faustregel lautet, zuerst zu versuchen, die Layer-API zu verwenden, da sie der gut übernommenen Keras-API nachempfunden ist. Die Layers-API bietet auch verschiedene Standardlösungen wie Gewichtsinitialisierung, Modellserialisierung, Überwachungstraining, Portabilität und Sicherheitsprüfung.

Möglicherweise möchten Sie die Core-API verwenden, wenn:

  • Sie benötigen maximale Flexibilität oder Kontrolle.
  • Und Sie benötigen keine Serialisierung oder können Ihre eigene Serialisierungslogik implementieren.

Weitere Informationen zu dieser API finden Sie im Abschnitt "Kern-API" im Handbuch " Modelle und Ebenen" .

Das gleiche Modell wie oben, das mit der Core-API geschrieben wurde, sieht folgendermaßen aus:

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

Neben der Layer-API arbeitet die Daten-API auch nahtlos mit der Core-API zusammen. Lassen Sie uns das zuvor im Abschnitt model.fitDataset () definierte Dataset wiederverwenden, das für uns das Mischen und Stapeln übernimmt :

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

Lassen Sie uns das Modell trainieren:

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

Der obige Code ist das Standardrezept beim Trainieren eines Modells mit der Core-API:

  • Schleife über die Anzahl der Epochen.
  • Durchlaufen Sie in jeder Epoche Ihre Datenstapel. Wenn Sie ein Dataset , ist dataset.forEachAsync() eine bequeme Möglichkeit, Ihre dataset.forEachAsync() .
  • Rufen Sie für jeden Stapel optimizer.minimize(f) , das f ausführt und seine Ausgabe minimiert, indem Gradienten in Bezug auf die vier zuvor definierten Variablen berechnet werden.
  • f berechnet den Verlust. Es ruft eine der vordefinierten Verlustfunktionen auf, wobei die Vorhersage des Modells und der wahre Wert verwendet werden.