Classificateur d'images TensorFlow.js avec apprentissage par transfert

Dans cet atelier de programmation, vous allez apprendre à créer une Teachable Machine simple, c'est-à-dire un classificateur d'images personnalisé que vous allez entraîner à la volée dans un navigateur à l'aide de TensorFlow.js, une bibliothèque de machine learning puissante et flexible pour JavaScript. Pour commencer, vous allez charger et exécuter le modèle populaire pré-entraîné MobileNet pour permettre la classification d'images dans le navigateur. Ensuite, vous allez utiliser une technique appelée "apprentissage par transfert" pour amorcer l'entraînement de la machine avec le modèle MobileNet pré-entraîné, avant de le personnaliser pour votre application.

Nous n'aborderons pas les bases théoriques sur lesquelles repose l'application Teachable Machine. Si vous souhaitez en savoir plus à ce sujet, consultez ce tutoriel.

Objectifs de l'atelier

  • Charger un modèle MobileNet pré-entraîné et effectuer une prédiction sur de nouvelles données
  • Effectuer des prédictions via une webcam
  • Utiliser les activations intermédiaires de MobileNet pour appliquer l'apprentissage par transfert à un nouvel ensemble de classes définies à la volée avec la webcam

C'est parti !

Pour suivre cet atelier de programmation, vous aurez besoin :

  1. de Chrome ou d'un autre navigateur récent (version à jour) ;
  2. d'un éditeur de texte s'exécutant localement sur votre ordinateur ou sur le Web via Codepen ou Glitch, par exemple ;
  3. d'une bonne connaissance des langages HTML, CSS et JavaScript ainsi que des Outils pour les développeurs Chrome (ou des outils de développement de votre navigateur préféré) ;
  4. d'une bonne compréhension du concept de réseau de neurones. Si vous avez besoin d'une présentation ou d'un rappel, vous pouvez regarder cette vidéo de 3blue1brown ou cette vidéo sur le deep learning en JavaScript d'Ashi Krishnan.

Ouvrez le fichier index.html dans un éditeur et ajoutez le contenu suivant :

<html>
  <head>
    <!-- Load the latest version of TensorFlow.js -->
    <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script>
    <script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/mobilenet"></script>
  </head>
  <body>
    <div id="console"></div>
    <!-- Add an image that we will use to test -->
    <img id="img" crossorigin src="https://i.imgur.com/JlUvsxa.jpg" width="227" height="227"/>
    <!-- Load index.js after the content of the page -->
    <script src="index.js"></script>
  </body>
</html>

Ensuite, ouvrez/créez un fichier index.js dans un éditeur de code et incluez le code suivant :

let net;

async function app() {
  console.log('Loading mobilenet..');

  // Load the model.
  net = await mobilenet.load();
  console.log('Successfully loaded model');

  // Make a prediction through the model on our image.
  const imgEl = document.getElementById('img');
  const result = await net.classify(imgEl);
  console.log(result);
}

app();

Pour lancer la page Web, il vous suffit d'ouvrir le fichier index.html dans un navigateur Web. Si vous utilisez Cloud Console, actualisez la page d'aperçu.

Vous devriez voir la photo d'un chien, et sous "Outils pour développeurs" dans la console JavaScript, les meilleures prédictions de MobileNet. Notez que le téléchargement du modèle peut prendre un certain temps.

L'image a-t-elle été correctement classée ?

Sachez que cela fonctionne également sur les téléphones mobiles.

À présent, ajoutons plus d'interactions en temps réel. Nous allons configurer la webcam pour réaliser des prédictions sur les images provenant de celle-ci.

Commencez par configurer l'élément Vidéo de la webcam. Ouvrez le fichier index.html, ajoutez la ligne suivante dans la section <body>, puis supprimez la balise <img> servant à charger l'image du chien :

<video autoplay playsinline muted id="webcam" width="224" height="224"></video>

Ouvrez le fichier index.js et ajoutez l'élément Webcam tout en haut du fichier.

const webcamElement = document.getElementById('webcam');

Maintenant, dans la fonction app() que vous avez ajoutée précédemment, vous pouvez supprimer la prédiction via l'image et la remplacer par une boucle infinie qui effectue des prédictions via l'élément Webcam.

async function app() {
  console.log('Loading mobilenet..');

  // Load the model.
  net = await mobilenet.load();
  console.log('Successfully loaded model');

  // Create an object from Tensorflow.js data API which could capture image
  // from the web camera as Tensor.
  const webcam = await tf.data.webcam(webcamElement);
  while (true) {
    const img = await webcam.capture();
    const result = await net.classify(img);

    document.getElementById('console').innerText = `
      prediction: ${result[0].className}\n
      probability: ${result[0].probability}
    `;
    // Dispose the tensor to release the memory.
    img.dispose();

    // Give some breathing room by waiting for the next animation frame to
    // fire.
    await tf.nextFrame();
  }
}

