Automatyczne Uczenie Maszynowe – TPOT

Funkcje tworzące model, hiperparametry, przekształcenia, wybór cech. Dobranie tych wszystkich elementów powinno znaleźć się w każdym procesie uczenia maszynowego. Dopasowanie ich wszystkich jednak może zająć bardzo dużo czasu. Możemy też popełnić wiele mniejszych lub większych błędów w poszczególnych krokach. Czy da się jakoś sprytnie ogarnąć ten proces w bardziej automatyczny sposób?

TPOT

TPOT Logo
TPOT Logo

TPOT jest moim ulubionym modułem Pythonowym, który automatyzuje proces budowania procesów uczenia maszynowego. Realizuje to poprzez testowanie wybranych modeli w uczeniu nadzorowanym wraz z testowaniem hiperparametrów. Dodatkowo zajmuje się selekcją i przekształcaniem cech. Wybór składników tych wszystkich elementów dokonywany jest na badzie algorytmów ewolucyjnych.

Przykład

Zacznijmy od przykładu użycia TPOT. Skorzystamy w nim z poznanego wcześniej zbioru breast cancer:

import pandas as pd
from tpot import TPOTClassifier
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split

breast_cancer = load_breast_cancer()
X = pd.DataFrame(breast_cancer["data"], 
                 columns = breast_cancer["feature_names"])
y = pd.Series(breast_cancer["target"])

X_train, X_test, y_train, y_test = train_test_split(X, y, 
                                                    test_size = 0.25, 
                                                    random_state = 42)

klasyfikator = TPOTClassifier(random_state = 42, early_stop = 10, verbosity = 2)

klasyfikator.fit(features = X_train, target = y_train)

klasyfikator.score(testing_features = X_test, testing_target = y_test)
klasyfikator.export("tpot.py")

Jak widać, użycie TPOT w zasadzie nie różni się niczym od użycia funkcji, które możemy napotkać, chociażby w module Scikit-Learn. Taki był cel twórców tego modułu.

Uruchomienie powyższego kawałka kodu powinno skutkować sprawdzeniem 3201 różnych kombinacji, z których najlepsza uzyskała wynik 0.965034965034965 na zbiorze testowym. Zaproponowana przez TPOT kombinacja wygląda tak:

LinearSVC(LinearSVC(GradientBoostingClassifier(input_matrix, learning_rate=0.001, max_depth=2, max_features=0.5, min_samples_leaf=5, min_samples_split=13, n_estimators=100, subsample=0.6500000000000001), C=10.0, dual=True, loss=hinge, penalty=l2, tol=0.0001), C=25.0, dual=False, loss=squared_hinge, penalty=l1, tol=0.01)

We wcześniejszym artykule opisałem używanie GridSearchCV w celu odnalezienia optymalnej kombinacji hiperparametrów. Takich kombinacji może być cała masa. Sprawdzenie każdej z nich (wraz ze sprawdzianem krzyżowym) może zająć bardzo dużo czasu. TPOT podchodzi do sprawy inaczej.

Ewolucja modelu predykcyjnego

Gdy TPOT zaczyna pracę, sprawdza, ile osobników ma mieć w populacji (domyślnie population_size = 100). Osobnik taki to nic innego jak model. Może to być prosty model typu DecisionTreeClassifier, ale może to również być cały proces, w którym stosowane jest wiele funkcji. Następnie sprawdza score każdego z tych osobników. Po sprawdzeniu każdego z nich zostawia najlepsze do dalszego użytku, a pozostałe zmienia w losowy sposób. Dzięki takiemu podejściu bardziej męczone są funkcje, które dały dobre wyniki i one są używane jako baza dla bardziej skomplikowanych procesów.

Proces ten jest powtarzany tak długo, aż osiągnięty zostanie limit pokoleń (domyślnie generations = 100) albo limit czasu (domyślnie max_time_mins = None). Najbardziej praktyczna jest jeszcze jedna opcja, czyli parametr early_stop. Domyślnie ustawiony na None, a w moim przykładzie na 10. Parametrem tym informujemy TPOT, po ilu pokoleniach, w których nie znalazł lepszego modelu ma przerwać.

