🌐 TensorFlow.js – Le ML dans le Navigateur
Guide complet IDEO-Lab : Tensors, Backends, Modèles Pré-entraînés & Conversion.
Vue d'ensemble
Bibliothèque JS (comme NumPy/Keras) pour le ML client-side.
JavaScript Client-SidePourquoi TF.js ?
Privacité (data reste client), Latence (0 réseau), Interactivité.
Privacy LatencyInstallation (Script/NPM)
<script src="..."> (CDN) ou npm install @tensorflow/tfjs.
Concept N°1 : Tensors
L'unité de base (NumPy-like). tf.tensor(), .print().
Concept N°2 : Backends
Où s'exécute le code : webgl (GPU), wasm, cpu.
Concept N°3 : API Modèles
Keras-like. tf.sequential(), tf.layers.dense().
Concept N°4 : Mémoire (GPU)
tf.tidy() (essentiel) et .dispose(). (WebGL n'a pas de GC).
Voie 1 : Modèles Pré-entraînés
@tensorflow-models. (Coco-SSD, MoveNet, FaceLandmarks).
Usage 1 : Détection d'Objets
cocoSsd.load(), model.detect(video).
Usage 2 : Pose (Corps)
movenet.load(), model.estimatePoses(video).
Usage 3 : Visage (Mesh)
faceLandmarksDetection.load(), .estimateFaces().
Usage 4 : Audio
speechCommands.create(). (Reconnaissance de mots).
Voie 2 : Conversion (Python)
tensorflowjs_converter (CLI) pour Keras/TF/TF Hub.
Conversion : Keras/TF
SavedModel (TF) ou .h5 (Keras) -> model.json + weights.bin.
Usage : loadGraphModel
tf.loadGraphModel("url/model.json"). model.execute(tensor).
Usage : TF Hub
Charger directement depuis TF Hub (tf.loadGraphModel(hub_url)).
Voie 3 : Entraînement (JS)
model.compile(optimizer, loss). (Keras-like).
Usage : model.fit()
await model.fit(xs, ys, {epochs: 10}). (Asynchrone).
Écosystème : Node.js
@tensorflow/tfjs-node (Bindings C) & -gpu (CUDA).
Vitrine (Cas d'usages)
Google (Teachable Machine), TF.js Demos, Apps React/Electron.
Teachable Machine WebcamLiens Utiles & Formation
tensorflow.org/js (Docs), Démos, @tensorflow-models.
Cheat-sheet
Workflow (Load/Convert, Predict, Train).
cheat WorkflowQu'est-ce que TensorFlow.js ?
TensorFlow.js (TF.js) est une bibliothèque **JavaScript** pour développer et entraîner des modèles de Machine Learning (ML).
Elle permet de faire du ML **directement dans le navigateur (client-side)** ou côté serveur (via **Node.js**).
TF.js fournit des API similaires à NumPy (Tensors) et Keras (Modèles) pour le monde JavaScript.
Diagramme : Python (Serveur) vs JS (Client)
(Voie 1: Python - Serveur)
+-----------+ +----------+ +-----------+
| Navigateur| ->| API REST | ->| Serveur |
| (Input) | | (Fetch) | | (Python/GPU)|
+-----------+ +----------+ +-----------+
| | (TF/PyTorch)
| (Latence) |
+--------------------------+
| (Retour)
(Voie 2: TF.js - Client)
+------------------------------------------+
| Navigateur (Input + Modèle TF.js + GPU) |
| (Exécution locale, pas d'API) |
+------------------------------------------+
| (Retour instantané) |
Pourquoi exécuter un modèle lourd (ML) dans un navigateur ?
| Avantage | Description |
|---|---|
| 🔒 Privacité (Privacy) | Le point clé. Les données (ex: webcam, micro) ne quittent **jamais** le navigateur de l'utilisateur. Pas de risque RGPD/GDPR. |
| ⚡ Latence (Latency) | Pas d'aller-retour réseau (API). L'inférence est instantanée (idéal pour la vidéo temps-réel). |
| 💻 Interactivité | Accès direct aux capteurs (Webcam, Micro, Gyroscope) via les APIs du navigateur. |
| 💸 Coût (Serveur) | Le calcul (souvent GPU via WebGL) est effectué par le **client**. Zéro coût de GPU côté serveur. |
| 🚀 Accessibilité | Pas d'installation (Python, CUDA...). N'importe qui peut accéder à l'app via une URL. |
1. <script> (CDN)
Pour les pages HTML simples. L'objet tf est ajouté à la window.
2. npm (React, Vue, Node.js)
Pour les applications JavaScript modernes (avec import).
# 1. Installer le Core npm install @tensorflow/tfjs # 2. (Optionnel) Installer un modèle npm install @tensorflow-models/coco-ssd # 3. Utiliser (app.js) import * as tf from '@tensorflow/tfjs'; import * as cocoSsd from '@tensorflow-models/coco-ssd'; const t = tf.tensor([1, 2]); t.print();
L'API de TF.js est (presque) identique à celle de NumPy ou TensorFlow (Python). L'unité de base est le Tensor.
Création & Opérations
import * as tf from '@tensorflow/tfjs'; // 1. Création const t1 = tf.tensor([1, 2, 3]); // 1D const t2 = tf.tensor2d([[1, 2], [3, 4]]); // 2D // 2. Attributs (similaires à NumPy) console.log(t2.shape); // [2, 2] console.log(t2.dtype); // 'float32' (défaut) // 3. Opérations (Vectorisées) const a = tf.tensor([1, 2]); const b = tf.tensor([3, 4]); const c = a.add(b); // c = [4, 6] const d = a.mul(b); // c = [3, 8] // 4. Affichage c.print(); // (Affiche dans la console) // 5. Récupérer les données (JS natif) const data = await c.data(); // (Asynchrone!) console.log(data); // Float32Array[4, 6]
TF.js choisit automatiquement le meilleur "backend" (moteur d'exécution) disponible.
| Backend | Package (NPM) | Description |
|---|---|---|
webgl (Défaut) | @tensorflow/tfjs-backend-webgl | Le plus rapide (GPU). Utilise le GPU du client via WebGL. |
wasm | @tensorflow/tfjs-backend-wasm | WebAssembly. Plus rapide que JS (cpu), plus lent que webgl. (Bon fallback). |
cpu | @tensorflow/tfjs-backend-cpu | JavaScript pur. Le plus lent, mais le plus compatible. |
node | @tensorflow/tfjs-node | (Pour Node.js) Bindings C (CPU) ou CUDA (GPU). |
Changer de Backend (Ex: Forcer WASM)
import * as tf from '@tensorflow/tfjs';
import '@tensorflow/tfjs-backend-wasm';
async function setup() {
// (Attendre que WASM soit prêt)
await tf.setBackend('wasm');
console.log(tf.getBackend()); // 'wasm'
}
setup();
TF.js réplique l'API tf.keras, vous permettant de définir des modèles (ou des couches) directement en JavaScript.
Exemple (tf.sequential)
const model = tf.sequential();
// 1. Ajouter une couche Dense (Hidden)
model.add(tf.layers.dense({
inputShape: [784], // (Input)
units: 64,
activation: 'relu'
}));
// 2. Ajouter une couche de sortie
model.add(tf.layers.dense({
units: 10,
activation: 'softmax'
}));
// 3. Visualiser
model.summary();
tf.tidy)CONCEPT LE PLUS IMPORTANT (et le plus piégeux) :
Le Garbage Collector (GC) de JavaScript nettoie la mémoire JS (ex: a, b), mais **PAS** la mémoire GPU (WebGL) (les données du Tensor).
Si vous créez des Tensors dans une boucle (ex: requestAnimationFrame), vous aurez une **FUITE MÉMOIRE (GPU)** et le navigateur plantera.
1. .dispose() (Manuel)
function monCalcul() {
const a = tf.tensor([1, 2]);
const b = tf.tensor([3, 4]);
const c = a.add(b);
// ... utiliser c ...
// (Nettoyage manuel)
a.dispose();
b.dispose();
c.dispose();
}
2. tf.tidy() (Automatique)
tf.tidy() "nettoie" (dispose) automatiquement **tous** les Tensors intermédiaires créés dans la fonction, *sauf* celui retourné (return).
function monCalcul() {
// 'c' est retourné, il n'est pas "disposé"
const c = tf.tidy(() => {
const a = tf.tensor([1, 2]);
const b = tf.tensor([3, 4]);
// (a et b seront "disposés"
// automatiquement à la fin)
return a.add(b);
});
// ... utiliser c ...
c.dispose(); // (Nettoyer c manuellement)
}
@tensorflow-models)C'est la voie "facile". Google fournit une collection de modèles SOTA (@tensorflow-models) "plug-and-play" (souvent optimisés pour le web).
Paquet (@tensorflow-models/...) | Tâche |
|---|---|
coco-ssd | Détection d'Objets (90 classes). |
mobilenet | Classification d'Images (1000 classes). |
posenet / movenet | Estimation de Pose (Corps). |
face-landmarks-detection | Détection de points-clés du visage (Mesh). |
speech-commands | Reconnaissance de mots (Audio). |
universal-sentence-encoder | Embeddings de texte (NLP). |
(Nécessite @tensorflow/tfjs et @tensorflow-models/coco-ssd).
// (Ex: dans une boucle requestAnimationFrame) // 1. Charger le modèle (1 fois) const model = await cocoSsd.load(); // (videoEl =
(Nécessite @tensorflow-models/pose-detection). (MoveNet est plus récent/rapide que PoseNet).
import * as posedetection from '@tensorflow-models/pose-detection';
// 1. Charger le détecteur
const detector = await posedetection.createDetector(
posedetection.SupportedModels.MoveNet
);
async function detectPose(videoEl) {
// 2. Estimer
const poses = await detector.estimatePoses(videoEl);
// 3. Utiliser
// poses = [ { keypoints: [...] } ]
// keypoints = [
// { x: ..., y: ..., score: ..., name: 'left_eye' },
// { x: ..., y: ..., score: ..., name: 'right_shoulder' },
// ... (17 points)
// ]
// (Dessiner le squelette sur un (Nécessite @tensorflow-models/face-landmarks-detection). (Filtres type "Snapchat").
import * as faceLandmarksDetection from '@tensorflow-models/face-landmarks-detection';
// 1. Charger le modèle
const model = await faceLandmarksDetection.load(
faceLandmarksDetection.SupportedPackages.mediapipeFacemesh
);
async function detectFace(videoEl) {
// 2. Estimer
const faces = await model.estimateFaces({
input: videoEl
});
// 3. Utiliser
// faces = [ { keypoints: [...] } ]
// keypoints = [ (468 points (x, y, z)) ]
// (Dessiner le "mesh" (maillage) sur un (Nécessite @tensorflow-models/speech-commands). Reconnaissance de mots-clés (ex: "up", "down", "yes", "no").
import * as speechCommands from '@tensorflow-models/speech-commands';
// 1. Créer le reconnaisseur
// ('BROWSER_FFT' -> utilise le micro)
const recognizer = speechCommands.create('BROWSER_FFT');
// 2. S'assurer que le modèle est chargé
await recognizer.ensureModelLoaded();
// 3. Écouter (Callback)
recognizer.listen(result => {
// result.scores = [0.1, 0.9, 0.05, ...]
// (Trouver l'index du score max)
const bestMatchIndex = result.scores.indexOf(Math.max(...result.scores));
const word = recognizer.wordLabels()[bestMatchIndex];
console.log(word); // (ex: "up", "noise", "down")
}, { probabilityThreshold: 0.75 }); // (Seuil de confiance)
Voie la plus courante : Entraîner le modèle en Python (Keras/TF), puis le **convertir** au format TF.js (Graph Model) pour l'inférence (.predict) dans le navigateur.
Outil (Python) : tensorflowjs_converter
# 1. Installer le convertisseur (en Python) pip install tensorflowjs
Le convertisseur (CLI) prend le modèle Python (H5 ou SavedModel) et génère un model.json (Topologie/Graphe) et des groupX-shardXofX.bin (Poids).
1. Keras (.h5)
# (Modèle Keras .h5 ou .keras)
tensorflowjs_converter \
--input_format keras \
./mon_modele.h5 \
./tfjs_output_folder/
2. TF (SavedModel)
# (Dossier SavedModel de TensorFlow)
tensorflowjs_converter \
--input_format tf_saved_model \
./mon_saved_model_dossier/ \
./tfjs_output_folder/
tf.loadGraphModel()tf.loadGraphModel (recommandé) charge le modèle converti (model.json). Il est optimisé pour l'inférence (pas d'entraînement).
import * as tf from '@tensorflow/tfjs';
// 1. Charger le modèle (depuis votre serveur)
const model = await tf.loadGraphModel("url/tfjs_output_folder/model.json");
// 2. Préparer l'input (Tensor)
const inputTensor = tf.tensor2d([[1, 2, 3, 4]], [1, 4]);
// 3. Prédire (Inférence)
// (Utiliser tf.tidy() !)
const result = tf.tidy(() => {
// .execute() (pour GraphModel)
// (vs .predict() pour LayersModel)
const outputTensor = model.execute(inputTensor);
return outputTensor;
});
result.print();
TF Hub héberge de nombreux modèles (ex: MobileNet) déjà au format TF.js. On peut les charger directement via URL (pas de conversion manuelle).
const MOBILENET_URL =
"https://tfhub.dev/google/tfjs-model/imagenet/mobilenet_v2_100_224/classification/3/default/1";
// 1. Charger
const model = await tf.loadGraphModel(MOBILENET_URL, {fromTFHub: true});
// 2. Prédire
// (Input shape [1, 224, 224, 3])
const inputTensor = tf.zeros([1, 224, 224, 3]);
const preds = model.execute(inputTensor);
preds.print();
.compile())On peut entraîner (ou fine-tuner) un modèle Keras-like (tf.LayersModel) directement en JS. L'API est identique à Keras (Python).
// (model = tf.sequential(...) (voir 2.2))
// 1. Compiler (Configurer l'entraînement)
model.compile({
// (Optimiseur)
optimizer: tf.train.adam(0.01), // (ou 'adam')
// (Loss)
loss: 'meanSquaredError', // (ou 'categoricalCrossentropy')
// (Métriques)
metrics: ['accuracy']
});
model.summary();
model.fit().fit() (ou .fitDataset()) lance la boucle d'entraînement. C'est **asynchrone** (await) pour ne pas bloquer le navigateur.
async function train() {
// (Données d'entraînement (Tensors))
const xs = tf.tensor2d(...);
const ys = tf.tensor2d(...);
// 1. Entraîner (Asynchrone)
const history = await model.fit(xs, ys, {
epochs: 10,
batchSize: 32,
validationSplit: 0.2,
callbacks: {
// (Callback pour logger la perte à chaque epoch)
onEpochEnd: (epoch, logs) => {
console.log(`Epoch ${epoch}: Loss = ${logs.loss}`);
}
}
});
console.log(history.history.loss);
}
tfjs-node)Pour utiliser TF.js côté serveur (ex: dans une API), on utilise les backends Node.js (qui sont des bindings C/C++).
| Paquet (NPM) | Description |
|---|---|
@tensorflow/tfjs-node | Exécute sur CPU (utilise les bindings C de TensorFlow). |
@tensorflow/tfjs-node-gpu | Exécute sur GPU (utilise les bindings CUDA de TensorFlow). |
// (Backend: Node.js) // (Nécessite 'npm install @tensorflow/tfjs-node') // (Importe le backend) import * as tf from '@tensorflow/tfjs-node'; // (Le code est identique au JS client) const a = tf.tensor([1, 2]); const b = tf.tensor([3, 4]); const c = a.add(b); c.print(); // (Pas de tf.tidy() requis, // la mémoire des Tensors est gérée // par le C++, comme en Python)
TF.js est utilisé pour des applications interactives, "temps-réel", où la privacité est clé.
| Projet | Cas d'usage |
|---|---|
| Google Teachable Machine | (Projet Google) Entraîne (model.fit) des modèles simples (Image, Son) dans le navigateur. |
| Google Meet / Zoom (Web) | Utilise des modèles (type FaceMesh) pour le floutage d'arrière-plan (Segmentation) et les filtres faciaux. |
| Démos (Webcam) | (Ex: tensorflow.org/js/demos) Contrôler un jeu (ex: Pac-Man) avec sa tête (PoseNet). |
| Applications Electron | Utilise tfjs-node (ou WebGL) pour des applications ML desktop (ex: éditeurs d'images). |
Ressources pour apprendre et travailler avec TensorFlow.js.
| Site | Description |
|---|---|
| tensorflow.org/js | Le site officiel (Docs, Démos, API). |
GitHub (@tensorflow-models) | (github.com/tensorflow/tfjs-models) Le code source des modèles pré-entraînés (Coco-SSD, etc.). |
| TF Hub (tfhub.dev) | Trouver des modèles (GraphModels) compatibles TF.js. |
| Google (Teachable Machine) | (teachablemachine.withgoogle.com) Exporte des modèles Keras -> TF.js. |
Voie 1 : Pré-entraîné (Facile)
import * as cocoSsd from '@tensorflow-models/coco-ssd';
// 1. Load
const model = await cocoSsd.load();
// 2. Predict (Tidy!)
const preds = tf.tidy(() => {
const img = tf.browser.fromPixels(imgEl);
return model.detect(img);
});
// preds = [{bbox, class, score}]
Voie 2 : Converti (Python->JS)
import * as tf from '@tensorflow/tfjs';
// 1. Convert (Python)
// tensorflowjs_converter ...
// 2. Load (JS)
const model = await tf.loadGraphModel(
'model.json'
);
// 3. Predict (Tidy!)
const result = tf.tidy(() => {
const input = tf.tensor(...);
return model.execute(input);
});
Voie 3 : Entraîner (JS)
import * as tf from '@tensorflow/tfjs';
// 1. Define
const model = tf.sequential();
model.add(tf.layers.dense({
inputShape: [1], units: 1
}));
// 2. Compile
model.compile({
optimizer: 'sgd',
loss: 'mse'
});
// 3. Train
const xs = tf.tensor2d([1, 2], [2, 1]);
const ys = tf.tensor2d([1, 2], [2, 1]);
await model.fit(xs, ys, {
epochs: 10
});