Sur la page Web., ouvrez la console. Vous devriez maintenant voir une prédiction MobileNet avec une probabilité associée à chaque image recueillie via la webcam.

Ces prédictions peuvent sembler absurdes, car l'ensemble de données ImageNet ne ressemble pas vraiment aux images généralement capturées par une webcam. Vous pouvez placer votre téléphone avec la photo d'un chien devant la webcam de votre ordinateur portable pour vérifier que l'algorithme fonctionne.

À présent, rendons ce classificateur d'images encore plus utile. Nous allons créer un classificateur d'objets personnalisé à trois classes en utilisant la webcam. Nous allons établir une classification via MobileNet, mais cette fois, nous allons utiliser une représentation interne (activation) du modèle pour une image de webcam donnée et l'utiliser à des fins de classification.

Nous allons utiliser un module appelé "classificateur de k plus proches voisins" (K-Nearest Neighbors, KNN), qui nous permettra de classer efficacement les images de la webcam (ou plutôt leur activation MobileNet) dans différentes catégories (ou "classes"). Lorsque l'utilisateur demandera une prédiction, nous choisirons la classe qui présente l'activation la plus proche de celle pour laquelle nous effectuons la prédiction.

Ajoutez le classificateur KNN à la fin des importations dans la balise <head> du fichier index.html (vous aurez toujours besoin de MobileNet, alors ne supprimez pas cette importation) :

...
<script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/knn-classifier"></script>
...

Ajoutez trois boutons pour chacun des boutons du fichier index.html sous l'élément Vidéo. Ils vous permettront d'ajouter des images d'entraînement au modèle.

...
<button id="class-a">Add A</button>
<button id="class-b">Add B</button>
<button id="class-c">Add C</button>
...

En haut du fichier index.js, créez le classificateur :

const classifier = knnClassifier.create();

Mettez à jour le fonctionnement de l'application :

async function app() {
  console.log('Loading mobilenet..');

  // Load the model.
  net = await mobilenet.load();
  console.log('Successfully loaded model');

  // Create an object from Tensorflow.js data API which could capture image
  // from the web camera as Tensor.
  const webcam = await tf.data.webcam(webcamElement);

  // Reads an image from the webcam and associates it with a specific class
  // index.
  const addExample = async classId => {
    // Capture an image from the web camera.
    const img = await webcam.capture();

    // Get the intermediate activation of MobileNet 'conv_preds' and pass that
    // to the KNN classifier.
    const activation = net.infer(img, true);

    // Pass the intermediate activation to the classifier.
    classifier.addExample(activation, classId);

    // Dispose the tensor to release the memory.
    img.dispose();
  };

  // When clicking a button, add an example for that class.
  document.getElementById('class-a').addEventListener('click', () => addExample(0));
  document.getElementById('class-b').addEventListener('click', () => addExample(1));
  document.getElementById('class-c').addEventListener('click', () => addExample(2));

  while (true) {
    if (classifier.getNumClasses() > 0) {
      const img = await webcam.capture();

      // Get the activation from mobilenet from the webcam.
      const activation = net.infer(img, 'conv_preds');
      // Get the most likely class and confidence from the classifier module.
      const result = await classifier.predictClass(activation);

      const classes = ['A', 'B', 'C'];
      document.getElementById('console').innerText = `
        prediction: ${classes[result.label]}\n
        probability: ${result.confidences[result.label]}
      `;

      // Dispose the tensor to release the memory.
      img.dispose();
    }

    await tf.nextFrame();
  }
}

Lorsque vous chargez la page index.html, vous pouvez utiliser des objets courants ou des mimiques/gestes pour enregistrer des images de chacune des trois classes. Chaque fois que vous cliquez sur l'un des boutons "Add" (Ajouter), une image est ajoutée à cette classe comme exemple d'entraînement. Pendant ce temps, le modèle continue d'effectuer des prédictions sur les images de la webcam et affiche les résultats en temps réel.

Maintenant, essayez d'ajouter une autre classe qui ne représente aucune action.

Dans cet atelier de programmation, vous avez implémenté une application Web simple de machine learning à l'aide de TensorFlow.js. Vous avez chargé et utilisé un modèle MobileNet pré-entraîné pour classer des images provenant d'une webcam. Vous avez ensuite personnalisé le modèle pour classer les images dans trois catégories personnalisées.

Rendez-vous sur js.tensorflow.org pour voir d'autres exemples et démonstrations de codage, et apprendre à utiliser TensorFlow.js dans vos applications.