Wady TPOT

Oczywistą i chyba największą wadą TPOT jest to, że jest to proces oparty o losowość. Oznacza to w praktyce tyle, że nigdy nie wiemy, czy już przypadkiem nie mamy wyznaczonego najlepszego rozwiązania naszego problemu. Działa to również w drugą stronę, może się zdarzyć, że będziemy czekać bardzo długo na lepsze rozwiązanie niż to, które pojawiło się od razu. Musimy więc oszacować czas, który chcemy przeznaczyć na proces ewolucji i uzbroić się w cierpliwość.

TPOT ma też inną wadę, która niekiedy może być istotna – aktualnie nie da się zapisać uzyskanego modelu. Jeśli więc poświęcimy jakiś czas na znalezienie dość dobrego modelu, to jedyne co możemy z nim zrobić przy pomocy TPOT to wyświetlić proponowany proces na ekranie, albo go zapisać do szablonu pliku skryptu Pythonowego. I jedno i drugie rozwiązanie nie jest optymalne, gdyż skoro poświęciliśmy już czas na trening, to fajnie byłoby zachować sobie już wytrenowany model na przyszłość.

Trzecią odkrytą przeze mnie wadą jest brak możliwości skonfigurowania TPOT w taki sposób, żeby nie tworzył stacking estimator i innych podobnych procesów. Czasem po prostu chcę wyszukać w miarę sensowną kombinację hiperparametrów dla jednej funkcji, a TPOT buduje proces z kilkoma użyciami tej funkcji z różnymi hiperparametrami. Ale z tego, co widziałem (np. tutaj) to być może odpowiedni parametr sterujący trafi niedługo do oficjalnego wydania.

Szablon skryptu Python

Wspomniałem powyżej, że TPOT może stworzyć nam szablon skryptu Python z definicją modelu. Jak wygląda taki szablon? W naszym wypadku jest to:

import numpy as np
import pandas as pd
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.model_selection import train_test_split
from sklearn.pipeline import make_pipeline, make_union
from sklearn.svm import LinearSVC
from tpot.builtins import StackingEstimator

# NOTE: Make sure that the class is labeled 'target' in the data file
tpot_data = pd.read_csv('PATH/TO/DATA/FILE', sep='COLUMN_SEPARATOR', dtype=np.float64)
features = tpot_data.drop('target', axis=1).values
training_features, testing_features, training_target, testing_target = \
            train_test_split(features, tpot_data['target'].values, random_state=42)

# Score on the training set was:0.9858803986710963
exported_pipeline = make_pipeline(
    StackingEstimator(estimator=GradientBoostingClassifier(learning_rate=0.001, max_depth=2, max_features=0.5, min_samples_leaf=5, min_samples_split=13, n_estimators=100, subsample=0.6500000000000001)),
    StackingEstimator(estimator=LinearSVC(C=10.0, dual=True, loss="hinge", penalty="l2", tol=0.0001)),
    LinearSVC(C=25.0, dual=False, loss="squared_hinge", penalty="l1", tol=0.01)
)

exported_pipeline.fit(training_features, training_target)
results = exported_pipeline.predict(testing_features)

Mamy tutaj widoczne cztery bloki. Pierwszy blok nie zawiera niczego szczególnego, są to importy używanych funkcji. Drugi blok jest już ciekawszy. Mamy tutaj szablon wczytywania danych z pliku CSV. Jeśli mamy odpowiednio przygotowany plik CSV (z nazwami kolumn i kolumną „target”), to wystarczy, że podamy ścieżkę do niego i symbol oddzielający. W tym miejscu mamy też propozycję podziału na zbiory train i test. Najciekawszy jest blok trzeci, gdzie mamy definicję naszego procesu (pipeline), który zawiera wybrane funkcje i ich hiperparametry. Ta zmienna (exported_pipeline) jest dla nas najważniejszym elementem tego pliku. W ostatnim bloku mamy uruchamianie treningu i tworzenie predykcji dla zbioru testowego.

