Okej, przeczytałeś więc gdzieś (może u mnie?) jakiś artykuł, nowinkę albo samouczek związany z uczeniem maszynowym. Przyszło Ci do głowy, że uczenie maszynowe to fajna sprawa, hype jest i hajs się zgadza. Postanowiłeś więc sprawdzić, na czym to w ogóle polega. Zrobiłeś własne badania pt. „o co tu chodzi” i doszedłeś do własnych wniosków. Wnioski te mogą być zbliżone do „hmmm… to uczenie maszynowe to takie trochę bardziej sprytne programowanie, które bardziej polega na danych”. I jest to całkiem sensowny wniosek. Ale możesz też dojść do czegoś następującego: „o rety, sama matematyka, całe mnóstwo pojęć, które ledwie co wymawiam i dyskusja nad problemami, których nie rozumiem”. I to też może być całkiem sensowny wniosek. Może on jednak Cię nieco zablokować i sprawić, że stwierdzisz „a, chrzanić to, wracam do pisania UI w TypeScripcie, tu przynajmniej nie muszę się przejmować gradientami i entropią”. I moment chwilkę przed sformułowaniem tego ostatniego stwierdzenia jest momentem, w którym chciałbym podzielić się z Tobą moim pomysłem na to, jak zacząć działać w uczeniu maszynowym.
Uczenie maszynowe to stale rozwijająca się dziedzina. Oprócz tego, że ilość zagadnień z nią związanych stale rośnie, rozrasta się ona również w wielu kierunkach. Zastosowanie uczenia maszynowego przyniosło też wiele zysków wielu firmom. Okazuje się więc, że jeśli nie wiemy, czego szukamy, możemy trafiać na materiały dotyczące bardzo odległych od siebie zagadnień i na różnych poziomach trudności. Możemy też trafiać na różne opinie i wręcz sprzeczne ze sobą wiadomości. Osoba początkująca może więc bardzo łatwo się w tym pogubić i zrezygnować. Przygotowałem więc listę kilku punktów, które taka osoba powinna ogarnąć, żeby dobrze wgryźć się w swój pierwszy projekt uczenia maszynowego.
Elementy, które według mnie należy dobrać do dobrego (niekoniecznie startowego) projektu:
- język programowania
- typ problemu
- podejście
- moduły/biblioteki
- dane
- cel
- metryka
- algorytm
- hiperparametry
Elementy te możemy sobie dobierać prawie w dowolnej kolejności, z pewnymi wyjątkami, bo np. algorytm będziemy dobierać z puli, którą otrzymamy, gdy wybierzemy typ problemu. Ale o tym dokładniej poniżej.
Język programowania
Język programowania będzie jednym z najprostszych wyborów. Wybierzesz ten, który najlepiej znasz, pod warunkiem, że będzie to język z puli Python, R i Julia. Faktem jest, że uczenie maszynowe możemy stosować z wykorzystaniem każdego języka programowania, jednakże prawdopodobnie nie będzie to miało za dużo sensu, szczególnie jeśli jesteś osobą początkującą. Myślę, że najszybciej uda Ci się osiągnąć wyniki, jeśli wybierzesz Pythona. Nawet jeśli go nie znasz i będziesz się go musiał nauczyć, w najgorszym wypadku poznasz jeden z najpopularniejszych i najszerzej używanych języków programowania. Moje zalecenie: Python3.
Typ problemu
W uczeniu maszynowym, jednym z najpopularniejszych podziałów jest podział ze względu na typ problemu, który chcemy rozwiązać. Mamy tu więc uczenie nadzorowane, nienadzorowane i ze wzmacnianiem (więcej w artykule Czym właściwie jest Machine Learning?). Problemy, które występują w każdym z tych obszarów, różnią się dość znacząco od siebie. Poziom trudności rośnie w nich w takiej kolejności, w jakiej je wypisałem. I nie jest to tylko związane z algorytmami, które są tam używane. Kontekst, w którym są stosowane, również się komplikuje. Według mnie najlepiej jest zacząć od uczenia nadzorowanego – uzyskasz wtedy konkretny wynik, który będziesz mógł zinterpretować i pracować nad jego polepszeniem. Moje zalecenie: Uczenie nadzorowane.
Podejście
W uczeniu maszynowym możemy też spostrzec inny podział. Znajdziemy w nim dwie grupy: uczenie maszynowe klasyczne i głębokie sieci neuronowe. Podział ten jest znacznie bardziej umowny niż wspomniany powyżej i dla niektórych w ogóle może nie istnieć. Ja jednak należę do osób, które wydzielają głębokie sieci neuronowe jako osobny byt, a nie kolejny algorytm. Jakie podejście wybrać? Na start proponuję Ci podejście klasyczne. Sieci neuronowe to dość rozbudowana zabawka (mimo bardzo prostych założeń) i może okazać się, że będziesz dużo kluczył, zanim uda Ci się dojść do czegoś sensownego. Moje zalecenie: Podejście klasyczne – bez sieci neuronowych.
Moduły/Biblioteki
Jednym z moich wcześniejszych zaleceń było wybranie któregoś języka z listy Python, R, Julia. Zalecenie to nie było przypadkowe. Dodatkowym argumentem, żeby skoncentrować się na którymś z tych języków, jest to, że mają one całkiem fajne dodatkowe moduły i biblioteki. Jeśli miałeś już do czynienia z programowaniem, to pewnie zauważyłeś, że w „gołym” języku programowania fajnie programuje się rzeczy dość proste (niekoniecznie łatwe). Natomiast często, gdy chcemy skorzystać z jakiegoś bardziej wyrafinowanego algorytmu albo idei, wspieramy się specjalnymi napisanymi przez kogoś innego kawałkami kodu. Takie kawałki kodu są osobno rozwijane i testowane oraz często są dedykowane tylko jednej idei którą (w założeniu) realizują jak najlepiej. Nie inaczej jest w przypadku Pythona. Tutaj, jeśli mówimy o klasycznym uczeniu maszynowym, pierwszym wyborem jest Scikit-Learn. Wraz z tym modułem dostajemy całą masę funkcji do transformacji danych, ich modelowania i eksploracji. Jeśli więc masz zamiar zajmować się uczeniem maszynowym przy pomocy Pythona, Scikit-Learn powinien należeć do Twojego portfolio. Moje zalecenie: Scikit-Learn.
Dane
Okej, zagłębiamy się coraz bardziej w uczenie maszynowe, a nie omówiliśmy jeszcze sprawy danych. Żeby mieć szansę nauczyć się czegokolwiek, to zdecydowanie musimy zabrać się za odpowiedni zbiór danych. Wiem, brzmi to trochę ostrożnie – Ale jak to? To uczenie maszynowe nie zadziała dla każdego zbioru danych? No okazuje się, że nie musi. Tzn. prawie zawsze będziemy mogli uruchomić daną funkcję modelującą, ale nie zawsze uzyskamy sensowny wynik. Warto więc przy pierwszym podejściu wybrać dane, które mają szansę dać sensowny model. Temat danych ogólnie jest bardzo ciekawy. Aktualnie w internecie mamy dostęp do całkiem sporej ilości darmowych zbiorów danych. Można by rzec, że dla początkującego jest to klęska urodzaju. W takiej sytuacji mogę Ci polecić dwa źródła danych. Pierwsze źródło to UCI Machine Learning Repository. Mamy w nim kilkaset mniej lub bardziej sensownych zbiorów danych, które zostały użyte do badań związanych z uczeniem maszynowym. Nie wszystkie te zbiory nadają się na zadanie dla początkujących, jeśli jednak znudzi Ci się to, co Ci zaproponuję poniżej, to zachęcam do własnej eksploracji tego repozytorium. Drugim źródłem danych są funkcje dostarczone przez Scikit-Learn. Po uruchomieniu odpowiednich funkcji i przypisaniu ich wyników do zmiennych uzyskamy zmienne, których zawartością będą dane. Część uzyskanych w ten sposób danych pochodzi z wyżej wspomnianego repozytorium. I stamtąd pochodzi też zbiór uzyskany jako wyniki funkcji breast_cancer(). Zbiór ten jest fajny, bo jest na tyle mały, że uda nam się błyskawicznie uzyskać wyniki przy zastosowaniu prawie każdego algorytmu. A jest na tyle duży, że można faktycznie użyć go do uczenia maszynowego. A, no i jest od razu gotowy do używania – nie trzeba się trapić jego przekształcaniem do użytecznej formy. Czegóż chcieć więcej? Moje zalecenie: Breast Cancer Wisconsin Dataset.
Cel
Mamy już odpowiednie narzędzia i dane. Warto byłoby więc zastanowić się, jaki cel chcemy zrealizować. Jest on niejako zdeterminowany już przez dane. Bo w naszych danych, najbardziej dla nas interesująca kolumna zawiera dwie wartości 0 i 1 odpowiadające klasom malignant i benign. Więc chcąc nie chcąc naturalnym krokiem będzie zwrócenie się ku klasyfikacji. Dodatkowym atutem naszego zbioru danych jest to, że mamy tylko dwie klasy, więc naszym celem będzie przeprowadzenie jak najlepszej klasyfikacji binarnej. Klasyfikacja binarna jest chyba najłatwiejsza w debugowaniu i najłatwiejsza w zrozumieniu więc idealnie się tutaj nada. Moje zalecenie: klasyfikacja binarna.
Metryka
Skoro wyznaczyliśmy już cel naszego projektu (np. klasyfikacja), to możemy przystąpić już do pracy. Ale czy aby na pewno? Skąd będziemy wiedzieli, że zbliżamy się do naszego celu? Czy ten nasz cel jest w ogóle mierzalny? Czy klasyfikator dający nam losowe predykcje będzie tym, czego poszukiwaliśmy? Okazuje się, że na razie brakuje nam jeszcze metryki związanej z naszym celem. Taka metryka powinna dać nam jakąś liczbę, którą możemy później użyć do porównania. Jeśli jesteś początkujący w uczeniu maszynowym, to wystarczy, że wybierzesz jakąś uniwersalną metrykę i zaznajomisz się z faktem, czy wyższa wartość oznacza lepszy wynik, czy lepszym wynikiem będzie niższa uzyskana wartość. Uniwersalną metryką popularną w klasyfikacji jest accuracy score, czyli proporcja dobrze dokonanych predykcji do wszystkich predykcji. Wartość ta mieści się w zakresie od 0 do 1 i im jest większa, tym lepiej. Moje zalecenie: funkcja accuracy_score.
Algorytm
Powoli zbliżamy się już do końca budowania naszego idealnego projektu dla początkujących. Zostało nam jeszcze w zasadzie samo mięso uczenia maszynowego, czyli algorytm. Jeśli spojrzymy sobie na dokumentację Scikit-Learn dotyczącą uczenia nadzorowanego, zauważymy, że mamy tam całą masę różnych fajnych algorytmów. Fakt, nie wszystkie nadają się do klasyfikacji, ale wciąż mamy zdecydowanie za duży wybór, żeby czuć się komfortowo. Moim ulubionym algorytmem klasyfikacji jest drzewo decyzyjne (Jak wyhodować drzewo decyzyjne?, Drzewo decyzyjne a hiperparametry). Drzewo jest bardzo proste w interpretacji, a sam algorytm też daje się łato ogarnąć, idąc krok po kroku. Z tego powodu, zawsze, gdy komuś tłumaczę zagadnienia związane z uczeniem maszynowym, staram się odnieść do modelu stworzonego przez ten algorytm. Moje zalecenie: funkcja DecisionTreeClassifier().
Hiperparametry
Ostatnim elementem naszej układanki są hiperparametry. Dzięki temu, że funkcje w Scikit-Learn mają ustawione domyśle wartości hiperparametrów, możesz potraktować ten element jako opcjonalny. Hiperparametry są jednak bardzo ważnym elementem każdego procesu uczenia maszynowego. Najłatwiej będzie Ci się o tym przekonać, modyfikując wartości hiperparametrów i obserwując uzyskane w ten sposób wyniki. Nie ma idealnej recepty na optymalizację hiperparametrów, warto jednak mieć je na uwadze przez cały czas realizacji projektu. Moje zalecenie: 'criterion’: [„gini”, „entropy”], 'max_depth’: range(1, 11), 'min_samples_split’: range(2, 21), 'min_samples_leaf’: range(1, 21).
Co teraz?
Teraz, skoro znasz już zarys projektu i wiesz mniej więcej co robić, powinieneś zastanowić się, ile czasu chcesz przeznaczyć na pracę. Z własnego doświadczenia wiem, że im więcej czasu poświęcimy pracy z problemem, tym więcej wiedzy zdobędziemy. Do czasu. Okazuje się bowiem, że na tyle mały zbiór danych (ilość kolumn i ilość wierszy) nie daje opcji na walczenie z nim w nieskończoność. Warto natomiast poświęcić mu około 20 godzin, żeby dobrze zapoznać się potencjalnymi problemami, które mogą się pojawić w czasie pracy. Tak czy siak, zachęcam Cię do rozpoczęcia takiego projektu i podzielenia się z nami jego wynikami i potencjalnymi problemami, na jakie natrafiłeś. Jeśli będziesz mieć jakieś problemy nie do przejścia, to również napisz w komentarzu, spróbuję pomóc Ci z nimi jak najszybciej. Powodzenia!