Uczenie maszynowe na produkcji. Dlaczego to takie trudne?

Według zbiorowej pracy analizującej rozwój uczenia maszynowego w ponad 300 organizacjach projekty te są jednymi z największych wyzwań dla firm [1], a specjaliści data science regularnie narzekają, że ich modele są wdrażane na produkcję tylko czasami lub nigdy [2].

Co jest przyczyną trudności  powodujących falę rozczarowań i wkładanie projektów do szuflady? Zastanówmy się, co się zmieniło. W klasycznym projekcie IT wersja kodu określa wersję oprogramowania. W projektach z uczeniem maszynowym na wersję modelu wpływa wersja kodu i wersja danych. Czy to możliwe, że wprowadzenie kilku tabel do równania tak drastycznie wpłynęło na złożoność, a co za tym idzie – powodzenie projektów? 

Reagowanie na zmianę kodu spowodowało rozwój specjalizacji DevOps oraz setki konkurujących ze sobą usług, mniej lub bardziej ułatwiających ciągłą integrację i ciągłe dostarczanie. Natomiast projekt z uczeniem maszynowym to reagowanie na zmiany w kodzie i w danych, co podnosi trudność przynajmniej do kwadratu, co mam zamiar udowodnić Ci w tym artykule.

Dłuższa pętla zwrotna

Praca z danymi stawia nas przed zupełnie nowymi wyzwaniami. Podczas gdy oprogramowanie na ogół może być opracowywane lokalnie wraz z natychmiastową pętlą zwrotną, jak nowa linia kodu wpływa na wynik końcowy. Piszesz test, sprawdzasz, czy świecą się tylko zielone światła, i idziesz dalej. W uczeniu maszynowym pętla zwrotna zaczyna się w tym samym miejscu, jednak może się skończyć za parę godzin, kiedy to skończysz trenować model.

Nawet jeśli pracujemy na niedużym zbiorze danych, a nasz model nie wymaga zaplecza kart graficznych, to podczas strojenia jego parametrów będziemy skazani zapewne na  parę godzin oczekiwania. Co więcej, docelowo trenowanie i tak musi się odbywać cyklicznie (o czym więcej w dalszej części artykułu), więc dochodzi dodatkowy proces do przeniesienia na zdalne środowisko.

Kolejnym ograniczeniem dla pracy na lokalnej maszynie jest rozmiar zbioru danych. 

Żeby zapełnić dysk nawet kilkuletniego laptopa danymi tabelarycznymi (a takich projektów z uczeniem maszynowym jest najwięcej), to ich zbiór musiałby mieć miliardy wierszy z setkami kolumn. Mamy jednak projekty dotykające ścieżek audio, obrazów i wideo. Wprawdzie można eksperymentować i rozwijać model na wycinku zbioru danych, co jest powszechną praktyką, jednak ostateczna ewaluacja odbywa się na całym zbiorze danych.

Co więcej, w środowisku ML nasilają się głosy, aby nie wykonywać eksperymentów na lokalnej maszynie, nawet jeśli jest to możliwe, ponieważ docelowo proces trenowania i tak musi wylądować w chmurze. Im wcześniej tam się znajdzie, tym lepiej.

Wersjonowany zawsze ubezpieczony

Nikt już sobie chyba nie wyobraża komercyjnego projektu bez systemu kontroli wersji. Dzięki niemu możemy wygodnie współpracować i cofać się w czasie, co kosztuje nas jedynie kilka uderzeń w klawiaturę. Ponieważ to wersja kodu tworzy wersję oprogramowania, dzięki systemowi kontroli wersji możemy w dowolnej chwili zbudować dowolny wariant aplikacji. W przypadku uczenia maszynowego jest inaczej. 

Po pierwsze, wynikiem pracy nie jest kod, a model. Ten natomiast wynika z wersji kodu, który tworzy i trenuje model, oraz danych, które wykorzystuje. Dlatego jeśli chcesz mieć taką samą maszynę czasu, kiedy rozwijasz projekty z uczeniem maszynowym, musisz wersjonować kod, dane, a najlepiej i modele.

