Платформа для анализа данных за вечер

Как поднять платформу для анализа данных за вечер

Рассказываем, как подготовить облачное окружение и начать работу с Jupyter, Superset, PostgreSQL и другими инструментами.

Изображение записи

Текущее состояние российского рынка аналитических и ML-решений сложно назвать стабильным. Какие-то инструменты более недоступны, а на их место регулярно приходят новые. Причем не только вендорские, но еще и open source, а также облачные сервисы. 

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

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

В статье рассказываем, как всего за час (или почти) подготовить облачное окружение, создать свою небольшую платформу для анализа данных и спарсить весь Hugging Face.

Набор джентельмена: инструменты для аналитики

Для начала давайте разберемся, какие инструменты нужны для базовых задач — простого исследования данных (EDA), построения наглядных визуализаций, регрессионного анализа, прогнозирования, классификации, кластеризации или обучения ML-моделей. Можно выделить следующий джентльменский набор:

  • Jupyter, Zeppelin или DataSpell — среды разработки для DataScince- и ML-специалистов.
  • Airflow, Prefect или Dagster — инструменты для построения пайплайнов обработки данных. Помогает регулярно запускать ETL-процессы и мониторить результаты их выполнения.
  • Metabase, Power BI, Superset, Redash, Tableau или Qlik — компонент для визуализации данных и построения дашбордов.
  • Базы данных PostgreSQL, Clickhouse или облачные DataWarehouse — неотъемлемая часть каждой платформы для анализа данных. 
  • Python и специализированные библиотеки — например, TensorFlow или PyTorch. Выбор зависит от вашей задачи.

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

Выбор сервера

Выделенный сервер можно более гибко настроить, в том числе и на уровне железа. Ресурсы ни с кем делить не нужно — вычислительные мощности работают только на вас.

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

Однако нужно помнить, что для настройки всех компонентов понадобится навык работы с Docker или Linux, а также время, которое есть не всегда. Многие инструменты, упомянутые в начале статьи, — это решения с открытым исходным кодом, настройка которых может занять более одного вечера. Помимо этого, необходимо выбрать и правильно настроить веб-сервер (Nginx или Apache), на котором будут запущены нужные инструменты.

Чтобы сэкономить свое время и не разбираться с сотнями страниц документации, корректной настройкой Nginx и другими компонентами, можно арендовать DAVM (Data Analytics Virtual Machine) — виртуальный сервер с предустановленным набором инструментов для анализа данных и машинного обучения. Среди них — Jupyter Lab, Superset и Prefect.

DAVM быстро разворачивается и позволяет:

  • строить процессы обработки данных (ETL/ELT) с помощью Prefect,
  • разрабатывать ML-модели с помощью PyTorch, TensorFlow, Keras, XGBoost, OpenCV в интерактивной среде JupyterLab,
  • визуализировать данные с помощью Apache Superset.

Все инструменты уже настроены и готовы к работе, поэтому экономить время удается на каждом этапе.

Парсинг и обработка данных

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

Подготавливаем облачное окружение

Запустить сервер DAVM можно всего за несколько шагов:

  1. Переходим в раздел Облачная платформа внутри панели управления.
  2. Выбираем пул ru-7a и создаем облачный сервер с дистрибутивом Ubuntu LTS Data Analytics 64-bit и нужной конфигурацией.

Подробная инструкция по созданию и запуску DAVM доступна в документации.

Выбор дистрибутива для Data Analytics Virtual Machine.
Важно, чтобы сервер был доступен из интернета, иначе с компьютера не подключиться. Для этого во время настройки конфигураций выберите новый публичный IP-адрес.

Подключаемся к DAVM

Нужно дать системе пару минут на подгрузку всех Docker-образов. Потом нужно подключиться к серверу по SSH — тогда он покажет данные для авторизации в окружении DAVM.

Данные для подключения к DAVM.

Теперь, если перейти по ссылке из сообщения и авторизоваться в DAVM, можно запустить JupyterLab, Keycloak, Prefect или Superset.

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

Парсим данные с Hugging Face

Для примера напишем простой парсер библиотеки Hugging Face. А после — загрузим полученную информацию в базу данных и построим дашборд для визуализации.

Получение данных

Для парсинга данных будем использовать стандартный API Hugging Face. Для этого устанавливаем через pip и импортируем необходимые библиотеки в программу:


    import pandas as pd
import matplotlib.pyplot as plt
from datetime import datetime
from sqlalchemy import create_engine
import json
from huggingface_hub import HfApi
from huggingface_hub import ModelSearchArguments, DatasetSearchArguments

Далее необходимо инициализировать API Hugging Face и спарсить датасеты, модели и метрики:


    # инициализируем API, парсим модели и датасеты
# получите токен по ссылке: https://huggingface.co/settings/token
api = HfApi(token="ваш токен")
hugging_face_models = list(iter(api.list_models()))
hugging_face_datasets = list(iter(api.list_datasets()))

