02 · Dane · 4 min czytania · Interaktywne · aktualizacja
Jak komputer widzi obraz i jak zamienić zdjęcie na dane dla modelu?
W skrócie
Dla komputera obraz to tablica liczb: jasności pikseli w kanałach kolorów. Spłaszczenie do wektora gubi sąsiedztwo pikseli, z którego korzystają sieci CNN.
Co to jest
Obraz cyfrowy to tablica liczb: każdy piksel ma wartość jasności, a obraz kolorowy — trzy wartości, po jednej dla kanału czerwonego, zielonego i niebieskiego (RGB). Zdjęcie 224 × 224 pikseli w kolorze to tablica o kształcie 224 × 224 × 3, czyli 150 528 liczb, zwykle całkowitych od 0 do 255.
Dla modelu uczenia maszynowego obraz jest więc po prostu bardzo długim wektorem cech. Różnica wobec danych tabelarycznych polega na tym, że te cechy mają strukturę: sąsiednie piksele są ze sobą silnie powiązane, a ten sam kształt może pojawić się w dowolnym miejscu kadru.
Intuicja: tabela z wiekiem i dochodem nie zmienia sensu, gdy zamienimy kolumny miejscami. Obraz z przemieszanymi pikselami przestaje być dla człowieka obrazem — choć zawiera dokładnie te same liczby.
Mechanizm — dlaczego tak działa
Najprostszy sposób użycia obrazu to spłaszczenie (flatten): tablicę 8 × 8 zamieniamy na wektor 64 liczb i podajemy klasycznemu modelowi — regresji logistycznej, SVM, k najbliższym sąsiadom. Działa to na małych, wyśrodkowanych obrazach, ale ma fundamentalną wadę: model nie wie, które piksele są sąsiadami. Dla niego piksel 12 i 13 są tak samo „daleko” jak 12 i 60. Każde przesunięcie obiektu o piksel zmienia, które cechy są zapalone, więc model musi osobno nauczyć się każdego położenia.
Druga trudność to wymiar. Nawet małe zdjęcie ma dziesiątki tysięcy cech, a przestrzeń możliwych obrazów jest astronomicznie duża. Prawdziwe obrazy zajmują w niej jednak cienką, uporządkowaną część — zgodnie z hipotezą rozmaitości (manifold hypothesis) — i dobra architektura potrafi ją wykorzystać.
Sieci konwolucyjne (CNN) wprowadzają do modelu wiedzę o strukturze obrazu. Filtr konwolucyjny patrzy na mały fragment (np. 3 × 3) i przesuwa się po całym obrazie z tymi samymi wagami. Daje to dwie własności: lokalność (cechy budowane są z sąsiednich pikseli) i współdzielenie wag (detektor krawędzi działa tak samo w każdym miejscu). Stąd ekwiwariancja względem przesunięć i ogromna oszczędność parametrów w porównaniu z warstwą w pełni połączoną.
Przygotowanie obrazów zwykle obejmuje: skalowanie wartości do zakresu [0, 1] lub standaryzację kanałów (średnia i odchylenie liczone na zbiorze treningowym), ujednolicenie rozmiaru, a podczas treningu — augmentację danych. W PyTorch kolejność wymiarów to zwykle kanały × wysokość × szerokość, w wielu innych bibliotekach wysokość × szerokość × kanały; pomylenie tego to częsty błąd.
Na przykładzie
Zbiór Digits z scikit-learn zawiera 1797 odręcznie pisanych cyfr, każdą jako obraz 8 × 8 pikseli w skali szarości z wartościami od 0 do 16. Klasy są zrównoważone (174–183 przykładów na cyfrę). Prawie połowa wartości (48,9%) to zera — tło — a 3 piksele są zerowe na wszystkich obrazach. Pierwsza cyfra, zero, wygląda w liczbach jak owal: wysokie wartości (13–15) po bokach, zera w środku i w rogach.
Regresja logistyczna na spłaszczonych 64 pikselach osiąga w 5-krotnej walidacji krzyżowej 91,4%, a k najbliższych sąsiadów (k = 3) — 96,7%. Gdy losowo przemieszamy kolejność pikseli (tę samą permutację dla każdego obrazu), wyniki się nie zmieniają: 91,5% i 96,7%. To dowód, że te modele w ogóle nie korzystają z układu przestrzennego. Za to przesunięcie obrazów testowych o jeden piksel w prawo obniża trafność regresji logistycznej z 96,1% do 46,3%, a o dwa piksele — do 8,7%, poniżej zgadywania. Model nauczył się, które piksele są zapalone, a nie jaki kształt widzi.
Dane: Digits (ręcznie pisane cyfry 8×8)
W praktyce
- Wczytywanie:
PIL.Image.open+np.asarray, w PyTorchtorchvision.io.read_imagelubtorchvision.transforms.ToTensor()(skaluje do [0, 1] i zmienia kolejność na C × H × W). - Spłaszczanie dla klasycznych modeli:
images.reshape(n, -1); w scikit-learn Digits ma gotowedata(1797 × 64) iimages(1797 × 8 × 8). - Normalizacja:
transforms.Normalize(mean, std)z wartościami policzonymi na zbiorze treningowym. - Dla zdjęć większych niż kilkadziesiąt pikseli używaj sieci konwolucyjnych lub gotowych modeli z transfer learningiem.
- Sprawdzaj typ danych:
uint8(0–255) przy odejmowaniu się „zawija”, więc przed obliczeniami rzutuj nafloat32. - Typowy błąd: pomylenie kolejności kanałów (RGB vs BGR w OpenCV) lub wymiarów (C × H × W vs H × W × C).
Najczęstsze pytania
- Dlaczego nie wystarczy zwykła sieć w pełni połączona?
- Wystarczy dla małych, wyśrodkowanych obrazów, ale nie wie, które piksele sąsiadują, i ma ogromną liczbę wag. Dla obrazu 224 × 224 × 3 jedna warstwa z 1000 neuronów to ponad 150 milionów parametrów, a każde przesunięcie obiektu trzeba uczyć osobno.
- Czy obrazy trzeba normalizować?
- Praktycznie zawsze. Wartości 0–255 utrudniają optymalizację gradientową; skalowanie do [0, 1] lub standaryzacja kanałów stabilizuje uczenie. Dla gotowych modeli trzeba użyć tej samej normalizacji, z jaką je trenowano.
- Czy kolor jest potrzebny?
- Zależy od zadania. Dla cyfr czy rentgenów wystarcza skala szarości (jeden kanał), dla rozpoznawania owoców czy znaków drogowych kolor niesie ważną informację.
Źródła
- Goodfellow I., Bengio Y., Courville A. „Deep Learning”. MIT Press, 2016, rozdz. 9 (Convolutional Networks) i 12.2 (Computer Vision).
- LeCun Y., Bottou L., Bengio Y., Haffner P. (1998). „Gradient-based learning applied to document recognition”. Proceedings of the IEEE, 86(11), 2278–2324.
- Zhang A., Lipton Z. C., Li M., Smola A. J. „Dive into Deep Learning”, d2l.ai, rozdz. „Convolutional Neural Networks”.
- Dokumentacja scikit-learn: Toy datasets — Optical recognition of handwritten digits, https://scikit-learn.org/stable/datasets/toy_dataset.html