MLOps — Książka kucharska, rozdział 1

MLOps — Książka kucharska, rozdział 1

Cześć wszystkim! Jestem programistą CV w KROK. Od 3 lat realizujemy projekty w zakresie CV. W tym czasie zrobiliśmy wiele różnych rzeczy, takie jak: monitorowanie kierowców, aby w trakcie jazdy nie pili, nie palili, nie rozmawiali przez telefon, patrzyli na drogę, a nie we śnie lub w chmury; rejestrowanie tych, którzy jeżdżą po wydzielonych pasach i zajmują kilka miejsc na parkingu; dbanie o to, aby pracownicy nosili kaski, rękawice itp.; identyfikowanie pracownika, który chce wejść na teren obiektu; liczenie wszystkiego, co tylko możliwe.

Do czego zmierzam?

W trakcie realizacji projektów napotkaliśmy trudności, wiele trudności, z niektórymi problemami możecie być już zaznajomieni, lub poznacie je w przyszłości.

Modelujemy sytuację

Załóżmy, że przyjęliśmy pracę w młodej firmie „N”, która zajmuje się ML. Pracujemy nad projektem ML (DL, CV), a potem z jakiegoś powodu przeskakujemy na inną pracę, w każdym razie robimy przerwę i wracamy do naszej lub cudzej sieci neuronowej.

  1. Przychodzi moment prawdy, musimy jakoś przypomnieć sobie, na czym stanęliśmy, jakie hiperparametry próbowaliśmy i, co najważniejsze, do jakich wyników one prowadziły. Może być wiele sposobów, jak kto przechowywał informacje o wszystkich uruchomieniach: w głowie, w konfiguracjach, w notesie, w środowisku roboczym w chmurze. Miałem okazję zobaczyć wariant, w którym hiperparametry były przechowywane w postaci skomentowanych linii w kodzie, ogólnie rzecz biorąc, pole do wyobraźni. A teraz wyobraźcie sobie, że wracacie nie do swojego projektu, a do projektu osoby, która opuściła firmę, a w spadku dostaliście kod i model o nazwie model_1.pb. Dla pełniejszego obrazu i oddania całej bolesnej sytuacji, załóżmy, że jesteście również początkującym specjalistą.
  2. Idźmy dalej. Aby uruchomić kod, my i wszyscy, którzy będą z nim pracować, musimy stworzyć środowisko. Często zdarza się, że tego również z jakichś powodów nie pozostawiono nam w spadku. To także może być nietrywialne zadanie. Nie chcemy tracić czasu na ten krok, prawda?
  3. Trenujemy model (na przykład detektor samochodów). Dochodzimy do momentu, w którym staje się on całkiem zadowalający — to czas, aby zapisać wyniki. Nazwiemy go car_detection_v1.pb. Następnie trenujemy kolejny model — car_detection_v2.pb. Po pewnym czasie nasi koledzy lub my sami uczymy się kolejnych wersji, korzystając z różnych architektur. W końcu powstaje wiele artefaktów, które musimy dokładnie zebrać (ale tym zajmiemy się później, bo mamy teraz inne, ważniejsze sprawy).
  4. No i to wszystko! Mamy model! Możemy przejść do uczenia kolejnego modelu, opracowania architektury dla nowego zadania, czy może wyjść na herbatę? A kto zajmie się wdrożeniem?

Wykrywanie problemów

Praca nad projektem lub produktem to wysiłek wielu osób. Z biegiem czasu ludzie odchodzą i przychodzą, projektów przybywa, a same projekty stają się coraz bardziej skomplikowane. Tak czy inaczej, sytuacje z opisanego powyżej cyklu (i nie tylko) w różnych kombinacjach będą się pojawiać z iteracji na iterację. Wszystko to prowadzi do straty czasu, zamieszania, frustracji, a być może – do niezadowolenia klienta, a w końcu – do utraconych pieniędzy. Chociaż zwykle przechodzimy przez te same pułapki, sądzę, że nikt nie chce powtarzać tych chwil raz za razem.

MLOps — Książka kucharska, rozdział 1