# выводим количество моделей и датасетов
print(len(hugging_face_models))
print(len(hugging_face_datasets))

# загружаем поля (свойства и атрибуты) моделей и датасетов
for i in range(len(hugging_face_models)):
    hugging_face_models[i] = hugging_face_models[i].__dict__
for i in range(len(hugging_face_datasets)):
    hugging_face_datasets[i] = hugging_face_datasets[i].__dict__

# переводим данные объектов в json
hugging_face_models_json = json.dumps(hugging_face_models)
hugging_face_datasets_json = json.dumps(hugging_face_datasets)

Обработка результата

Теперь то, ради чего мы и парсим Hugging Face. Данные из этой библиотеки можно использовать для сравнения моделей и поиска лучших. А также, например, для поиска датасетов под свои задачи:


    # настраиваем отображение датафреймов
pd.options.display.max_rows = 200
pd.options.display.max_colwidth = None
n = 20

# читаем json-структуру с моделями
models_slice_df = pd.read_json(hugging_face_models_json)
# сортируем значения по лайкам и скачиваниям
models_slice_df.sort_values(["likes", "downloads"], ascending=False).head(n)
Отсортированный по лайкам список моделей Hugging Face.

Готово — в нотбуке появился отсортированный список моделей Hugging Face. То же самое можно провернуть с датасетами и другими спаршенными данными. Также для моделей можно назначить «домены», которые помогут при анализе данных.


    task2domain = {
    "text-classification": "natural-language-processing",
    "reinforcement-learning": "reinforcement-learning",
    "text2text-generation": "natural-language-processing",
    "text-to-image": "multimodal",
    ...
    "depth-estimation": "computer-vision",
    "document-question-answering": "multimodal",
    "text-to-video": "multimodal",
    "visual-question-answering": "multimodal",
    "voice-activity-detection": "audio",
    "robotics": "robotics",
    "other": "unknown-domain",
    "graph-ml": "graph",
    "time-series-forecasting": "time-series"
}
models_slice_df["domain"] = models_slice_df.pipeline_tag.apply(lambda tag: task2domain.get(tag, "unknown-domain"))
models_slice_df["slice_datetime"] = datetime.now()
models_slice_df.sort_values(["likes", "downloads"], ascending=False).head(n)
Датафрейм с моделями.
Код шаблона для работы с датасетами и моделями Hugging Face доступен в нашем репозитории на GitHub. Делайте форк и предлагайте свои улучшения!

При желании можно автоматизировать процесс парсинга данных и регулярно обновлять датасет, написав один небольшой flow в Prefect. Для простоты, мы опустим подобные детали, но вы можете посмотреть реализацию в нашем репозитории.

Подключение базы данных 

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

Создаем кластер PostgreSQL

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

Создать кластер PostgreSQL можно в несколько кликов:

1. Переходим в раздел Облачная платформа → Базы данных в панели управления.

2. Выбираем пул и нажимаем Создать кластер. Рекомендуем выбрать пул в Санкт-Петербурге — в нем же находится сервер DAVM. Близость обеспечит высокую скорость передачи данных. 

3. Настраиваем кластер. При желании можно увеличить или уменьшить количество реплик.

Создание кластера PostgreSQL.

4. Кликните по кластеру, создайте нового пользователя и саму базу данных. Сохраните пароль — его нельзя будет посмотреть в панели управления. 

Настраиваем подключение

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

Выходим из панели управления и возвращаемся в DAVM, чтобы подключиться к PostgreSQL. В DAVM уже установлена библиотека для работы с ней — psycopg. Поэтому открываем JupyterLab и просто делаем Ctrl+C:


    import psycopg2

con = psycopg2.connect(
    host="master.1a029756-adce-44cb-b0fc-f195cb3562fe.c.dbaas.selcloud.ru",
    dbname=<database_name>,
    user=<database_user_name>,
    password=<database_password>,
    port=5432
)
cur = con.cursor()
cur.execute('SELECT 40+2')
print(cur.fetchone())
cur.close()
con.close()

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

1. Переходим в терминал JupyterLab и добавляем новые секреты:


    nano /home/davm/.prefect/config.toml

    [context.secrets]
DB_HOST = "master.1a029756-adce-44cb-b0fc-f195cb3562fe.c.dbaas.selcloud.ru"
DB_NAME = "davm_db"
DB_USER = "davm_db_user"
DB_PASSWORD = "c8BVYD2oj6n2"

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


    from prefect.client import Secret
import psycopg2
...

con = psycopg2.connect(
    host=Secret("DB_HOST").get(),
    dbname=Secret("DB_NAME").get(),
    user=Secret("DB_USER").get(),
    password=Secret("DB_PASSWORD").get(),
    port=5432
)
cur = conn.cursor()
cur.execute('SELECT 40+2')

