De nombreux algorithmes ML de Sklearn supportent l'apprentissage incrémental, c'est-à-dire un entraînement par mini-batches.

Ça les rend très utiles quand toutes les données ne tiennent pas en mémoire.

Données découpées en chunks pour l'apprentissage incrémental par mini-batches avec Scikit-learn

Voici les algorithmes concernés, pour référence :

Liste des algorithmes Scikit-learn qui supportent l'apprentissage incrémental, dont KMeans

Si tu regardes bien, KMeans figure dans cette liste.

C'est un algorithme de clustering populaire, et c'est une bonne chose de pouvoir l'utiliser sur de grands datasets si besoin.

Mais quand j'ai découvert que KMeans pouvait être implémenté en mini-batch, je me suis demandé comment ça pouvait concrètement fonctionner.

En y réfléchissant quelques instants, j'ai eu une idée que je veux partager avec toi aujourd'hui.

C'est parti !

Le vrai problème du KMeans classique

Avant de comprendre l'implémentation en mini-batch, il faut identifier le problème du KMeans habituel.

Pour rappel, KMeans fonctionne comme suit :

  • Étape 1) Initialiser les centroïdes.

  • Étape 2) Trouver le centroïde le plus proche pour chaque point.

  • Étape 3) Recalculer chaque centroïde comme la moyenne des points qui lui sont assignés.

  • Étape 4) Répéter jusqu'à convergence.

Dans cette implémentation, le principal goulot d'étranglement mémoire vient de l'étape 3.

C'est là qu'on calcule la moyenne de tous les points assignés à un centroïde pour le déplacer.

Étape 3 du KMeans : calcul de la moyenne de tous les points assignés à un centroïde

Classiquement, tous les points assignés à un centroïde doivent donc être disponibles en mémoire pour calculer cette moyenne.

Points assignés à un centroïde devant tous être disponibles en mémoire pour calculer la moyenne

Mais dans notre cas, tous les points ne tiennent pas en mémoire en même temps. L'averaging direct n'est donc pas faisable.

Voici pourtant comment on peut résoudre ça intelligemment.

❝

Note : je n'ai pas vérifié l'implémentation exacte de MiniBatchKMeans dans Sklearn. La doc n'en dit pas grand-chose non plus.

Ce que je vais te présenter, c'est la solution à laquelle je suis arrivé en réfléchissant au problème.

Si elle recoupe parfaitement ce que fait Sklearn, tant mieux !

Sinon, pas de problème, car cette solution est parfaitement viable.

MiniBatchKMeans

On commence par choisir k, le nombre de centroïdes.

Ensuite, il faut leur donner une position initiale : on tire m points aléatoires (avec m << n) pour initialiser les centroïdes.

Initialisation des centroïdes du MiniBatchKMeans à partir de m points tirés aléatoirement

Rappelle-toi maintenant le problème identifié : tous les points doivent être en mémoire pour calculer la moyenne.

Pour y remédier, il faut un moyen de garder une trace des points assignés à chaque centroïde au fur et à mesure qu'on charge et traite chaque mini-batch.

❝

On ne peut pas maintenir une liste grandissante de points assignés à chaque centroïde : ça finirait par occuper autant de mémoire que le dataset entier.

Voici comment remplir cet objectif intelligemment.

On exploite la propriété mathématique suivante qui relie somme et moyenne :

Équation : propriété mathématique qui relie la somme et la moyenne d'un ensemble de points

Comment ?

Dans un KMeans classique, on moyenne tous les points assignés à un centroïde pour déterminer sa nouvelle position.

Mais comme on ne peut pas garder tous ces points en mémoire, voilà ce qu'on fait dans le cadre du KMeans en mini-batch.

Pour chaque centroïde :

  • On maintient un vecteur-somme, qui accumule la somme des vecteurs de tous les points qui lui ont été assignés jusqu'ici. Au départ, c'est un vecteur nul.

  • Une variable count, qui compte le nombre de points assignés à ce centroïde. Au départ, count vaut zéro.

Centroïdes avec leur vecteur-somme et leur count de points assignés, tous deux initialisés à zéro

À chaque itération sur les mini-batches :

  • Le vecteur-somme de chaque centroïde continue d'accumuler la somme des points qui lui sont assignés.

  • Le count de chaque centroïde continue de comptabiliser le nombre de ces points.

Données parcourues en mini-batches : accumulation du vecteur-somme et du count de chaque centroïde

Une fois tous les mini-batches parcourus, on effectue une division scalaire entre le vecteur-somme et le count pour obtenir le vecteur moyen :

Équation : division scalaire du vecteur-somme par le count pour obtenir le vecteur moyen

Cette moyenne nous donne précisément la nouvelle position du centroïde, comme si tous les points avaient été disponibles en mémoire.

On répète jusqu'à convergence.

Et avant de démarrer l'itération suivante du MiniBatchKMeans, on réinitialise le vecteur-somme à zéro et le count à zéro.

C'est tout ce qu'il faut pour implémenter une version mini-batch de KMeans.

Simple, non ?

Il est assez évident que les étapes décrites ci-dessus impliquent essentiellement des calculs matriciels et vectoriels, qui peuvent être chargés rapidement sur un GPU pour accélérer l'exécution.

On peut donc facilement implémenter une version tensor de KMeans.

Ce qui l'est moins, c'est comment convertir, par exemple, un arbre de décision ou une random forest en calculs tensoriels pour les faire tourner sur GPU.

Conversion d'un arbre de décision ou d'une random forest en calculs tensoriels pour GPU

Si tu veux en savoir plus, on en a parlé ici :

Par ailleurs, même si on a parlé de KMeans dans ce deep dive, cet algorithme a de nombreuses limites qui le rendent inadapté dans beaucoup de situations.

Connaître d'autres algorithmes de clustering et savoir quand les utiliser est donc essentiel.

On a couvert deux grandes familles d'algorithmes de clustering, les approches density-based et distribution-based, dans ces deep dives :

👉 Quels autres algorithmes ML classiques pourraient, selon toi, être implémentés en mini-batch mais ne le sont pas encore dans Sklearn ?

Envie d'aller plus loin ? DataXp t'attend : formations et parcours pour progresser en data science, machine learning et IA.


Commentaires

Avatar

ou participer

À lire ensuite

Des shots dans la même veine, à lire entre deux tâches.

Voir tous les shots
caret-right