Введение

До магазина функций Vertex AI

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

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

В среднем человек создавал 1,7 МБ данных каждую секунду в 2022 году. Сегодня в Интернете 5 миллиардов человек. Посчитайте, и вы поймете, что ежедневно создается огромное количество данных!

Общий объем данных, хранящихся только у большой четверки членов Nasdaq (а именно Google, Amazon, Microsoft и Facebook), уже составляет 1,2 миллиона терабайт данных. Специалисты, такие как инженеры по данным и машинному обучению, работают с этими данными, делают прогнозы, находят решения повседневных проблем и улучшают жизнь людей. По мере роста данных работать с ними становится все труднее. Следовательно, создаются более гибкие инструменты, облегчающие работу людей и облегчающие ее.

Новый продукт Vertex AI, Feature Store, играет важную роль в научно-техническом прогрессе. Статья начнется с обзора и обсуждения преимуществ продукта. В нем также будет рассмотрена архитектура Vertex AI Feature Store, а в завершение приведен практический пример.

Что такое Vertex AI Feature Store?

Давайте поговорим о воображаемой компании под названием Armcomp. С момента развертывания своих первых моделей ML с использованием Auto ML и BigQuery ML команда Armcomp добавила в свой набор навыков разработку функций. Однако теперь команда разделена на несколько подгрупп, воссоздающих одни и те же функции, что приводит к избыточной работе. Каждый раз, когда команде нужно добавить новую функцию в модель, они зависят от команды эксплуатации. Члены команды также тратят слишком много времени, пытаясь управлять жизненным циклом функции, начиная с обучения и заканчивая развертыванием и обслуживанием.

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

Ресурс Armcomp DevOps является новым для команды Armcomp, и ему необходимо понимать, как отслеживать и поддерживать инфраструктуру обслуживания и управления функциями.

Вот основные проблемы, с которыми часто сталкиваются люди, работающие с функциями машинного обучения:

  1. Функции трудно совместно использовать и повторно использовать.
  2. Надежное обслуживание в производственной среде с низкой задержкой — непростая задача.
  3. Непреднамеренный перекос в значениях функций между обучением и обслуживанием является распространенным явлением.

Все эти три ключевые проблемы считаются болями в управлении функциями. Так как же расширяющаяся команда Armcomp по машинному обучению может решить эти проблемы? Именно здесь Vertex AI Feature Store приходит на помощь, чтобы решить эти проблемы управления функциями.

Прежде чем использовать Feature Store, Armcomp вычислил значения характеристик и сохранил их в различных местах, таких как таблицы в BigQuery или файлы хеджирования в облачном хранилище. Они также создавали и управляли отдельными решениями для хранения и использования значений функций. Vertex AI Feature Store предоставляет централизованный репозиторий для организации, храненияи обслуживания функций машинного обучения. Используя центральное хранилище функций, команда Armcomp может эффективно совместно использовать, обнаруживать ии повторно использовать функции машинного обучения в любом масштабе, позволяя команде увеличить скорость , с которой они могут разрабатывать и развертывать новые приложения для обучения управлению. Feature Store — это полностью управляемое решение. Он управляет базовой инфраструктурой и масштабирует ее за нас, а это означает, что наши специалисты по данным могут сосредоточиться на логике вычисления функций, а не беспокоиться о проблемах развертывания функций в рабочей среде.

Преимущества магазина Vertex AI Feature Store

  1. Команды могут совместно использовать и повторно использовать функции машинного обучения в разных сценариях использования, поскольку Feature Store имеет централизованный репозиторий функций с простыми API-интерфейсами для создания, изменения, поиска и обнаружения функций, извлечения их для обучения и обслуживания, а также для управления разрешениями.
  2. Команды могут обслуживать функции машинного обучения в масштабе с низкой задержкой, поскольку операционные издержки ложатся на Feature Store.
  3. Распространенная проблема в машинном обучении называется перекосом при обучении, что означает, что данные, которые мы тренируем, могут быть искажены или отличаться от тех, которые обслуживаются в производственной среде. Feature Store устраняет перекос в обучении, поскольку позволяет своим пользователям вычислять значения функций один раз в одном репозитории, а затем повторно использовать его как для обучения, так и для обслуживания. Дрейф и другие проблемы с качеством также можно отслеживать и контролировать.
  4. Feature Store также позволяет принимать функции большими партиями или в режиме реального времени по мере поступления потоков данных. С Vertex AI Feature Store команда может хранить функции с помощью API пакетного и потокового импорта и регистрировать функцию в своем реестре функций.

