Pull to refresh
64.89
ITMO
IT's MOre than a University

Подручный для бизнеса

Reading time10 min
Views2.5K

Введение

Всем привет! Я Дима Кирпа, студент ИТМО. Занимаюсь исследованиями современных ML и DL подходов для работы с табличными данными. Хочу рассказать об одной интересной задаче, с которой мне пришлось столкнуться.

В прошлом году мы с командой друзей из Семёна Орехова, Олега Неволина, Анастасии Сыпачевой, Валерии Бызовой и меня приняли участие в Хакатоне Finodays. Участникам предлагался шведский стол из самых горячих и вкусных проблем в области финтеха, среди которых больше всех нас привлекла задача от Альфа-банка в рамках трека «Искусственный интеллект и машинное обучение». Заключалась она в разработке решения, помогающего руководителям, продуктовым менеджерам и аналитикам искать точки роста и скрытые закономерности в своём продукте. Сервис должен принимать на вход описание продукта/бизнес-процесса/системы в табличном виде, а на выходе отдавать набор гипотез ― утверждений о данных, выраженных в виде текста и графиков. Гипотезы должны быть правдивыми и соответствовать поданным на вход данным. Сверх того, смысл задумки состоит в генерации креативных и полезных гипотез. Корреляции времени в пути с пройденным расстоянием или связь колонок ID и Time нас не интересует. Наша цель ― полноценный помощник бизнесу, который, например, по данным о продажах товаров может посоветовать, на каком их них стоит сосредоточиться и почему.

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

Вдохновленные задачей и сильной поддержкой коллег из Альфа-банка мы смогли разработать требуемый продукт, показать его на форуме Банка России и лидеров IT и финансового рынка Finopolis 2023, получить приз зрительских симпатий и несколько предложений о сотрудничестве от одних из известных финансовых организаций России.

Решение

Решение задачки мы начали с поиска примеров для подражания. 

Наиболее близкий аналог ― Kanaries: GPT powered visual analytics. Этот сервис умеет искать инсайты в данных, но сфокусирован именно на удобном визуальном представлении. Креатив и решение бизнес-задач в продукт не входят.

Что будет, если просто залить таблицу в ChatGPT в режиме Advanced Data Analysis? Можно получить крутую вопросно-ответную систему, помогающую быстро понять, о чём данные. Можно строить графики и получать разные статистики. Однако, опять же, креатив и поиск фактов из предметной области требует составления специального промпта, последовательных рассуждений и правильного представления данных. Для работы в таком режиме необходимы глубокое погружение в контекст данных и большие затраты времени. Наша же цель ― дать менеджеру понятные гипотезы сразу, по нажатию кнопки, не грузить статистикой и долгими разговорами с сеткой, обеспечить возможность работать с данными в любом представлении, без предобработок.

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

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

Для поиска решения, мы декомпозировали систему на 2 части:

 

1) «Понималка» данных, которая вычислит скрытые закономерности и поймёт, о чём вообще данные;

2) Генератор гипотез, который на основании представления о данных расскажет, что значат найденные закономерности, и предложит способы их применения.

Разберём каждую часть подробнее.

Понимаем данные

Во времена больших языковых моделей и сетей, генерирующих ёлочные игрушки, хочется взять какую-нибудь большую предобученную на все случаи жизни нейронку, натравить на данные, получить результат и наслаждаться победой. Однако количество нейросетевых архитектур, которые умеют работать с таблицами, довольно невелико, а их качество неидеально. Трансформеры на таблицах часто проигрывают решающим деревьям и бустингам. Архитектуры, уверенно чувствующие себя в схватке с классическими методами, начали появляться относительно недавно. Найти готовое и универсальное нейросетевое решение, очевидно, не выйдет. Подход Table2Text, где нейронка сворачивает таблицу в скрытое представление и разворачивает в текст, за 2 дня хакатона придётся изобретать самим. По этой причине мы переключились с нейронок и использовали гораздо более простое и понятное решение.

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

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

Генерируем гипотезы

На данном этапе у нас есть статистика по данным, текст описывающий смысл колонок и текст с общим смыслом таблицы. На основании этого довольно несложно сгенерировать гипотезы, попросив об этом ChatGPT или LLaMA. Здесь мы можем влиять на промпт любым образом, попросив сетку придумать способы доказательства, места применения, возможное объяснение закономерности или способы её отображения на графике.