I tak, przeszliśmy przez jeden cykl rozwoju i widzimy, że są problemy, które trzeba rozwiązać. W tym celu potrzebujemy:

  • wygodnie przechowywać wyniki pracy;
  • usprawnić proces wprowadzania nowych pracowników;
  • uprościć proces wdrażania środowiska deweloperskiego;
  • ustalić proces wersjonowania modeli;
  • posiadać wygodny sposób walidacji modeli;
  • znaleźć narzędzie do zarządzania stanem modeli;
  • znaleźć sposób dostarczania modeli do produkcji.

Wygląda na to, że musimy wymyślić workflow, który umożliwi łatwe i wygodne zarządzanie tym cyklem życia? Taka praktyka nosi nazwę MLOps.

MLOps, czyli DevOps dla uczenia maszynowego, umożliwia zespołom danych i specjalistom IT współpracę oraz zwiększa tempo rozwoju i wdrażania modeli poprzez monitorowanie, walidację i zarządzanie modelami uczenia maszynowego.

Możesz przeczytać, co na ten temat myślą chłopaki z Google. Z artykułu wynika, że MLOps to dość obszerna rzecz.

MLOps — Książka kucharska, rozdział 1

W swojej artykule opiszę tylko część procesu. Do realizacji wykorzystam narzędzie MLflow, ponieważ jest to projekt open-source, do połączenia potrzeba niewielkiej ilości kodu i istnieje integracja z popularnymi frameworkami ML. Możesz poszukać w internecie innych narzędzi, na przykład Kubeflow, SageMaker, Trains itp. i może znaleźć takie, które lepiej odpowiada Twoim potrzebom.

"Budujemy" MLOps na przykładzie wykorzystania narzędzia MLFlow

