Modèles et calques

En apprentissage automatique, un modèle est une fonction avec des paramètres apprenables qui mappent une entrée à une sortie. Les paramètres optimaux sont obtenus en entraînant le modèle sur les données. Un modèle bien entraîné fournira une cartographie précise de l’entrée à la sortie souhaitée.

Dans TensorFlow.js, il existe deux manières de créer un modèle d'apprentissage automatique :

  1. en utilisant l'API Layers où vous créez un modèle à l'aide de layer .
  2. en utilisant l'API Core avec des opérations de niveau inférieur telles que tf.matMul() , tf.add() , etc.

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

Créer des modèles avec l'API Layers

Il existe deux manières de créer un modèle à l'aide de l'API Layers : un modèle séquentiel et un modèle fonctionnel . Les deux sections suivantes examinent chaque type de plus près.

Le modèle séquentiel

Le type de modèle le plus courant est le modèle Sequential , qui est une pile linéaire de couches. Vous pouvez créer un modèle Sequential en passant une liste de couches à la fonction sequential() :

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

Ou via la méthode 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'}));

IMPORTANT : la première couche du modèle nécessite un inputShape . Assurez-vous d'exclure la taille du lot lorsque vous fournissez le inputShape . Par exemple, si vous envisagez d'alimenter les tenseurs du modèle de forme [B, 784] , où B peut être n'importe quelle taille de lot, spécifiez inputShape comme [784] lors de la création du modèle.

Vous pouvez accéder aux couches du modèle via model.layers , et plus précisément model.inputLayers et model.outputLayers .

Le modèle fonctionnel

Une autre façon de créer un LayersModel consiste à utiliser la fonction tf.model() . La principale différence entre tf.model() et tf.sequential() est que tf.model() vous permet de créer un graphique arbitraire de couches, à condition qu'elles n'aient pas de cycles.

Voici un extrait de code qui définit le même modèle que ci-dessus en utilisant 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});

Nous appelons apply() sur chaque couche afin de la connecter à la sortie d'une autre couche. Le résultat de apply() dans ce cas est un SymbolicTensor , qui agit comme un Tensor mais sans aucune valeur concrète.

Notez que contrairement au modèle séquentiel, nous créons un SymbolicTensor via tf.input() au lieu de fournir un inputShape à la première couche.

apply() peut également vous donner un Tensor concret, si vous lui transmettez un Tensor concret :

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

Cela peut être utile pour tester les couches de manière isolée et voir leur sortie.

Tout comme dans un modèle séquentiel, vous pouvez accéder aux couches du modèle via model.layers , et plus précisément model.inputLayers et model.outputLayers .

Validation

Le modèle séquentiel et le modèle fonctionnel sont des instances de la classe LayersModel . L'un des principaux avantages de travailler avec un LayersModel est la validation : elle vous oblige à spécifier la forme d'entrée et l'utilisera plus tard pour valider votre entrée. Le LayersModel effectue également une inférence de forme automatique à mesure que les données circulent à travers les couches. Connaître la forme à l'avance permet au modèle de créer automatiquement ses paramètres, et peut vous indiquer si deux calques consécutifs ne sont pas compatibles entre eux.

Résumé du modèle

Appelez model.summary() pour imprimer un résumé utile du modèle, qui comprend :

  • Nom et type de tous les calques du modèle.
  • Forme de sortie pour chaque couche.
  • Nombre de paramètres de poids de chaque couche.
  • Si le modèle a une topologie générale (discutée ci-dessous), les entrées que chaque couche reçoit
  • Le nombre total de paramètres pouvant être entraînés et non pouvant être entraînés du modèle.

Pour le modèle que nous avons défini ci-dessus, nous obtenons le résultat suivant sur la console :

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

Notez les valeurs null dans les formes de sortie des couches : un rappel que le modèle s'attend à ce que l'entrée ait une taille de lot comme dimension la plus externe, qui dans ce cas peut être flexible en raison de la valeur null .

Sérialisation

L'un des principaux avantages de l'utilisation d'un LayersModel par rapport à l'API de niveau inférieur est la possibilité d'enregistrer et de charger un modèle. Un LayersModel connaît :

  • l'architecture du modèle, vous permettant de recréer le modèle.
  • les poids du modèle
  • la configuration de la formation (perte, optimiseur, métriques).
  • l'état de l'optimiseur, vous permettant de reprendre l'entraînement.

Pour enregistrer ou charger un modèle, il suffit d'une seule ligne de code :

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

L'exemple ci-dessus enregistre le modèle dans le stockage local dans le navigateur. Consultez la model.save() documentation et le guide de sauvegarde et de chargement pour savoir comment enregistrer sur différents supports (par exemple, stockage de fichiers, IndexedDB , déclencher un téléchargement dans le navigateur, etc.)

Calques personnalisés

Les calques sont les éléments constitutifs d'un modèle. Si votre modèle effectue un calcul personnalisé, vous pouvez définir une couche personnalisée, qui interagit bien avec le reste des couches. Ci-dessous, nous définissons une couche personnalisée qui calcule la somme des carrés :

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

Pour le tester, on peut appeler la méthode apply() avec un tenseur concret :

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

IMPORTANT : Si vous ajoutez une couche personnalisée, vous perdez la possibilité de sérialiser un modèle.

Créer des modèles avec l'API Core

Au début de ce guide, nous avons mentionné qu'il existe deux façons de créer un modèle d'apprentissage automatique dans TensorFlow.js.

La règle générale est de toujours essayer d'utiliser l'API Layers en premier, car elle est calquée sur l'API Keras bien adoptée qui suit les meilleures pratiques et réduit la charge cognitive . L'API Layers propose également diverses solutions prêtes à l'emploi telles que l'initialisation du poids, la sérialisation des modèles, la formation à la surveillance, la portabilité et le contrôle de sécurité.

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

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

Les modèles de l'API Core ne sont que des fonctions qui prennent un ou plusieurs Tensors et renvoient un Tensor . 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).softmax();
}

Notez que dans l'API Core, nous sommes responsables de la création et de l'initialisation des poids du modèle. Chaque poids est soutenu par une Variable qui signale à TensorFlow.js que ces tenseurs peuvent être appris. Vous pouvez créer une Variable en utilisant tf.variable() et en transmettant un Tensor existant.

Dans ce guide, vous vous êtes familiarisé avec les différentes manières de créer un modèle à l'aide des Layers et de l'API Core. Ensuite, consultez le guide des modèles de formation pour savoir comment former un modèle.