Технические подробности

Объединим все части нашей схемы и получим готовый к бою продукт:

Более подробная схема работы выглядит следующим образом:

API состоит из ручек загрузки датасета (/upload), получения списков всех загруженных датасетов (/all_datasets), отображения подробной информации по конкретному датасету (/dataset) и ручки ответа на произвольный вопрос по заданному датасету (/dataset_chat).

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

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

Отдельного упоминания заслуживает система построения графиков. Самая простая идея ― попросить ChatGPT дать какое-то количество точек и отобразить их. В нашем случае, идея не лучшая: заслать 1Гб датасет и получить по нему разумное количество точек в четко выдержанном формате ― сложная и ненадежная схема. Раз в 10 запросов ChatGPT на наших промптах стабильно делала нарушения в JSON-формате, даже учитывая one-shot. Другой интересный подход ― PandasAI. Про эту библиотеку мы узнали слишком поздно. Можно попросить ChatGPT описать график для демонстрации гипотезы и заслать в PandasAI. Мы же сделали небольшую вариативность по типам графиков: столбчатый, круговой и линия и просили ChatGPT уточнить, какой из графиков был бы лучше.

Бэкенд-инфраструктура построена на связке FastAPI + Starlette. На нашем стенде на конференции стояло 4 компьютера, поэтому для надёжности запустили 4 воркера для каждого из них. Нагрузка не планировалась огромной, главное требование ― быстрая работа и возможность поддерживать 4 пользователей одновременно.

Все имеющиеся запчасти для плавности движений были смазаны асинхронностью. Использовали асинхронные методы OpenAI-клиента и библиотеку Motor для работы с MongoDB.

Одной из самой технически сложных задач было получение качественного ответа от LLM. Попытки вытащить список гипотез в заданном сетке формате успехом не увенчались. Под разные данные требовались разные промпты, текст получался размытым, сеть часто не выдерживала запрашиваемую структуру, упиралась в ограничение по токенам. Поэтому получение гипотезы из каждой корреляции мы разделили на разные запросы: за каждой гипотезой ходим в LLM отдельно. Один запрос в среднем занимал от 15 до 90 секунд. Если, к примеру, найдено 10 корреляций, то пользователю пришлось бы ждать минимум 15 * 10 = 150 секунд. Чтобы экономить, а не отнимать бесценное время наших пользователей, запросы мы стали пускать параллельно, сократив общую длительность получения гипотез до длительности получения самой долгой из них.

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

Из важных технических решений: сетку и её настройки мы скрываем за слоем ML. Вся остальная часть системы рассматривала LLM, как чёрный ящик, в которой можно послать текст и получить текст в ответ. Какая именно используется сеть, с какими настройками от оставшейся программы, было скрыто. Это позволило нам проводить опыты по сравнению работы GPT-3.5, GPT-4, LLAMA. Качество гипотез от LLAMA оказалось ожидаемо ниже гипотез от ChatGPT. Сравнение GPT-3.5 и GPT-4 не дало сильных различий в качестве при сильной разнице в стоимости.

Для пущего повышения производительности особо тяжелые части мы кэшируем стандартными питонячьими методами.

В итоге мы получаем гипотезы, пайплайн построен так, чтобы гипотезы были релевантны датасету. Но как обеспечить их полезность? Как получать настоящий креатив, а не зависимости колонок с ID товаров? В какой-то момент к нам пришла хорошая идея создать классификатор, который по тексту гипотезы понимал бы, насколько она хороша. Отказались, отдав предпочтение написанию более качественных промптов и более дотошному отбору корреляций. В итоге, глупые гипотезы практически исчезли без затрат лишних ресурсов и добавления ещё одного слабого места в производительности.

Разберем по шагам работу алгоритма на примере датасета «Титаник»:

  1. Вычисляем корреляции. Делается несложно: подчищаем датасет, преобразуем фичи, применяем метод .corr(). После, в зависимости от количества корреляций, отбираем верхний и нижние пороги корреляций. 100%-ные и 2%-ные корреляции нам явно не подходят. По «Титанику» мы нашли 54%-ную корреляцию между колонками

  1. Получаем краткую информацию по датасету, понимаем контекст данных по названиям колонок:

async def get_brief_info(columns: list[str], results):

    columns_as_str = ", ".join(columns)

    results["brief"] = await get_answer_gpt(

        f"В наборе данных есть колонки: {columns_as_str}. О чём эти данные? Дай ответ в одном предложении"

    )

Осмысленные названия значительно помогают модели, но даже для колонок “” модель верно поняла контекст (спойлер: “”). Если же колонки называются 1, 2, 3, то система работать не будет.

Для колонок «Титаника» (PassengerId,Survived,Pclass,Name,Sex,Age,SibSp,Parch,Ticket,Fare,Cabin,Embarked) получаем:

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

  1. Формулируем по корреляции и контексту гипотезу:

async def correlation_hypothesis_brief(main_text: str, sub_hypothesis: dict):

    title = await get_answer_gpt(f"{main_text}. Приведи краткое описание гипотезы, 5-10 слов")

    sub_hypothesis["title"] = title

async def correlation_hypothesis_full(main_text: str, sub_hypothesis: dict):

    main = await get_answer_gpt(f"{main_text}. Дай подробное описание гипотезы с обоснованием, примерами и способами проверки. Ответ дай в виде HTML-разметки")

    sub_hypothesis["main"] = main or ""

async def correlation_hypothesis(

    info_data: str, col1: str, col2: str, corr: float, result: dict, res_index: int

):

    try:

        sub_hypothesis = {}

        main_text = f"У нас есть {info_data}. Сформулируй гипотезу, зная, что корреляция между колонками {col1} и {col2} составляет {round(corr, 2)}"

        await asyncio.gather(

            asyncio.create_task(correlation_hypothesis_brief(main_text, sub_hypothesis)),

            asyncio.create_task(correlation_hypothesis_full(main_text, sub_hypothesis))

        )

        print(sub_hypothesis)

        result[res_index] = "\n\n".join([sub_hypothesis["title"], sub_hypothesis["main"]])

    except Exception as exep:

        print(f"Load hypothesis failed: {exep}")

        result[res_index] = None

В итоге получается следующая гипотеза:

Гипотеза: Пассажиры женского пола имели больше шансов на выживание, чем пассажиры мужского пола.

Расширенное описание гипотезы: Гипотеза заключается в том, что пол пассажира (мужской или женский) может быть связан с его выживаемостью на борту корабля. Корреляция между колонками Sex и Survived, равная 0.54, подтверждает эту гипотезу. Это означает, что существует положительная связь между полом пассажира и его выживаемостью ― женщины имели больше шансов на выживание, чем мужчины. Гипотеза также подтверждается фактами из истории катастрофы, где женщины и дети были предпочтительно эвакуированы на спасательных шлюпках.

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

На вход системе была подана только таблица. Никаких дополнительных описаний или пояснений.

Сборка приложения

Некоторое время были попытки избежать написания своего фронтенда, применив фреймоврк streamlit. Разработка на нём была довольно простой, а дизайн получался действительно сочный:

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

В итоге проект разместили в Яндекс Облаке. Использовали виртуалку и сервис Managed Mongo.

На текущий момент мы ведём работу над добавлением специфического контекста в запросы. Наша цель ― дать пользователю возможность гибко настраивать, какие гипотезы и в каком формате он хочет видеть. Наша же система, обладая знания про статистические закономерности в данных, сможет извлекать их и передавать правильный набор промптов в ChatGPT с тем, чтобы получить наиболее релевантные гипотезы. Также работаем над добавлением LLAMA-индекса, в который будем записывать корпоративную специфику и добавлять её в контекст. Идеальная форма системы ― рекомендательная система гипотез. Наша нейронка будет обучаться под генерацию самых качественных инсайтов.

Результат

Упаковываем в красивый дизайн и динамичный фронт и получаем Подручного ― лучшего помощника для бизнеса:

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

Итоги

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

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

Tags:
Hubs:
Total votes 4: ↑3 and ↓1+3
Comments1

Articles

Information

Website
en.itmo.ru
Registered
Founded
Employees
Unknown
Location
Россия
Representative
itmo