Создание API данных для MLOps — 4 года усвоенных уроков

Когда речь идет о хранилищах характеристик, существует два основных подхода к разработке характеристик. Один подход заключается в создании языка, специфичного для конкретной области (DSL), который охватывает все возможные этапы разработки признаков (например, агрегирование, снижение размерности и преобразование), которые могут понадобиться специалисту по исследованию данных. Второй подход заключается в использовании фреймворка общего назначения для разработки признаков, основанного на DataFrames (Pandas или Spark), чтобы пользователи могли выполнять разработку признаков, используя свой любимый фреймворк. Подход DSL требует переписывания с нуля всех существующих конвейеров функциональной инженерии, в то время как подход DataFrames обратно совместим с существующим кодом функциональной инженерии, написанным для Pandas или Spark.

В компании Hopsworks мы стали пионерами подхода DataFrames, и наши API отражают это. Этот выбор объясняется несколькими причинами.

  • Гибкость: Хотя самые первые хранилища данных (например, Michelangelo от Uber, Zipline от AirBnB) использовали DSL, они были разработаны внутри компании для конкретных нужд этой компании. Hopsworks — это хранилище функций общего назначения, и наши клиенты используют Hopsworks во множестве различных сценариев использования: обнаружение аномалий, рекомендации, прогнозирование временных рядов, NLP и т. д. Чтобы Hopsworks мог поддерживать все эти различные сценарии использования, нам необходимо предоставить специалистам по анализу данных мощный и гибкий API для достижения нужных им результатов. Такие инструменты уже существуют и представлены Pandas, PySpark и огромным количеством библиотек, которые уже предоставляет экосистема Python. Новые библиотеки Python для функциональной инженерии можно сразу же использовать в конвейерах функциональной инженерии.

  • Пользовательский опыт: Магазин функций Hopsworks задуман как платформа для совместной работы и повышения производительности команд. Мы считаем, что если бы пользователям пришлось изучать новый DSL для создания функций, это резко снизило бы привлекательность магазина функций для разработчиков из-за необходимости изучать новый фреймворк с ограниченными навыками передачи — DSL рассматривается как форма блокировки поставщика. С Hopsworks пользователи могут продолжать использовать те же библиотеки и процессы, которые они уже умеют применять.

  • Принесите свой собственный конвейер: Подавляющее большинство пользователей Hopsworks работают над проектами «коричневого поля». Это означает, что в их среде уже есть конвейеры функционального проектирования, и они не начинают с нуля. Наличие DSL означало бы необходимость перестраивать эти конвейеры, чтобы иметь возможность использовать хранилище характеристик. С Hopsworks и DataFrame APIs не имеет значения, используют ли конвейеры Python, PySpark или SQL. Пользователям просто нужно изменить вывод конвейера, чтобы записывать DataFrame в Hopsworks вместо сохранения DataFrame в ведро S3 или хранилище данных.

API для записи — группа функций

Хранилище функций Hopsworks не зависит от этапа разработки функций. Вы можете запускать процесс в различных средах: от Colab до Snowflake, от Databricks до SageMaker и на самом Hopsworks. Единственное требование к разработчикам — использовать библиотеку HSFS (HopsworkS Feature Store) для взаимодействия с Hopsworks.

В конце вашего конвейера функций, когда у вас есть окончательный DataFrame, вы можете зарегистрировать его в Hopsworks с помощью HSFS API. Признаки в Hopsworks регистрируются в виде таблицы признаков, называемой группой признаков.

