Hallo, hier ist Alex von DEV STORIES DOT EU. scikit-image: Die AI Image Pipeline, Folge 1 von 5. Bevor ein Deep Learning Model ein Gesicht erkennen kann, muss es ein Grid aus Zahlen verarbeiten. Wenn du dieses Grid in der falschen Reihenfolge fütterst, lernt dein Model nichts und deine Verarbeitung wird extrem langsam. Die AI Image Pipeline:
NumPy at the Core ist die Lösung, um dieses Grid richtig zu strukturieren.
Wenn du ein Bild mit scikit-image lädst, bekommst du kein proprietäres Image-Objekt. Du bekommst ein Standard-N-dimensionales Array, bekannt als ndarray. Ein Bild ist einfach eine Matrix aus Pixeln. Weil es ein ganz normales NumPy-Array ist, kannst du jede Standardoperation nutzen, um die Image-Daten direkt zu slicen, zu maskieren oder zu manipulieren.
Hier ist die wichtigste Erkenntnis. Die Art, wie scikit-image diese Arrays indiziert, bringt viele Developer ins Stolpern. In der Standardgeometrie benutzt du x- und y-Koordinaten, wobei x horizontal und y vertikal ist. scikit-image verzichtet darauf zugunsten der Matrix-Notation. Der erste Index ist die Row, was der vertikalen Position entspricht. Der zweite Index ist die Column, was der horizontalen Position entspricht. Wenn du ein Farbbild hast, ist der dritte Index der Color Channel. Ein Standard-zweidimensionales Farbbild ist eigentlich ein dreidimensionales Array, angeordnet als Row, Column, Channel.
Angenommen, du bereitest einen Batch von Farbbildern vor, um sie in ein Convolutional Neural Network zu füttern. Dein Network erwartet einen bestimmten Shape. Wenn dein Bild 256 Pixel hoch und 256 Pixel breit ist, mit roten, grünen und blauen Channels, ist der Shape eines einzelnen Bildes 256, 256, 3. Aber ein Batch dieser Bilder fügt am Anfang eine vierte Dimension hinzu, die die Anzahl der Bilder repräsentiert.
Wenn du scikit-image-Funktionen auf diese Daten anwendest, muss die Funktion wissen, welche Dimension die Farbwerte enthält, damit sie diese nicht als räumliche Daten verarbeitet. Das wird über das channel axis Argument geregelt. Indem du das channel axis Argument auf minus eins setzt, sagst du der Funktion, dass die Color Channels immer in der letzten Dimension des Arrays sind. Das stellt sicher, dass die Funktion die richtigen Farbdaten ansteuert, egal ob du ihr ein einzelnes Bild oder einen großen Batch mit zusätzlichen räumlichen Dimensionen übergibst.
Das bringt uns zum Memory. Das ist der Teil, auf den es bei der Processing Speed ankommt. NumPy-Arrays werden in zusammenhängenden Memory-Blöcken gespeichert, standardmäßig in einer C-like Order. Das bedeutet, dass sich die letzte Dimension im Array-Shape im physischen Memory am schnellsten ändert. Bei unserem Standard-Image-Array aus Row, Column, Channel liegen die einzelnen Color Channels für einen einzelnen Pixel in deinem Hardware-RAM direkt nebeneinander.
Wenn du Custom Code schreibst, um über diese Pixel zu loopen, musst du dieses Memory Layout respektieren. Die Regel ist absolut: Die rechteste Dimension deines Arrays sollte in der innersten Loop verarbeitet werden. Du iterierst über Rows in der äußeren Loop, dann Columns, dann Channels ganz innen. Wenn du das umkehrst und innen über Rows loopst, zwingst du die CPU, zwischen fragmentierten Memory-Adressen hin und her zu springen. Das zerstört die Cache Locality und macht deinen Code deutlich langsamer.
Das Wichtigste, was du dir merken musst, ist, dass scikit-image keine horizontalen und vertikalen Koordinaten verwendet; es nutzt striktes Matrix-Indexing aus Row, Column und Channel. Und wenn du deine Loops genau an diese Memory Order anpasst, bleibt deine Data Pipeline schnell.
Wenn du helfen willst, diesen Podcast am Laufen zu halten, kannst du die Show unterstützen, indem du auf Patreon nach DevStoriesEU suchst. Das war's für diese Folge. Danke fürs Zuhören und keep building!