Архитектура магазина Vertex AI Feature Store

В Feature Store есть три основных концепции.

Featurestore -> EntityType -> Feature

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

Чтобы двигаться дальше, давайте сравним архитектуру Feature Store с архитектурой реляционной базы данных.

Тип объекта в хранилище функций аналогичен столбцу первичного ключа в реляционной базе данных. Это набор семантически связанных признаков.

Сущность — это экземпляр типа сущности. Это похоже на значение столбца первичного ключа в СУБД. Например, movie_01 и movie_02 являются объектами типа фильма. В хранилище функций каждый объект должен иметь уникальный идентификатор, как и каждое значение столбца первичного ключа в СУБД, и должен иметь тип STRING.

Функция в хранилище функций похожа на неосновной столбец в СУБД. Это измеримое свойство или атрибут типа объекта. Например, тип сущности фильма имеет такие функции, как average_rating и название, которые отслеживают различные свойства фильмов. Функции связаны с типами сущностей. Они должны различаться в пределах данного типа сущности, но не обязательно должны быть глобально уникальными. Например, если мы используем title для двух разных типов сущностей, Vertex AI Feature Store интерпретирует title как две разные функции. При чтении значений функций мы предоставляем функцию и тип ее сущности как часть запроса.

Значение функции похоже на значение столбца, не являющегося первичным ключом, в реляционной базе данных. Vertex AI Feature Store фиксирует значения функций для функции в определенный момент времени. Другими словами, у нас может быть несколько значений для данного объекта и функции. Например, объект movie_01 может иметь несколько значений свойства для свойства medium_rating. Значение может быть 4,4 в один момент и 4,8 в какой-то момент позже. Vertex AI Feature Store связывает идентификатор кортежа с каждым значением функции (entity_id, feature_id, timestamp), который Vertex AI Feature Store использует для поиска значений во время обслуживания.

Временная метка – это отдельная концепция в Vertex AI Feature Store, которой нет альтернативы в реляционной базе данных. Для пакетной загрузки Vertex AI Feature Store требуются предоставленные пользователем временные метки для загружаемых значений функций. Мы можем указать конкретную метку времени для каждого значения или указать одну и ту же метку времени для всех значений:

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

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

Прием функций

Процесс импорта значений функций, вычисленных нашими заданиями по разработке функций, в хранилище функций. Прежде чем мы сможем принимать данные, соответствующий тип объекта и функции должны быть определены в хранилище функций. Vertex AI Feature Store предлагает пакетную и потоковую загрузку, что позволяет нам добавлять значения функций массово или в режиме реального времени.

Показ функций

Процесс экспорта сохраненных значений признаков для обучения или логического вывода. Vertex AI Feature Store предлагает два метода предоставления функций: пакетный и онлайн. Пакетное обслуживание предназначено для обеспечения высокой пропускной способности и обслуживания больших объемов данных для автономной обработки. Онлайн-обслуживание предназначено для извлечения данных с малой задержкой из небольших пакетов данных для обработки в реальном времени.

Демо

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

  1. Создает хранилище функций, тип объекта, функцию
  2. Кодирует и загружает 100 изображений из облачного хранилища в хранилище функций (прием функций).
  3. Считывает случайно выбранное изображение из хранилища функций, декодирует и передает обратно в облачное хранилище (обслуживание функций)
  4. Удаляет магазин функций

Что у нас должно быть под рукой?

  • Локальная или виртуальная машина с любой ОС (в этой демонстрации мы будем использовать Ubuntu)
  • Питон 3.6+
  • Gcloud CLI установлен

Все коды находятся в открытом доступе в моем репозитории GitHub.

Пользовательский интерфейс Vertex AI Feature Store довольно прост. Мы можем создать хранилище функций прямо из пользовательского интерфейса, но для нашего приложения мы будем использовать скрипт Python.

  1. Укажите учетные данные GCP

Наше приложение будет работать в виртуальной среде с ОС Ubuntu. Поэтому мы должны указать учетные данные GCP для запуска приложения. Для этого мы должны создать учетную запись службы с учетом принципа наименьших привилегий. Мы должны предоставить следующие роли:

  • Администратор вершинного ИИ
  • Администратор объекта хранения
  • Редактор данных BigQuery (при загрузке из DataFrame в хранилище объектов временный набор данных BigQuery автоматически создается и удаляется в том же проекте GCP, который используется в качестве промежуточного хранилища для загрузки значений функций из фрейма данных в хранилище объектов.)

