Создание простого конвейера машинного обучения, готового к производству

Содержание

1) Введение
2) ZenML
3) Практический пример — обзор
3.1) Набор данных
4) Практический пример — код Python
4.1) Как создать шаги ZenML?
4.2) Создание конвейера
4.3) Запуск конвейера
4.4) Создание стека для MLFlow
5) Заключение и резюме: зачем вообще все это нужно?
6) Ресурсы

1. Введение

В общем, в проекте машинного обучения фаза производства — это время, когда построенная нами модель проявит себя. Однако сделать его доступным для производства всегда сложно, так как нам нужно развернуть весь конвейер разработки: загрузка данных, разработка и выбор функций, переобучение, оценка и создание прогнозов. Кроме того, мы должны обеспечивать воспроизводимость и масштабируемость системы машинного обучения, отклонение данных и концепций, отслеживание экспериментов и мониторинг производительности. Много, да?

Дело в том, что в большинстве случаев мы не создаем воспроизводимые пайплайны на этапе разработки. Итак, когда приходит время развертывания нашей модели, дела обстоят хуже: как мы можем переделать все шаги, которые мы сделали? Сделали ли мы чистые шаги на этапе экспериментов? Иногда ответ на этот последний вопрос — нет.

Вот где на помощь приходит ZenML: это платформа (с открытым исходным кодом) для создания конвейеров MLOps таким образом, чтобы они могли быть готовы к работе. . Одним словом, он предоставляет удивительный набор инструментов, упрощающих работу над проектом машинного обучения.

2. ЗенМЛ

Ключевыми понятиями здесь являются конвейер, этапы и стек. Проще говоря, конвейер в рабочем процессе ZenML представляет собой последовательность шагов (таких как задачи в других библиотеках конвейеров), где следующий шаг зависит от результатов предыдущего шага. Изображение ниже иллюстрирует это:

В этом случае мы могли бы построить столько шагов, сколько захотим, в зависимости от проблемы, которую мы пытаемся решить. Единственное, нам нужно следовать последовательной логике, так как выход используется как вход для следующего шага.

В ZenML гораздо больше компонентов, чем представлено в этом посте, поэтому я настоятельно рекомендую вам ознакомиться с документацией (ссылки в конце этого поста).

Но я хотел бы отметить, что настоящая сила ZenML заключается в том, что он позволяет нам управлять конвейером независимо от других инструментов, с которыми мы хотели бы использовать: MLFlow, KubeFlow, Spark, облачных сервисов и т. д.

Например, как мы увидим далее в этом посте, можно работать с ZenML, взаимодействуя с MLFlow для отслеживания наших экспериментов и развертывания наших моделей.

Третье важное понятие — стек. По сути, мы настраиваем, где будет работать наш конвейер. ZenML по умолчанию предоставляет нам стек для локального запуска наших пайплайнов. Например, если нам в конечном итоге понадобится работать в облаке, нам просто нужно изменить стек.

Есть множество компонентов, которые мы можем настроить в стеке, например оркестратор конвейера, такой как Kubeflow и Airflow, и трекер экспериментов, такой как MLFlow. Чтобы узнать больше о компонентах, у них есть довольно крутая документация.

Позже в этом посте мы настроим стек для запуска MLFlow.

3. Практический пример — обзор

Итак, давайте погрузимся в практический пример, чтобы сделать эти концепции более понятными.

Мы собираемся построить простой конвейер обучения, содержащий 4 шага, как показано на изображении выше. Они есть:

  • Получение необработанных данных: загрузите файл .csv, содержащий 5 функций и один целевой столбец (подробнее о наборе данных далее в этом посте);
  • Подготовка данных: изменение типа столбца и разделение набора данных на обучение и тестирование. Для простоты мы не будем использовать проверочный набор данных;
  • Обучение модели машинного обучения. Здесь классификатор случайного леса обучается с использованием параметров по умолчанию, за исключением того, что максимальная глубина равна 4;
  • Оценка модели.наконец, мы делаем прогнозы для набора тестов и рассчитываем показатели оценки: точность, точность, отзыв. em> и f1.

3.1. Набор данных

Прежде чем мы перейдем к коду, позвольте мне дать вам обзор набора данных.

Данные можно найти на Kaggle. Он состоит из 70 тыс. записей пациентов с 11 признаками и целью (наличие или отсутствие сердечно-сосудистых заболеваний). Для простоты я выбрал 5 функций и цель из этого набора, так как сейчас мы просто хотим запустить конвейер.

4. Практический пример — код Python

Во-первых, исходный код можно найти в следующем репозитории Github: https://github.com/KattsonBastos/mlops-zenml-pipelines.

До сегодняшнего дня (пятница, 19 августа 2022 г.) репозиторий содержал две папки: data и pipeline. Предыдущая папка содержит скрипт .py для каждой задачи и один скрипт .py для конвейера (тот, кто вызывает шаги). Кроме того, есть файл run.py, который вызывает конвейер.