https://valohai.com/assets/files/practical-mlops-ebook.pdf

Dlaczego wersjonować również modele, a nie tylko dane?

Stworzyłeś nowy model, wdrażasz go na produkcję. Wszystko dobrze działa, jednak tylko przez chwilę. Być może model na nowych danych zachowuje się niepokojąco albo jest zbyt skomplikowany, przez co trudniej mu obsłużyć większy ruch. Musisz cofnąć zmiany. Jaki będzie tego efekt, jeśli nie wersjonujesz modeli? Czy musisz wytrenować go na poprzedniej wersji kodu i danych? Ile to zajmie: 5 minut czy 2 dni? Nawet jeśli mniej niż kwadrans, to co jeśli pojawią się problemy podczas trenowania modelu? Wersjonowanie modeli jest polisą ubezpieczeniową, za którą płaci się miesięczną ratę w postaci rachunku za usługi do przechowywania danych w chmurze. Wysokość składki zależy od liczby wersji, które chcesz przechowywać, oraz rozmiaru modelu. Oszacujmy jej koszt. Załóżmy, że pracujesz w dojrzałym projekcie, który wersjonuje aż 1000 modeli głębokiego uczenia maszynowego, a każdy z nich waży 500 MB. Miesięczna składka wynosi około 23 $.

Testowanie danych przynajmniej tak samo jak modelu

Testowanie danych

Warto jest się czasem wynurzyć na powierzchnię i odkryć oczywistości, zamiast tonąć cały czas w szczegółach. Zgodzisz się zapewne, że tempo czytania jest tempem patrzenia. Nie potrafisz czytać szybciej, niż ruszasz gałkami ocznymi. W kontekście ML jest oczywiste, że model będzie tak dobry, jak dobre są dane, które służą do jego trenowania. Mimo że to truizm, już nieraz na dźwięk tego (wydawać by się mogło) banału zauważyłem błysk w oku osoby, z którą rozmawiałem. Jaki płynie z tego morał? Testuj dane przynajmniej tak dobrze jak model.

Dane, które „wkładamy” do modelu, przebyły długą drogę. Zwiedziły zapewne wiele miejsc ekosystemu, a podczas tej podróży dbano o nie czasem lepiej, a czasem gorzej. Nam natomiast przychodzi wyciągać wnioski z tych zmęczonych tułaczy. Co więcej, nie wiemy, jakie dane przyjdą do nas w przyszłości. Możemy natomiast zautomatyzować upewnianie się, czy są w takim stanie, w jakim oczekujemy. Co istotne, testowanie danych powinno być spójne dla danych treningowych i podczas predykcji na żywo. Ma ono ukazać błędy i niepowodzenia, które w przyszłości mogą się zdarzyć oryginalnym producentom. Problem polega na tym, że wprawdzie  model może przewidywać na podstawie błędnych danych, jednak pytanie, kiedy to zachowanie zostanie wyłapane. Dla modelu nie ma znaczenia, czy dom ma 3, czy minus 8 sypialni. Nie wszystkie testy jednak są tak oczywiste. Na przykład jeśli oczekiwanymi danymi jest tekst w języku polskim, to testem będzie upewnienie się, że najczęstszymi słowami są „się”, „i”, „w”. Jeśli częściej pojawiają się inne wyrazy, to może oznaczać, że nie mamy do czynienia ze spodziewanym językiem.

Testowanie modeli

Mimo że większość gatunków modeli jest deterministyczna (takie samo wejście zawsze daje takie samo wyjście), to ich testowanie również jest trudniejsze, ponieważ ich natura polega na dynamicznym odkrywaniu istotnych cech ciągle zmieniających się danych. Modele wymagają regularnego odświeżania, ponieważ danych cały czas przybywa, a ich charakter ulega ciągłej zmianie. Co to oznacza w praktyce? Że przyszły model zajmujący się wyceną nieruchomości będzie sugerował inną cenę dla tego samego domu.

