top of page

MNIST Express - 2/8 - NumPy, la géométrie invisible derrière MNIST

  • 26 févr.
  • 4 min de lecture

Dernière mise à jour : 22 mars

Lien vers le repo du projet : https://github.com/vohorgeez/MNIST-Express


Dans le premier article, j'expliquais pourquoi j'avais décidé de reconstruire MNIST Express proprement. Aujourd'hui, on attaque le socle. Le truc qu'on ne voit jamais, mais qui fait tout tenir debout : NumPy.



Aussi indispensable que non-sexy. Et pour comprendre pourquoi, commençons par la base, voulez-vous.


MNIST, d'accord, mais c'est quoi en fait ?



MNIST, en fait, c'est ça ☝🏻

Un dataset de chiffres manuscrit, ni plus, ni moins.

  • 70 000 images

  • 28x28 pixels

  • en niveaux de gris

  • 10 classes (0 à 9)

Chaque image représente un chiffre écrit à la main.


Pourquoi c'est devenu un standard mondial ?

Parce que :

  • C'est simple (on aime la simplicité)

  • C'est propre (on aime la propreté)

  • C'est équilibré

  • C'est public

  • C'est suffisamment petit pour tourner dans un laptop


Un terrain de jeu incontournable pour commencer à apprendre le Machine Learning (c'est mon cas).

Si ton modèle ne sait pas classer MNIST, en gros, il ne sait probablement pas classer grand chose.



Ce qu'on croit manipuler... et ce qu'on manipule vraiment


Quand nous, humains faits de chair et de sang, nous regardons MNIST, nous voyons une image. Un petit carré noir et blanc avec un chiffre écrit dessus.

Mais un modèle de Machine Learning, tout comme n'importe quelle machine en vérité, ne voit pas d'image, ou du moins il n'interprète absolument pas ce que cette image représente. ça c'est un truc d'humain.

La machine, elle, ne voit que des... données. Un amoncellement de pixels en niveau de gris dont la cohérence n'est lisible que par un cerveau humain entraîné. Comment faire pour inculquer ce savoir-faire rudimentaire à la machine ?

C'est là que NumPy entre en scène.


Le coût mémoire : la réalité brutale des pixels


Une image MNIST :

  • 28 x 28 = 784 pixels

  • chaque pixel est un entier entre 0 et 255


Donc 784 valeurs numériques par image.


Pour 70 000 images : 70 000 x 784 = 54 880 000 valeurs.


Si chaque valeur est stockée en `float64` (8 octets) ≈ 439 Mo.


Tout ça pour des petits chiffres écrits à la main, quand même.


Heureusement, il est possible d'optimiser :

  • `uint8` -> 1 octet

  • `float32` -> 4 octets


Et soudain, on divise la mémoire par 2 ou par 8. C'est ce que permet NumPy, entre autres : contrôler le type de donnée. Sans lui, ce pourrait devenir rapidement ingérable.


Mais ce n'est pas la moindre de ses qualités comme nous allons le voir.


Pourquoi scikit-learn veut des vecteurs ?



Les modèles de machine learning "classiques" (comme k-NN dans notre projet) ne savent pas traiter les images, nous l'avons déjà dit.


Par contre, ils savent traiter des vecteurs. Un vecteur, c'est juste une liste de nombres. Une image 28x28 devient donc :


[0, 0, 0, 12, 140, 255, ...]

Une ligne de 784 valeurs. On appelle ça "aplatir" l'image. En pratique, ça donne une matrice :


(n_samples, n_features)

Pour MNIST :


(70000, 784)

Et c'est exactement le format attendu par scikit-learn. Parce que les algorithmes classiques fonctionnent en géométrie vectorielle. Ils calculent des distances, des moyennes, des projections... Tout ça nécessite des vecteurs.


(En passant : le site de scikit-learn est une petite mine d'or alors on va y faire un tour hop hop hop)


La vectorisation : la vraie puissance de NumPy


Sans NumPy, on manipulerait des listes Python. Et bon, j'adore Python d'un amour profond et sincère mais... il est un peu lent. Déso, pas déso.



NumPy permet :

  • des calculs en C sous le capot

  • des opérations sur des tableaux entiers d'un seul coup

  • aucune boucle Python explicite


Exemple conceptuel :


Au lieu de faire :

  • 70 000 boucles

  • 784 multiplication à chaque fois

...on laisse NumPy appliquer l'opération sur toute la matrice d'un coup. Paf. La puissance de la vectorisation. Et c'est ce qui rend le Machine Learning possible sur un PC personnel.


Le prix à payer : la perte de spatialité


Et c'est un point critique : quand on transforme une image 28x28 en vecteur de 784 valeurs... on perd l'information spatiale.


L'algorithme ne sait plus que :

  • tel pixel est "au-dessus"

  • tel pixel est "à droite"

  • untel et untel sont voisins

  • etc

Il voit juste 784 dimensions indépendantes.


Pour un k-NN, ça marche encore parce qu'il compare des distances globales. Mais pour des modèles plus avancés, c'est un problème.


C'est d'ailleurs sans doute pour ça que les réseaux de neurones convolutionnels existent, car eux ont le bon goût de conserver la structure 2D. Mais bon, dans MNIST Express, on fait le choix volontaire d'utiliser un modèle classique et de travailler en géométrie vectorielle pure. Parce qu'il faut commencer par comprendre la base sans mettre la charrue avant les boeufs...


NumPy : la géométrie invisible


Quand on entraîne un modèle sur MNIST, ce qu'on manipule vraiment, c'est :

  • une matrice

  • dans un espace à 784 dimensions (🤯)

  • où chaque image est un point


NumPy est le moteur qui permet :

  • de stocker ces points efficacement

  • de les transformer

  • de les normaliser

  • de les projeter (coucou PCA)

  • de calculer des distances


Bref, il est partout dans le pipeline. 😅 On ne le voit jamais dans la démo Streamlit, mais sans lui, rien ne fonctionne.


Ce que ça change pour le projet MNIST Express


Dans le repo, tout repose sur cette représentation vectorielle :

  • preprocessing -> transforme les images en matrices NumPy

  • training -> entraîne le modèle sur ces matrices

  • inference -> compare des vecteurs

  • PCA (optionnel) -> projette ces vecteurs dans un espace plus petit


Même le dessin utilisateur est converti en vecteur 784D avant prédiction. Tout est géométrie.


Tous les héros ne portent pas de cape


Au delà du dataset d'images, MNIST est un problème de géométrie en grande dimension. NumPy est l'outil qui permet de transformer des pixels en points dans un espace mathématique. Et c'est seulement une fois qu'on accepte cette transformation mentale — image → vecteur → point dans ℝ⁷⁸⁴ — qu'on commence vraiment à comprendre ce qu'on fait.


Dans le prochain article, on attaquera ce qui se passe quand on compare ces points entre eux. Bref, on va parler de k-Nearest Neighbors, et la géométrie va devenir encore plus concrète.


Commentaires


RETROUVEZ-MOI

  • X
  • GitHub
  • LinkedIn
  • Instagram
  • YouTube
bottom of page