Hopsworks предоставляет несколько режимов записи для различных случаев использования:

  • Пакетная запись: Это был режим по умолчанию до версии 3.0. Он предполагает пакетную запись DataFrame либо в автономное хранилище признаков, либо в онлайновое, либо в оба. Этот режим по-прежнему используется по умолчанию при записи Spark DataFrame.
  • Потоковая запись: Этот режим был введен в версии 2.0 и расширен в версии 3.0. Потоковая запись обеспечивает очень низкую задержку потоковых обновлений в онлайн-магазине и эффективные пакетные обновления в автономном магазине, обеспечивая при этом согласованность между онлайн и автономным магазинами. В Hopsworks 3.0 это режим для клиентов Python.
  • Внешние коннекторы: Этот режим позволяет пользователям монтировать таблицы (функции) в Хранилищах данных, таких как Snowflake, Redshift, Delta Lake и BigQuery, как группы функций в Hopsworks. Таблицы не копируются в Hopsworks, а Хранилище данных становится автономным хранилищем для Hopsworks. Hopsworks управляет метаданными, статистикой, контролем доступа и историей внешних таблиц. Hopsworks может действовать как виртуальное хранилище данных, где множество различных Хранилищ данных могут быть автономными хранилищами в одном хранилище данных Hopsworks.

Создание

Перед загрузкой разработанных функций необходимо создать группу функций и определить ее метаданные. Ниже приведен пример определения группы признаков:

fg = fs.get_or_create_feature_group(
          name="transactions",
          version=1,
          description="Transaction data",
          primary_key=['cc_num'],
          event_time='datetime',
          online_enabled=True
)
Вход в полноэкранный режим Выход из полноэкранного режима

В приведенном выше примере мы определяем группу характеристик под названием транзакции. Она имеет версию (читайте о нашем подходе к версионированию), описание, первичный ключ, ключ раздела и время события. Первичный ключ primary_key необходим, если мы (1) хотим иметь возможность объединять признаки этой группы признаков с признаками других групп признаков и (2) для извлечения предварительно вычисленных признаков из интернет-магазина. Ключ_раздела используется для эффективного добавления в хранилище и эффективного запроса больших объемов данных о признаках, уменьшая объем данных, считываемых в обрезанных запросах. event_time указывает столбец в нашей группе признаков, содержащий временную метку обновления строки (когда произошло событие в реальном мире), что позволяет корректно объединять признаки без утечки данных. Атрибут online_enabled определяет, будет ли группа признаков доступна онлайн для обслуживания в реальном времени или нет.

Как вы можете видеть, мы не определили полную схему группы функций. Это потому, что информация об именах функций и их типах данных при записи выводится из Pandas DataFrame.

Чтобы записать характеристики в Hopsworks, пользователям нужно вызвать fg.insert(df), где df — это Pandas DataFrame. На этом этапе платформа берет на себя ответственность и начинает создавать все необходимые метаданные функций и строительные леса. Как упоминалось выше, вы можете, но не обязаны, явно указать схему группы функций. В противном случае имена характеристик и типы данных сопоставляются на основе столбцов Pandas DataFrame (подробнее о типах данных и сопоставлении).

Валидация данных признаков

В Hopsworks 3.0 мы представили первоклассную поддержку Great Expectations для проверки данных признаков. Разработчики имеют возможность зарегистрировать набор Great Expectation в группе характеристик. В этом случае, прежде чем отправить Pandas DataFrame в Hopsworks для записи, API хранилища функций прозрачно вызывает библиотеку Great Expectations и проверяет DataFrame. Если он соответствует ожиданиям, конвейер записи продолжается, и данные записываются в хранилище признаков. Если DataFrame не соответствует набору ожиданий, предупреждение может быть отправлено на настроенный канал (например, Slack или Email). Каналы оповещения безопасно определяются в Hopsworks.

Запись

Конвейер записи включает в себя сериализацию Pandas DataFrame в формате Avro и безопасную запись в тему Kafka. API также заботятся о сериализации сложных функций, таких как вкрапления, таким образом, чтобы они могли быть сохранены правильно.

Из темы Kafka данные немедленно забираются службой онлайн хранилища функций, которая передает их в онлайн хранилище функций (RonDB). Для автономного хранения можно запланировать задание на регулярные интервалы для записи данных в автономное хранилище функций. Благодаря такой «каппа-архитектуре» Hopsworks может гарантировать, что онлайн-данные будут доступны как можно скорее (TM), и в то же время их можно уплотнять и периодически записывать большими партиями в автономное хранилище данных, чтобы воспользоваться преимуществами повышения производительности больших файлов в таких системах, как Spark, S3 и HopsFS. Наконец, Kafka обеспечивает только семантику at-least-once для функций, записанных в тему Kafka, но мы обеспечиваем правильную, последовательную репликацию данных в онлайн и офлайн хранилища, используя идемпотентную запись в онлайн хранилище и ACID обновления с удалением дубликатов записей в офлайн хранилище.

