company_banner

Нейросети и Process Mining: пытаемся подружиться

    Process Mining — область анализа данных, позволяющая выполнять анализ процессов на основе логов информационных систем. Поскольку публикаций по теме применения машинного обучения в данной сфере на Хабре очень мало, мы решили поделиться нашим опытом разработки предиктивных моделей для решения процессно-ориентированных задач. В рамках программы ВТБ IT-юниор для начинающих IT-специалистов стажеры команды Process mining провели апробацию методов машинного обучения в контексте задач исследования процессов банка. Под катом мы расскажем о том, когда и как у нас возникла идея решения таких задач, что мы делали и какие результаты получили.



    Программа IT-Юниор — ежегодная программа стажировок для начинающих IT-специалистов в банке ВТБ, которая впервые стартовала в сентябре 2019 года. Стажировка длится полгода. По результатам программы 2019 года  больше половины стажеров перешли в штат и стали сотрудниками компании. Подробнее о программе, старте отбора и требованиях к кандидатам можно узнать по ссылке. Вот как подошли к решению задач банка стажеры этой программы.

    В классической системе координат, чтобы понять и формализовать процесс, необходимо:

    • провести интервью с сотрудниками;
    • проанализировать доступные отчеты и документацию.

    В подходе Process Mining цифровая модель процесса формируется на основе не только экспертного мнения участников процесса, но и актуальных данных из информационных систем.

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

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

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

    Далее мы пошагово опишем, как мы решали задачу предсказания длительности процесса закупки (на примере датасета BPI Challenge 2019) по набору известных событий с использованием высокопроизводительной станции DGX Station, любезно предоставленной нам для проведения исследования компанией NVIDIA.

    Применение машинного обучения для Process Mining


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

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

    Описание данных


    Было решено использовать внешние данные, которые подходили бы нам по бизнес-области и обладали схожим набором признаков. Используемый датасет BPI Challenge 2019 включает 250 тыс. кейсов — это 1,5 млн событий. Исходные данные описываются набором из 21 признака: 18 категориальных (есть индексовые признаки), два булевых и один вещественный. В качестве целевой переменной было выбрано время исполнения закупочного процесса, что соответствовало реальным потребностям бизнеса. Для детального описания признаков можно обратиться к описанию датасета.

    Baseline


    До обучения моделей данные были разделены на обучающую (train) и тестовую (test) выборки в отношении 0.8 / 0.2. При этом разделение происходило не по событиям, а по кейсам.

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

    • Время с прошлого события. Считаем время, прошедшее между двумя событиями с одним лишь нюансом: мы не хотим нулей между событиями, то есть если два события идут друг за другом, но с одинаковым временным штампом, то для последнего из них мы считаем время до события, идущего до него, но обязательно с отличным временным штампом.
    • Exponential Moving Average на времени с прошлого события. EMA считаем для каждого кейса отдельно, чтобы зафиксировать тренд по временным промежуткам для разных кейсов.
    • По традиции добавляем характеристики даты (месяц, день, день недели).

    После обучения CatBoostRegressor на обучающей выборке мы получили следующий результат: MAE (Mean Absolute Error) = 17,5 дня (то есть значение предсказанной целевой переменной в среднем отличается от истинного значения на 17,5 дня). Этот результат был использован для проверки эффективности нейронной сети. 

    Одна из важных деталей здесь — это разработка целевой переменной для baseline. 

    Пусть у нас есть кейс. Обозначим его c_i из множества C (множества всех кейсов в нашем датасете). Каждый кейс — это упорядоченная последовательность событий, то есть c_i = (e_0, ..., e_ni ), где ni — длина i-го кейса. Для каждого события у нас есть временной штамп — точное время его начала. По этим временным штампам можно посчитать длительность кейса без последнего события. Однако присваивать такой таргет каждому событию, то есть сделать соответствие ek ∈ ci, ek → ti (ti − длительность i-го кейса), не очень хорошо. Во-первых, в разных по длительности кейсах могут встречаться похожие события (типовые). Во-вторых, мы хотим предсказывать длительность кейса по некоторой подпоследовательности (упорядоченной во времени) событий (это мотивировано тем, что мы как бы не знаем целую последовательность событий, то есть не знаем кейс до того, как он произошел, но хотим сделать оценку длительности целого кейса по некоторым известным (произошедшим) событиям из этого кейса).

    Поэтому нужно разбить каждый кейс на подпоследовательности длины от единицы до длины кейса упорядоченных по времени событий и каждой такой последовательности назначить целевую переменную, равную длительности кейса, из которого эти подпоследовательности получаются, то есть соответствия ci ∈ C, ci → {sub_cj}ni (ni, как и раньше, длина i-го кейса), j=1 и len(sub_cj ) = j.

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

    Подробнее о подпоследовательностях

    Как было сказано ранее, мы разбиваем кейс на подпоследовательности и каждой из них присваиваем длительность кейса. Мы собираемся использовать бустинг, который требователен к размеру входных данных. Так, сейчас у нас есть X = {{sub_cki } ni k=1}t=1 N, sub_c ik – k-ая подпоследовательность i-го кейса, ti — длина i-го кейса, N — количество кейсов. То есть размерность [∑N t=1 ni, sc, 17], sc — переменная величина, равная длине подпоследовательности соответствующего кейса.

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

    После усреднения sc по размерности получаем следующую размерность: [∑N t=1 ni, 17].

    Построение модели

    На основании кейсов делим train на ещё один train и валидационную выборку, берем CatBoostRegressor c дефолтными параметрами, передаем ему обучающую выборку, валидируемся на валидационной выборке, берем лучшую итерацию, используем MAE как валидационную метрику. Получаем следующее (на рисунке ниже) на тесте (отдельно готовим тест по тому же pipeline, по которому строили train. Все признаки основаны на данных, которые есть в тесте, то есть у нас нет признаков, которые ориентированы на целевую переменную. Единственный нюанс: если в категориальных признаках в тесте не встречается значение, которое мы видели в train, то считаем частоту этого значения на тесте и обновляем словарь для кодирования).

    Результаты baseline



    • Iterations: 500.
    • Learning rate: 0.1.

    Параметры обучения:

    • Время на обучение: меньше 2 минут.
    • Железо: Tesla k80 (из colab).

    Результаты:

    • Test MAE: 17,5 дня.
    • Средняя продолжительность кейса в тесте: 66,3 дня.

    Нейронная сеть


    Setup


    Для обучения нейронной сети данные были усовершенствованы: были построены эмбеддинги для категориальных переменных, а также скорректировано распределение целевой переменной.  Далее нейронная сеть была обучена на NVIDIA Tesla K80 (Google Colab) и на NVIDIA DGX Station.

    Были получены следующие результаты:

    • Время на обучение на NVIDIA K80 (Google Colab): 20 минут.
    • Время на обучение на NVIDIA DGX Station: 8 минут.

    Время обучения нейронной сети обусловлено разницей в технических характеристиках использованных GPU:
    NVIDIA Tesla K80 (Google Colab)
    NVIDIA DGX Station
    1X NVIDIA Tesla K80 12GB
    4X NVIDIA Tesla V100 32GB

    Препроцессинг


    Новые признаки

    • EMA на стоимости события: хотим уловить тренд по стоимости активностей для каждого кейса.
    • Type of flaw: в описании датасета можно найти информацию про четыре типа некоторой описательной статистики закупки (события) — эти типы разбиты на значения двух переменных в изначальном датасете. Мы это просто агрегируем обратно (если посмотреть описание датасета, будет понятно, о чем здесь речь).

    Категориальные признаки

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

    Эмбеддинги для категориальных переменных

    Определяем размерность эмбеддингов для каждой категориальной переменной:

    • Смотрим, сколько уникальных значений в категориальной переменной. Выбираем минимум из некоторой константы, которая обозначает минимум по размерности эмбеддингов для категориальных фичей с высокой кардинальностью, и количества уникальных значений, поделенного пополам. Другими словами: MUi  = min(CAT_EMBEDDING_DIM; (len(uniquei) + 1) // 2), CAT_EMBEDDING_DIM — константа, uniquei — уникальные значения i-ой категориальной фичи.
    • Не хотим, чтобы размерность эмбеддингов была меньше 3, поэтому в итоге выбираем размерность для i-й категориальной фичи как max(3;MUi)+1, добавляем 1, потому что можем увидеть в тестовых данных значение, которое не видели на train, то есть это как бы unk-токен.

    Корректируем распределение таргета на train выборке 

    Изначальное распределение получилось очень сильно смещенным влево за счет выбросов (кейсов, которые длились 250 тыс. дней) и большого количества коротких кейсов, поэтому считаем 0,05 и 0,95 перцентили и оставляем данные из train с таргетом между этими порогами.

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

    Результат представлен на графике ниже (черная линия — нормальное распределение).



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

    Строим признаки


    Идея

    • Мы берем только категориальные признаки из нашего train, кодированные натуральными числами.
    • Берем не подстроки из кейсов, а просто события, то есть одна строка в наших данных для эмбеддингов — это одно событие, характеризующееся закодированными категориальными признаками.
    • Целевая переменная: каждому событию присваиваем целевую переменную, равную длительности кейса, из которого мы взяли это событие, исходя из того, что мы хотим выучить такие эмбеддинги категориальных переменных, которые хорошо улавливали бы соответствие между набором категориальных переменных в подпоследовательности событий в кейсе и длительностью этого кейса. Из-за того, что большинство категориальных переменных принимает одинаковое значение внутри кейса, каждое событие, в принципе, не сильно отличается от кейса (так как отсутствуют вещественные признаки), тем более для обучения эмбеддингов (а вообще пока просто не понятно, как по-другому дизайнить целевую переменную).
    • Каждую категориальную переменную в строке заменяем на соответствующий эмбеддинг и конкатенируем эти эмбеддинги в одну строку.
    • Целевая переменная на такую строку есть, поэтому подаем это в 8-слойный персептрон с elu в качестве активаций, считаем ошибку (мы подкорректировали таргет, поэтому можем считать, что мы находим хорошие веса, минимизируя L2-функционал) и делаем коррекцию для весов.
    • Матрицы, из которых мы берем эмбеддинги для категориальных переменных на каждом шаге, — обучаемые переменные в графе, поэтому градиенты считаются и на них, и так они учатся.
    • Summary: просто берем эмбеддинг — слой для каждой категориальной переменной и прогоняем это через персептрон с таргетом — длительностью кейса.

    Архитектура графа вычислений эмбеддингов


    • Batch size = 1000
    • Learning rate = 3e-04.
    • Количество эпох = 15.
    • Железо: Tesla k80 (colab) + Nvidia DGX Station .
    • Время (colab) – 50 минут.
    • Время (Nvidia DGX Station) — 18 минут.



    Архитектура модели


    Подготовка данных

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

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

    В том, как обучать этот вектор, кроется направление для улучшения модели. Идея состоит в том, что очень редкие значения в train можно кодировать этим вектором, потому что, если мы увидим новое значение уже только в тесте, который условно составляет 20% от всей исходной выборки, то это значение является редким и, наверное, ведет себя так же, как и редкие значения в train.

    Заменяем в каждом событии категориальные переменные на соответствующий эмбеддинг, соединяем с вещественными и булевыми признаками, получаем матрицу размера [N, F], где F — сумма размерностей эмбедингов для категориальных переменных, количество вещественных и булевых признаков.

    Осуществляем группировку событий в подпоследовательности (как делали ранее). Целевая переменная для подпоследовательности — длительность кейса, из которого была получена подпоследовательность. Добавляем в вектор подпоследовательности количество событий и сумму стоимостей событий в этой подпоследовательности.

    Теперь у нас есть матрица фиксированного размера — можно подавать в модель (перед этим нормируем матрицу).

    Метод распараллеливания

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

    Проблемы

    • К градиентному спуску добавляется еще стохастики за счет распиливания батча (сначала) и агрегирования (усреднения) градиентов (потом).
    • Очевидный нюанс: сервер параметров — это точка синхронизации, то есть если одна gpu тормозит с вычислением ее градиентов, то остальные будут простаивать, пока тормозящая gpu не справится со своими градиентами.

    Обучение

    • Архитектура: 7-слойный персептрон с активациями elu.
    • Таргет по распределению такой же, как при обучении эмбеддингов.
    • Batch size = 1000.
    • Learning rate = 3e-04.
    • Количество эпох = 15.
    • Железо: Tesla k80 (colab) + Nvidia DGX Station.
    • Время (colab) = 20 минут.
    • Время (Nvidia DGX Station) = 8 минут.

    Кусочек графа модели



    Потребление ресурсов и распараллеливание

    Обучение нейронных сетей на CPU занимает приблизительно в четыре раза больше времени, чем на NVIDIA DGX Station. В данном случае разница кажется незначительной — восемь минут на NVIDIA DGX Station и 32 минуты на CPU. Однако это небольшая модель с маленьким количеством данных. При реализации реальных проектов, где будет в несколько раз больше кейсов и событий, обучение на CPU будет занимать минимум неделю. В таком случае использование NVIDIA DGX Station уменьшит время обучения до двух дней, что сильно увеличит эффективность работы. 

    Также было выявлено, что скорость процесса обучения сильно зависит от количества используемых GPU, что показывает преимущество NVIDIA DGX Station.

    Это подтверждается проведенными ранее экспериментами на CPU и GPU NVIDIA DGX Station с использованием исходного набора данных без какой-либо предварительной обработки:

    • Время на обучение на CPU: 6 минут 18 секунд.
    • Время на обучение на GPU: 34 секунды.

    Визуализация загрузки GPU



    Визуализация загрузки CPU



    Результаты нейросети




    • Test MAE = 10 дней.
    • Средняя продолжительность кейса на тесте = 67 дней.
    • Inference time = 20 секунд.

    Выводы


    • Мы реализовали пилот для оценки методов машинного обучения в контексте задач Process Mining.
    • Апробировали и расширили перечень наших инструментов, которыми будем решать задачи, важные для бизнеса.
    • Одним из интересных результатов стало написание собственной реализации параллельных вычислений на 4 картах Тesla v100, которыми укомплектована DGX station: использование нескольких gpu ускоряет обучение почти в линию от количества gpu (код распараллелен).
    • Переход на полностью непрерывный вход и использование нейросети позволил снять с baseline’a неделю.
    • Время увеличивается с нескольких минут до полутора часов (обучение финальной архитектуры и эмбеддингов, но эмбеддинги можно использовать предобученные, поэтому время сокращается до 20 минут).

    Описанные эксперименты показывают, что в области Process mining можно успешно применять алгоритмы машинного и глубокого обучения. Кроме этого, было выявлено, что скорость процесса обучения сильно зависит от количества используемых GPU,  что показывает преимущество NVIDIA DGX Station.

    Что и как можно улучшить


    Word2vec-style эмбеддинги для событий

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

    Идея

    • Берем одну категориальную фичу и одну вещественную, делим вещественную на бакеты, тогда каждая транзакция будет характеризоваться значением категориальной переменной и бакетом, в который попадает значение вещественной переменной. Объединяем эти два значения, получаем как бы аналог слова для события.
    • Кейс рассматриваем как предложение (набор слов в предложении соответствует набору событий в кейсе).
    • Выбрать категориальный признак и посчитать бакеты нужно так, чтобы мощность получившегося словаря была намного меньше количества всех событий во всех кейсах, иначе может получиться так, что почти все предложения состоят из уникальных слов и здесь будет мало информации.
    • Когда получим корпус предложений, сформируем датасет для обучения Skipgram или CBOW и обучим эмбеддинги.
    • Когда обучим эмбединги, добавляем их к другим признакам транзакций, усредняем их по подпоследовательности вместе с остальными и так подаем в модель.

    Что получилось

    • Использовали архитектуру Skipgram.
    • Размер окна — 5.

    • Batch size = 1000.
    • Learning rate = 3e-04.
    • Количество эпох = 10.
    • Железо: Tesla k80 (colab) + Nvidia DGX Station.
    • Время (colab) — 20 минут.
    • Время (Nvidia DGX Station) — 8 минут.
    • Test MAE вместе с семантическими фичами: 10 дней. 

    Граф



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

    В итоге

    • Эмбеддинги получились, конечно, недообученные, потому что обучались мало.
    • Фичей из категориальных эмбедингов — около 290, а фичей из семантических эмбеддингов — 20 (делать больше не имеет смысла, потому что размер словаря небольшой), поэтому влияние этих семантических фичей может быть снивелированно из-за дисбаланса в пропорции фичей.
    • Семантику между событиями нужно как-то добавлять в обучающую выборку, ведь из-за того, что последовательности событий (кейсы) упорядоченные, порядок имеет значение, и из этого можно извлекать информацию.
    • Можно использовать более изощренные архитектуры для эмбеддингов.
    • Если решить проблему с дисбалансом и придумать, как лучше добавлять фичи из семантических эмбеддингов, может получиться здорово — это направление для улучшения модели.
    ВТБ
    Компания

    Комментарии 0

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

    Самое читаемое