AI w Twojej bibliotece zdjęć i dlaczego przenieśliśmy ją na własne karty GPU

Kiedy przeszukujesz swoją bibliotekę zdjęć hasłem „pies w śniegu” i pojawia się właściwe zdjęcie, coś już przeczytało to zdjęcie za Ciebie. Nikt go nie otagował. Model machine learning spojrzał na piksele, ustalił, co jest w kadrze, i zapisał to zrozumienie, żebyś mógł je później odnaleźć. Niedawno przenieśliśmy tę pracę z procesorów CPU na nasze własne karty GPU (graphics processing units, procesory graficzne). Ten wpis wyjaśnia, co ta AI faktycznie robi i dlaczego sprzęt pod spodem ma znaczenie.
Modele, które to umożliwiają, nie są nasze. Pochodzą z projektu open source Immich, na którym zbudowany jest PixelUnion. Nasze jest to, gdzie działają: na sprzęcie, który sami posiadamy i obsługujemy, na europejskiej ziemi, a nie w cudzej chmurze AI. Modele czytają Twoje zdjęcia i dla nas ma znaczenie, że robią to w naszych własnych szafach serwerowych i nigdzie indziej.
Jest jedno rozróżnienie, które warto zrobić, zanim pójdziemy dalej, bo to ono liczy się najbardziej dla Twojej prywatności. Używanie modelu to nie to samo co jego trenowanie. Trenowanie to kosztowny, jednorazowy proces, w którym model uczy się z milionów przykładowych obrazów, i wykonują je autorzy modelu na długo przed tym, zanim trafi on do nas. To, co robimy my, to inferencja: bierzemy gotowy, już wytrenowany model i przepuszczamy Twoje zdjęcie przez niego raz, aby uzyskać wynik, tak jak przepuszczasz dokument przez skaner. Twoje zdjęcia nigdy nie służą do niczego, czego model miałby się uczyć. Nie są dodawane do zbioru treningowego, nie ulepszają wspólnego modelu i nic z nich nie wypływa, by uczynić przyszłą wersję mądrzejszą. Model patrzy na Twoje zdjęcie, podaje swoją odpowiedź i zapomina o nim.
Trzy zadania, jedna wspólna sztuczka: uczynić piksele przeszukiwalnymi
Immich uruchamia swoją AI w osobnej usłudze, kontenerze immich-machine-learning, opisanym w pliku README machine learning projektu. Wykonuje trzy zadania, a każde rozwiązuje inny problem:
- Inteligentne wyszukiwanie zamienia zdjęcie w coś, co możesz przeszukiwać zwykłym językiem, za pomocą modelu CLIP.
- Rozpoznawanie twarzy znajduje twarze i ustala, które należą do tej samej osoby, za pomocą pakietu modeli takiego jak
buffalo_l. - OCR czyta tekst, który pojawia się na Twoich zdjęciach, za pomocą modelu
PP-OCRv5.
Warto być tu precyzyjnym, bo „trzy modele” to uproszczenie. Dwa z tych zadań to w rzeczywistości para modeli działających po kolei, a każde zadanie można wymienić na inny model. Rozpoznawanie twarzy uruchamia model detekcji, a po nim model rozpoznawania, i buffalo_l to pakiet zawierający oba. Immich dostarcza też alternatywy, takie jak antelopev2, buffalo_m i buffalo_s. OCR działa tak samo: jeden model do znajdowania tekstu i drugi do jego czytania. A sam CLIP to para enkoderów, jeden dla obrazów i jeden dla tekstu, z wieloma wymiennymi wariantami. Nie ma w ogóle osobnego modelu detekcji obiektów: rozpoznanie, że zdjęcie zawiera psa lub plażę, obsługuje CLIP, a nie dedykowany model tagujący.
To, co ma znaczenie dla ich zrozumienia, to fakt, że wszystkie trzy zadania dzielą jedną leżącą u podstaw sztuczkę. Zrozummy więc najpierw tę sztuczkę. Potem różnice nabiorą sensu.