Вычисление статистики

Наконец, после записи данных в автономное хранилище характеристик, обновляется его статистика. Для каждой группы признаков по умолчанию Hopsworks прозрачно вычисляет описательную статистику, распределение и корреляционную матрицу для признаков в группе признаков. Статистика затем представляется в пользовательском интерфейсе для изучения и анализа.

API для чтения — представление признаков

Представление признаков — это новая абстракция, представленная в Hopsworks 3.0. Представления характеристик — это шлюз для доступа пользователей к данным характеристик из хранилища характеристик. По своей сути, представление характеристик представляет собой информацию о том, какие характеристики, из каких групп характеристик, нужны модели. Представления характеристик содержат только метаданные о характеристиках, подобно тому, как представления в базах данных содержат информацию о таблицах. Однако, в отличие от представлений баз данных, представления характеристик могут расширять характеристики (столбцы) с помощью преобразований характеристик — подробнее об этом позже.

Выбор характеристик

Первым шагом для создания представления признаков является выбор набора признаков из хранилища признаков. Признаки могут быть выбраны из различных групп признаков, которые объединены вместе. Hopsworks предоставляет API в стиле Pandas для выбора и объединения признаков из различных групп признаков. Например:

# Get a reference to the transactions and aggregation feature groups
trans_fg =
   fs.get_feature_group(
    name='transactions_fraud_batch_fg', 
    version=1)

window_aggs_fg =
   fs.get_feature_group(
    name='transactions_4h_aggs_fraud_batch_fg',
    version=1)