Podczas mierzenia jakości modelu sprawdza się jego dopasowanie do danych. Jeśli jest za słabe, po prostu mamy kiepski model. Nie potrafi on wówczas dobrze wyciągnąć wniosków z danych, które dostał, aby się uczyć, nie mówiąc już nawet o przyszłych, których nigdy nie widział. Przeciwna sytuacja, to znaczy kiedy dopasowanie jest za mocne, też nie jest dobra. Model radzi sobie przyzwoicie na danych, które otrzymał podczas trenowania, jednak nie potrafi dobrze wnioskować na danych, których nie widział wcześniej. Zbyt słabe i zbyt mocne dopasowania są bezpiecznikami z perspektywy całego zbioru danych i jest mierzone na etapie trenowania. Te dwie wartości są jednymi z najważniejszych kiedy idzie o ocenę modelu. Problem tkwi w testowaniu i wykrywaniu niepokojących zachowań dla konkretnych przypadków. Rozwiązaniem jest monitoring.

Reagowanie na żywo

Zdefiniowanie niepokojącego zachowania czy niestabilności modelu i użycie testów do ich wykrywania przed wdrożeniem na produkcję to jedno. Wykrywanie zaś anomalii na produkcji, szczególnie kiedy model odpowiada w czasie rzeczywistym, to inna para kaloszy, ponieważ model spotka się z danymi, których nigdy wcześniej nie widział, a musi odpowiedzieć od razu. Znów, problem może tkwić w samych danych, które spływają z innej części systemu i nie są nadzorowane w przeciwieństwie do danych treningowych, bądź w naturze modelu, który na nowe dane po prostu nie jest przygotowany. Co więcej, pojedyncza predykcja, która wyjątkowo odstaje, mimo wszystko może być poprawna. Jak zatem monitorować model, aby wykorzystać jego potencjał, a jednocześnie reagować na jego wynaturzone zachowanie?

W klasycznej aplikacji monitorujemy zarówno zużycie hardware (RAM, CPU), jak i samą aplikację, mierząc liczbę zapytań na sekundę. Na podstawie tych metryk, zmieniających się z każdą chwilą, możemy reagować w czasie rzeczywistym, na przykład skalując aplikację, czy wykrywać podejrzane zachowania wynikające zarówno z błędów w systemie, jak i dobrze życzących nam użytkowników, blokując dany adres IP.

Monitorowanie modelu również polega na obserwowaniu jego zachowania w czasie. Zachowania, czyli przewidywania, które zwraca, porównuje się do wartości bazowej. Na przykład dla modelu, który przewiduje ceny nieruchomości, średnia cena domu w zbiorze treningowym wynosiła 400 000 zł, a dla ostatnich 100 predykcji na produkcji z 2 dni średnia wartość wynosi 500 000 zł, co mogłoby uruchomić alarm. Innymi słowy, monitorowanie modelu to porównywanie atrybutów statystycznych danych wejściowych i predykcji w odniesieniu do atrybutów statystycznych podczas nadzorowanego uczenia. 

Nawet jeśli predykcje mają prawidłowy charakter (tzn. np. średnia cena domów jest utrzymana na odpowiednim poziomie), to istotne jest również, co wpłynęło na to konkretne przewidywanie. Wróćmy jeszcze raz do tematu nieruchomości, załóżmy, że nasz model przewidział cenę domu 400 000 zł. Okazało się jednak, że na tę decyzję bardziej wpłynęła powierzchnia garażu zamiast liczby sypialni. W danych treningowych nie było domu, który ma garaż o powierzchni 120 mkw. Przecież to nie może się wydarzyć na produkcji! 

Obszar interpretowania i wyjaśniania decyzji modelu jest specjalizacją samą w sobie, jednak kojarzony jest głównie z uzasadnianiem zachowania modelu w trakcie jego doskonalenia, a nie jako narzędzie do reagowania w produkcyjnym systemie.

Ciągłe dostarczanie i ciągłe trenowanie