Однако, чтобы упростить задачу, я создал один скрипт .py для запуска всего, назвав его simple_run.py. Кроме того, simple_run.py имеет меньше шагов, чем полный.

Но прежде чем мы посмотрим на это, давайте сначала подготовим нашу среду.

Во-первых, нам нужно установить некоторые библиотеки. В репозитории Github есть текстовый файл требований. Итак, нам просто нужно установить с его помощью (я предполагаю, что у вас уже есть созданная и активированная виртуальная среда):

pip install -r requirements.txt

После завершения мы можем инициализировать наш репозиторий ZenML:

zenml init

Затем нам нужно установить некоторые интеграции с помощью ZenML, как показано ниже:

zenml integration install mlflow
zenml integration install sklearn

Кроме того, нам все еще нужно установить некоторые конфигурации ZenML, чтобы иметь возможность запускать его с MLFlow, но мы сделаем это позже в этом посте.

Итак, во-первых, давайте импортируем все библиотеки, которые нам нужны для создания и запуска конвейера.

import mlflow
import numpy as np
import pandas as pd
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
# zenml importing
from zenml.steps import step, Output, BaseStepConfig
from sklearn.base import ClassifierMixin
from zenml.pipelines import pipeline
from zenml.integrations.mlflow.mlflow_step_decorator import enable_mlflow

4.1. Как создать шаги ZenML?

Как мы видели ранее, ZenML работает с шагами в конвейере. На практике мы создаем функции Python для выполнения нужных нам задач (загрузка данных, удаление столбца) и украшаем их декоратором @step, как показано ниже:

@step
def load_data() -> Output(
data=pd.DataFrame
):
"""Load a dataset."""
data = pd.read_csv('../data/cardio_train_sampled.csv')
return data

Итак, давайте сделаем то же самое с другими функциями. В последовательности мы переводим столбец age из дней в годы. Кроме того, мы разделили 20% данных для тестирования.

@step
def data_preparation(data: pd.DataFrame) -> Output(
X_train = np.ndarray, X_test = np.ndarray, y_train = np.ndarray, y_true = np.ndarray
):
dataframe = data.copy()
dataframe['age'] = round(dataframe['age'] / 365).astype(int)
X = data.drop('cardio', axis = 1).values
y = data['cardio'].values
X_train, X_test, y_train, y_true = train_test_split(X, y, test_size = 0.2, random_state=42)
return X_train, X_test, y_train, y_true

И с X, и с y мы можем обучить модель. Как для этапов обучения, так и для оценки вы заметите, что у них есть два декоратора: @step и @enable_mlflow.. Последний позволяет MLFLow регистрироваться в рамках шага. Для регистрации мы просто делаем то же самое, что и всегда с MLFlow.

Следующий обучающий сценарий просто соответствует классификатору RF и регистрирует его в MLFlow:

@enable_mlflow
@step(enable_cache=False)
def train_rf(X_train: np.ndarray, y_train: np.ndarray, config: ModelConfig) -> Output(
model = ClassifierMixin
):
"""Training a sklearn RF model."""
params = config.model_params
model = RandomForestClassifier(**config.model_params)
model.fit(X_train, y_train)
# mlflow logging
mlflow.sklearn.log_model(model,config.model_name)
for param in params.keys():
mlflow.log_param(f'{param}', params[param])
return model

Шаг оценки, в свою очередь, также имеет декоратор включения MLFlow, так как мы хотели бы регистрировать метрики.

@enable_mlflow
@step(enable_cache=False)
def evaluate_model(model: ClassifierMixin, X_test: np.ndarray, y_test: np.ndarray) -> Output(
recall = float #accuracy = float, precision = float, recall = float, f1 = float
):
"""Model Evaluation and ML metrics register."""
y_pred = model.predict(X_test)
# metricas
accuracy, precision, recall, f1 = get_clf_metrics(y_test, y_pred)
mlflow.log_metric("accuracy", accuracy)
mlflow.log_metric("precision", precision)
mlflow.log_metric("recall", recall)
mlflow.log_metric("f1", f1)
return recall

Сделав это для всех наших функций, мы создадим все наши шаги (вы можете проверить их все прямо здесь).

4.2. Создание конвейера

Как только мы создали все шаги, мы можем объединить их все в конвейер:

@pipeline(enable_cache=False)
def training_rf_pipeline(
get_data,
data_preparation,
train_model,
evaluate_model
):
data = get_data()
X_train, X_test, y_train, y_test = data_preparation(data = data)
model = train_model(X_train = X_train, y_train = y_train)
recall_metric = evaluate_model(model=model, X_test = X_test, y_test = y_test)
print(recall_metric)

Возможно, вы заметили, что enable_cache и в декораторах шагов, и в конвейерах. По умолчанию кэширование в ZenML включено. Таким образом, если мы не изменили шаг между двумя запусками конвейера, например, выходные данные для этого шага в первом выполнении будут использоваться для следующего запуска (второго), что сэкономит некоторое время выполнения.