После того, как мы создадим учетную запись службы в GCP, мы должны сгенерировать новый ключ в формате json, загрузить его и сохранить на виртуальной машине, где будет запускаться приложение. Затем мы можем указать учетные данные GCP в среде Python.

import os

# Specify GCP credentials
def specifyGoogleCredentials():
   key_path = os.path.dirname(__file__) + '/key.json'
   os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = key_path

2. Чтение из GCS

Поскольку мы будем принимать данные из DataFrame в GCS, давайте прочитаем 100 изображений из облачного хранилища, закодируем их и сохраним в кадре данных pandas.

import pandas as pd
from datetime import datetime, timezone

from google.cloud import storage

def readFromGCS(SOURCE_BUCKET: str):
# Read images from GCS bucket and convert them from jpeg to string
# Then define DataFrame in put all the information there

   image_id = []
   image_byte = []
   update_time = []

   client = storage.Client()
   bucket = client.get_bucket(SOURCE_BUCKET)
   blobs = list(bucket.list_blobs())
   i = 1
   for blob in blobs:
       image_id.append('image-' + str(i))
      
       img_byte = blob.download_as_bytes()
       image_byte.append(img_byte)
      
       feature_time_str = datetime.now().isoformat(sep=" ", timespec="milliseconds")
       feature_time = datetime.strptime(feature_time_str, "%Y-%m-%d %H:%M:%S.%f")
       update_time.append(feature_time)
      
       i += 1
      
   imageDF = pd.DataFrame(list(zip(image_id, image_byte, update_time)), columns =['image_id', 'image_byte', 'update_time']) 
  
   print('===================================================================')
   print(f'==========> 1. Image dataframe is created with {len(imageDF)} rows')
   print('===================================================================')
   return imageDF

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

Существуют и другие типы данных:

  • BOOL
  • BOOL_ARRAY
  • ДВОЙНОЙ
  • DOUBLE_ARRAY
  • INT64
  • INT64_ARRAY
  • НИТЬ
  • STRING_ARRAY
  • БАЙТ

Почему мы выбираем байты? Изначально было два варианта, которые легко работают с форматом jpeg. Это STRING и BYTES. Метод download_as_string() устарел, вместо него используется download_as_bytes() для загрузки содержимого большого двоичного объекта в виде объекта bytes.

Датафрейм состоит из 3 столбцов:

  • image_id
  • image_byte
  • Время обновления

Источник, будь то DataFrame, файл csv или avro в облачном хранилище или BigQuery, должен содержать не менее 3 столбцов. Первым всегда является тип объекта, вторым — функция (у нас может быть более одной функции), а последний столбец — время_обновления. который включает предоставленные пользователем временные метки для загруженных значений функций. Мы можем указать конкретную метку времени для каждого значения или указать одну и ту же метку времени для всех значений.

3. Создайте хранилище функций, тип объекта, функцию и загрузите данные

import pandas as pd

from google.cloud import aiplatform
from google.cloud.aiplatform import Feature, Featurestore

def FeatureStore(PROJECT_ID: str, REGION: str, FEATURESTORE_ID: str, ONLINE_STORE_FIXED_NODE_COUNT: int, source: pd.DataFrame):
   # Create Featurestore
   fs = Featurestore.create(
       featurestore_id=FEATURESTORE_ID,
       online_store_fixed_node_count=ONLINE_STORE_FIXED_NODE_COUNT,
       project=PROJECT_ID,
       location=REGION,
       sync=True,
   )

   print('============================================================')
   print('==========> 2.', FEATURESTORE_ID, 'feature store is created.')
   print('============================================================')

   # Create Images Entity Type
   images_entity_type = fs.create_entity_type(
       entity_type_id="images",
       description="Images entity",
   )

   print('=============================================')
   print('==========> 3. images entity type is created.')
   print('=============================================')

   image_byte = images_entity_type.create_feature(
       feature_id="image_byte",
       value_type="BYTES",
       description="image converted from jpeg to byte",
   )

   print('=============================================')
   print('==========> 4. image_byte feature is created.')
   print('=============================================')

   # Import to Feature Store from dataframe
   IMAGES_FEATURES_IDS = [feature.name for feature in images_entity_type.list_features()]
   IMAGES_FEATURE_TIME = "update_time"
   IMAGES_ENTITY_ID_FIELD = "image_id"
           
   # DATAFRAME
   images_entity_type.ingest_from_df(
       feature_ids = IMAGES_FEATURES_IDS,
       feature_time = IMAGES_FEATURE_TIME,
       df_source = source,
       entity_id_field = IMAGES_ENTITY_ID_FIELD,
   )

   print('===============================================')
   print('==========> 5. Batch ingestion process is done.')
   print('===============================================')

