Cette page a été traduite par l'API Cloud Translation.
Switch to English

Modèles de formation

Ce guide suppose que vous avez déjà lu le guide des modèles et des calques .

Dans TensorFlow.js, il existe deux façons de former un modèle d'apprentissage automatique:

  1. en utilisant l'API Layers avec LayersModel.fit() ou LayersModel.fitDataset() .
  2. en utilisant l'API Core avec Optimizer.minimize() .

Tout d'abord, nous examinerons l'API Layers, qui est une API de niveau supérieur pour la création et la formation de modèles. Ensuite, nous montrerons comment entraîner le même modèle à l'aide de l'API Core.

introduction

Un modèle d' apprentissage automatique est une fonction avec des paramètres apprenables qui mappe une entrée à une sortie souhaitée. Les paramètres optimaux sont obtenus en entraînant le modèle sur des données.

La formation comprend plusieurs étapes:

  • Obtenir un lot de données dans le modèle.
  • Demander au modèle de faire une prédiction.
  • Comparaison de cette prédiction avec la valeur "vraie".
  • Décider du degré de modification de chaque paramètre afin que le modèle puisse effectuer une meilleure prédiction à l'avenir pour ce lot.

Un modèle bien formé fournira une cartographie précise de l'entrée à la sortie souhaitée.

Paramètres du modèle

Définissons un modèle simple à 2 couches à l'aide de l'API Layers:

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

Sous le capot, les modèles ont des paramètres (souvent appelés poids ) qui peuvent être appris en s'entraînant sur des données. Imprimons les noms des poids associés à ce modèle et leurs formes:

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

Nous obtenons la sortie suivante:

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

Il y a 4 poids au total, 2 par couche dense. Ceci est attendu puisque les couches denses représentent une fonction qui mappe le tenseur d'entrée x à un tenseur de sortie y via l'équation y = Ax + bA (le noyau) et b (le biais) sont des paramètres de la couche dense.

REMARQUE: Par défaut, les couches denses incluent un biais, mais vous pouvez l'exclure en spécifiant {useBias: false} dans les options lors de la création d'une couche dense.

model.summary() est une méthode utile si vous souhaitez avoir un aperçu de votre modèle et voir le nombre total de paramètres:

Calque (type) Forme de sortie Param #
dense_Dense1 (dense) [nul, 32] 25120
dense_Dense2 (dense) [null, 10] 330
Paramètres totaux: 25450
Paramètres entraînables: 25450
Paramètres non entraînables: 0

Chaque poids du modèle est backend par un objet Variable . Dans TensorFlow.js, une Variable est un Tensor à virgule flottante avec une méthode supplémentaire assign() utilisée pour mettre à jour ses valeurs. L'API Layers initialise automatiquement les pondérations en utilisant les meilleures pratiques. Pour des raisons de démonstration, nous pourrions écraser les poids en appelant assign() sur les variables sous-jacentes:

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

Optimiseur, perte et métrique

Avant de vous entraîner, vous devez décider de trois choses:

  1. Un optimiseur . Le travail de l'optimiseur est de décider dans quelle mesure chaque paramètre du modèle doit être modifié, compte tenu de la prédiction actuelle du modèle. Lorsque vous utilisez l'API Layers, vous pouvez fournir soit un identificateur de chaîne d'un optimiseur existant (tel que 'sgd' ou 'adam' ), soit une instance de la classe Optimizer .
  2. Une fonction de perte . Un objectif que le modèle tentera de minimiser. Son objectif est de donner un chiffre unique indiquant «à quel point» la prédiction du modèle était erronée. La perte est calculée sur chaque lot de données afin que le modèle puisse mettre à jour ses poids. Lorsque vous utilisez l'API Layers, vous pouvez fournir soit un identificateur de chaîne d'une fonction de perte existante (telle que 'categoricalCrossentropy' ), soit toute fonction qui prend une valeur prédite et une valeur vraie et renvoie une perte. Consultez la liste des pertes disponibles dans nos documents API.
  3. Liste des métriques. Semblable aux pertes, les métriques calculent un seul nombre, résumant les performances de notre modèle. Les métriques sont généralement calculées sur l'ensemble des données à la fin de chaque époque. À tout le moins, nous voulons surveiller que nos pertes diminuent avec le temps. Cependant, nous voulons souvent une métrique plus conviviale, telle que la précision. Lorsque vous utilisez l'API Layers, vous pouvez fournir soit un identificateur de chaîne d'une métrique existante (telle que 'accuracy' ), soit toute fonction qui prend une valeur prédite et vraie et renvoie un score. Consultez la liste des métriques disponibles dans nos documents sur l'API.