MLFlow to platforma z otwartym kodem źródłowym do zarządzania cyklem życia modeli ml (https://mlflow.org/).

MLflow składa się z czterech komponentów:

  • MLflow Tracking — zajmuje się rejestrowaniem wyników i parametrów, które prowadzą do tych wyników;
  • MLflow Project — pozwala na pakowanie kodu i jego reprodukcję na dowolnej platformie;
  • MLflow Models — odpowiada za wdrażanie modeli do produkcji;
  • MLflow Registry — umożliwia przechowywanie modeli i zarządzanie ich stanem w centralnym repozytorium.

MLflow operuje na dwóch bytach:

  • uruchomienie — to pełny cykl uczenia, parametry i metryki, które chcemy zarejestrować;
  • eksperyment — to "temat", który łączy uruchomienia.

Wszystkie kroki przykładu zrealizowane są na systemie operacyjnym Ubuntu 18.04.

1. Rozwijamy serwer

Abyśmy mogli łatwo zarządzać naszym projektem i uzyskiwać wszystkie potrzebne informacje, rozwiniemy serwer. Serwer śledzenia MLflow ma dwa główne komponenty:

  • backend store — odpowiada za przechowywanie informacji o zarejestrowanych modelach (obsługuje 4 bazy danych: mysql, mssql, sqlite i postgresql);
  • artifact store — odpowiada za przechowywanie artefaktów (obsługuje 7 możliwości przechowywania: Amazon S3, Azure Blob Storage, Google Cloud Storage, serwer FTP, serwer SFTP, NFS, HDFS).

Jako artifact store dla uproszczenia weźmy serwer SFTP.

  • tworzymy grupę
    $ sudo groupadd sftpg
  • dodajemy użytkownika i ustawiamy mu hasło
    $ sudo useradd -g sftpg mlflowsftp
    $ sudo passwd mlflowsftp 
  • korygujemy kilka ustawień dostępu
    $ sudo mkdir -p /data/mlflowsftp/upload
    $ sudo chown -R root.sftpg /data/mlflowsftp
    $ sudo chown -R mlflowsftp.sftpg /data/mlflowsftp/upload
  • dodajemy kilka linii do /etc/ssh/sshd_config
    Match Group sftpg
     ChrootDirectory /data/%u
     ForceCommand internal-sftp
  • restartujemy usługę
    $ sudo systemctl restart sshd

Jako backend store weźmy postgresql.

$ sudo apt update
$ sudo apt-get install -y postgresql postgresql-contrib postgresql-server-dev-all
$ sudo apt install gcc
$ pip install psycopg2
$ sudo -u postgres -i
# Utwórz nowego użytkownika: mlflow_user
[postgres@user_name~]$ createuser --interactive -P
Wprowadź nazwę roli do dodania: mlflow_user
Wprowadź hasło dla nowej roli: mlflow
Wprowadź je ponownie: mlflow
Czy nowa rola ma być superużytkownikiem? (y/n) n
Czy nowa rola ma mieć możliwość tworzenia baz danych? (y/n) n
Czy nowa rola ma mieć możliwość tworzenia nowych ról? (y/n) n
# Utwórz bazę danych mlflow_bd, której właścicielem jest mlflow_user
$ createdb -O mlflow_user mlflow_db

Aby uruchomić serwer, należy zainstalować następujące pakiety Pythona (zalecam utworzenie osobnego wirtualnego środowiska):

pip install mlflow
pip install pysftp

Uruchamiamy nasz serwer

$ mlflow server  
                 --backend-store-uri postgresql://mlflow_user:mlflow@localhost/mlflow_db 
                 --default-artifact-root sftp://mlflowsftp:mlflow@sftp_host/upload  
                --host server_host 
                --port server_port

2. Dodajemy śledzenie

Aby wyniki naszych treningów nie zniknęły, przyszłe pokolenia programistów rozumiały, co się działo, a starsi koledzy i Ty mogli spokojnie analizować proces uczenia, musimy dodać śledzenie. Pod śledzeniem rozumiemy zapisywanie parametrów, metryk, artefaktów oraz wszelkich dodatkowych informacji o przebiegu szkolenia, w naszym przypadku na serwerze.

Na przykład stworzyłem mały projekt na githubie na Kerasie do segmentacji wszystkiego, co jest w zbiorze danych COCO. Aby dodać śledzenie, stworzyłem plik mlflow_training.py.

Oto linijki, w których dzieje się najciekawsze:

def run(self, epochs, lr, experiment_name):
        # uzyskanie id eksperymentu, stworzenie eksperymentu w jego braku
        remote_experiment_id = self.remote_server.get_experiment_id(name=experiment_name)
        # stworzenie "uruchomienia" i uzyskanie jego id
        remote_run_id = self.remote_server.get_run_id(remote_experiment_id)

        # wskazujemy, że chcemy zapisać wyniki na zdalnym serwerze
        mlflow.set_tracking_uri(self.tracking_uri)
        mlflow.set_experiment(experiment_name)

        with mlflow.start_run(run_id=remote_run_id, nested=False):
            mlflow.keras.autolog()
            self.train_pipeline.train(lr=lr, epochs=epochs)

        try:
            self.log_tags_and_params(remote_run_id)
        except mlflow.exceptions.RestException as e:
            print(e)

Tutaj self.remote_server to niewielkie opakowanie nad metodami mlflow.tracking. MlflowClient (zrobiłem to dla wygody), za pomocą których tworzę eksperyment i uruchomienie na serwerze. Następnie wskazuję, gdzie powinny trafić wyniki uruchomienia (mlflow.set_tracking_uri(self.tracking_uri)). Aktywizuję automatyczne logowanie mlflow.keras.autolog(). Obecnie MLflow Tracking wspiera automatyczne logowanie dla TensorFlow, Keras, Gluon XGBoost, LightGBM, Spark. Jeśli nie znalazłeś swojego frameworka lub biblioteki, zawsze możesz logować w sposób jawny. Rozpoczynamy trening. Rejestrujemy tagi i parametry wejściowe na zdalnym serwerze.

Parę linii kodu i masz, jak wszyscy chętni, dostęp do informacji o wszystkich uruchomieniach. Fajnie?

3. Przygotowujemy projekt

Teraz sprawimy, że uruchomienie projektu będzie dziecinnie proste. W tym celu dodajemy do głównego katalogu plik MLproject i conda.yaml.
MLproject

name: flow_segmentation
conda_env: conda.yaml

entry_points:
  main:
    parameters:
        categories: {help: 'lista kategorii z zestawu danych coco'}
        epochs: {type: int, help: 'liczba epok w treningu'}

        lr: {type: float, default: 0.001, help: 'wskaźnik uczenia'}
        batch_size: {type: int, default: 8}
        model_name: {type: str, default: 'Unet', help: 'Unet, PSPNet, Linknet, FPN'}
        backbone_name: {type: str, default: 'resnet18', help: 'przykład resnet18, resnet50, mobilenetv2 ...'}

        tracking_uri: {type: str, help: 'adres serwera'}
        experiment_name: {type: str, default: 'My_experiment', help: 'nazwa eksperymentu zdalnego i lokalnego'}
    command: "python mlflow_training.py 
            --epochs={epochs}
            --categories={categories}
            --lr={lr}
            --tracking_uri={tracking_uri}
            --model_name={model_name}
            --backbone_name={backbone_name}
            --batch_size={batch_size}
            --experiment_name={experiment_name}"

Projekt MLflow ma kilka właściwości:

  • Name — nazwa Twojego projektu;
  • Environment — w moim przypadku conda_env wskazuje, że do uruchomienia używana jest Anaconda, a opis zależności znajduje się w pliku conda.yaml;
  • Entry Points — wskazuje, jakie pliki i z jakimi parametrami możemy uruchomić (wszystkie parametry podczas uruchomienia treningu są automatycznie logowane)

conda.yaml

name: flow_segmentation
channels:
  - defaults
  - anaconda
dependencies:
  - python==3.7
  - pip:
    - mlflow==1.8.0
    - pysftp==0.2.9
    - Cython==0.29.19
    - numpy==1.18.4
    - pycocotools==2.0.0
    - requests==2.23.0
    - matplotlib==3.2.1
    - segmentation-models==1.0.1
    - Keras==2.3.1
    - imgaug==0.4.0
    - tqdm==4.46.0
    - tensorflow-gpu==1.14.0

Jako środowisko wykonawcze możesz użyć dockera, po więcej informacji odsyłam do dokumentacji.

4. Rozpoczynamy trening

Klonujemy projekt i przechodzimy do katalogu projektu:

git clone https://github.com/simbakot/mlflow_example.git
cd mlflow_example/

Aby uruchomić, musisz zainstalować biblioteki

pip install mlflow
pip install pysftp

Ponieważ w przykładzie używam conda_env, na Twoim komputerze musi być zainstalowane Anaconda (ale można to również obejść, instalując wszystkie niezbędne pakiety samodzielnie i eksperymentując z parametrami uruchamiania).

Wszystkie przygotowania są zakończone i możemy przejść do uruchamiania szkolenia. Z katalogu głównego projektu:

$ mlflow run -P epochs=10 -P categories=cat,dog -P tracking_uri=http://server_host:server_port .

Po wprowadzeniu polecenia automatycznie utworzy się środowisko conda i rozpocznie się trenowanie.
W powyższym przykładzie przekazałem liczbę epok do nauki oraz kategorie, na które chcemy segmentować (pełną listę można zobaczyć tutaj) oraz adres naszego zdalnego serwera.
Pełną listę możliwych parametrów można znaleźć w pliku MLproject.

5. Oceniając wyniki szkolenia

Po zakończeniu szkolenia możemy przejść w przeglądarce pod adres naszego serwera http://server_host:server_port

MLOps — Książka kucharska, rozdział 1

Tutaj widzimy listę wszystkich eksperymentów (w lewym górnym rogu), a także informacje o uruchomieniach (na środku). Możemy zobaczyć bardziej szczegółowe informacje (parametry, metryki, artefakty oraz dodatkowe informacje) dotyczące każdego uruchomienia.

MLOps — Książka kucharska, rozdział 1

Dla każdej metryki możemy obserwować historię zmian.

MLOps — Książka kucharska, rozdział 1

Oznacza to, że obecnie możemy analizować wyniki w "ręcznym" trybie, a także możesz ustawić automatyczną walidację za pomocą MLflow API.

6. Rejestracja modelu

Po przeanalizowaniu naszego modelu i stwierdzeniu, że jest gotowy do użycia, przystępujemy do jego rejestracji. Wybieramy odpowiednie uruchomienie (jak pokazano w poprzednim punkcie) i przechodzimy w dół.

MLOps — Książka kucharska, rozdział 1

Po nadaniu naszemu modelowi nazwy, pojawia się jego wersja. Przy zapisaniu innego modelu o tej samej nazwie wersja automatycznie wzrośnie.

MLOps — Książka kucharska, rozdział 1

Dla każdego modelu możemy dodać opis i wybrać jedno z trzech stanów (Staging, Production, Archived), co w połączeniu z wersjonowaniem daje dodatkową elastyczność w dostępie do tych stanów za pomocą API.

MLOps — Książka kucharska, rozdział 1

Mamy również wygodny dostęp do wszystkich modeli

MLOps — Książka kucharska, rozdział 1

i ich wersji.

MLOps — Książka kucharska, rozdział 1

Podobnie jak w poprzednim punkcie, wszystkie operacje można wykonać za pomocą API.

7. Wdrażamy model

Na tym etapie mamy już wytrenowany model (keras). Oto przykład, jak można go użyć:

class SegmentationModel:
    def __init__(self, tracking_uri, model_name):

        self.registry = RemoteRegistry(tracking_uri=tracking_uri)
        self.model_name = model_name
        self.model = self.build_model(model_name)

    def get_latest_model(self, model_name):
        registered_models = self.registry.get_registered_model(model_name)
        last_model = self.registry.get_last_model(registered_models)
        local_path = self.registry.download_artifact(last_model.run_id, 'model', '.\/')
        return local_path

    def build_model(self, model_name):
        local_path = self.get_latest_model(model_name)

        return mlflow.keras.load_model(local_path)

    def predict(self, image):
        image = self.preprocess(image)
        result = self.model.predict(image)
        return self.postprocess(result)

    def preprocess(self, image):
        image = cv2.resize(image, (256, 256))
        image = image / 255.
        image = np.expand_dims(image, 0)
        return image

    def postprocess(self, result):
        return result

Tutaj self.registry to ponownie mała osłona nad mlflow.tracking.MlflowClient, dla wygody. Chodzi o to, że łączę się z zdalnym serwerem i wyszukuję model o podanej nazwie, przy czym pobieram najnowszą wersję produkcyjną. Następnie ściągam artefakt lokalnie do katalogu .\/model i buduję model z tego katalogu za pomocą mlflow.keras.load_model(local_path). Teraz możemy korzystać z naszego modelu. Programiści CV (ML) mogą spokojnie skupić się na ulepszaniu modelu i publikowaniu nowych wersji.

Na zakończenie

Przedstawiłem system, który pozwala:

  • centralnie przechowywać informacje o modelach ML, postępach i wynikach nauki;
  • szybko uruchamiać środowisko programistyczne;
  • śledzić i analizować postępy pracy nad modelami;
  • wygodnie prowadzić wersjonowanie i zarządzać stanem modeli;
  • łatwo wdrażać uzyskane modele.

Ten przykładowy projekt jest modelowy i służy jako punkt wyjścia do budowy własnego systemu, który być może będzie zawierał automatyzację oceny wyników i rejestracji modeli (pkt 5 i pkt 6 odpowiednio) lub dodasz wersjonowanie zbiorów danych, czy może coś jeszcze? Chciałem przekazać myśl, że potrzebujesz MLOps jako całości, MLflow to tylko środek do osiągnięcia celu.

Napisz, jakie problemy, z którymi się borykałeś, nie zostały przeze mnie odzwierciedlone?
Co byś dodał do systemu, aby spełniał Twoje potrzeby?
Jakie narzędzia i podejścia stosujesz, aby rozwiązywać wszystkie lub część problemów?

P.S. Zostawię kilka linków:
projekt github — https://github.com/simbakot/mlflow_example
MLflow — https://mlflow.org/
Mój służbowy e-mail na pytania — ikryakin@croc.ru

W naszej firmie okresowo organizowane są różne wydarzenia dla specjalistów IT, na przykład: 8 lipca o 19:00 czasu MSK odbędzie się meetup dotyczący CV w formacie online. Jeśli jesteś zainteresowany, możesz wziąć udział, rejestracja. tutaj .

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster