TensorFlow.js
Maîtrisez le Machine Learning dans le navigateur
Introduction à TensorFlow.js
TensorFlow.js est une bibliothèque JavaScript pour le machine learning développée par Google. Elle permet d'entraîner et d'exécuter des modèles de ML directement dans le navigateur ou Node.js.
Dans le Navigateur
Exécutez des modèles ML sans serveur backend, directement côté client avec WebGL.
Performance GPU
Accélération GPU via WebGL pour des calculs rapides et efficaces.
Confidentialité
Les données restent sur l'appareil de l'utilisateur, sans transmission au serveur.
Réutilisation
Importez des modèles Python TensorFlow/Keras existants.
Installation et Configuration
Via CDN (Recommandé pour débuter)
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@4.11.0"></script>
<script>
// Vérifier que TensorFlow.js est chargé
console.log('TensorFlow.js version:', tf.version.tfjs);
</script>
Via NPM
npm install @tensorflow/tfjs
import * as tf from '@tensorflow/tfjs';
console.log('TensorFlow.js version:', tf.version.tfjs);
Les Tenseurs — Concept Fondamental
Un tenseur est une structure de données multi-dimensionnelle, similaire à un tableau. C'est l'unité de base de TensorFlow.js.
Scalaire (0D)
Une seule valeur5
Vecteur (1D)
Tableau 1D[1, 2, 3]
Matrice (2D)
Tableau 2D[[1,2], [3,4]]
Tenseur (3D+)
Tableau 3D+Images RGB
Création de Tenseurs
// Scalaire (0D)
const scalar = tf.scalar(42);
scalar.print(); // Tensor 42
// Vecteur (1D)
const vector = tf.tensor1d([1, 2, 3, 4, 5]);
vector.print(); // Tensor [1, 2, 3, 4, 5]
// Matrice (2D)
const matrix = tf.tensor2d([[1, 2], [3, 4], [5, 6]], [3, 2]);
matrix.print();
// Tenseur 3D (ex: image RGB 2x2 pixels)
const image = tf.tensor3d([
[[255, 0, 0], [0, 255, 0]],
[[0, 0, 255], [255, 255, 0]]
], [2, 2, 3]);
// Depuis un tableau avec shape
const fromArray = tf.tensor([1, 2, 3, 4], [2, 2]);
fromArray.print(); // [[1, 2], [3, 4]]
tensor.dispose() ou tf.tidy() pour libérer la mémoire.
// ❌ Mauvaise pratique — fuite mémoire
const a = tf.tensor([1, 2, 3]);
const b = tf.tensor([4, 5, 6]);
const c = a.add(b);
// ✅ Bonne pratique avec dispose
const a = tf.tensor([1, 2, 3]);
const b = tf.tensor([4, 5, 6]);
const c = a.add(b);
a.dispose();
b.dispose();
// ✅ Meilleure pratique avec tidy
const result = tf.tidy(() => {
const a = tf.tensor([1, 2, 3]);
const b = tf.tensor([4, 5, 6]);
return a.add(b);
});
// a et b sont automatiquement nettoyés
result.print();
result.dispose();
Opérations sur les Tenseurs
Opérations Mathématiques de Base
const a = tf.tensor([1, 2, 3, 4]);
const b = tf.tensor([5, 6, 7, 8]);
a.add(b).print(); // [6, 8, 10, 12]
a.sub(b).print(); // [-4, -4, -4, -4]
a.mul(b).print(); // [5, 12, 21, 32]
a.div(b).print(); // [0.2, 0.33, 0.43, 0.5]
a.pow(tf.scalar(2)).print(); // [1, 4, 9, 16]
tf.sqrt(a).print(); // [1, 1.41, 1.73, 2]
Opérations d'Agrégation
const tensor = tf.tensor2d([[1, 2, 3], [4, 5, 6]]);
tensor.sum().print(); // 21
tensor.mean().print(); // 3.5
tensor.max().print(); // 6
tensor.min().print(); // 1
// Somme par axe
tensor.sum(0).print(); // [5, 7, 9] — colonnes
tensor.sum(1).print(); // [6, 15] — lignes
Transformation de Forme
const original = tf.tensor([1, 2, 3, 4, 5, 6]);
original.reshape([2, 3]).print(); // [[1,2,3], [4,5,6]]
const matrix = tf.tensor2d([[1, 2, 3], [4, 5, 6]]);
matrix.transpose().print(); // [[1,4], [2,5], [3,6]]
matrix.flatten().print(); // [1, 2, 3, 4, 5, 6]
original.expandDims(0); // shape: [1, 6]
Créer des Modèles
TensorFlow.js propose deux API pour créer des modèles :
1. API Sequential (Plus simple)
Empilez des couches les unes sur les autres de manière linéaire.
const model = tf.sequential();
model.add(tf.layers.dense({
units: 32, // 32 neurones
activation: 'relu', // Fonction d'activation
inputShape: [10] // 10 features en entrée
}));
model.add(tf.layers.dense({
units: 16,
activation: 'relu'
}));
model.add(tf.layers.dense({
units: 1, // 1 sortie
activation: 'sigmoid' // Classification binaire
}));
model.summary();
2. API Functional (Plus flexible)
Pour des architectures complexes avec plusieurs entrées/sorties.
const input = tf.input({shape: [10]});
const dense1 = tf.layers.dense({units: 32, activation: 'relu'}).apply(input);
const dense2 = tf.layers.dense({units: 16, activation: 'relu'}).apply(dense1);
const output = tf.layers.dense({units: 1, activation: 'sigmoid'}).apply(dense2);
const model = tf.model({inputs: input, outputs: output});
model.summary();
Types de Couches Courantes
Dense
Fully connected — chaque neurone relié à tous.
Dropout
Désactive aléatoirement des neurones (anti-surapprentissage).
Conv2D
Convolution 2D pour traiter les images.
MaxPooling2D
Réduit la dimensionnalité spatiale.
Entraînement d'un Modèle
Étape 1 : Compiler le Modèle
model.compile({
optimizer: 'adam', // Algorithme d'optimisation
loss: 'binaryCrossentropy', // Fonction de perte
metrics: ['accuracy'] // Métriques à suivre
});
// Autres optimiseurs : 'sgd', 'rmsprop', 'adagrad'
// Autres losses : 'meanSquaredError', 'categoricalCrossentropy'
Étape 2 : Préparer les Données
// Features
const xs = tf.tensor2d([[0,0], [0,1], [1,0], [1,1]]);
// Labels (XOR)
const ys = tf.tensor2d([[0], [1], [1], [0]]);
// Normalisation (important!)
const xsNormalized = xs.div(xs.max());
Étape 3 : Entraîner
async function trainModel() {
const history = await model.fit(xs, ys, {
epochs: 100,
batchSize: 4,
validationSplit: 0.2,
callbacks: {
onEpochEnd: (epoch, logs) => {
console.log(`Epoch ${epoch}: loss = ${logs.loss.toFixed(4)}`);
}
}
});
console.log('Entraînement terminé!');
}
trainModel();
Étape 4 : Prédictions
const input = tf.tensor2d([[0, 0]]);
const prediction = model.predict(input);
prediction.print();
const value = await prediction.data();
console.log('Prédiction:', value[0]);
input.dispose();
prediction.dispose();
Exemple Complet : Régression Linéaire
Créons un modèle qui apprend la relation y = 2x + 1
async function linearRegressionExample() {
// 1. Modèle
const model = tf.sequential();
model.add(tf.layers.dense({ units: 1, inputShape: [1] }));
// 2. Compiler
model.compile({
optimizer: tf.train.sgd(0.1),
loss: 'meanSquaredError'
});
// 3. Données (y = 2x + 1)
const xs = tf.tensor2d([1, 2, 3, 4, 5], [5, 1]);
const ys = tf.tensor2d([3, 5, 7, 9, 11], [5, 1]);
// 4. Entraîner
await model.fit(xs, ys, {
epochs: 500,
callbacks: {
onEpochEnd: (epoch, logs) => {
if (epoch % 100 === 0)
console.log(`Epoch ${epoch}: loss = ${logs.loss.toFixed(4)}`);
}
}
});
// 5. Tester
for (const x of [6, 7, 10]) {
const pred = model.predict(tf.tensor2d([x], [1, 1]));
const val = (await pred.data())[0];
console.log(`x=${x} → prédit=${val.toFixed(2)}, attendu=${2*x+1}`);
pred.dispose();
}
// 6. Sauvegarder
await model.save('localstorage://linear-model');
}
linearRegressionExample();
Classification Multi-Classes
Exemple : Classifier des fleurs Iris (3 classes)
async function irisClassification() {
const trainingData = tf.tensor2d([
[5.1, 3.5, 1.4, 0.2], // Setosa
[4.9, 3.0, 1.4, 0.2],
[7.0, 3.2, 4.7, 1.4], // Versicolor
[6.4, 3.2, 4.5, 1.5],
[6.3, 3.3, 6.0, 2.5], // Virginica
[5.8, 2.7, 5.1, 1.9]
]);
// Labels one-hot
const labels = tf.tensor2d([
[1,0,0], [1,0,0], // Setosa
[0,1,0], [0,1,0], // Versicolor
[0,0,1], [0,0,1] // Virginica
]);
const model = tf.sequential();
model.add(tf.layers.dense({units:10, activation:'relu', inputShape:[4]}));
model.add(tf.layers.dense({units:10, activation:'relu'}));
model.add(tf.layers.dense({units:3, activation:'softmax'}));
model.compile({
optimizer: 'adam',
loss: 'categoricalCrossentropy',
metrics: ['accuracy']
});
await model.fit(trainingData, labels, {epochs: 100, shuffle: true});
const test = tf.tensor2d([[5.0, 3.5, 1.3, 0.3]]);
const pred = model.predict(test);
const probs = await pred.data();
const classes = ['Setosa', 'Versicolor', 'Virginica'];
const max = probs.indexOf(Math.max(...probs));
console.log('Prédiction:', classes[max]);
console.log('Probabilités:', probs);
}
irisClassification();
softmax. Chaque label → vecteur : [1,0,0], [0,1,0], [0,0,1].
Modèles Pré-entraînés
TensorFlow.js propose des modèles pré-entraînés prêts à l'emploi :
MobileNet — Classification d'Images
async function classifyImage() {
const model = await mobilenet.load();
const img = document.getElementById('imageToClassify');
const predictions = await model.classify(img);
predictions.forEach(pred => {
console.log(`${pred.className}: ${(pred.probability * 100).toFixed(2)}%`);
});
}
PoseNet — Détection de Pose
async function detectPose() {
const net = await posenet.load();
const video = document.getElementById('video');
const pose = await net.estimateSinglePose(video);
console.log('Points clés:', pose.keypoints);
}
Toxicity — Détection de Contenu Toxique
async function checkToxicity() {
const model = await toxicity.load(0.9);
const sentences = ['You are awesome!', 'I hate you'];
const predictions = await model.classify(sentences);
predictions.forEach(p => {
p.results.forEach(r => {
if (r.match) console.log(`⚠️ ${r.label} détecté`);
});
});
}
MobileNet
Classification d'images (1000 classes)
PoseNet
Détection de poses humaines
Face-API
Détection et reconnaissance faciale
Toxicity
Détection de contenu toxique
BodyPix
Segmentation de personnes
Speech Commands
Reconnaissance vocale
Techniques Avancées
Transfer Learning
Réutilisez un modèle pré-entraîné et adaptez-le à votre cas d'usage.
async function transferLearning() {
// Charger MobileNet
const mobilenet = await tf.loadLayersModel(
'https://storage.googleapis.com/tfjs-models/tfjs/mobilenet_v1_0.25_224/model.json'
);
// Tronquer à une couche intermédiaire
const layer = mobilenet.getLayer('conv_pw_13_relu');
const truncated = tf.model({
inputs: mobilenet.inputs,
outputs: layer.output
});
// Ajouter vos couches personnalisées
const newModel = tf.sequential();
newModel.add(truncated);
newModel.add(tf.layers.flatten());
newModel.add(tf.layers.dense({units: 100, activation: 'relu'}));
newModel.add(tf.layers.dense({units: 10, activation: 'softmax'}));
// Geler les poids de MobileNet
for (const l of truncated.layers) l.trainable = false;
newModel.compile({
optimizer: 'adam',
loss: 'categoricalCrossentropy',
metrics: ['accuracy']
});
}
Callbacks Personnalisés
let bestAccuracy = 0;
const callbacks = {
onEpochEnd: async (epoch, logs) => {
console.log(`Epoch ${epoch}: loss = ${logs.loss.toFixed(4)}`);
if (logs.val_accuracy > bestAccuracy) {
bestAccuracy = logs.val_accuracy;
await model.save('localstorage://best-model');
}
},
onBatchEnd: async (batch, logs) => {
updateProgressBar(batch);
}
};
await model.fit(xs, ys, { epochs: 50, callbacks });
Sauvegarder et Charger des Modèles
// Sauvegarder
await model.save('localstorage://my-model'); // localStorage
await model.save('indexeddb://my-model'); // IndexedDB
await model.save('downloads://my-model'); // Télécharger
// Charger
const loaded = await tf.loadLayersModel('localstorage://my-model');
const remote = await tf.loadLayersModel('https://example.com/model.json');
localstorage:// — Stockage local (~5-10MB max)indexeddb:// — IndexedDB (modèles plus gros)downloads:// — Télécharger les fichiershttp(s):// — Charger depuis un serveur