Retour au blog

JavaScript + Machine Learning : Comment TensorFlow.js Apporte l'IA au Navigateur

Salut HaWkers, avez-vous deja imagine executer des modeles de Machine Learning complexes directement dans le navigateur, sans avoir besoin de serveur ou de Python ?

TensorFlow.js a democratise l'IA pour les developpeurs JavaScript. Vous pouvez entrainer des reseaux de neurones, faire de la reconnaissance d'image, traiter le langage naturel - tout tournant cote client avec une performance surprenante grace a WebGL et WebGPU. Et le mieux : vos utilisateurs gardent une confidentialite totale, car les donnees ne quittent jamais l'appareil.

Pourquoi le Machine Learning dans le Navigateur Est Revolutionnaire

Traditionnellement, Machine Learning signifiait Python, serveurs puissants, et APIs couteuses. TensorFlow.js a completement change la donne en apportant la meme puissance au JavaScript qui tourne deja dans des milliards de navigateurs.

Avantages du ML dans le Navigateur :

  • Confidentialite Totale - Les donnees ne quittent jamais l'appareil de l'utilisateur
  • Latence Zero - Pas de roundtrips vers le serveur
  • Scalabilite Infinie - Le traitement se fait chez le client
  • Fonctionne Hors Ligne - Apres le telechargement du modele
  • Reduction des Couts - Pas d'infrastructure serveur pour l'inference

Des entreprises comme Uber, Airbnb et Google utilisent TensorFlow.js en production pour des features qui traitent des millions de requetes par jour - tout dans le navigateur de l'utilisateur.

Votre Premier Modele avec TensorFlow.js

Creons un modele simple qui apprend la fonction XOR - un probleme classique de ML qui n'est pas lineairement separable.

// Importe TensorFlow.js
import * as tf from '@tensorflow/tfjs';

// Cree le modele de reseau de neurones
function createModel() {
  const model = tf.sequential();

  // Couche d'entree avec 2 neurones
  model.add(tf.layers.dense({
    units: 4,
    activation: 'relu',
    inputShape: [2]
  }));

  // Couche cachee
  model.add(tf.layers.dense({
    units: 4,
    activation: 'relu'
  }));

  // Couche de sortie
  model.add(tf.layers.dense({
    units: 1,
    activation: 'sigmoid'
  }));

  // Compile le modele
  model.compile({
    optimizer: tf.train.adam(0.1),
    loss: 'binaryCrossentropy',
    metrics: ['accuracy']
  });

  return model;
}

// Donnees d'entrainement pour XOR
const xorInputs = tf.tensor2d([
  [0, 0],
  [0, 1],
  [1, 0],
  [1, 1]
]);

const xorOutputs = tf.tensor2d([
  [0],
  [1],
  [1],
  [0]
]);

// Entraine le modele
async function trainModel() {
  const model = createModel();

  console.log('Debut de l\'entrainement...');

  await model.fit(xorInputs, xorOutputs, {
    epochs: 500,
    shuffle: true,
    callbacks: {
      onEpochEnd: (epoch, logs) => {
        if (epoch % 100 === 0) {
          console.log(`Epoch ${epoch}: loss = ${logs.loss.toFixed(4)}`);
        }
      }
    }
  });

  console.log('Entrainement termine!');

  return model;
}

// Teste le modele entraine
async function testModel(model) {
  const testInputs = [
    [0, 0],
    [0, 1],
    [1, 0],
    [1, 1]
  ];

  console.log('\nTest du modele:');

  for (const input of testInputs) {
    const inputTensor = tf.tensor2d([input]);
    const prediction = model.predict(inputTensor);
    const value = await prediction.data();

    console.log(
      `Input: ${input} => Prediction: ${value[0].toFixed(4)} => ` +
      `Resultat: ${value[0] > 0.5 ? 1 : 0}`
    );

    // Libere la memoire
    inputTensor.dispose();
    prediction.dispose();
  }
}

// Execute
async function main() {
  const model = await trainModel();
  await testModel(model);

  // Libere la memoire
  xorInputs.dispose();
  xorOutputs.dispose();
}

main();

Ce code entraine un reseau de neurones directement dans le navigateur ! Apres 500 epochs, le modele apprend parfaitement la fonction XOR.

Reconnaissance d'Images dans le Navigateur

Creons quelque chose de plus impressionnant : un classificateur d'images utilisant le transfer learning avec MobileNet.