Stacking Estimator

Ciekawym pomysłem na zwiększenie dokładności modelu jest tzw. stacking. Polega on, na stworzeniu nowej kolumny w ramce danych X, która jest wynikiem predykcji jakiegoś modelu. Tak rozbudowana ramka danych służy jako wejście do kolejnej funkcji modelującej. Możemy tak zagnieżdżać różne funkcje modelujące, aż uzyskamy wystarczający wynik. W naszym przypadku pierwszą funkcją modelującą była GradientBoostingClassifier. Predykcje tej funkcji zostały dołożone do X i wtedy została uruchomiona druga funkcja LinearSVC. Predykcje uzyskane z tego procesu zostały dołączone do X i wtedy została wytrenowana po raz drugi funkcja LinearSVC. Warto zwrócić uwagę, że hiperparametry podwójnie użytej funkcji LinearSVC są różne, więc są to w zasadzie dwie zupełnie inne funkcje modelujące.

Konfiguracja TPOT

Oprócz garści hiperparametrów (domyślne wartości są całkiem sensowne – ale jakby ktoś chciał nimi pomieszać to tutaj jest dokumentacja) mamy możliwość skonfigurować pulę funkcji modelujących, przekształcających i wybierających cechy. Robimy to za pomocą słownika w następujący sposób:

import numpy as np

config_TPOT = {
    # Classifiers
    'sklearn.tree.DecisionTreeClassifier': {
        'criterion': ["gini", "entropy"],
        'max_depth': range(1, 11),
        'min_samples_split': range(2, 21),
        'min_samples_leaf': range(1, 21)
    },
    'sklearn.neighbors.KNeighborsClassifier': {
        'n_neighbors': range(1, 101),
        'weights': ["uniform", "distance"],
        'p': [1, 2]
    },
    # Preprocesssors
    'sklearn.preprocessing.MinMaxScaler': {
    },
    # Selectors
    'sklearn.feature_selection.VarianceThreshold': {
        'threshold': [0.0001, 0.0005, 0.001, 0.005, 0.01, 0.05, 0.1, 0.2]
    }
}

W słowniku podajemy po prostu nazwę funkcji, która nas interesuje i zakres jej hiperparametrów. I to tyle. Nie musimy się martwić  licznością wartości każdego hiperparametru, bo TPOT i tak będzie je testował losowo. Jedyne, nad czym warto się zastanowić to decyzja, czy na pewno chcemy wrzucić do puli funkcje, które będą się długo trenować. Ale to wychodzi zawsze w praktyce w czasie używania TPOT na konkretnym zbiorze danych. TPOT ma wbudowane cztery domyślne konfiguracje, przy czym najczęściej będziemy przełączać się pomiędzy domyślną, light i własną.

Konkluzja

Proces TPOT
Proces TPOT

TPOT jest bardzo ciekawym pomysłem na automatyczne testowanie różnych kombinacji funkcji uczenia maszynowego i ich hiperparametrów. Jest prosty w użyciu (małpuje Scikit-Learn) i wygodny w konfiguracji. Ma kilka mankamentów, które w niektórych sytuacjach są nieco uciążliwe, ale jest aktywnie rozwijany i już niedługo część z tych problemów może przestać istnieć. Programiści pracują również nad zwiększeniem wydajności TPOT poprzez użycie np. modułu Dask (dyskusja tutaj), możemy więc się spodziewać potencjalnego skoku szybkości trenowania modeli. Sądzę więc, że warto mieć TPOTa w swoim schowku modułów Pythona.

Kursy Online

Jeśli jesteś zainteresowany zakupem wideo kursów online które przygotowałem, sprawdź tę stronę – może akurat opublikowałem tam kupony zniżkowe 🙂

Podobne artykuły

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *