Salut, c'est Alex de DEV STORIES DOT EU. scikit-image : The AI Image Pipeline, épisode 1 sur 5. Avant qu'un modèle de deep learning puisse reconnaître un visage, il doit digérer une grille de nombres. Si tu fournis cette grille dans le mauvais ordre, ton modèle n'apprend rien, et ton processing devient extrêmement lent. The AI Image Pipeline:
NumPy at the Core, c'est la solution pour structurer cette grille correctement.
Quand tu charges une image avec scikit-image, tu n'obtiens pas un objet image propriétaire. Tu obtiens un array à N dimensions standard, connu sous le nom de ndarray. Une image, c'est tout simplement une matrice de pixels. Comme c'est un simple array NumPy, tu peux utiliser n'importe quelle opération standard pour slicer, masker, ou manipuler directement les données de l'image.
Voici le point clé. La façon dont scikit-image indexe ces arrays piège beaucoup de développeurs. En géométrie classique, tu utilises les coordonnées x et y, où x est l'horizontale et y la verticale. scikit-image abandonne ça pour une notation matricielle. Le premier index est la ligne, qui correspond à la position verticale. Le deuxième index est la colonne, qui correspond à la position horizontale. Si tu as une image en couleur, le troisième index est le channel de couleur. Une image en couleur standard en deux dimensions est en fait un array en trois dimensions ordonné en ligne, colonne, channel.
Supposons que tu prépares un batch d'images en couleur pour les passer à un Convolutional Neural Network. Ton réseau s'attend à une shape spécifique. Si ton image fait 256 pixels de haut et 256 pixels de large avec les channels rouge, vert et bleu, la shape d'une seule image est 256, 256, 3. Mais un batch de ces images ajoute une quatrième dimension au début, qui représente le nombre d'images.
Quand tu appliques des fonctions scikit-image à ces données, la fonction a besoin de savoir quelle dimension contient les valeurs de couleur pour ne pas les traiter comme des données spatiales. C'est géré par l'argument channel axis. En réglant l'argument channel axis sur -1, tu dis à la fonction que les channels de couleur sont toujours dans la dernière dimension de l'array. Ça garantit que la fonction cible les bonnes données de couleur, peu importe si tu lui passes une seule image ou un grand batch avec des dimensions spatiales supplémentaires.
Ce qui nous amène à la mémoire. C'est la partie qui compte pour la vitesse de processing. Les arrays NumPy sont stockés dans des blocs de mémoire contigus, en utilisant un ordre de type C par défaut. Ça veut dire que la dernière dimension dans la shape de l'array est celle qui change le plus vite dans la mémoire physique. Pour notre array d'image standard en ligne, colonne, channel, les channels de couleur individuels pour un seul pixel se trouvent juste à côté les uns des autres dans ta RAM.
Si tu écris du code custom pour boucler sur ces pixels, tu dois respecter ce memory layout. La règle est absolue : la dimension la plus à droite de ton array doit être traitée dans la boucle la plus interne. Tu itères sur les lignes dans la boucle externe, puis les colonnes, puis les channels à l'intérieur. Si tu inverses ça et que tu boucles sur les lignes à l'intérieur, tu forces le CPU à faire des allers-retours sur des adresses mémoire fragmentées. Ça détruit la cache locality et rend l'exécution de ton code beaucoup plus lente.
La chose la plus critique à retenir, c'est que scikit-image n'utilise pas de coordonnées horizontales et verticales ; il utilise un indexage matriciel strict en ligne, colonne et channel, et c'est en faisant correspondre tes boucles à cet ordre mémoire exact que tu gardes ton data pipeline rapide.
Si tu veux aider à faire vivre ce podcast, tu peux soutenir l'émission en cherchant DevStoriesEU sur Patreon. C'est tout pour aujourd'hui. Merci d'avoir écouté, et continue de développer !