// image-classifier.js
import * as tf from '@tensorflow/tfjs';
import * as mobilenet from '@tensorflow-models/mobilenet';

class ImageClassifier {
  constructor() {
    this.model = null;
  }

  // Charge le modele pre-entraine
  async load() {
    console.log('Chargement de MobileNet...');
    this.model = await mobilenet.load();
    console.log('Modele charge!');
  }

  // Classifie une image
  async classify(imageElement) {
    if (!this.model) {
      throw new Error('Modele non charge. Appelez load() d\'abord.');
    }

    // Fait la prediction
    const predictions = await this.model.classify(imageElement);

    return predictions.map(pred => ({
      className: pred.className,
      probability: (pred.probability * 100).toFixed(2) + '%'
    }));
  }

  // Extrait les features d'une image (utile pour le transfer learning)
  async getImageFeatures(imageElement) {
    if (!this.model) {
      throw new Error('Modele non charge.');
    }

    const activation = this.model.infer(imageElement, true);
    return activation;
  }
}

// Usage dans une application React
function ImageClassifierApp() {
  const [classifier, setClassifier] = useState(null);
  const [predictions, setPredictions] = useState([]);
  const [loading, setLoading] = useState(false);
  const imageRef = useRef(null);

  // Initialise le classificateur
  useEffect(() => {
    const initClassifier = async () => {
      const clf = new ImageClassifier();
      await clf.load();
      setClassifier(clf);
    };

    initClassifier();
  }, []);

  // Traite l'image selectionnee
  const handleImageUpload = async (event) => {
    const file = event.target.files[0];
    if (!file || !classifier) return;

    setLoading(true);

    // Cree un apercu de l'image
    const reader = new FileReader();
    reader.onload = async (e) => {
      const img = imageRef.current;
      img.src = e.target.result;

      // Attend le chargement de l'image
      img.onload = async () => {
        try {
          // Classifie l'image
          const preds = await classifier.classify(img);
          setPredictions(preds);
        } catch (error) {
          console.error('Erreur de classification:', error);
        } finally {
          setLoading(false);
        }
      };
    };

    reader.readAsDataURL(file);
  };

  return (
    <div className="image-classifier">
      <h2>Classificateur d'Images avec IA</h2>

      {!classifier ? (
        <div>Chargement du modele d'IA...</div>
      ) : (
        <>
          <input
            type="file"
            accept="image/*"
            onChange={handleImageUpload}
          />

          <div className="preview">
            <img
              ref={imageRef}
              alt="Preview"
              style={{ maxWidth: '400px', display: 'none' }}
            />
          </div>

          {loading && <div>Traitement de l'image...</div>}

          {predictions.length > 0 && (
            <div className="predictions">
              <h3>Resultats:</h3>
              <ul>
                {predictions.map((pred, idx) => (
                  <li key={idx}>
                    <strong>{pred.className}</strong>: {pred.probability}
                  </li>
                ))}
              </ul>
            </div>
          )}
        </>
      )}
    </div>
  );
}

export default ImageClassifierApp;

Ce code charge un modele pre-entraine et classifie des images en temps reel dans le navigateur ! Tout hors ligne, apres le premier telechargement.

Detection d'Objets en Temps Reel avec Webcam

Elevons le niveau : detection d'objets en video depuis la webcam utilisant COCO-SSD.

// object-detection.js
import * as tf from '@tensorflow/tfjs';
import * as cocoSsd from '@tensorflow-models/coco-ssd';

class ObjectDetector {
  constructor() {
    this.model = null;
    this.videoElement = null;
    this.canvasElement = null;
    this.ctx = null;
    this.animationId = null;
  }

  async initialize(videoElement, canvasElement) {
    this.videoElement = videoElement;
    this.canvasElement = canvasElement;
    this.ctx = canvasElement.getContext('2d');

    // Charge le modele COCO-SSD
    console.log('Chargement du modele de detection...');
    this.model = await cocoSsd.load();
    console.log('Modele charge!');

    // Demarre la webcam
    await this.startWebcam();
  }

  async startWebcam() {
    const stream = await navigator.mediaDevices.getUserMedia({
      video: { facingMode: 'user' },
      audio: false
    });

    this.videoElement.srcObject = stream;

    return new Promise((resolve) => {
      this.videoElement.onloadedmetadata = () => {
        this.videoElement.play();
        resolve();
      };
    });
  }

  async detectFrame() {
    if (!this.model || !this.videoElement) return;

    // Detecte les objets dans le frame actuel
    const predictions = await this.model.detect(this.videoElement);

    // Dessine sur le canvas
    this.ctx.clearRect(0, 0, this.canvasElement.width, this.canvasElement.height);
    this.ctx.drawImage(
      this.videoElement,
      0, 0,
      this.canvasElement.width,
      this.canvasElement.height
    );

    // Dessine les bounding boxes
    predictions.forEach(prediction => {
      const [x, y, width, height] = prediction.bbox;
      const confidence = (prediction.score * 100).toFixed(1);

      // Box
      this.ctx.strokeStyle = '#00ff00';
      this.ctx.lineWidth = 3;
      this.ctx.strokeRect(x, y, width, height);

      // Label
      this.ctx.fillStyle = '#00ff00';
      this.ctx.font = '18px Arial';
      this.ctx.fillText(
        `${prediction.class} (${confidence}%)`,
        x,
        y > 20 ? y - 5 : y + 20
      );
    });

    // Prochain frame
    this.animationId = requestAnimationFrame(() => this.detectFrame());
  }

  start() {
    this.detectFrame();
  }

  stop() {
    if (this.animationId) {
      cancelAnimationFrame(this.animationId);
    }

    if (this.videoElement && this.videoElement.srcObject) {
      const tracks = this.videoElement.srcObject.getTracks();
      tracks.forEach(track => track.stop());
    }
  }
}

Cette application detecte des objets en temps reel via webcam - personnes, animaux, objets - tout tournant dans le navigateur !

Performance : WebGL vs WebGPU

TensorFlow.js peut utiliser differents backends pour accelerer les calculs.

WebGL - Disponible dans tous les navigateurs modernes, utilise le GPU pour le calcul.

WebGPU - Nouvelle API qui offre jusqu'a 3x plus de performance que WebGL, encore experimentale.

CPU - Fallback quand le GPU n'est pas disponible.

// Configuration du backend
import * as tf from '@tensorflow/tfjs';

async function setupBackend() {
  // Essaie d'utiliser WebGPU d'abord (plus rapide)
  try {
    await tf.setBackend('webgpu');
    console.log('Utilisation de WebGPU (performance maximale)');
  } catch (e) {
    // Fallback vers WebGL
    try {
      await tf.setBackend('webgl');
      console.log('Utilisation de WebGL (bonne performance)');
    } catch (e) {
      // Fallback vers CPU
      await tf.setBackend('cpu');
      console.log('Utilisation du CPU (performance limitee)');
    }
  }

  await tf.ready();
  console.log(`Backend actif: ${tf.getBackend()}`);
}

setupBackend();

Gestion de la Memoire

Un aspect critique du ML dans le navigateur est la gestion de la memoire. Les Tensors doivent etre explicitement liberes.

// ❌ MAUVAIS - Cause une fuite memoire
function processImage(imageData) {
  const tensor = tf.browser.fromPixels(imageData);
  const normalized = tensor.div(255);
  const batched = normalized.expandDims(0);
  // Les tensors ne sont pas liberes!
  return model.predict(batched);
}

// ✅ CORRECT - Gere la memoire adequatement
function processImage(imageData) {
  return tf.tidy(() => {
    const tensor = tf.browser.fromPixels(imageData);
    const normalized = tensor.div(255);
    const batched = normalized.expandDims(0);
    // tf.tidy() libere automatiquement les tensors intermediaires
    return model.predict(batched);
  });
}

// Monitoring de la memoire
console.log(`Tensors en memoire: ${tf.memory().numTensors}`);
console.log(`Octets en memoire: ${tf.memory().numBytes}`);

L'Avenir du ML dans le Navigateur

Avec WebGPU devenant standard et le hardware mobile de plus en plus puissant, le ML dans le navigateur ne fera que croitre.

Les modeles deviennent plus petits et plus efficaces. Des techniques comme la quantification reduisent la taille de 4x sans perte significative de precision. Et des outils comme TensorFlow Lite permettent de convertir facilement des modeles Python vers JavaScript.

L'avenir est l'IA tournant partout - navigateurs, appareils IoT, edge computing - sans dependre de serveurs centralises.

Si vous etes fascine par la convergence des technologies modernes, je recommande de lire sur JavaScript et le Monde de l'IoT ou nous explorons comment JavaScript conquiert le monde physique.

C'est parti !

Commentaires (0)

Cet article n'a pas encore de commentaires. Soyez le premier!

Ajouter des commentaires