CLIP: wyszukiwanie po znaczeniu, nie po tagach
Dawne wyszukiwanie zdjęć opierało się na nazwach plików i ręcznych tagach. Jeśli nie wpisałeś „plaża” w podpisie, wyszukiwanie „plaża” nie znajdowało nic. CLIP, model opublikowany pierwotnie przez OpenAI (artykuł tutaj), usuwa to ograniczenie. Patrzy na rzeczywistą zawartość obrazu.
Oto część, na której ludzie się potykają, wyjaśniona prosto. CLIP nie przechowuje listy słów dla każdego zdjęcia. Zamienia każde zdjęcie w wektor: długą listę liczb, kilkaset z nich, które razem opisują znaczenie obrazu. Zdjęcie husky’ego w świeżym śniegu i zdjęcie innego psa w śniegu kończą z podobnymi listami liczb, ponieważ znaczą coś podobnego. Ta lista nazywa się embedding.
Czym naprawdę jest wyszukiwanie wektorowe
Gdy każde zdjęcie w Twojej bibliotece jest wektorem, przechowujemy wszystkie te wektory w bazie danych. Wyszukiwanie działa tak:
- Wpisujesz „pies w śniegu”.
- Ten sam model zamienia Twoje słowa w wektor, w tym samym systemie liczb co zdjęcia.
- Baza danych porównuje Twój wektor zapytania z przechowywanymi wektorami zdjęć i mierzy, jak blisko leży każdy z nich.
- Najbliższe dopasowania wracają jako pierwsze.
„Blisko” to tutaj matematyka. Każdy wektor to punkt w przestrzeni, a system mierzy odległość między Twoim zapytaniem a każdym zdjęciem. W najprostszej formie to brute force: sprawdź odległość do każdego pojedynczego zdjęcia, posortuj według najbliższego. W tym procesie nigdzie nie ma dopasowywania tagów ani wyszukiwania po słowach kluczowych. Zdjęcie bez podpisu, bez nazwy pliku i bez opisu i tak się pojawi, ponieważ jego znaczenie żyje w liczbach.