#Select features from feature groups and join them with other features
ds_query = trans_fg.select(["fraud_label", "category", "amount", 
                 "age_at_transaction", "days_until_card_expires", 
                 "loc_delta"])
    .join(window_aggs_fg.select_except(["cc_num"])
Войти в полноэкранный режим Выйти из полноэкранного режима

Функциональное хранилище Hopsworks делает это от вашего имени: транспонирует код, подобный Pandas, в сложный SQL-запрос, который реализует корректный JOIN. В качестве примера можно привести приведенный выше фрагмент:

WITH right_fg0 AS (
  SELECT 
    * 
  FROM 
    (
      SELECT 
        `fg1`.`fraud_label` `fraud_label`, 
        `fg1`.`category` `category`, 
        `fg1`.`amount` `amount`, 
        `fg1`.`age_at_transaction` `age_at_transaction`, 
        `fg1`.`days_until_card_expires` `days_until_card_expires`, 
        `fg1`.`loc_delta` `loc_delta`, 
        `fg1`.`cc_num` `join_pk_cc_num`, 
        `fg1`.`datetime` `join_evt_datetime`, 
        `fg0`.`trans_volume_mstd` `trans_volume_mstd`, 
        `fg0`.`trans_volume_mavg` `trans_volume_mavg`, 
        `fg0`.`trans_freq` `trans_freq`, 
        `fg0`.`loc_delta_mavg` `loc_delta_mavg`, 
        RANK() OVER (
          PARTITION BY `fg0`.`cc_num`, 
          `fg1`.`datetime` 
          ORDER BY 
            `fg0`.`datetime` DESC
        ) pit_rank_hopsworks 
      FROM 
        `fabio_featurestore`.`transactions_1` `fg1` 
        INNER JOIN `fabio_featurestore`.`transactions_4h_aggs_1` `fg0` ON `fg1`.`cc_num` = `fg0`.`cc_num` 
        AND `fg1`.`datetime` >= `fg0`.`datetime`
    ) NA 
  WHERE 
    `pit_rank_hopsworks` = 1
) (
  SELECT 
    `right_fg0`.`fraud_label` `fraud_label`, 
    `right_fg0`.`category` `category`, 
    `right_fg0`.`amount` `amount`, 
    `right_fg0`.`age_at_transaction` `age_at_transaction`, 
    `right_fg0`.`days_until_card_expires` `days_until_card_expires`, 
    `right_fg0`.`loc_delta` `loc_delta`, 
    `right_fg0`.`trans_volume_mstd` `trans_volume_mstd`, 
    `right_fg0`.`trans_volume_mavg` `trans_volume_mavg`, 
    `right_fg0`.`trans_freq` `trans_freq`, 
    `right_fg0`.`loc_delta_mavg` `loc_delta_mavg` 
  FROM 
    right_fg0
)
Войти в полноэкранный режим Выйти из полноэкранного режима

Приведенный выше SQL-запрос извлекает данные из указанных источников данных, например, если это внешняя группа характеристик, определенная в таблице Snowflake, SQL-запрос извлекает необходимые данные из Snowflake. API HSFS также определяет ключи объединения на основе наибольшего совпадающего подмножества первичных ключей объединяемых групп признаков. Это поведение по умолчанию может быть отменено специалистами по анализу данных, которые могут предоставить свои собственные условия объединения.

Однако более важно то, что запрос обеспечивает корректность соединяемых данных в момент времени. API соединяет каждое событие, которое вы хотите использовать для обучения, с самым последним значением признака до наступления события (для каждого выбранного признака).

Как вы можете видеть выше, запрос довольно сложный, и его составление вручную было бы сопряжено с ошибками. Хранилище признаков Hopsworks облегчает специалистам по анализу данных выбор и правильное объединение признаков с помощью API, подобного Pandas, с которым они уже знакомы.

Чтобы создать представление признаков, вы вызываете метод create_feature_view(). Вам нужно указать имя, версию, объект запроса, содержащий входные признаки, и список признаков, которые будут использоваться вашей моделью в качестве метки (цели). Метка(и) не будет возвращена при получении данных для пакетного или интерактивного скоринга.

feature_view = fs.create_feature_view(
    name='transactions_view',
    version=1,
    query=ds_query,
    labels=["fraud_label"]
)
Вход в полноэкранный режим Выход из полноэкранного режима

Преобразования признаков

Хотя преобразования признаков могут быть выполнены до хранения признаков в хранилище признаков, хранилище признаков может увеличить повторное использование признаков в различных моделях за счет поддержки последовательных преобразований признаков для автономных и онлайн API (обучение и вывод). Hopsworks может прозрачно выполнять преобразования признаков с помощью Python UDFs (пользовательских функций), когда вы выбираете признаки из хранилища признаков. Например, когда вы выбираете признаки для использования в представлении признаков, вы можете решить нормализовать числовой признак в представлении признаков.

Давайте рассмотрим последствия поддержки преобразований характеристик только перед хранилищем характеристик (как это происходит во многих известных хранилищах характеристик). Предположим, что вы используете подход моделирования данных OBT (одна большая таблица) и храните данные за несколько лет в группе характеристик, содержащей данные по всем вашим клиентам. У вас может быть несколько моделей, использующих одни и те же характеристики в этой группе характеристик. Одна модель может быть обучена на строках с данными только по американским клиентам, вторая модель использует данные только по европейским клиентам, третья модель может быть обучена на всей истории данных, имеющихся в группе характеристик, а четвертая модель может быть обучена только на данных за последний год. Каждая модель обучается на отдельном наборе данных. И каждый из этих наборов данных имеет разные строки, а значит, и разные описательные статистики (min, max, среднее, стандартное отклонение). Многие функции преобразования являются государственными и используют описательную статистику. Например, при нормализации числового признака используется среднее значение для этого признака в обучающем наборе данных.

Если бы вы преобразовали признаки перед сохранением их в хранилище признаков, вы не смогли бы создать четыре разных обучающих набора, используя одни и те же группы признаков. Вместо этого у вас была бы одна группа признаков со всеми данными, доступными для третьей модели. Также возникла бы проблема, как обучить четвертую модель на данных за последний год. Его описательная статистика отличается от полного набора данных, поэтому преобразованные значения признаков для полного набора данных и данных за последний год будут разными. Данные за последний год нужно будет хранить в другой группе признаков. То же самое справедливо для моделей, обученных на данных о клиентах из США и ЕС соответственно. При такой схеме объем хранилища данных, необходимый для хранения признаков, и количество необходимых групп признаков зависит от количества моделей, находящихся в производстве, а не от количества признаков, используемых моделями!

Применяя преобразования только при использовании функций, один и тот же набор функций может использоваться всеми моделями — это означает, что вам нужно хранить данные о функциях только один раз, а ваша модель преобразует функцию по требованию. Преобразование признаков до хранилища признаков, в общем случае, является анти-паттерном, который увеличивает затраты как с точки зрения хранения, так и с точки зрения количества конвейеров признаков, которые необходимо поддерживать. Единственным исключением из этого правила являются онлайн-модели с высокой стоимостью, когда задержка онлайн-преобразования слишком высока для конкретного случая использования, но это редкое исключение из правила (которое в любом случае поддерживается в Hopsworks).

Вы можете указать, какие признаки нужно преобразовать и какие функции преобразования применить к этим признакам, предоставив словарь признаков и функций преобразования. Hopsworks поставляется с набором встроенных функций преобразования (таких как MinMax Scalar и LabelEncoder). Вы также можете определить и зарегистрировать пользовательские функции преобразования как функции Python, которые принимают функцию на вход и возвращают преобразованную функцию на выход.

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

# Load transformation functions.
min_max_scaler = 
    fs.get_transformation_function(name="min_max_scaler")
label_encoder = 
    fs.get_transformation_function(name="label_encoder")
# Map features to transformations.
transformation_functions_map = {
    "category": label_encoder,
    "amount": min_max_scaler,
    "trans_volume_mavg": min_max_scaler,
    "trans_volume_mstd": min_max_scaler,
    "trans_freq": min_max_scaler,
    "loc_delta": min_max_scaler,
    "loc_delta_mavg": min_max_scaler,
    "age_at_transaction": min_max_scaler,
    "days_until_card_expires": min_max_scaler,
}
Вход в полноэкранный режим Выход из полноэкранного режима

Данные для обучения

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

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

Обучающие данные можно генерировать «на лету», как показано ниже:

X_train, y_train, X_val, y_val, X_test, y_test = feature_view.train_validation_test_splits(validation_size=0.3, test_size=0.2)

Войти в полноэкранный режим Выход из полноэкранного режима

Кроме того, пользователи могут запустить задание Hopsworks, которое генерирует и сохраняет обучающие данные в виде файлов нужного формата (например, CSV, TFRecord). Это полезно, например, когда данные обучения не помещаются в Pandas DataFrame, но ваш конвейер обучения модели может инкрементально загружать данные обучения из файлов, как это делает TensorFlow с помощью DataSet API для файлов, хранящихся в формате TFRecord.

Службы прогнозирования

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

  • Аналитические модели: Модели, в которых вывод происходит периодически и пакетно.

  • Операционные модели: Модели, в которых вывод происходит в реальном времени с жесткими требованиями к задержкам.

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

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

Для получения данных пакетного анализа можно использовать метод get_batch_data. Вам необходимо указать временной интервал для окна данных, которые нужно оценить. Пример:

transactions_to_score = 
     feature_view.get_batch_data(start_time = start_time, end_time = end_time)

Вход в полноэкранный режим Выход из полноэкранного режима

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

transactions_to_score = 
       feature_view.get_feature_vector(entry={'cc_num': '12124324235'})

Войти в полноэкранный режим Выход из полноэкранного режима

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

Начало работы

Как всегда, вы можете начать строить отличные модели на Hopsworks, используя наше бессерверное развертывание. Вам не нужно подключать облачный аккаунт или развертывать что-либо, вы можете просто зарегистрироваться на app.hopsworks.ai и начать строить.

Первоначально опубликовано на https://www.hopsworks.ai.

Оцените статью
devanswers.ru
Добавить комментарий