O ile bardzo satysfakcjonująca jest praca nad kodem funkcjonującym w próżni, o tyle w rzeczywistości tylko oprogramowanie, które wyjdzie do ludzi, może zasilić budżet. 

Ciągła integracja i ciągle dostarczanie to zbiór praktyk, które mają na celu automatyzować wdrożenia i codzienną pracę nad kodem tak, aby każda zmiana bez dodatkowego tarcia dotarła na zdalne środowisko. W podręcznikowej aplikacji jedynym powodem do zbudowania i wdrożenia nowej wersji jest zmiana w kodzie. Ta może być wywołana przez wprowadzenie nowej funkcjonalności czy naprawienie błędu. Zmieniamy kod, stajemy przed bramami produkcji, pokazujemy zielone naklejki wykonanych testów i jeśli nie zaplątał się inny kolor, aplikacja zaczyna żyć w prawdziwym świecie. Nie trzeba wdrażać tej samej wersji kodu, jeśli baza danych, którą on obsługuje, powiększy się dwukrotnie. Kiedy pojawi się nowa kolekcja porcelany w sklepie internetowym, nie ma powodu, aby skompilować kod, który odpowiada za serwowanie filiżanek do naszego e-commerce. 

Z modelami i tym razem jest inaczej. Modele się starzeją, a po pewnym czasie stają się bezużyteczne. Tym razem – dla odmiany – to przez dane. Dane, w których pojawiają się nowe wzorce, zmieniają się trendy i przybywa produktów. Model rekomendujący filmy, nie poleci tych, których nie widział na etapie trenowania (nie we wszystkich implementacjach systemów rekomendacyjnych), a nawigacja wspierana przez AI nie zaproponuje trasy nowego odcinka A4. Rozwiązaniem tego problemu jest cykliczne, regularne trenowanie modeli. Jak widzisz, to nie tylko zmiana kodu powoduje wdrożenie nowych modeli. Oznacza to, że musisz stworzyć i utrzymywać dodatkowy proces.

Podsumowanie

Czy to wszystko jest naprawdę potrzebne, jeśli chcesz zajmować się uczeniem maszynowym? Nie, to jest konieczne, aby zwiększyć swoje szanse na dotarcie do mety oraz zminimalizować koszty utrzymania. Rodzi się nowa specjalizacja MLOps mająca na celu rozwiązanie wyżej opisanych problemów, aby specjaliści od statystyki i sieci neuronowych mogli się skupić na swojej pracy. 

Wprawdzie nie każdy projekt ML musi interpretować predykcje na żywo, natomiast prawie każdy z nich jest bardziej złożony niż tradycyjna aplikacja, ale większość z nich powinna wersjonować dane i wdrożyć proces ciągłego trenowania.

Dobrze jest zdać sobie z tego sprawę przed rozpoczęciem projektu. Odpowiadając sobie na istotne pytania przed startem, możemy uniknąć zakopania miesięcy pracy albo przynajmniej ustrzec się błędów, co pozwoli oszczędzić nam kilka dni albo tygodni.

Udostępnij ten wpis


Dobrnąłeś do końca. Jeśli ten artykuł był dla Ciebie wartościowy i chcesz otrzymywać informacje o kolejnych, to zapraszam Cię do zapisania się do listy mailingowej. Gwarantuję zero spamu.

Radek.

Inne artykuły

Transakcje ACID

W trakcie zapisu danych do bazy wiele rzeczy może pójść nie tak. Może zapełnić się dysk, połączenie sieciowe zostanie zerwane pomiędzy bazą a klientem, przewróci się aplikacja, która wysyła …
Partycjonowanie bazy danych okładka

Partycjonowanie bazy danych

Partycjonowanie pozwala podzielić tabelę na mniejsze części, gdzie każda z nich może się znajdować na innym serwerze. Zobacz, jak to działa oraz dlaczego jest to …

2 thoughts on “Uczenie maszynowe na produkcji. Dlaczego to takie trudne?

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.