To porównanie brute force to uczciwa wersja i dla normalnej biblioteki działa dobrze. Nazywa też koszt. Porównywanie jednego zapytania z milionami wektorów, po kolei, staje się wolne. W dużej skali przechodzi się na sprytniejsze indeksy, wyszukiwanie przybliżonych najbliższych sąsiadów, które pomija większość porównań, a mimo to znajduje właściwe dopasowania. To, jakiego podejścia potrzebujesz, zależy od rozmiaru biblioteki, ale zasada pozostaje ta sama: zamień wszystko w wektory, a potem znajdź najbliższe.
Jeszcze jedna rzecz, która ma znaczenie w Europie. Domyślny model CLIP dobrze radzi sobie z angielskim, a słabo z innymi językami. Istnieją warianty wielojęzyczne, a Immich pozwala je wymieniać, jak opisuje jego przewodnik po wyborze modelu. Kompromis jest realny: lepsze modele wielojęzyczne są większe i potrzebują więcej pamięci, żeby działać. Ta presja na pamięć to jeden z powodów, dla których wybór sprzętu zaczyna mieć znaczenie, i do tego dojdziemy.
buffalo_l: znajdowanie tej samej osoby na wszystkich Twoich zdjęciach
Rozpoznawanie twarzy w Immichu używa buffalo_l, pakietu modeli z projektu InsightFace, hostowanego dla Immicha na Hugging Face. Działa w dwóch etapach i oba warto zrozumieć, bo często zakłada się, że robi coś, czego nie robi.
Pierwszy etap to detekcja. Model skanuje obraz i ustala, gdzie są twarze. Pomyśl o kwadracie ostrości, który aparat rysuje wokół twarzy, tyle że model robi to po fakcie, na każdym zdjęciu. Wynikiem jest zestaw ramek: tu jest twarz, tu jest kolejna.
Drugi etap to rozpoznawanie. Dla każdej znalezionej twarzy model tworzy wektor, ta sama idea co w CLIP, ale dostrojona do twarzy. Możesz go traktować jako liczbowy odcisk palca tej twarzy. Dwa zdjęcia tej samej osoby, w różnym świetle i pod różnymi kątami, dają wektory leżące blisko siebie. Dwie różne osoby leżą daleko od siebie.
To cały mechanizm stojący za „osobami” w Twojej bibliotece. Nie sprawdzamy Twojej twarzy w żadnej zewnętrznej bazie danych i do niczego nie jest przypisane imię, dopóki sam nie zdecydujesz się oznaczyć osoby. Model mierzy geometrię twarzy i zamienia ją w liczby, a następnie grupuje liczby, które są blisko siebie. Własny przewodnik Immicha po klastrach twarzy opisuje, jak to grupowanie można doprecyzować. Odciski palca pozostają w naszym systemie, na naszym sprzęcie. Nigdy nie są produktem.
PP-OCRv5: czytanie tekstu wewnątrz Twoich obrazów
Najnowsze z trzech to OCR, optyczne rozpoznawanie znaków, dodane w Immichu w wersji 2.2. Używa PP-OCRv5, modelu z projektu PaddleOCR firmy Baidu. OCR to to, co pozwala Ci wyszukiwać słowa pojawiające się wewnątrz zdjęcia: znak drogowy, witryna sklepu, tablica, etykieta na butelce.
To również działa w dwóch etapach, a podział odzwierciedla rozpoznawanie twarzy.
Najpierw wykrywa tekst. Model znajduje obszary obrazu zawierające pismo i rysuje wokół nich ramki, tak samo jak model twarzy obramowuje twarze. Zdjęcie ulicy może mieć tekst w pięciu miejscach: znak, tablica rejestracyjna, plakat, menu, autobus. Każde staje się ramką.
Potem czyta. Dla każdej ramki drugi model ustala, jakie znaki tam faktycznie są, i zamienia je w prawdziwy, czytelny maszynowo tekst. Ten tekst trafia do indeksu wyszukiwania, więc później możesz wyszukać „pizzeria” i znaleźć zdjęcie fasady restauracji, mimo że nigdy nie wpisałeś podpisu.
Kompromis to jeden z tych typowych dla Marca szczegółów, który warto wskazać: OCR jest dobry w wyraźnym druku w obsługiwanych pismach, a znacznie słabszy przy piśmie odręcznym lub mocno stylizowanych krojach. Immich oficjalnie obsługuje angielski, chiński i japoński, a języki oparte na alfabecie łacińskim na ogół działają z nieco niższą dokładnością, jak omówiono w wątku projektu o językach OCR. To naprawdę użyteczna funkcja, a nie magiczna.
Dlaczego to wszystko działa o wiele lepiej na GPU
Każdy z powyższych modeli wykonuje pod spodem ten sam rodzaj arytmetyki: ogromne ilości drobnych mnożeń i dodawań, ułożonych jako matematyka macierzowa. Zamiana jednego zdjęcia w wektor to miliony tych operacji. Ten jeden fakt wyjaśnia całą historię sprzętu.
CPU ma niewielką liczbę bardzo wydajnych rdzeni, od kilku do kilkudziesięciu. Każdy rdzeń jest elastyczny i szybki, a zadania wykonuje w dużej mierze po kolei. Ta konstrukcja jest doskonała do zróżnicowanej, rozgałęzionej pracy, którą serwer wykonuje przez cały dzień. Słabo pasuje do wykonywania tego samego prostego mnożenia kilka milionów razy z rzędu.
GPU jest przeciwieństwem. Ma tysiące prostszych rdzeni, zbudowanych, by wykonywać tę samą operację jednocześnie na ogromnych partiach liczb, równolegle. Karty graficzne zostały zaprojektowane do cieniowania milionów pikseli jednocześnie, i okazuje się, że inferencja machine learning to ten sam rodzaj problemu: ta sama matematyka, powtórzona na wielu danych. Więc zamiast żeby miliony operacji zdjęcia sączyły się fala za falą przez kilka rdzeni CPU, rozkładają się wspólnie na tysiące rdzeni GPU.