print(cur.fetchone())
cur.close()
con.close()

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

Загружаем датафреймы

Чтобы наша платформа загружала в облачную базу данных информацию по моделькам и датасетам с Hugging Face, будь то датасеты или модели, нужно описать создание соответствующих таблиц:

create_tables.sql, запрос для создания таблиц.

После необходимо добавить код для запуска crete_tables.sql:


    from prefect.client import Secret
import psycopg2
from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT
...

con = psycopg2.connect(
    host=Secret("DB_HOST").get(),
    dbname=Secret("DB_NAME").get(),
    user=Secret("DB_USER").get(),
    password=Secret("DB_PASSWORD").get(),
    port=5432
)
con.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT)
cur = conn.cursor()

# последовательно создаем таблицы, 
# описанные в транзакции create_tables.sql 
with open("create_tables.sql", "r") as file:
    cursor.execute(file.read())

Дело осталось за малым — нужно загрузить сами датафреймы. Это можно сделать через sqlalchemy:


    from sqlalchemy import create_engine
… 

engine = create_engine('postgresql://{}:{}@{}:5432/{}'.format(db_user, db_password, db_host, db_name))
models_df = pd.read_sql('hugging_face_models', engine)
models_df.head()
datasets_df = pd.read_sql('hugging_face_datasets', engine)
datasets_df.head()

# подготовка масок для загрузки данных в таблицы
models_mask = [col for col in models_df.columns if col not in ["likes", "downloads"]]
datasets_mask = [col for col in datasets_df.columns if col not in ["likes", "downloads"]]
if len(models_slice_df[~models_slice_df.modelid.isin(models_df.modelid)]) > 0:
    models_slice_df[~models_slice_df.modelid.isin(models_df.modelid)][models_mask].to_sql('hugging_face_models', engine, if_exists='append', index=False)
if len(datasets_slice_df[~datasets_slice_df.datasetid.isin(datasets_df.datasetid)]) > 0:
    datasets_slice_df[~datasets_slice_df.datasetid.isin(datasets_df.datasetid)][datasets_mask].to_sql('hugging_face_datasets', engine, if_exists='append', index=False)

# для таблиц daily_dynamics используем другие маски.
# daily_dynamic нужны, чтобы мониторить ТОП датасетов и моделей
models_mask = ["modelid", "likes", "downloads", "slice_datetime"]
datasets_mask = ["datasetid", "likes", "downloads", "slice_datetime"]
models_slice_df[models_mask].to_sql('hugging_face_models_daily_dynamics', engine, if_exists='append', index=False)
datasets_slice_df[datasets_mask].to_sql('hugging_face_datasets_daily_dynamics', engine, if_exists='append', index=False)

Готово — данные загружены. В таблицах hugging_face_models и hugging_face_datasets загружены сами модели и датасеты, а в hugging_face_models_daily_dynamics и hugging_face_datasets_daily_dynamics — их показатели популярности на Hugging Face.

Визуализация данных

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

Знакомство с Superset

Для начала запускаем Superset и в разделе Settings → Database Connectionsподключаемся к нашей облачной базе данных:

В меню Datasets необходимо добавить датафреймы, которые хотите проанализировать:

После загрузки датафреймов можно построить графики. Какие именно — решать вам. В рамках примера сгенерируем столбцовую диаграмму (bar chart), чтобы посмотреть, какие типы моделей встречаются на Hugging Face чаще всего. Для этого нужно перейти в раздел Charts, выбрать соответствующий тип графика, в качестве Chart Source указать hugging_face_models и настроить параметры отображения:

Как мы видим, большинство моделей помечены авторами, как other (unknown-domain). Почему так — открытый вопрос. Но стало понятно, что не все, например, модели текстовой классификации можно найти по тегу natural-language-processing.

Настройка источников данных

Можно пойти дальше и построить столбцовую диаграмму, которая покажет, какой тип модели самый популярный. Но для этого нужно объединить два датафрейма — hugging_face_models и hugging_face_models_daily_dynamics. Из первого мы получим типы моделей, а из второго — количество лайков и скачиваний.

Объединить датафреймы можно с помощью специального SQL-запроса в разделе SQL → SQL Lab:

Параметр modelid — общий для hugging_face_models и huggins_face_models_dayli_dynamics. Поэтому объединяем таблицы по нему.

У нас получилась новая таблица — источник данных с полями modelid, likes, downloads и pipeline_tag. Аналогичным образом можно перейти в раздел Charts и создать гистограмму с рейтингом популярности моделей:

Готово — диаграмма построена, первое место занимают модели текстовой генерации.

Заключение

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

Подключайтесь к нашему репозиторию на GitHub, делайте форк и используйте его в качестве референса, если хотите разобрать кейс из статьи подробнее. До связи!