Отключив этот кеш, мы гарантируем, что он будет работать, особенно для тех, кто использует внешние данные.

В нашем случае, поскольку мы будем использовать MLFlow, если для кеша установлено значение True, пока мы запускаем конвейер несколько раз без изменения кода, он не запустит, например, этап оценки, а затем t зарегистрировать метрики.

4.3. Запуск конвейера

Создав конвейер, давайте создадим его работающий код:

training = training_rf_pipeline(
get_data = load_data(),
data_preparation = data_preparation(),
train_model = train_rf(),
evaluate_model = evaluate_model()
)
training.run()

Так же просто, как и должно.

Однако перед запуском скрипта с нашим любимым python3, давайте настроим стек ZenML, чтобы разрешить отслеживание MLFlow.

4.4. Создание стека для MLFlow

В ZenML нам обычно нужны три компонента: Orchestrator, Artifact Store и Metadada Store. Кроме того, мы можем передать средство отслеживания экспериментов. Это то, что мы собираемся сделать, но сначала давайте создадим трекер экспериментов:

zenml experiment-tracker register mlflow_tracker --type=mlflow

Первая часть кода, zenml experiment-tracker register,, указывает, что мы хотим зарегистрировать новое средство отслеживания экспериментов. При этом мы передаем имя mlflow_tracker,, а затем указываем, что этот трекер, который мы создаем, является трекером MLFlow.

Поскольку у нас есть средство отслеживания экспериментов, давайте создадим новый стек:

zenml stack register mlflow_stack \
    -e mlflow_tracker \
    -m default \
    -a default \
    -o default \

Параметры:

  • e: укажите средство отслеживания экспериментов, которое мы хотим использовать. В данном случае это тот трекер, который мы создали;
  • m: хранилище метаданных, которое для простоты будет использоваться по умолчанию.
  • a: хранилище артефактов, которое для простоты будет использоваться по умолчанию.
  • o: оркестратор, который будет использоваться по умолчанию для простоты.

Вот и все. Теперь все, что нам нужно сделать, это запустить наш код:

python3 simple_run.py

После запуска мы можем проверить результаты в интерфейсе MLFlow, но сначала нам нужно запустить его:

mlflow ui --backend-store-uri file:/home/<your_username>/.config/zenml/local_stores/<your_persornal_id>/mlruns

Обратите внимание, что вам нужно изменить две части:

  • your_username: имя пользователя вашей ОС.
  • your_personal_id: чтобы получить его, вам нужно всего лишь перейти в этот каталог local_stores и скопировать имя папки.

Все сделано!!

Теперь мы можем проверить результат в https://127.0.0.1:5000, и вот он:

Заключение и резюме: зачем нам все это вообще нужно?

Основная цель этого поста заключалась в разработке конвейера обучения, сочетающего ZenML и MLFLow. Итак, мы рассмотрели некоторые ключевые концепции ZenML, а затем разработали наш конвейер. Однако, почему мы используем все это? Эти декораторы действительно нужны.

Итак, прежде чем мы закончим этот пост, давайте немного поговорим о том, почему создание пайплайна важно (и почему мы использовали ZenML).

В проекте машинного обучения иногда нам приходится повторять шаги несколько раз, и со временем мы теряем контроль над версиями данных, кода, параметров модели и зависимостей.

Стремясь к успеху проекта, мы должны заботиться о таких вопросах с самого начала. Вот где появляется такой инструмент, как ZenML: под капотом, когда мы проходим те шаги, которые мы видели раньше, данные отслеживаются и версионируются, то же самое касается параметров модели и артефактов.

Таким образом, конвейер можно воспроизвести на любом другом локальном компьютере или в облачном ресурсе.

Но у него есть кое-что еще лучше: с помощью оркестратора мы можем развернуть этот конвейер для производства настолько просто, насколько это должно быть (я рассмотрю такое развертывание в следующем посте).

Вот и все. Надеюсь, я помог вам познакомиться с таким удивительным инструментом. Я планирую продолжать просматривать документы ZenML (и другие инструменты MLOps) в будущем, поэтому, если вам интересно, рассмотрите возможность подписаться на мой профиль и связаться со мной в социальных сетях.

Спасибо, что уделили время, и желаю всего наилучшего!!!

Ресурсы

  1. Мой репозиторий Github для этого сообщения: https://github.com/KattsonBastos/mlops-zenml-pipelines
  2. Официальные документы ZenML: https://docs.zenml.io/getting-started/introduction
  3. Репозиторий ZenML Github с практическими примерами:https://github.com/zenml-io/zenfiles
  4. Видео Хамзы Тахира (соавтора ZenML), демонстрирующее конвейер обучения: https://youtube.com/watch?v=EVueQ8zq4eE

Где меня найти:

Линкедин

Гитхаб