Wynik to nie mała poprawa, to inny rząd wielkości szybkości dla tego konkretnego obciążenia. Immich udostępnia dokładnie to w swojej dokumentacji o akceleracji sprzętowej, która pozwala usłudze machine learning działać na CUDA, ROCm lub OpenVINO zamiast na CPU. Raporty społeczności dają wyczucie skali. Na CPU inteligentne wyszukiwanie jest niezmiennie najwolniejszym z zadań machine learning, a użytkownicy opisują je jako wąskie gardło przy indeksowaniu dużej biblioteki. Na skromnym sprzęcie GPU jeden opis dokumentuje osadzenie około 300 000 zdjęć w mniej niż jedną noc. To liczby zewnętrzne, z konfiguracji innych osób, nie nasze, ale kierunek jest wszędzie spójny: GPU nadrabia zaległości w ułamku czasu.
Karty, które wybraliśmy do tego, to starsze karty graficzne konsumenckie, a nie nowe akceleratory do centrów danych. To celowy wybór i wiąże się z kompromisami, które warto nazwać. Taka karta wciąż ma tysiące równoległych rdzeni i wystarczająco dużo pamięci pokładowej, by wygodnie pomieścić te modele, a tyle właśnie potrzebuje to obciążenie. Modele nie są duże jak na dzisiejsze standardy. CLIP jest najcięższy z trzech, podczas gdy modele twarzy i OCR są stosunkowo lekkie. Ponowne użycie sprawnego starszego sprzętu utrzymuje dobry krzem w służbie zamiast odkładać go na półkę, i utrzymuje cały potok na sprzęcie, który jest w pełni nasz.
Po drugiej stronie rachunku jest realny koszt, a udawanie inaczej byłoby nieuczciwe. GPU pod obciążeniem pobiera więcej prądu niż bezczynny CPU, a prowadzenie własnego sprzętu oznacza, że to my ponosimy konserwację, sterowniki i energię elektryczną. Uważamy, że to właściwy kompromis. Na przetworzone zdjęcie GPU wykonuje pracę ze znacznie lepszą wydajnością, i oznacza to, że AI czytająca Twoje wspomnienia działa na maszynach, które kontrolujemy, pod prawem europejskim, zamiast być wysyłana do cudzej chmury w celu przetworzenia.
Na razie uruchamiamy domyślne modele Immicha, te same, które każdy użytkownik Immicha dostaje z pudełka. Powód, dla którego ten krok sprzętowy wykracza poza szybkość, to zapas. Większe modele zazwyczaj potrzebują więcej mocy obliczeniowej i więcej pamięci, by działać w użytecznym tempie, dokładnie tego, czego CPU nie mógł zapewnić. Z naszymi własnymi kartami GPU na miejscu uruchomienie większego wariantu CLIP dla ostrzejszego wyszukiwania albo cięższego modelu twarzy dla lepszego grupowania staje się praktyczną opcją, a nie rzeczą niemożliwą. Nie składamy tu obietnic co do konkretnych modeli. Rzecz w tym, że ten krok otwiera drzwi, a lepsze wyniki dla naszych klientów to powód, by przez nie przejść.
Jest haczyk przy przejściu na większy model i lepiej być wobec niego szczerym. Inny model tworzy inne wektory. Liczby, które jeden model CLIP przypisuje zdjęciu, nic nie znaczą dla innego modelu CLIP, więc nie możesz mieszać starego i nowego. Jeśli kiedykolwiek przejdziemy na większy model, musielibyśmy przeliczyć embeddingi dla każdego zdjęcia w bibliotece każdego użytkownika od zera, na naszych własnych kartach GPU. Dla dużej bazy użytkowników to ogromna ilość obliczeń, i jest to dokładnie ten rodzaj zadania, który na CPU jest beznadziejny, a na GPU tylko duży. Ten krok przybliża nas do gotowości na to, ale jeszcze tam nie jesteśmy. Kiedy będziemy, będzie to warte osobnego wpisu.
Dlaczego robimy to sami
Żaden z tych modeli nie jest egzotyczny i żaden nie jest tajny. Taka jest natura budowania na open source: możesz dokładnie przeczytać, co robią CLIP, buffalo_l i PP-OCRv5, i my też możemy. Decyzją, która naprawdę kształtuje Twoją prywatność, nie jest to, który model działa, lecz gdzie działa i kto go obsługuje.
Uruchamiamy je na naszych własnych kartach GPU, w naszym własnym środowisku, na europejskiej ziemi. Twoje zdjęcia są czytane przez maszyny, za które odpowiadamy, a wektory i odciski palca, które wychodzą z tego procesu, zostają u nas i nigdy nie są sprzedawane. To jest ta część, której Big Tech Ci nie zaoferuje, bo dla nich czytanie Twoich zdjęć to model biznesowy, a nie funkcja.
Żeby było jasne, gdzie jesteśmy: to pierwszy krok, a nie skończony obraz. Modele machine learning działają teraz na naszych własnych kartach GPU, ale nie cała nasza platforma działa jeszcze na sprzęcie, który posiadamy. Budujemy samodzielnie prowadzoną infrastrukturę kawałek po kawałku, a AI czytająca Twoje zdjęcia była celowym punktem startu, bo to najbardziej wrażliwa część. Wolimy powiedzieć Ci dokładnie, co i gdzie dziś działa, niż sugerować, że jesteśmy dalej, niż jesteśmy. Spodziewaj się, że rozwiniemy to w przyszłych wpisach, w miarę jak coraz większa część stosu będzie przenoszona na nasz własny sprzęt.
Jeśli chcesz biblioteki zdjęć z tak sprawnym wyszukiwaniem, bez oddawania danych, które za nim stoją, firmie, która na nich zarabia, to właśnie to budujemy.
Uwaga o obrazach: infografiki w tym wpisie zostały wygenerowane przy użyciu AI. Uważamy, że zasługują na swoje miejsce, bo ułatwiają wyobrażenie sobie tych idei.