Lorsque vous avez décidé, compilez un LayersModel en appelant model.compile() avec les options fournies:

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

Lors de la compilation, le modèle effectuera une validation pour s'assurer que les options que vous avez choisies sont compatibles les unes avec les autres.

Formation

Il existe deux façons de former un LayersModel :

  • Utilisation de model.fit() et fourniture des données sous la forme d'un grand tenseur.
  • Utilisation de model.fitDataset() et fourniture des données via un objet Dataset .

model.fit ()

Si votre jeu de données tient dans la mémoire principale et est disponible en tant que tenseur unique, vous pouvez entraîner un modèle en appelant la méthode fit() :

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

Sous le capot, model.fit() peut faire beaucoup pour nous:

  • Divise les données en un ensemble de train et de validation, et utilise l'ensemble de validation pour mesurer les progrès pendant la formation.
  • Mélange les données, mais seulement après le fractionnement. Pour être sûr, vous devez pré-mélanger les données avant de les transmettre à fit() .
  • Divise le grand tenseur de données en plus petits tenseurs de taille batchSize.
  • Appelle optimizer.minimize() lors du calcul de la perte du modèle par rapport au lot de données.
  • Il peut vous informer du début et de la fin de chaque époque ou lot. Dans notre cas, nous sommes notifiés à la fin de chaque lot en utilisant l'option callbacks.onBatchEnd . Les autres options incluent: onTrainBegin , onTrainEnd , onEpochBegin , onEpochEnd et onBatchBegin .
  • Il cède au thread principal pour garantir que les tâches mises en file d'attente dans la boucle d'événements JS peuvent être traitées en temps opportun.

Pour plus d'informations, consultez la documentation de fit() . Notez que si vous choisissez d'utiliser l'API Core, vous devrez implémenter cette logique vous-même.

model.fitDataset ()

Si vos données ne tiennent pas entièrement dans la mémoire ou sont en cours de diffusion, vous pouvez entraîner un modèle en appelant fitDataset() , qui prend un objet Dataset . Voici le même code d'entraînement mais avec un ensemble de données qui encapsule une fonction de générateur:

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

Pour plus d'informations sur les ensembles de données, consultez la documentation de model.fitDataset() .

Prédire de nouvelles données

Une fois le modèle entraîné, vous pouvez appeler model.predict() pour effectuer des prédictions sur des données invisibles:

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

API principale

Plus tôt, nous avons mentionné qu'il existe deux façons de former un modèle d'apprentissage automatique dans TensorFlow.js.

La règle générale est d'essayer d'utiliser d'abord l'API Layers, car elle est modelée sur l'API Keras bien adoptée. L'API Layers propose également diverses solutions prêtes à l'emploi telles que l'initialisation du poids, la sérialisation du modèle, la formation au suivi, la portabilité et le contrôle de sécurité.

Vous souhaiterez peut-être utiliser l'API Core chaque fois que:

  • Vous avez besoin d'un maximum de flexibilité ou de contrôle.
  • Et vous n'avez pas besoin de sérialisation ou pouvez implémenter votre propre logique de sérialisation.

Pour plus d'informations sur cette API, lisez la section "API principale" du guide Modèles et couches .

Le même modèle que ci-dessus écrit à l'aide de l'API Core ressemble à ceci:

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

En plus de l'API Layers, l'API Data fonctionne également de manière transparente avec l'API Core. Réutilisons l'ensemble de données que nous avons défini précédemment dans la section model.fitDataset () , qui effectue le mélange et le traitement par lots pour nous:

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

Entraînons le modèle:

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

Le code ci-dessus est la recette standard lors de la formation d'un modèle avec l'API Core:

  • Boucle sur le nombre d'époques.
  • À l'intérieur de chaque époque, parcourez vos lots de données. Lors de l'utilisation d'un Dataset , dataset.forEachAsync() est un moyen pratique de boucler sur vos lots.
  • Pour chaque lot, appelez optimizer.minimize(f) , qui exécute f et minimise sa sortie en calculant des gradients par rapport aux quatre variables que nous avons définies précédemment.
  • f calcule la perte. Il appelle l'une des fonctions de perte prédéfinies à l'aide de la prédiction du modèle et de la valeur vraie.