Функция FeatureStore заботится о создании Feature Store, типа сущности, называемого images, и одной функции, называемой image_byte, которая включает данные закодированных изображений. После этого функция организует процесс приема данных из DataFrame в хранилище объектов. При загрузке из DataFrame в хранилище объектов автоматически создается временный набор данных BigQuery (промежуточное хранилище для загрузки значений функций из DataFrame в хранилище объектов) для передачи после того, как последний будет удален в том же проекте GCP.

4. Показ в Интернете

from google.cloud import aiplatform

def onlineServing(PROJECT_ID: str, REGION: str, FEATURESTORE_ID: str, entity_ids: str):

   aiplatform.init(project=PROJECT_ID, location=REGION)
   my_entity_type = aiplatform.featurestore.EntityType(
           entity_type_name='images', featurestore_id=FEATURESTORE_ID
       )
   my_dataframe = my_entity_type.read(entity_ids=entity_ids, feature_ids='image_byte')

   print('========================================================')
   print(f'==========> 6. Computer randomly selected {entity_ids}.')
   print('========================================================')

   return my_dataframe

Онлайн-обслуживание позволяет нам обслуживать значения функций для небольших групп сущностей с низкой задержкой. Для каждого запроса вы можете предоставлять значения функций только из одного типа сущности. Vertex AI Feature Store возвращает только последнее ненулевое значение каждой функции.

В функции onlineServing случайно выбранные entity_id считываются из хранилища объектов в фрейм данных.

5. Перенос из магазина функций в облачное хранилище

import pandas as pd
from google.cloud import storage

def backToBucket(df: pd.DataFrame, DESTINATION_BUCKET: str):
   imgByte = df['image_byte'][0]
   imgName = 'img' + df['entity_id'][0][6:] + '.jpg'

   f = open(imgName, 'wb')
   f.write(imgByte)
   f.close()

   client = storage.Client()
   bucket = client.get_bucket(DESTINATION_BUCKET)
   blob = bucket.blob(imgName)
   blob.upload_from_filename(imgName)

print('=============================================================================')
print(f'==========> 7. Randomly selected image is converted from bytes to jpg and uploaded into {DESTINATION_BUCKET}.')
   print('=============================================================================')
print('==============================')
print('==========> Just go and check!')
print('==============================')

Здесь случайно выбранное изображение декодируется и переносится обратно в облачное хранилище.

6. Удалить магазин функций

Последнее действие, которое делает наше приложение, — это удаление хранилища функций просто для экономии денег.

from google.cloud import aiplatform

def deletFS(PROJECT_ID: str, REGION: str, FEATURESTORE_ID: str):

   aiplatform.init(project=PROJECT_ID, location=REGION)
   fs = aiplatform.featurestore.Featurestore(featurestore_name=FEATURESTORE_ID)
   fs.delete(sync=True, force=True)

   print('===========================================================')
   print('==========> 8.', FEATURESTORE_ID, 'feature store is deleted')
   print('===========================================================')

7. Выполнение программы выше

Прежде всего, давайте соберем всю необходимую информацию.

PROJECT_ID = ...
REGION = ...
SOURCE_BUCKET = ...
DESTINATION_BUCKET = ...
FS = ...
ONLINE_STORE_FIXED_NODE_COUNT = ...
FEATURESTORE_ID = ...

Теперь давайте запустим приложение.

import random

# GOOGLE  CREDENTIALS
gcpCredentials.specifyGoogleCredentials()

# READ  IMAGES  FROM  GCS,  CREATE  DATAFRAME
df = readFromGCS(SOURCE_BUCKET)

# CREATE  FEATURE  STORE, MANAGE BATCH INGESTION
FeatureStore(PROJECT_ID, REGION, FEATURESTORE_ID, ONLINE_STORE_FIXED_NODE_COUNT, df)

# ONLINE SERVING, READ A RANDOMLY SELECTED IMAGE
entity_ids = 'image-' + str(random.randint(1, 100))
testDF = onlineServing(PROJECT_ID, REGION, FEATURESTORE_ID, entity_ids)

# DECODE A RANDOMLY SELECTED IMAGE AND PUT IT BACK INTO BUCKET
backToBucket(testDF, DESTINATION_BUCKET)

# DELETE FEATURE STORE
deletFS(PROJECT_ID, REGION, FEATURESTORE_ID)

Вот как вы можете разработать конвейер, который выполняет прием и обслуживание функций. Наслаждайтесь процессом!

Свяжитесь со мной через LinkedIn.