La catégorisation automatique des images représente un enjeu essentiel dans le domaine du traitement de données. En astrophysique, avec le lancement du télescope James Webb, des millions de données vont être recueillies. Cependant, cet afflux de données sera difficile à traiter. Je me souviens d'une conférence donnée par l’un de mes professeurs en astrophysique, qui a grandement contribué à la construction de James Webb. Il nous disait qu'il manquait déjà de main-d'œuvre pour traiter les données de Hubble, et que la tâche de traitement de ce nouveau satellite serait faramineuse. Il nous confiait cette mission, notre département d'astrophysique à l’Université de Montréal étant très reconnu.
Après avoir étudié l'intelligence artificielle appliquée à la physique, notamment avec le modèle de Hopfield et les perceptrons, j’ai voulu m’orienter vers des méthodes plus récentes, notamment via PyTorch. C’est dans ce cadre que j’ai découvert "Galaxy Zoo – The Galaxy Challenge" et que j’ai décidé, moi aussi, de tenter ma propre approche.
L’objectif est de concevoir un système sophistiqué capable de classifier avec précision différentes galaxies en se basant sur des méthodes d’apprentissage en profondeur, telles que les réseaux de neurones convolutifs (CNN). Pour cela, j’ai suivi plusieurs étapes importantes : exploration initiale des données, préparation et prétraitement des images, création et entraînement d’un CNN personnalisé. Ce document expose toutes les étapes suivies, les choix techniques effectués tout au long du processus, ainsi que les conclusions tirées de notre modèle final, avec un regard critique.
Toutes les données sont disponibles ici : https://www.kaggle.com/c/galaxy-zoo-the-galaxy-challenge/data
Le format initial des images n'est pas optimal. Le format est grand (424 × 424) et il y a beaucoup d'espace vide autour des galaxies. Écrivez un code qui effectue les tâches suivantes :
Les données sont maintenant compatibles avec PyTorch et sont prêtes à être analysées. Il faut ensuite définir un CNN qui va prendre en entrée les images 64 × 64 avec 3 couleurs et nous donner une probabilité pour les 37 classes en sortie. Pour commencer, on définit un CNN avec les éléments suivants :
conv_stack
) :
Le modèle commence avec une couche convolutive prenant des images à 3 canaux (RGB) et les transforme en un ensemble de cartes de caractéristiques à 6 canaux.
Une deuxième couche convolutive augmente davantage le nombre de canaux de 6 à 16 pour extraire des caractéristiques plus profondes.
Ces couches fonctionnent en appliquant un ensemble de filtres (ou noyaux) sur l'image d'entrée. Ces filtres se déplacent à travers l'image (un processus appelé convolution)
pour détecter des caractéristiques telles que les bords, les textures ou d'autres motifs spécifiques.
En ajustant les poids de ces filtres pendant l'entraînement, le réseau apprend à extraire les caractéristiques les plus pertinentes pour la tâche donnée.
BatchNorm2d
) :
Chaque couche convolutive est suivie d'une normalisation par lots, qui agit en normalisant les sorties de la couche précédente pour chaque mini-lot d'entraînement.
Elle ajuste et met à l'échelle les activations pour que leur distribution ait une moyenne proche de 0 et une variance proche de 1.
Cela réduit le problème du décalage des covariables, stabilise l'apprentissage et permet d'utiliser des taux d'apprentissage plus élevés.
ReLU
) :
Chaque normalisation est suivie de la fonction d'activation ReLU (Rectified Linear Unit), qui transforme les valeurs négatives en zéro et laisse passer les valeurs positives.
Cela introduit une non-linéarité essentielle pour apprendre des relations complexes entre les entrées et les sorties.
self.pool
) :
Une opération de pooling (généralement de taille 2×2) réduit la dimensionnalité des cartes de caractéristiques,
en conservant les informations les plus importantes. Cela augmente la robustesse aux petites variations de position.
Flatten
) :
Avant de passer aux couches pleinement connectées, les cartes de caractéristiques 2D doivent être converties en un vecteur 1D.
L'aplatissement permet cette transformation, préparant les données à la suite du traitement.
linear_stack
) :
Les caractéristiques extraites sont ensuite passées à des couches entièrement connectées.
Ces couches combinent les caractéristiques pour produire des représentations de plus haut niveau,
puis génèrent des prédictions pour les 37 classes possibles.
Sigmoid
) :
La dernière couche utilise une fonction sigmoïde
pour transformer les valeurs de sortie (logits)
en probabilités entre 0 et 1. Chaque neurone représente la probabilité que l'image appartienne à une classe donnée.
Maintenant que notre CNN (réseau de neurones convolutif) est prêt, on peut commencer son entraînement à reconnaître les galaxies. Pour cela, on procède à une segmentation de l'ensemble des données en deux parties distinctes : environ 80 % des informations sont consacrées à l'entraînement du modèle afin qu'il puisse assimiler les caractéristiques des galaxies, et 20 % des données restantes sont utilisées pour tester comment le modèle se comporte sur des exemples qu'il ne connaît pas. Cela permet de vérifier s'il comprend bien l'ensemble ou s'il se contente juste d'apprendre par cœur les images (phénomène appelé surapprentissage ou surajustement).
Pour orienter l'apprentissage du réseau neuronal, une fonction de perte est employée. Dans notre cas, il s'agit de la MSE (Mean Squared Error), ou erreur quadratique moyenne. À chaque prédiction du réseau est associée une valeur d'erreur correspondant à l'écart entre la prédiction et la réponse attendue. On élève cette valeur au carré afin d'éliminer les valeurs négatives et d'amplifier les grosses erreurs.
Ensuite, la moyenne de ces erreurs est calculée sur toutes les données disponibles. Plus cet écart est important, plus le modèle est éloigné de la bonne réponse. Pour corriger cette erreur, il est nécessaire de mettre à jour les poids internes (les paramètres qui déterminent les connexions entre les neurones) en utilisant un optimiseur, ici Adam (Adaptive Moment Estimation).
Adam est un algorithme d'optimisation qui ajuste automatiquement la taille des pas (learning rate) pour chaque poids, en se basant sur les gradients antérieurs. Il fusionne deux concepts :
Grâce à cela, notre modèle apprend de manière plus rapide et efficace que s’il utilisait une méthode de mise à jour simple. Enfin, nous effectuons 6 époques d’entraînement, ce qui signifie que le modèle parcourt six fois l’ensemble des données d’apprentissage, lui permettant d’apprendre progressivement à identifier les galaxies avec une meilleure précision.
train_loop
)learning_rate
) et le nombre d'époques (epochs
).
Le taux d'apprentissage contrôle à quel point les poids du modèle sont ajustés par rapport au gradient de la fonction de perte.
Les époques représentent le nombre de fois que l'ensemble des données d'entraînement est passé à travers le réseau.
nn.MSELoss()
:
La fonction de perte Mean Squared Error (MSE) mesure la différence quadratique moyenne entre les valeurs prédites et les valeurs réelles,
pour estimer la performance du modèle. La perte MSE est calculée comme suit :
$$\text{MSE} = \frac{1}{n} \sum_{i=1}^{n} (y_{\text{pred},i} - y_{\text{true},i})^2$$
où n est le nombre d'échantillons, ypred sont les prédictions du modèle, et ytrue sont les valeurs cibles réelles. Ainsi le modèle s'efforce de minimiser cette perte, et donc de réduire l'erreur entre ses prédictions et les valeurs réelles.optim.Adam()
:
L'optimiseur Adam est un algorithme de descente de gradient qui ajuste les poids du réseau de manière adaptative,
en utilisant des estimations des premiers et seconds moments des gradients.
Plus concrètement, il trouve efficacement un bon ensemble de poids pour le réseau,
permettant de minimiser la fonction de perte sur les données d'entraînement, tout en évitant un surajustement.
DataLoader
d'entraînement, qui fournit des lots (batches) des données d'entrée (X
)
et des étiquettes cibles (y
). Pour chaque lot, le processus suivant est exécuté :
loss_fn
).optimizer
).test_loop
)Après chaque époque d'entraînement, le modèle est évalué sur l'ensemble de test :
torch.no_grad()
est utilisé pour désactiver le calcul du gradient, pour économiser du temps car ce n'est pas nécessaire ici.RMSE sur les données de test: 0.09339757263660431
C'est mieux ! Je pense même que j'aurai pu accroître les époques ! Le système semblait encore stable. Avec ceci on obtient la 30ème place du classment, avec 10 ans de retard...
Voilà c'est tout pour ce projet, je serai curieux de savoir si depuis tout ce temps des techniques plus puissantes pourraient battre le 1er du classment : 0.07491 par un chercheur de chez DeepMind. La suite au prochain episode...